summaryrefslogtreecommitdiffstats
path: root/drivers/ddr/marvell
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ddr/marvell')
-rw-r--r--drivers/ddr/marvell/a38x/Makefile19
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_a38x.c741
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_a38x.h98
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h226
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_a38x_topology.h22
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_a38x_training.c40
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_debug.c1551
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c148
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h49
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h467
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h17
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_init.c852
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_init.h395
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_logging_def.h101
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h924
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_topology_def.h76
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training.c2644
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_bist.c289
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_centralization.c714
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_db.c652
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c686
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h14
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip.h180
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h54
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h15
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_db.h34
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_def.h173
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c1354
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h85
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h349
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h41
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h107
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_ip_static.h31
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_leveling.c1836
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_leveling.h17
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_pbs.c995
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_static.c538
-rw-r--r--drivers/ddr/marvell/a38x/ddr_topology_def.h112
-rw-r--r--drivers/ddr/marvell/a38x/ddr_training_ip_db.h16
-rw-r--r--drivers/ddr/marvell/a38x/silicon_if.h17
-rw-r--r--drivers/ddr/marvell/a38x/xor.c356
-rw-r--r--drivers/ddr/marvell/a38x/xor.h92
-rw-r--r--drivers/ddr/marvell/a38x/xor_regs.h236
-rw-r--r--drivers/ddr/marvell/axp/Makefile14
-rw-r--r--drivers/ddr/marvell/axp/ddr3_axp.h510
-rw-r--r--drivers/ddr/marvell/axp/ddr3_axp_config.h146
-rw-r--r--drivers/ddr/marvell/axp/ddr3_axp_mc_static.h284
-rw-r--r--drivers/ddr/marvell/axp/ddr3_axp_training_static.h770
-rw-r--r--drivers/ddr/marvell/axp/ddr3_axp_vars.h226
-rw-r--r--drivers/ddr/marvell/axp/ddr3_dfs.c1552
-rw-r--r--drivers/ddr/marvell/axp/ddr3_dqs.c1374
-rw-r--r--drivers/ddr/marvell/axp/ddr3_hw_training.c1115
-rw-r--r--drivers/ddr/marvell/axp/ddr3_hw_training.h392
-rw-r--r--drivers/ddr/marvell/axp/ddr3_init.c1219
-rw-r--r--drivers/ddr/marvell/axp/ddr3_init.h143
-rw-r--r--drivers/ddr/marvell/axp/ddr3_patterns_64bit.h924
-rw-r--r--drivers/ddr/marvell/axp/ddr3_pbs.c1592
-rw-r--r--drivers/ddr/marvell/axp/ddr3_read_leveling.c1214
-rw-r--r--drivers/ddr/marvell/axp/ddr3_sdram.c669
-rw-r--r--drivers/ddr/marvell/axp/ddr3_spd.c1300
-rw-r--r--drivers/ddr/marvell/axp/ddr3_write_leveling.c1366
-rw-r--r--drivers/ddr/marvell/axp/xor.c436
-rw-r--r--drivers/ddr/marvell/axp/xor.h70
-rw-r--r--drivers/ddr/marvell/axp/xor_regs.h103
64 files changed, 32782 insertions, 0 deletions
diff --git a/drivers/ddr/marvell/a38x/Makefile b/drivers/ddr/marvell/a38x/Makefile
new file mode 100644
index 0000000000..bf6ea4945f
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/Makefile
@@ -0,0 +1,19 @@
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD) += ddr3_a38x.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_a38x_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_debug.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_hws_hw_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_init.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_bist.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_centralization.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_db.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_hw_algo.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_ip_engine.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_leveling.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_pbs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_static.o
+obj-$(CONFIG_SPL_BUILD) += xor.o
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x.c b/drivers/ddr/marvell/a38x/ddr3_a38x.c
new file mode 100644
index 0000000000..f4699076e8
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define A38X_NUMBER_OF_INTERFACES 5
+
+#define SAR_DEV_ID_OFFS 27
+#define SAR_DEV_ID_MASK 0x7
+
+/* Termal Sensor Registers */
+#define TSEN_STATE_REG 0xe4070
+#define TSEN_STATE_OFFSET 31
+#define TSEN_STATE_MASK (0x1 << TSEN_STATE_OFFSET)
+#define TSEN_CONF_REG 0xe4074
+#define TSEN_CONF_RST_OFFSET 8
+#define TSEN_CONF_RST_MASK (0x1 << TSEN_CONF_RST_OFFSET)
+#define TSEN_STATUS_REG 0xe4078
+#define TSEN_STATUS_READOUT_VALID_OFFSET 10
+#define TSEN_STATUS_READOUT_VALID_MASK (0x1 << \
+ TSEN_STATUS_READOUT_VALID_OFFSET)
+#define TSEN_STATUS_TEMP_OUT_OFFSET 0
+#define TSEN_STATUS_TEMP_OUT_MASK (0x3ff << TSEN_STATUS_TEMP_OUT_OFFSET)
+
+static struct dfx_access interface_map[] = {
+ /* Pipe Client */
+ { 0, 17 },
+ { 1, 7 },
+ { 1, 11 },
+ { 0, 3 },
+ { 1, 25 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+};
+
+/* This array hold the board round trip delay (DQ and CK) per <interface,bus> */
+struct trip_delay_element a38x_board_round_trip_delay_array[] = {
+ /* 1st board */
+ /* Interface bus DQS-delay CK-delay */
+ { 3952, 5060 },
+ { 3192, 4493 },
+ { 4785, 6677 },
+ { 3413, 7267 },
+ { 4282, 6086 }, /* ECC PUP */
+ { 3952, 5134 },
+ { 3192, 4567 },
+ { 4785, 6751 },
+ { 3413, 7341 },
+ { 4282, 6160 }, /* ECC PUP */
+
+ /* 2nd board */
+ /* Interface bus DQS-delay CK-delay */
+ { 3952, 5060 },
+ { 3192, 4493 },
+ { 4785, 6677 },
+ { 3413, 7267 },
+ { 4282, 6086 }, /* ECC PUP */
+ { 3952, 5134 },
+ { 3192, 4567 },
+ { 4785, 6751 },
+ { 3413, 7341 },
+ { 4282, 6160 } /* ECC PUP */
+};
+
+#ifdef STATIC_ALGO_SUPPORT
+/* package trace */
+static struct trip_delay_element a38x_package_round_trip_delay_array[] = {
+ /* IF BUS DQ_DELAY CK_DELAY */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+};
+
+static int a38x_silicon_delay_offset[] = {
+ /* board 0 */
+ 0,
+ /* board 1 */
+ 0,
+ /* board 2 */
+ 0
+};
+#endif
+
+static u8 a38x_bw_per_freq[DDR_FREQ_LIMIT] = {
+ 0x3, /* DDR_FREQ_100 */
+ 0x4, /* DDR_FREQ_400 */
+ 0x4, /* DDR_FREQ_533 */
+ 0x5, /* DDR_FREQ_667 */
+ 0x5, /* DDR_FREQ_800 */
+ 0x5, /* DDR_FREQ_933 */
+ 0x5, /* DDR_FREQ_1066 */
+ 0x3, /* DDR_FREQ_311 */
+ 0x3, /* DDR_FREQ_333 */
+ 0x4, /* DDR_FREQ_467 */
+ 0x5, /* DDR_FREQ_850 */
+ 0x5, /* DDR_FREQ_600 */
+ 0x3, /* DDR_FREQ_300 */
+ 0x5, /* DDR_FREQ_900 */
+ 0x3, /* DDR_FREQ_360 */
+ 0x5 /* DDR_FREQ_1000 */
+};
+
+static u8 a38x_rate_per_freq[DDR_FREQ_LIMIT] = {
+ /*TBD*/ 0x1, /* DDR_FREQ_100 */
+ 0x2, /* DDR_FREQ_400 */
+ 0x2, /* DDR_FREQ_533 */
+ 0x2, /* DDR_FREQ_667 */
+ 0x2, /* DDR_FREQ_800 */
+ 0x3, /* DDR_FREQ_933 */
+ 0x3, /* DDR_FREQ_1066 */
+ 0x1, /* DDR_FREQ_311 */
+ 0x1, /* DDR_FREQ_333 */
+ 0x2, /* DDR_FREQ_467 */
+ 0x2, /* DDR_FREQ_850 */
+ 0x2, /* DDR_FREQ_600 */
+ 0x1, /* DDR_FREQ_300 */
+ 0x2, /* DDR_FREQ_900 */
+ 0x1, /* DDR_FREQ_360 */
+ 0x2 /* DDR_FREQ_1000 */
+};
+
+static u16 a38x_vco_freq_per_sar[] = {
+ 666, /* 0 */
+ 1332,
+ 800,
+ 1600,
+ 1066,
+ 2132,
+ 1200,
+ 2400,
+ 1332,
+ 1332,
+ 1500,
+ 1500,
+ 1600, /* 12 */
+ 1600,
+ 1700,
+ 1700,
+ 1866,
+ 1866,
+ 1800, /* 18 */
+ 2000,
+ 2000,
+ 4000,
+ 2132,
+ 2132,
+ 2300,
+ 2300,
+ 2400,
+ 2400,
+ 2500,
+ 2500,
+ 800
+};
+
+u32 pipe_multicast_mask;
+
+u32 dq_bit_map_2_phy_pin[] = {
+ 1, 0, 2, 6, 9, 8, 3, 7, /* 0 */
+ 8, 9, 1, 7, 2, 6, 3, 0, /* 1 */
+ 3, 9, 7, 8, 1, 0, 2, 6, /* 2 */
+ 1, 0, 6, 2, 8, 3, 7, 9, /* 3 */
+ 0, 1, 2, 9, 7, 8, 3, 6, /* 4 */
+};
+
+static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
+ enum hws_ddr_freq freq);
+
+/*
+ * Read temperature TJ value
+ */
+u32 ddr3_ctrl_get_junc_temp(u8 dev_num)
+{
+ int reg = 0;
+
+ /* Initiates TSEN hardware reset once */
+ if ((reg_read(TSEN_CONF_REG) & TSEN_CONF_RST_MASK) == 0)
+ reg_bit_set(TSEN_CONF_REG, TSEN_CONF_RST_MASK);
+ mdelay(10);
+
+ /* Check if the readout field is valid */
+ if ((reg_read(TSEN_STATUS_REG) & TSEN_STATUS_READOUT_VALID_MASK) == 0) {
+ printf("%s: TSEN not ready\n", __func__);
+ return 0;
+ }
+
+ reg = reg_read(TSEN_STATUS_REG);
+ reg = (reg & TSEN_STATUS_TEMP_OUT_MASK) >> TSEN_STATUS_TEMP_OUT_OFFSET;
+
+ return ((((10000 * reg) / 21445) * 1000) - 272674) / 1000;
+}
+
+/*
+ * Name: ddr3_tip_a38x_get_freq_config.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq,
+ struct hws_tip_freq_config_info
+ *freq_config_info)
+{
+ if (a38x_bw_per_freq[freq] == 0xff)
+ return MV_NOT_SUPPORTED;
+
+ if (freq_config_info == NULL)
+ return MV_BAD_PARAM;
+
+ freq_config_info->bw_per_freq = a38x_bw_per_freq[freq];
+ freq_config_info->rate_per_freq = a38x_rate_per_freq[freq];
+ freq_config_info->is_supported = 1;
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tip_a38x_pipe_enable.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_pipe_enable(u8 dev_num, enum hws_access_type interface_access,
+ u32 if_id, int enable)
+{
+ u32 data_value, pipe_enable_mask = 0;
+
+ if (enable == 0) {
+ pipe_enable_mask = 0;
+ } else {
+ if (interface_access == ACCESS_TYPE_MULTICAST)
+ pipe_enable_mask = pipe_multicast_mask;
+ else
+ pipe_enable_mask = (1 << interface_map[if_id].pipe);
+ }
+
+ CHECK_STATUS(ddr3_tip_reg_read
+ (dev_num, PIPE_ENABLE_ADDR, &data_value, MASK_ALL_BITS));
+ data_value = (data_value & (~0xff)) | pipe_enable_mask;
+ CHECK_STATUS(ddr3_tip_reg_write(dev_num, PIPE_ENABLE_ADDR, data_value));
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tip_a38x_if_write.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_if_write(u8 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 data_value,
+ u32 mask)
+{
+ u32 ui_data_read;
+
+ if (mask != MASK_ALL_BITS) {
+ CHECK_STATUS(ddr3_tip_a38x_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, reg_addr,
+ &ui_data_read, MASK_ALL_BITS));
+ data_value = (ui_data_read & (~mask)) | (data_value & mask);
+ }
+
+ reg_write(reg_addr, data_value);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tip_a38x_if_read.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_if_read(u8 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 *data, u32 mask)
+{
+ *data = reg_read(reg_addr) & mask;
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tip_a38x_select_ddr_controller.
+ * Desc: Enable/Disable access to Marvell's server.
+ * Args: dev_num - device number
+ * enable - whether to enable or disable the server
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_select_ddr_controller(u8 dev_num, int enable)
+{
+ u32 reg;
+
+ reg = reg_read(CS_ENABLE_REG);
+
+ if (enable)
+ reg |= (1 << 6);
+ else
+ reg &= ~(1 << 6);
+
+ reg_write(CS_ENABLE_REG, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tip_init_a38x_silicon.
+ * Desc: init Training SW DB.
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_tip_init_a38x_silicon(u32 dev_num, u32 board_id)
+{
+ struct hws_tip_config_func_db config_func;
+ enum hws_ddr_freq ddr_freq;
+ int status;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* new read leveling version */
+ config_func.tip_dunit_read_func = ddr3_tip_a38x_if_read;
+ config_func.tip_dunit_write_func = ddr3_tip_a38x_if_write;
+ config_func.tip_dunit_mux_select_func =
+ ddr3_tip_a38x_select_ddr_controller;
+ config_func.tip_get_freq_config_info_func =
+ ddr3_tip_a38x_get_freq_config;
+ config_func.tip_set_freq_divider_func = ddr3_tip_a38x_set_divider;
+ config_func.tip_get_device_info_func = ddr3_tip_a38x_get_device_info;
+ config_func.tip_get_temperature = ddr3_ctrl_get_junc_temp;
+
+ ddr3_tip_init_config_func(dev_num, &config_func);
+
+ ddr3_tip_register_dq_table(dev_num, dq_bit_map_2_phy_pin);
+
+#ifdef STATIC_ALGO_SUPPORT
+ {
+ struct hws_tip_static_config_info static_config;
+ u32 board_offset =
+ board_id * A38X_NUMBER_OF_INTERFACES *
+ tm->num_of_bus_per_interface;
+
+ static_config.silicon_delay =
+ a38x_silicon_delay_offset[board_id];
+ static_config.package_trace_arr =
+ a38x_package_round_trip_delay_array;
+ static_config.board_trace_arr =
+ &a38x_board_round_trip_delay_array[board_offset];
+ ddr3_tip_init_static_config_db(dev_num, &static_config);
+ }
+#endif
+ status = ddr3_tip_a38x_get_init_freq(dev_num, &ddr_freq);
+ if (MV_OK != status) {
+ DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
+ ("DDR3 silicon get target frequency - FAILED 0x%x\n",
+ status));
+ return status;
+ }
+
+ rl_version = 1;
+ mask_tune_func = (SET_LOW_FREQ_MASK_BIT |
+ LOAD_PATTERN_MASK_BIT |
+ SET_MEDIUM_FREQ_MASK_BIT | WRITE_LEVELING_MASK_BIT |
+ /* LOAD_PATTERN_2_MASK_BIT | */
+ WRITE_LEVELING_SUPP_MASK_BIT |
+ READ_LEVELING_MASK_BIT |
+ PBS_RX_MASK_BIT |
+ PBS_TX_MASK_BIT |
+ SET_TARGET_FREQ_MASK_BIT |
+ WRITE_LEVELING_TF_MASK_BIT |
+ WRITE_LEVELING_SUPP_TF_MASK_BIT |
+ READ_LEVELING_TF_MASK_BIT |
+ CENTRALIZATION_RX_MASK_BIT |
+ CENTRALIZATION_TX_MASK_BIT);
+ rl_mid_freq_wa = 1;
+
+ if ((ddr_freq == DDR_FREQ_333) || (ddr_freq == DDR_FREQ_400)) {
+ mask_tune_func = (WRITE_LEVELING_MASK_BIT |
+ LOAD_PATTERN_2_MASK_BIT |
+ WRITE_LEVELING_SUPP_MASK_BIT |
+ READ_LEVELING_MASK_BIT |
+ PBS_RX_MASK_BIT |
+ PBS_TX_MASK_BIT |
+ CENTRALIZATION_RX_MASK_BIT |
+ CENTRALIZATION_TX_MASK_BIT);
+ rl_mid_freq_wa = 0; /* WA not needed if 333/400 is TF */
+ }
+
+ /* Supplementary not supported for ECC modes */
+ if (1 == ddr3_if_ecc_enabled()) {
+ mask_tune_func &= ~WRITE_LEVELING_SUPP_TF_MASK_BIT;
+ mask_tune_func &= ~WRITE_LEVELING_SUPP_MASK_BIT;
+ mask_tune_func &= ~PBS_TX_MASK_BIT;
+ mask_tune_func &= ~PBS_RX_MASK_BIT;
+ }
+
+ if (ck_delay == -1)
+ ck_delay = 160;
+ if (ck_delay_16 == -1)
+ ck_delay_16 = 160;
+ ca_delay = 0;
+ delay_enable = 1;
+
+ calibration_update_control = 1;
+
+ init_freq = tm->interface_params[first_active_if].memory_freq;
+
+ ddr3_tip_a38x_get_medium_freq(dev_num, &medium_freq);
+
+ return MV_OK;
+}
+
+int ddr3_a38x_update_topology_map(u32 dev_num, struct hws_topology_map *tm)
+{
+ u32 if_id = 0;
+ enum hws_ddr_freq freq;
+
+ ddr3_tip_a38x_get_init_freq(dev_num, &freq);
+ tm->interface_params[if_id].memory_freq = freq;
+
+ /*
+ * re-calc topology parameters according to topology updates
+ * (if needed)
+ */
+ CHECK_STATUS(hws_ddr3_tip_load_topology_map(dev_num, tm));
+
+ return MV_OK;
+}
+
+int ddr3_tip_init_a38x(u32 dev_num, u32 board_id)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (NULL == tm)
+ return MV_FAIL;
+
+ ddr3_a38x_update_topology_map(dev_num, tm);
+ ddr3_tip_init_a38x_silicon(dev_num, board_id);
+
+ return MV_OK;
+}
+
+int ddr3_tip_a38x_get_init_freq(int dev_num, enum hws_ddr_freq *freq)
+{
+ u32 reg;
+
+ /* Read sample at reset setting */
+ reg = (reg_read(REG_DEVICE_SAR1_ADDR) >>
+ RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) &
+ RST2_CPU_DDR_CLOCK_SELECT_IN_MASK;
+ switch (reg) {
+ case 0x0:
+ case 0x1:
+ *freq = DDR_FREQ_333;
+ break;
+ case 0x2:
+ case 0x3:
+ *freq = DDR_FREQ_400;
+ break;
+ case 0x4:
+ case 0xd:
+ *freq = DDR_FREQ_533;
+ break;
+ case 0x6:
+ *freq = DDR_FREQ_600;
+ break;
+ case 0x8:
+ case 0x11:
+ case 0x14:
+ *freq = DDR_FREQ_667;
+ break;
+ case 0xc:
+ case 0x15:
+ case 0x1b:
+ *freq = DDR_FREQ_800;
+ break;
+ case 0x10:
+ *freq = DDR_FREQ_933;
+ break;
+ case 0x12:
+ *freq = DDR_FREQ_900;
+ break;
+ case 0x13:
+ *freq = DDR_FREQ_900;
+ break;
+ default:
+ *freq = 0;
+ return MV_NOT_SUPPORTED;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq)
+{
+ u32 reg;
+
+ /* Read sample at reset setting */
+ reg = (reg_read(REG_DEVICE_SAR1_ADDR) >>
+ RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) &
+ RST2_CPU_DDR_CLOCK_SELECT_IN_MASK;
+ switch (reg) {
+ case 0x0:
+ case 0x1:
+ /* Medium is same as TF to run PBS in this freq */
+ *freq = DDR_FREQ_333;
+ break;
+ case 0x2:
+ case 0x3:
+ /* Medium is same as TF to run PBS in this freq */
+ *freq = DDR_FREQ_400;
+ break;
+ case 0x4:
+ case 0xd:
+ *freq = DDR_FREQ_533;
+ break;
+ case 0x8:
+ case 0x11:
+ case 0x14:
+ *freq = DDR_FREQ_333;
+ break;
+ case 0xc:
+ case 0x15:
+ case 0x1b:
+ *freq = DDR_FREQ_400;
+ break;
+ case 0x6:
+ *freq = DDR_FREQ_300;
+ break;
+ case 0x12:
+ *freq = DDR_FREQ_360;
+ break;
+ case 0x13:
+ *freq = DDR_FREQ_400;
+ break;
+ default:
+ *freq = 0;
+ return MV_NOT_SUPPORTED;
+ }
+
+ return MV_OK;
+}
+
+u32 ddr3_tip_get_init_freq(void)
+{
+ enum hws_ddr_freq freq;
+
+ ddr3_tip_a38x_get_init_freq(0, &freq);
+
+ return freq;
+}
+
+static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
+ enum hws_ddr_freq frequency)
+{
+ u32 divider = 0;
+ u32 sar_val;
+
+ if (if_id != 0) {
+ DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
+ ("A38x does not support interface 0x%x\n",
+ if_id));
+ return MV_BAD_PARAM;
+ }
+
+ /* get VCO freq index */
+ sar_val = (reg_read(REG_DEVICE_SAR1_ADDR) >>
+ RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) &
+ RST2_CPU_DDR_CLOCK_SELECT_IN_MASK;
+ divider = a38x_vco_freq_per_sar[sar_val] / freq_val[frequency];
+
+ /* Set Sync mode */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x20220, 0x0,
+ 0x1000));
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe42f4, 0x0,
+ 0x200));
+
+ /* cpupll_clkdiv_reset_mask */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0x1f,
+ 0xff));
+
+ /* cpupll_clkdiv_reload_smooth */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260,
+ (0x2 << 8), (0xff << 8)));
+
+ /* cpupll_clkdiv_relax_en */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260,
+ (0x2 << 24), (0xff << 24)));
+
+ /* write the divider */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4268,
+ (divider << 8), (0x3f << 8)));
+
+ /* set cpupll_clkdiv_reload_ratio */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264,
+ (1 << 8), (1 << 8)));
+
+ /* undet cpupll_clkdiv_reload_ratio */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0,
+ (1 << 8)));
+
+ /* clear cpupll_clkdiv_reload_force */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, 0,
+ (0xff << 8)));
+
+ /* clear cpupll_clkdiv_relax_en */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, 0,
+ (0xff << 24)));
+
+ /* clear cpupll_clkdiv_reset_mask */
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0,
+ 0xff));
+
+ /* Dunit training clock + 1:1 mode */
+ if ((frequency == DDR_FREQ_LOW_FREQ) || (freq_val[frequency] <= 400)) {
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x18488,
+ (1 << 16), (1 << 16)));
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1524,
+ (0 << 15), (1 << 15)));
+ } else {
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x18488,
+ 0, (1 << 16)));
+ CHECK_STATUS(ddr3_tip_a38x_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1524,
+ (1 << 15), (1 << 15)));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * external read from memory
+ */
+int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr,
+ u32 num_of_bursts, u32 *data)
+{
+ u32 burst_num;
+
+ for (burst_num = 0; burst_num < num_of_bursts * 8; burst_num++)
+ data[burst_num] = readl(reg_addr + 4 * burst_num);
+
+ return MV_OK;
+}
+
+/*
+ * external write to memory
+ */
+int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr,
+ u32 num_of_bursts, u32 *data) {
+ u32 burst_num;
+
+ for (burst_num = 0; burst_num < num_of_bursts * 8; burst_num++)
+ writel(data[burst_num], reg_addr + 4 * burst_num);
+
+ return MV_OK;
+}
+
+int ddr3_silicon_pre_init(void)
+{
+ int result;
+
+ result = ddr3_silicon_init();
+
+ return result;
+}
+
+int ddr3_post_run_alg(void)
+{
+ return MV_OK;
+}
+
+int ddr3_silicon_post_init(void)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* Set half bus width */
+ if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask)) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+ REG_SDRAM_CONFIG_ADDR, 0x0, 0x8000));
+ }
+
+ return MV_OK;
+}
+
+int ddr3_tip_a38x_get_device_info(u8 dev_num, struct ddr3_device_info *info_ptr)
+{
+ info_ptr->device_id = 0x6800;
+ info_ptr->ck_delay = ck_delay;
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x.h b/drivers/ddr/marvell/a38x/ddr3_a38x.h
new file mode 100644
index 0000000000..49621bc133
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_A38X_H
+#define _DDR3_A38X_H
+
+#define MAX_INTERFACE_NUM 1
+#define MAX_BUS_NUM 5
+
+#include "ddr3_hws_hw_training_def.h"
+
+/* Allow topolgy update from board TWSI device*/
+#if !defined(CONFIG_CUSTOMER_BOARD_SUPPORT)
+#define MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI
+#endif
+
+#define ECC_SUPPORT
+
+/* right now, we're not supporting this in mainline */
+#undef SUPPORT_STATIC_DUNIT_CONFIG
+
+/* Controler bus divider 1 for 32 bit, 2 for 64 bit */
+#define DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER 1
+
+/* Tune internal training params values */
+#define TUNE_TRAINING_PARAMS_CK_DELAY 160
+#define TUNE_TRAINING_PARAMS_CK_DELAY_16 160
+#define TUNE_TRAINING_PARAMS_PFINGER 41
+#define TUNE_TRAINING_PARAMS_NFINGER 43
+#define TUNE_TRAINING_PARAMS_PHYREG3VAL 0xa
+
+#define MARVELL_BOARD MARVELL_BOARD_ID_BASE
+
+
+#define REG_DEVICE_SAR1_ADDR 0xe4204
+#define RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET 17
+#define RST2_CPU_DDR_CLOCK_SELECT_IN_MASK 0x1f
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_5_CTRL_ADDR 0x20050
+#define REG_XBAR_WIN_5_BASE_ADDR 0x20054
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_4_CTRL_ADDR 0x20040
+#define REG_XBAR_WIN_4_BASE_ADDR 0x20044
+#define REG_XBAR_WIN_4_REMAP_ADDR 0x20048
+#define REG_XBAR_WIN_7_REMAP_ADDR 0x20078
+#define REG_XBAR_WIN_16_CTRL_ADDR 0x200d0
+#define REG_XBAR_WIN_16_BASE_ADDR 0x200d4
+#define REG_XBAR_WIN_16_REMAP_ADDR 0x200dc
+#define REG_XBAR_WIN_19_CTRL_ADDR 0x200e8
+
+#define REG_FASTPATH_WIN_BASE_ADDR(win) (0x20180 + (0x8 * win))
+#define REG_FASTPATH_WIN_CTRL_ADDR(win) (0x20184 + (0x8 * win))
+
+/* SatR defined too change topology busWidth and ECC configuration */
+#define DDR_SATR_CONFIG_MASK_WIDTH 0x8
+#define DDR_SATR_CONFIG_MASK_ECC 0x10
+#define DDR_SATR_CONFIG_MASK_ECC_PUP 0x20
+
+#define REG_SAMPLE_RESET_HIGH_ADDR 0x18600
+
+#define MV_BOARD_REFCLK MV_BOARD_REFCLK_25MHZ
+
+/* Matrix enables DRAM modes (bus width/ECC) per boardId */
+#define TOPOLOGY_UPDATE_32BIT 0
+#define TOPOLOGY_UPDATE_32BIT_ECC 1
+#define TOPOLOGY_UPDATE_16BIT 2
+#define TOPOLOGY_UPDATE_16BIT_ECC 3
+#define TOPOLOGY_UPDATE_16BIT_ECC_PUP3 4
+#define TOPOLOGY_UPDATE { \
+ /* 32Bit, 32bit ECC, 16bit, 16bit ECC PUP4, 16bit ECC PUP3 */ \
+ {1, 1, 1, 1, 1}, /* RD_NAS_68XX_ID */ \
+ {1, 1, 1, 1, 1}, /* DB_68XX_ID */ \
+ {1, 0, 1, 0, 1}, /* RD_AP_68XX_ID */ \
+ {1, 0, 1, 0, 1}, /* DB_AP_68XX_ID */ \
+ {1, 0, 1, 0, 1}, /* DB_GP_68XX_ID */ \
+ {0, 0, 1, 1, 0}, /* DB_BP_6821_ID */ \
+ {1, 1, 1, 1, 1} /* DB_AMC_6820_ID */ \
+ };
+
+enum {
+ CPU_1066MHZ_DDR_400MHZ,
+ CPU_RESERVED_DDR_RESERVED0,
+ CPU_667MHZ_DDR_667MHZ,
+ CPU_800MHZ_DDR_800MHZ,
+ CPU_RESERVED_DDR_RESERVED1,
+ CPU_RESERVED_DDR_RESERVED2,
+ CPU_RESERVED_DDR_RESERVED3,
+ LAST_FREQ
+};
+
+#define ACTIVE_INTERFACE_MASK 0x1
+
+#endif /* _DDR3_A38X_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h b/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h
new file mode 100644
index 0000000000..b879a01031
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_A38X_MC_STATIC_H
+#define _DDR3_A38X_MC_STATIC_H
+
+#include "ddr3_a38x.h"
+
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+static struct reg_data ddr3_customer_800[] = {
+ /* parameters for customer board (based on 800MHZ) */
+ {0x1400, 0x7b00cc30, 0xffffffff},
+ {0x1404, 0x36301820, 0xffffffff},
+ {0x1408, 0x5415baab, 0xffffffff},
+ {0x140c, 0x38411def, 0xffffffff},
+ {0x1410, 0x18300000, 0xffffffff},
+ {0x1414, 0x00000700, 0xffffffff},
+ {0x1424, 0x0060f3ff, 0xffffffff},
+ {0x1428, 0x0011a940, 0xffffffff},
+ {0x142c, 0x28c5134, 0xffffffff},
+ {0x1474, 0x00000000, 0xffffffff},
+ {0x147c, 0x0000d771, 0xffffffff},
+ {0x1494, 0x00030000, 0xffffffff},
+ {0x149c, 0x00000300, 0xffffffff},
+ {0x14a8, 0x00000000, 0xffffffff},
+ {0x14cc, 0xbd09000d, 0xffffffff},
+ {0x1504, 0xfffffff1, 0xffffffff},
+ {0x150c, 0xffffffe5, 0xffffffff},
+ {0x1514, 0x00000000, 0xffffffff},
+ {0x151c, 0x00000000, 0xffffffff},
+ {0x1538, 0x00000b0b, 0xffffffff},
+ {0x153c, 0x00000c0c, 0xffffffff},
+ {0x15d0, 0x00000670, 0xffffffff},
+ {0x15d4, 0x00000046, 0xffffffff},
+ {0x15d8, 0x00000010, 0xffffffff},
+ {0x15dc, 0x00000000, 0xffffffff},
+ {0x15e0, 0x00000023, 0xffffffff},
+ {0x15e4, 0x00203c18, 0xffffffff},
+ {0x15ec, 0xf8000019, 0xffffffff},
+ {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */
+ {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */
+ {0, 0, 0}
+};
+
+#else /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+struct reg_data ddr3_a38x_933[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* parameters for 933MHZ */
+ {0x1400, 0x7b00ce3a, 0xffffffff},
+ {0x1404, 0x36301820, 0xffffffff},
+ {0x1408, 0x7417eccf, 0xffffffff},
+ {0x140c, 0x3e421f98, 0xffffffff},
+ {0x1410, 0x1a300000, 0xffffffff},
+ {0x1414, 0x00000700, 0xffffffff},
+ {0x1424, 0x0060f3ff, 0xffffffff},
+ {0x1428, 0x0013ca50, 0xffffffff},
+ {0x142c, 0x028c5165, 0xffffffff},
+ {0x1474, 0x00000000, 0xffffffff},
+ {0x147c, 0x0000e871, 0xffffffff},
+ {0x1494, 0x00010000, 0xffffffff},
+ {0x149c, 0x00000001, 0xffffffff},
+ {0x14a8, 0x00000000, 0xffffffff},
+ {0x14cc, 0xbd09000d, 0xffffffff},
+ {0x1504, 0xffffffe1, 0xffffffff},
+ {0x150c, 0xffffffe5, 0xffffffff},
+ {0x1514, 0x00000000, 0xffffffff},
+ {0x151c, 0x00000000, 0xffffffff},
+ {0x1538, 0x00000d0d, 0xffffffff},
+ {0x153c, 0x00000d0d, 0xffffffff},
+ {0x15d0, 0x00000608, 0xffffffff},
+ {0x15d4, 0x00000044, 0xffffffff},
+ {0x15d8, 0x00000020, 0xffffffff},
+ {0x15dc, 0x00000000, 0xffffffff},
+ {0x15e0, 0x00000021, 0xffffffff},
+ {0x15e4, 0x00203c18, 0xffffffff},
+ {0x15ec, 0xf8000019, 0xffffffff},
+ {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */
+ {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */
+ {0, 0, 0}
+};
+
+static struct reg_data ddr3_a38x_800[] = {
+ /* parameters for 800MHZ */
+ {0x1400, 0x7b00cc30, 0xffffffff},
+ {0x1404, 0x36301820, 0xffffffff},
+ {0x1408, 0x5415baab, 0xffffffff},
+ {0x140c, 0x38411def, 0xffffffff},
+ {0x1410, 0x18300000, 0xffffffff},
+ {0x1414, 0x00000700, 0xffffffff},
+ {0x1424, 0x0060f3ff, 0xffffffff},
+ {0x1428, 0x0011a940, 0xffffffff},
+ {0x142c, 0x28c5134, 0xffffffff},
+ {0x1474, 0x00000000, 0xffffffff},
+ {0x147c, 0x0000d771, 0xffffffff},
+ {0x1494, 0x00030000, 0xffffffff},
+ {0x149c, 0x00000300, 0xffffffff},
+ {0x14a8, 0x00000000, 0xffffffff},
+ {0x14cc, 0xbd09000d, 0xffffffff},
+ {0x1504, 0xfffffff1, 0xffffffff},
+ {0x150c, 0xffffffe5, 0xffffffff},
+ {0x1514, 0x00000000, 0xffffffff},
+ {0x151c, 0x00000000, 0xffffffff},
+ {0x1538, 0x00000b0b, 0xffffffff},
+ {0x153c, 0x00000c0c, 0xffffffff},
+ {0x15d0, 0x00000670, 0xffffffff},
+ {0x15d4, 0x00000046, 0xffffffff},
+ {0x15d8, 0x00000010, 0xffffffff},
+ {0x15dc, 0x00000000, 0xffffffff},
+ {0x15e0, 0x00000023, 0xffffffff},
+ {0x15e4, 0x00203c18, 0xffffffff},
+ {0x15ec, 0xf8000019, 0xffffffff},
+ {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */
+ {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */
+ {0, 0, 0}
+};
+
+static struct reg_data ddr3_a38x_667[] = {
+ /* parameters for 667MHZ */
+ /* DDR SDRAM Configuration Register */
+ {0x1400, 0x7b00ca28, 0xffffffff},
+ /* Dunit Control Low Register - kw28 bit12 low (disable CLK1) */
+ {0x1404, 0x36301820, 0xffffffff},
+ /* DDR SDRAM Timing (Low) Register */
+ {0x1408, 0x43149997, 0xffffffff},
+ /* DDR SDRAM Timing (High) Register */
+ {0x140c, 0x38411bc7, 0xffffffff},
+ /* DDR SDRAM Address Control Register */
+ {0x1410, 0x14330000, 0xffffffff},
+ /* DDR SDRAM Open Pages Control Register */
+ {0x1414, 0x00000700, 0xffffffff},
+ /* Dunit Control High Register (2 :1 - bits 15:12 = 0xd) */
+ {0x1424, 0x0060f3ff, 0xffffffff},
+ /* Dunit Control High Register */
+ {0x1428, 0x000f8830, 0xffffffff},
+ /* Dunit Control High Register (2:1 - bit 29 = '1') */
+ {0x142c, 0x28c50f8, 0xffffffff},
+ {0x147c, 0x0000c671, 0xffffffff},
+ /* DDR SDRAM ODT Control (Low) Register */
+ {0x1494, 0x00030000, 0xffffffff},
+ /* DDR SDRAM ODT Control (High) Register, will be configured at WL */
+ {0x1498, 0x00000000, 0xffffffff},
+ /* DDR Dunit ODT Control Register */
+ {0x149c, 0x00000300, 0xffffffff},
+ {0x14a8, 0x00000000, 0xffffffff}, /* */
+ {0x14cc, 0xbd09000d, 0xffffffff}, /* */
+ {0x1474, 0x00000000, 0xffffffff},
+ /* Read Data Sample Delays Register */
+ {0x1538, 0x00000009, 0xffffffff},
+ /* Read Data Ready Delay Register */
+ {0x153c, 0x0000000c, 0xffffffff},
+ {0x1504, 0xfffffff1, 0xffffffff}, /* */
+ {0x150c, 0xffffffe5, 0xffffffff}, /* */
+ {0x1514, 0x00000000, 0xffffffff}, /* */
+ {0x151c, 0x0, 0xffffffff}, /* */
+ {0x15d0, 0x00000650, 0xffffffff}, /* MR0 */
+ {0x15d4, 0x00000046, 0xffffffff}, /* MR1 */
+ {0x15d8, 0x00000010, 0xffffffff}, /* MR2 */
+ {0x15dc, 0x00000000, 0xffffffff}, /* MR3 */
+ {0x15e0, 0x23, 0xffffffff}, /* */
+ {0x15e4, 0x00203c18, 0xffffffff}, /* ZQC Configuration Register */
+ {0x15ec, 0xf8000019, 0xffffffff}, /* DDR PHY */
+ {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */
+ {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */
+ {0, 0, 0}
+};
+
+static struct reg_data ddr3_a38x_533[] = {
+ /* parameters for 533MHZ */
+ /* DDR SDRAM Configuration Register */
+ {0x1400, 0x7b00d040, 0xffffffff},
+ /* Dunit Control Low Register - kw28 bit12 low (disable CLK1) */
+ {0x1404, 0x36301820, 0xffffffff},
+ /* DDR SDRAM Timing (Low) Register */
+ {0x1408, 0x33137772, 0xffffffff},
+ /* DDR SDRAM Timing (High) Register */
+ {0x140c, 0x3841199f, 0xffffffff},
+ /* DDR SDRAM Address Control Register */
+ {0x1410, 0x10330000, 0xffffffff},
+ /* DDR SDRAM Open Pages Control Register */
+ {0x1414, 0x00000700, 0xffffffff},
+ /* Dunit Control High Register (2 :1 - bits 15:12 = 0xd) */
+ {0x1424, 0x0060f3ff, 0xffffffff},
+ /* Dunit Control High Register */
+ {0x1428, 0x000d6720, 0xffffffff},
+ /* Dunit Control High Register (2:1 - bit 29 = '1') */
+ {0x142c, 0x028c50c3, 0xffffffff},
+ {0x147c, 0x0000b571, 0xffffffff},
+ /* DDR SDRAM ODT Control (Low) Register */
+ {0x1494, 0x00030000, 0xffffffff},
+ /* DDR SDRAM ODT Control (High) Register, will be configured at WL */
+ {0x1498, 0x00000000, 0xffffffff},
+ /* DDR Dunit ODT Control Register */
+ {0x149c, 0x00000003, 0xffffffff},
+ {0x14a8, 0x00000000, 0xffffffff}, /* */
+ {0x14cc, 0xbd09000d, 0xffffffff}, /* */
+ {0x1474, 0x00000000, 0xffffffff},
+ /* Read Data Sample Delays Register */
+ {0x1538, 0x00000707, 0xffffffff},
+ /* Read Data Ready Delay Register */
+ {0x153c, 0x00000707, 0xffffffff},
+ {0x1504, 0xffffffe1, 0xffffffff}, /* */
+ {0x150c, 0xffffffe5, 0xffffffff}, /* */
+ {0x1514, 0x00000000, 0xffffffff}, /* */
+ {0x151c, 0x00000000, 0xffffffff}, /* */
+ {0x15d0, 0x00000630, 0xffffffff}, /* MR0 */
+ {0x15d4, 0x00000046, 0xffffffff}, /* MR1 */
+ {0x15d8, 0x00000008, 0xffffffff}, /* MR2 */
+ {0x15dc, 0x00000000, 0xffffffff}, /* MR3 */
+ {0x15e0, 0x00000023, 0xffffffff}, /* */
+ {0x15e4, 0x00203c18, 0xffffffff}, /* ZQC Configuration Register */
+ {0x15ec, 0xf8000019, 0xffffffff}, /* DDR PHY */
+ {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */
+ {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */
+ {0, 0, 0}
+};
+
+#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+#endif /* SUPPORT_STATIC_DUNIT_CONFIG */
+
+#endif /* _DDR3_A38X_MC_STATIC_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h b/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h
new file mode 100644
index 0000000000..f27bbff733
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_A38X_TOPOLOGY_H
+#define _DDR3_A38X_TOPOLOGY_H
+
+#include "ddr_topology_def.h"
+
+/* Bus mask variants */
+#define BUS_MASK_32BIT 0xf
+#define BUS_MASK_32BIT_ECC 0x1f
+#define BUS_MASK_16BIT 0x3
+#define BUS_MASK_16BIT_ECC 0x13
+#define BUS_MASK_16BIT_ECC_PUP3 0xb
+
+#define DYNAMIC_CS_SIZE_CONFIG
+#define DISABLE_L2_FILTERING_DURING_DDR_TRAINING
+
+#endif /* _DDR3_A38X_TOPOLOGY_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_training.c b/drivers/ddr/marvell/a38x/ddr3_a38x_training.c
new file mode 100644
index 0000000000..52c43f75e0
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x_training.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+/*
+ * Name: ddr3_tip_init_silicon
+ * Desc: initiate silicon parameters
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+int ddr3_silicon_init(void)
+{
+ int status;
+ static int init_done;
+
+ if (init_done == 1)
+ return MV_OK;
+
+ status = ddr3_tip_init_a38x(0, 0);
+ if (MV_OK != status) {
+ printf("DDR3 A38x silicon init - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ init_done = 1;
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_debug.c b/drivers/ddr/marvell/a38x/ddr3_debug.c
new file mode 100644
index 0000000000..1d72bc569e
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_debug.c
@@ -0,0 +1,1551 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+u8 is_reg_dump = 0;
+u8 debug_pbs = DEBUG_LEVEL_ERROR;
+
+/*
+ * API to change flags outside of the lib
+ */
+#ifndef SILENT_LIB
+/* Debug flags for other Training modules */
+u8 debug_training_static = DEBUG_LEVEL_ERROR;
+u8 debug_training = DEBUG_LEVEL_ERROR;
+u8 debug_leveling = DEBUG_LEVEL_ERROR;
+u8 debug_centralization = DEBUG_LEVEL_ERROR;
+u8 debug_training_ip = DEBUG_LEVEL_ERROR;
+u8 debug_training_bist = DEBUG_LEVEL_ERROR;
+u8 debug_training_hw_alg = DEBUG_LEVEL_ERROR;
+u8 debug_training_access = DEBUG_LEVEL_ERROR;
+u8 debug_training_a38x = DEBUG_LEVEL_ERROR;
+
+void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level)
+{
+ switch (block) {
+ case DEBUG_BLOCK_STATIC:
+ debug_training_static = level;
+ break;
+ case DEBUG_BLOCK_TRAINING_MAIN:
+ debug_training = level;
+ break;
+ case DEBUG_BLOCK_LEVELING:
+ debug_leveling = level;
+ break;
+ case DEBUG_BLOCK_CENTRALIZATION:
+ debug_centralization = level;
+ break;
+ case DEBUG_BLOCK_PBS:
+ debug_pbs = level;
+ break;
+ case DEBUG_BLOCK_ALG:
+ debug_training_hw_alg = level;
+ break;
+ case DEBUG_BLOCK_DEVICE:
+ debug_training_a38x = level;
+ break;
+ case DEBUG_BLOCK_ACCESS:
+ debug_training_access = level;
+ break;
+ case DEBUG_STAGES_REG_DUMP:
+ if (level == DEBUG_LEVEL_TRACE)
+ is_reg_dump = 1;
+ else
+ is_reg_dump = 0;
+ break;
+ case DEBUG_BLOCK_ALL:
+ default:
+ debug_training_static = level;
+ debug_training = level;
+ debug_leveling = level;
+ debug_centralization = level;
+ debug_pbs = level;
+ debug_training_hw_alg = level;
+ debug_training_access = level;
+ debug_training_a38x = level;
+ }
+}
+#else
+void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level)
+{
+ return;
+}
+#endif
+
+struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM];
+u8 is_default_centralization = 0;
+u8 is_tune_result = 0;
+u8 is_validate_window_per_if = 0;
+u8 is_validate_window_per_pup = 0;
+u8 sweep_cnt = 1;
+u32 is_bist_reset_bit = 1;
+static struct hws_xsb_info xsb_info[HWS_MAX_DEVICE_NUM];
+
+/*
+ * Dump Dunit & Phy registers
+ */
+int ddr3_tip_reg_dump(u32 dev_num)
+{
+ u32 if_id, reg_addr, data_value, bus_id;
+ u32 read_data[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ printf("-- dunit registers --\n");
+ for (reg_addr = 0x1400; reg_addr < 0x19f0; reg_addr += 4) {
+ printf("0x%x ", reg_addr);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, reg_addr, read_data,
+ MASK_ALL_BITS));
+ printf("0x%x ", read_data[if_id]);
+ }
+ printf("\n");
+ }
+
+ printf("-- Phy registers --\n");
+ for (reg_addr = 0; reg_addr <= 0xff; reg_addr++) {
+ printf("0x%x ", reg_addr);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0;
+ bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA, reg_addr,
+ &data_value));
+ printf("0x%x ", data_value);
+ }
+ for (bus_id = 0;
+ bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_CONTROL, reg_addr,
+ &data_value));
+ printf("0x%x ", data_value);
+ }
+ }
+ printf("\n");
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Register access func registration
+ */
+int ddr3_tip_init_config_func(u32 dev_num,
+ struct hws_tip_config_func_db *config_func)
+{
+ if (config_func == NULL)
+ return MV_BAD_PARAM;
+
+ memcpy(&config_func_info[dev_num], config_func,
+ sizeof(struct hws_tip_config_func_db));
+
+ return MV_OK;
+}
+
+/*
+ * Read training result table
+ */
+int hws_ddr3_tip_read_training_result(
+ u32 dev_num, enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM])
+{
+ dev_num = dev_num;
+
+ if (result == NULL)
+ return MV_BAD_PARAM;
+ memcpy(result, training_result, sizeof(result));
+
+ return MV_OK;
+}
+
+/*
+ * Get training result info pointer
+ */
+enum hws_result *ddr3_tip_get_result_ptr(u32 stage)
+{
+ return training_result[stage];
+}
+
+/*
+ * Device info read
+ */
+int ddr3_tip_get_device_info(u32 dev_num, struct ddr3_device_info *info_ptr)
+{
+ if (config_func_info[dev_num].tip_get_device_info_func != NULL) {
+ return config_func_info[dev_num].
+ tip_get_device_info_func((u8) dev_num, info_ptr);
+ }
+
+ return MV_FAIL;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Convert freq to character string
+ */
+static char *convert_freq(enum hws_ddr_freq freq)
+{
+ switch (freq) {
+ case DDR_FREQ_LOW_FREQ:
+ return "DDR_FREQ_LOW_FREQ";
+ case DDR_FREQ_400:
+ return "400";
+
+ case DDR_FREQ_533:
+ return "533";
+ case DDR_FREQ_667:
+ return "667";
+
+ case DDR_FREQ_800:
+ return "800";
+
+ case DDR_FREQ_933:
+ return "933";
+
+ case DDR_FREQ_1066:
+ return "1066";
+ case DDR_FREQ_311:
+ return "311";
+
+ case DDR_FREQ_333:
+ return "333";
+
+ case DDR_FREQ_467:
+ return "467";
+
+ case DDR_FREQ_850:
+ return "850";
+
+ case DDR_FREQ_900:
+ return "900";
+
+ case DDR_FREQ_360:
+ return "DDR_FREQ_360";
+
+ case DDR_FREQ_1000:
+ return "DDR_FREQ_1000";
+ default:
+ return "Unknown Frequency";
+ }
+}
+
+/*
+ * Convert device ID to character string
+ */
+static char *convert_dev_id(u32 dev_id)
+{
+ switch (dev_id) {
+ case 0x6800:
+ return "A38xx";
+ case 0x6900:
+ return "A39XX";
+ case 0xf400:
+ return "AC3";
+ case 0xfc00:
+ return "BC2";
+
+ default:
+ return "Unknown Device";
+ }
+}
+
+/*
+ * Convert device ID to character string
+ */
+static char *convert_mem_size(u32 dev_id)
+{
+ switch (dev_id) {
+ case 0:
+ return "512 MB";
+ case 1:
+ return "1 GB";
+ case 2:
+ return "2 GB";
+ case 3:
+ return "4 GB";
+ case 4:
+ return "8 GB";
+
+ default:
+ return "wrong mem size";
+ }
+}
+
+int print_device_info(u8 dev_num)
+{
+ struct ddr3_device_info info_ptr;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ CHECK_STATUS(ddr3_tip_get_device_info(dev_num, &info_ptr));
+ printf("=== DDR setup START===\n");
+ printf("\tDevice ID: %s\n", convert_dev_id(info_ptr.device_id));
+ printf("\tDDR3 CK delay: %d\n", info_ptr.ck_delay);
+ print_topology(tm);
+ printf("=== DDR setup END===\n");
+
+ return MV_OK;
+}
+
+void hws_ddr3_tip_sweep_test(int enable)
+{
+ if (enable) {
+ is_validate_window_per_if = 1;
+ is_validate_window_per_pup = 1;
+ debug_training = DEBUG_LEVEL_TRACE;
+ } else {
+ is_validate_window_per_if = 0;
+ is_validate_window_per_pup = 0;
+ }
+}
+#endif
+
+char *ddr3_tip_convert_tune_result(enum hws_result tune_result)
+{
+ switch (tune_result) {
+ case TEST_FAILED:
+ return "FAILED";
+ case TEST_SUCCESS:
+ return "PASS";
+ case NO_TEST_DONE:
+ return "NOT COMPLETED";
+ default:
+ return "Un-KNOWN";
+ }
+}
+
+/*
+ * Print log info
+ */
+int ddr3_tip_print_log(u32 dev_num, u32 mem_addr)
+{
+ u32 if_id = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ mem_addr = mem_addr;
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+ if ((is_validate_window_per_if != 0) ||
+ (is_validate_window_per_pup != 0)) {
+ u32 is_pup_log = 0;
+ enum hws_ddr_freq freq;
+
+ freq = tm->interface_params[first_active_if].memory_freq;
+
+ is_pup_log = (is_validate_window_per_pup != 0) ? 1 : 0;
+ printf("===VALIDATE WINDOW LOG START===\n");
+ printf("DDR Frequency: %s ======\n", convert_freq(freq));
+ /* print sweep windows */
+ ddr3_tip_run_sweep_test(dev_num, sweep_cnt, 1, is_pup_log);
+ ddr3_tip_run_sweep_test(dev_num, sweep_cnt, 0, is_pup_log);
+ ddr3_tip_print_all_pbs_result(dev_num);
+ ddr3_tip_print_wl_supp_result(dev_num);
+ printf("===VALIDATE WINDOW LOG END ===\n");
+ CHECK_STATUS(ddr3_tip_restore_dunit_regs(dev_num));
+ ddr3_tip_reg_dump(dev_num);
+ }
+#endif
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("IF %d Status:\n", if_id));
+
+ if (mask_tune_func & INIT_CONTROLLER_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tInit Controller: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[INIT_CONTROLLER]
+ [if_id])));
+ }
+ if (mask_tune_func & SET_LOW_FREQ_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tLow freq Config: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[SET_LOW_FREQ]
+ [if_id])));
+ }
+ if (mask_tune_func & LOAD_PATTERN_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tLoad Pattern: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[LOAD_PATTERN]
+ [if_id])));
+ }
+ if (mask_tune_func & SET_MEDIUM_FREQ_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tMedium freq Config: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[SET_MEDIUM_FREQ]
+ [if_id])));
+ }
+ if (mask_tune_func & WRITE_LEVELING_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tWL: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[WRITE_LEVELING]
+ [if_id])));
+ }
+ if (mask_tune_func & LOAD_PATTERN_2_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tLoad Pattern: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[LOAD_PATTERN_2]
+ [if_id])));
+ }
+ if (mask_tune_func & READ_LEVELING_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tRL: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[READ_LEVELING]
+ [if_id])));
+ }
+ if (mask_tune_func & WRITE_LEVELING_SUPP_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tWL Supp: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[WRITE_LEVELING_SUPP]
+ [if_id])));
+ }
+ if (mask_tune_func & PBS_RX_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tPBS RX: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[PBS_RX]
+ [if_id])));
+ }
+ if (mask_tune_func & PBS_TX_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tPBS TX: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[PBS_TX]
+ [if_id])));
+ }
+ if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tTarget freq Config: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[SET_TARGET_FREQ]
+ [if_id])));
+ }
+ if (mask_tune_func & WRITE_LEVELING_TF_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tWL TF: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[WRITE_LEVELING_TF]
+ [if_id])));
+ }
+ if (mask_tune_func & READ_LEVELING_TF_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tRL TF: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[READ_LEVELING_TF]
+ [if_id])));
+ }
+ if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tWL TF Supp: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result
+ [WRITE_LEVELING_SUPP_TF]
+ [if_id])));
+ }
+ if (mask_tune_func & CENTRALIZATION_RX_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tCentr RX: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[CENTRALIZATION_RX]
+ [if_id])));
+ }
+ if (mask_tune_func & VREF_CALIBRATION_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tVREF_CALIBRATION: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[VREF_CALIBRATION]
+ [if_id])));
+ }
+ if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("\tCentr TX: %s\n",
+ ddr3_tip_convert_tune_result
+ (training_result[CENTRALIZATION_TX]
+ [if_id])));
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Print stability log info
+ */
+int ddr3_tip_print_stability_log(u32 dev_num)
+{
+ u8 if_id = 0, csindex = 0, bus_id = 0, idx = 0;
+ u32 reg_data;
+ u32 read_data[MAX_INTERFACE_NUM];
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* Title print */
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ printf("Title: I/F# , Tj, Calibration_n0, Calibration_p0, Calibration_n1, Calibration_p1, Calibration_n2, Calibration_p2,");
+ for (csindex = 0; csindex < max_cs; csindex++) {
+ printf("CS%d , ", csindex);
+ printf("\n");
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ printf("VWTx, VWRx, WL_tot, WL_ADLL, WL_PH, RL_Tot, RL_ADLL, RL_PH, RL_Smp, Cen_tx, Cen_rx, Vref, DQVref,");
+ printf("\t\t");
+ for (idx = 0; idx < 11; idx++)
+ printf("PBSTx-Pad%d,", idx);
+ printf("\t\t");
+ for (idx = 0; idx < 11; idx++)
+ printf("PBSRx-Pad%d,", idx);
+ }
+ }
+ printf("\n");
+
+ /* Data print */
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ printf("Data: %d,%d,", if_id,
+ (config_func_info[dev_num].tip_get_temperature != NULL)
+ ? (config_func_info[dev_num].
+ tip_get_temperature(dev_num)) : (0));
+
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x14c8,
+ read_data, MASK_ALL_BITS));
+ printf("%d,%d,", ((read_data[if_id] & 0x3f0) >> 4),
+ ((read_data[if_id] & 0xfc00) >> 10));
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x17c8,
+ read_data, MASK_ALL_BITS));
+ printf("%d,%d,", ((read_data[if_id] & 0x3f0) >> 4),
+ ((read_data[if_id] & 0xfc00) >> 10));
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1dc8,
+ read_data, MASK_ALL_BITS));
+ printf("%d,%d,", ((read_data[if_id] & 0x3f0000) >> 16),
+ ((read_data[if_id] & 0xfc00000) >> 22));
+
+ for (csindex = 0; csindex < max_cs; csindex++) {
+ printf("CS%d , ", csindex);
+ for (bus_id = 0; bus_id < MAX_BUS_NUM; bus_id++) {
+ printf("\n");
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ RESULT_DB_PHY_REG_ADDR +
+ csindex, &reg_data);
+ printf("%d,%d,", (reg_data & 0x1f),
+ ((reg_data & 0x3e0) >> 5));
+ /* WL */
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ WL_PHY_REG +
+ csindex * 4, &reg_data);
+ printf("%d,%d,%d,",
+ (reg_data & 0x1f) +
+ ((reg_data & 0x1c0) >> 6) * 32,
+ (reg_data & 0x1f),
+ (reg_data & 0x1c0) >> 6);
+ /* RL */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id,
+ READ_DATA_SAMPLE_DELAY,
+ read_data, MASK_ALL_BITS));
+ read_data[if_id] =
+ (read_data[if_id] &
+ (0xf << (4 * csindex))) >>
+ (4 * csindex);
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA,
+ RL_PHY_REG + csindex * 4,
+ &reg_data);
+ printf("%d,%d,%d,%d,",
+ (reg_data & 0x1f) +
+ ((reg_data & 0x1c0) >> 6) * 32 +
+ read_data[if_id] * 64,
+ (reg_data & 0x1f),
+ ((reg_data & 0x1c0) >> 6),
+ read_data[if_id]);
+ /* Centralization */
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG
+ + csindex * 4, &reg_data);
+ printf("%d,", (reg_data & 0x3f));
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA,
+ READ_CENTRALIZATION_PHY_REG
+ + csindex * 4, &reg_data);
+ printf("%d,", (reg_data & 0x1f));
+ /* Vref */
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA,
+ PAD_CONFIG_PHY_REG,
+ &reg_data);
+ printf("%d,", (reg_data & 0x7));
+ /* DQVref */
+ /* Need to add the Read Function from device */
+ printf("%d,", 0);
+ printf("\t\t");
+ for (idx = 0; idx < 11; idx++) {
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ 0xd0 +
+ 12 * csindex +
+ idx, &reg_data);
+ printf("%d,", (reg_data & 0x3f));
+ }
+ printf("\t\t");
+ for (idx = 0; idx < 11; idx++) {
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ 0x10 +
+ 16 * csindex +
+ idx, &reg_data);
+ printf("%d,", (reg_data & 0x3f));
+ }
+ printf("\t\t");
+ for (idx = 0; idx < 11; idx++) {
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ 0x50 +
+ 16 * csindex +
+ idx, &reg_data);
+ printf("%d,", (reg_data & 0x3f));
+ }
+ }
+ }
+ }
+ printf("\n");
+
+ return MV_OK;
+}
+
+/*
+ * Register XSB information
+ */
+int ddr3_tip_register_xsb_info(u32 dev_num, struct hws_xsb_info *xsb_info_table)
+{
+ memcpy(&xsb_info[dev_num], xsb_info_table, sizeof(struct hws_xsb_info));
+ return MV_OK;
+}
+
+/*
+ * Read ADLL Value
+ */
+int read_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+ int reg_addr, u32 mask)
+{
+ u32 data_value;
+ u32 if_id = 0, bus_id = 0;
+ u32 dev_num = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * multi CS support - reg_addr is calucalated in calling function
+ * with CS offset
+ */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id,
+ DDR_PHY_DATA, reg_addr,
+ &data_value));
+ pup_values[if_id *
+ tm->num_of_bus_per_interface + bus_id] =
+ data_value & mask;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Write ADLL Value
+ */
+int write_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+ int reg_addr)
+{
+ u32 if_id = 0, bus_id = 0;
+ u32 dev_num = 0, data;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * multi CS support - reg_addr is calucalated in calling function
+ * with CS offset
+ */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ data = pup_values[if_id *
+ tm->num_of_bus_per_interface +
+ bus_id];
+ CHECK_STATUS(ddr3_tip_bus_write(dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ reg_addr, data));
+ }
+ }
+
+ return 0;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+u32 rl_version = 1; /* 0 - old RL machine */
+struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM];
+u32 start_xsb_offset = 0;
+u8 is_rl_old = 0;
+u8 is_freq_old = 0;
+u8 is_dfs_disabled = 0;
+u32 default_centrlization_value = 0x12;
+u32 vref = 0x4;
+u32 activate_select_before_run_alg = 1, activate_deselect_after_run_alg = 1,
+ rl_test = 0, reset_read_fifo = 0;
+int debug_acc = 0;
+u32 ctrl_sweepres[ADLL_LENGTH][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u32 ctrl_adll[MAX_CS_NUM * MAX_INTERFACE_NUM * MAX_BUS_NUM];
+u8 cs_mask_reg[] = {
+ 0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+u32 xsb_test_table[][8] = {
+ {0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555,
+ 0x66666666, 0x77777777},
+ {0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd,
+ 0xeeeeeeee, 0xffffffff},
+ {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff},
+ {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff},
+ {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff},
+ {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff},
+ {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff},
+ {0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000},
+ {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff}
+};
+
+static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr);
+
+int ddr3_tip_print_adll(void)
+{
+ u32 bus_cnt = 0, if_id, data_p1, data_p2, ui_data3, dev_num = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_cnt,
+ DDR_PHY_DATA, 0x1, &data_p1));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA, 0x2, &data_p2));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA, 0x3, &ui_data3));
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ (" IF %d bus_cnt %d phy_reg_1_data 0x%x phy_reg_2_data 0x%x phy_reg_3_data 0x%x\n",
+ if_id, bus_cnt, data_p1, data_p2,
+ ui_data3));
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Set attribute value
+ */
+int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value)
+{
+ int ret;
+ u32 *ptr_flag = NULL;
+
+ ret = ddr3_tip_access_atr(dev_num, flag_id, value, &ptr_flag);
+ if (ptr_flag != NULL) {
+ printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x (was 0x%x)\n",
+ flag_id, value, *ptr_flag);
+ *ptr_flag = value;
+ } else {
+ printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x\n",
+ flag_id, value);
+ }
+
+ return ret;
+}
+
+/*
+ * Access attribute
+ */
+static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr)
+{
+ u32 tmp_val = 0, if_id = 0, pup_id = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ dev_num = dev_num;
+ *ptr = NULL;
+
+ switch (flag_id) {
+ case 0:
+ *ptr = (u32 *)&(tm->if_act_mask);
+ break;
+
+ case 0x1:
+ *ptr = (u32 *)&mask_tune_func;
+ break;
+
+ case 0x2:
+ *ptr = (u32 *)&low_freq;
+ break;
+
+ case 0x3:
+ *ptr = (u32 *)&medium_freq;
+ break;
+
+ case 0x4:
+ *ptr = (u32 *)&generic_init_controller;
+ break;
+
+ case 0x5:
+ *ptr = (u32 *)&rl_version;
+ break;
+
+ case 0x8:
+ *ptr = (u32 *)&start_xsb_offset;
+ break;
+
+ case 0x20:
+ *ptr = (u32 *)&is_rl_old;
+ break;
+
+ case 0x21:
+ *ptr = (u32 *)&is_freq_old;
+ break;
+
+ case 0x23:
+ *ptr = (u32 *)&is_dfs_disabled;
+ break;
+
+ case 0x24:
+ *ptr = (u32 *)&is_pll_before_init;
+ break;
+
+ case 0x25:
+ *ptr = (u32 *)&is_adll_calib_before_init;
+ break;
+#ifdef STATIC_ALGO_SUPPORT
+ case 0x26:
+ *ptr = (u32 *)&(silicon_delay[0]);
+ break;
+
+ case 0x27:
+ *ptr = (u32 *)&wl_debug_delay;
+ break;
+#endif
+ case 0x28:
+ *ptr = (u32 *)&is_tune_result;
+ break;
+
+ case 0x29:
+ *ptr = (u32 *)&is_validate_window_per_if;
+ break;
+
+ case 0x2a:
+ *ptr = (u32 *)&is_validate_window_per_pup;
+ break;
+
+ case 0x30:
+ *ptr = (u32 *)&sweep_cnt;
+ break;
+
+ case 0x31:
+ *ptr = (u32 *)&is_bist_reset_bit;
+ break;
+
+ case 0x32:
+ *ptr = (u32 *)&is_dfs_in_init;
+ break;
+
+ case 0x33:
+ *ptr = (u32 *)&p_finger;
+ break;
+
+ case 0x34:
+ *ptr = (u32 *)&n_finger;
+ break;
+
+ case 0x35:
+ *ptr = (u32 *)&init_freq;
+ break;
+
+ case 0x36:
+ *ptr = (u32 *)&(freq_val[DDR_FREQ_LOW_FREQ]);
+ break;
+
+ case 0x37:
+ *ptr = (u32 *)&start_pattern;
+ break;
+
+ case 0x38:
+ *ptr = (u32 *)&end_pattern;
+ break;
+
+ case 0x39:
+ *ptr = (u32 *)&phy_reg0_val;
+ break;
+
+ case 0x4a:
+ *ptr = (u32 *)&phy_reg1_val;
+ break;
+
+ case 0x4b:
+ *ptr = (u32 *)&phy_reg2_val;
+ break;
+
+ case 0x4c:
+ *ptr = (u32 *)&phy_reg3_val;
+ break;
+
+ case 0x4e:
+ *ptr = (u32 *)&sweep_pattern;
+ break;
+
+ case 0x50:
+ *ptr = (u32 *)&is_rzq6;
+ break;
+
+ case 0x51:
+ *ptr = (u32 *)&znri_data_phy_val;
+ break;
+
+ case 0x52:
+ *ptr = (u32 *)&zpri_data_phy_val;
+ break;
+
+ case 0x53:
+ *ptr = (u32 *)&finger_test;
+ break;
+
+ case 0x54:
+ *ptr = (u32 *)&n_finger_start;
+ break;
+
+ case 0x55:
+ *ptr = (u32 *)&n_finger_end;
+ break;
+
+ case 0x56:
+ *ptr = (u32 *)&p_finger_start;
+ break;
+
+ case 0x57:
+ *ptr = (u32 *)&p_finger_end;
+ break;
+
+ case 0x58:
+ *ptr = (u32 *)&p_finger_step;
+ break;
+
+ case 0x59:
+ *ptr = (u32 *)&n_finger_step;
+ break;
+
+ case 0x5a:
+ *ptr = (u32 *)&znri_ctrl_phy_val;
+ break;
+
+ case 0x5b:
+ *ptr = (u32 *)&zpri_ctrl_phy_val;
+ break;
+
+ case 0x5c:
+ *ptr = (u32 *)&is_reg_dump;
+ break;
+
+ case 0x5d:
+ *ptr = (u32 *)&vref;
+ break;
+
+ case 0x5e:
+ *ptr = (u32 *)&mode2_t;
+ break;
+
+ case 0x5f:
+ *ptr = (u32 *)&xsb_validate_type;
+ break;
+
+ case 0x60:
+ *ptr = (u32 *)&xsb_validation_base_address;
+ break;
+
+ case 0x67:
+ *ptr = (u32 *)&activate_select_before_run_alg;
+ break;
+
+ case 0x68:
+ *ptr = (u32 *)&activate_deselect_after_run_alg;
+ break;
+
+ case 0x69:
+ *ptr = (u32 *)&odt_additional;
+ break;
+
+ case 0x70:
+ *ptr = (u32 *)&debug_mode;
+ break;
+
+ case 0x71:
+ *ptr = (u32 *)&pbs_pattern;
+ break;
+
+ case 0x72:
+ *ptr = (u32 *)&delay_enable;
+ break;
+
+ case 0x73:
+ *ptr = (u32 *)&ck_delay;
+ break;
+
+ case 0x74:
+ *ptr = (u32 *)&ck_delay_16;
+ break;
+
+ case 0x75:
+ *ptr = (u32 *)&ca_delay;
+ break;
+
+ case 0x100:
+ *ptr = (u32 *)&debug_dunit;
+ break;
+
+ case 0x101:
+ debug_acc = (int)value;
+ break;
+
+ case 0x102:
+ debug_training = (u8)value;
+ break;
+
+ case 0x103:
+ debug_training_bist = (u8)value;
+ break;
+
+ case 0x104:
+ debug_centralization = (u8)value;
+ break;
+
+ case 0x105:
+ debug_training_ip = (u8)value;
+ break;
+
+ case 0x106:
+ debug_leveling = (u8)value;
+ break;
+
+ case 0x107:
+ debug_pbs = (u8)value;
+ break;
+
+ case 0x108:
+ debug_training_static = (u8)value;
+ break;
+
+ case 0x109:
+ debug_training_access = (u8)value;
+ break;
+
+ case 0x112:
+ *ptr = &start_pattern;
+ break;
+
+ case 0x113:
+ *ptr = &end_pattern;
+ break;
+
+ default:
+ if ((flag_id >= 0x200) && (flag_id < 0x210)) {
+ if_id = flag_id - 0x200;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].memory_freq);
+ } else if ((flag_id >= 0x210) && (flag_id < 0x220)) {
+ if_id = flag_id - 0x210;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].speed_bin_index);
+ } else if ((flag_id >= 0x220) && (flag_id < 0x230)) {
+ if_id = flag_id - 0x220;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].bus_width);
+ } else if ((flag_id >= 0x230) && (flag_id < 0x240)) {
+ if_id = flag_id - 0x230;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].memory_size);
+ } else if ((flag_id >= 0x240) && (flag_id < 0x250)) {
+ if_id = flag_id - 0x240;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].cas_l);
+ } else if ((flag_id >= 0x250) && (flag_id < 0x260)) {
+ if_id = flag_id - 0x250;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].cas_wl);
+ } else if ((flag_id >= 0x270) && (flag_id < 0x2cf)) {
+ if_id = (flag_id - 0x270) / MAX_BUS_NUM;
+ pup_id = (flag_id - 0x270) % MAX_BUS_NUM;
+ *ptr = (u32 *)&(tm->interface_params[if_id].
+ as_bus_params[pup_id].is_ck_swap);
+ } else if ((flag_id >= 0x2d0) && (flag_id < 0x32f)) {
+ if_id = (flag_id - 0x2d0) / MAX_BUS_NUM;
+ pup_id = (flag_id - 0x2d0) % MAX_BUS_NUM;
+ *ptr = (u32 *)&(tm->interface_params[if_id].
+ as_bus_params[pup_id].is_dqs_swap);
+ } else if ((flag_id >= 0x330) && (flag_id < 0x38f)) {
+ if_id = (flag_id - 0x330) / MAX_BUS_NUM;
+ pup_id = (flag_id - 0x330) % MAX_BUS_NUM;
+ *ptr = (u32 *)&(tm->interface_params[if_id].
+ as_bus_params[pup_id].cs_bitmask);
+ } else if ((flag_id >= 0x390) && (flag_id < 0x3ef)) {
+ if_id = (flag_id - 0x390) / MAX_BUS_NUM;
+ pup_id = (flag_id - 0x390) % MAX_BUS_NUM;
+ *ptr = (u32 *)&(tm->interface_params
+ [if_id].as_bus_params
+ [pup_id].mirror_enable_bitmask);
+ } else if ((flag_id >= 0x500) && (flag_id <= 0x50f)) {
+ tmp_val = flag_id - 0x320;
+ *ptr = (u32 *)&(clamp_tbl[tmp_val]);
+ } else {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("flag_id out of boundary %d\n",
+ flag_id));
+ return MV_BAD_PARAM;
+ }
+ }
+
+ return MV_OK;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Print ADLL
+ */
+int print_adll(u32 dev_num, u32 adll[MAX_INTERFACE_NUM * MAX_BUS_NUM])
+{
+ u32 i, j;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ dev_num = dev_num;
+
+ for (j = 0; j < tm->num_of_bus_per_interface; j++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, j);
+ for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+ printf("%d ,",
+ adll[i * tm->num_of_bus_per_interface + j]);
+ }
+ }
+ printf("\n");
+
+ return MV_OK;
+}
+#endif
+
+/* byte_index - only byte 0, 1, 2, or 3, oxff - test all bytes */
+static u32 ddr3_tip_compare(u32 if_id, u32 *p_src, u32 *p_dst,
+ u32 byte_index)
+{
+ u32 burst_cnt = 0, addr_offset, i_id;
+ int b_is_fail = 0;
+
+ addr_offset =
+ (byte_index ==
+ 0xff) ? (u32) 0xffffffff : (u32) (0xff << (byte_index * 8));
+ for (burst_cnt = 0; burst_cnt < EXT_ACCESS_BURST_LENGTH; burst_cnt++) {
+ if ((p_src[burst_cnt] & addr_offset) !=
+ (p_dst[burst_cnt] & addr_offset))
+ b_is_fail = 1;
+ }
+
+ if (b_is_fail == 1) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("IF %d exp: ", if_id));
+ for (i_id = 0; i_id <= MAX_INTERFACE_NUM - 1; i_id++) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("0x%8x ", p_src[i_id]));
+ }
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("\n_i_f %d rcv: ", if_id));
+ for (i_id = 0; i_id <= MAX_INTERFACE_NUM - 1; i_id++) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("(0x%8x ", p_dst[i_id]));
+ }
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("\n "));
+ }
+
+ return b_is_fail;
+}
+
+/* test_type = 0-tx , 1-rx */
+int ddr3_tip_sweep_test(u32 dev_num, u32 test_type,
+ u32 mem_addr, u32 is_modify_adll,
+ u32 start_if, u32 end_if, u32 startpup, u32 endpup)
+{
+ u32 bus_cnt = 0, adll_val = 0, if_id, ui_prev_adll, ui_mask_bit,
+ end_adll, start_adll;
+ u32 reg_addr = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ mem_addr = mem_addr;
+
+ if (test_type == 0) {
+ reg_addr = 1;
+ ui_mask_bit = 0x3f;
+ start_adll = 0;
+ end_adll = ui_mask_bit;
+ } else {
+ reg_addr = 3;
+ ui_mask_bit = 0x1f;
+ start_adll = 0;
+ end_adll = ui_mask_bit;
+ }
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("==============================\n"));
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("Test type %d (0-tx, 1-rx)\n", test_type));
+
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_cnt = startpup; bus_cnt < endpup; bus_cnt++) {
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA, reg_addr,
+ &ui_prev_adll));
+
+ for (adll_val = start_adll; adll_val <= end_adll;
+ adll_val++) {
+ if (is_modify_adll == 1) {
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id, bus_cnt,
+ DDR_PHY_DATA, reg_addr,
+ adll_val, ui_mask_bit));
+ }
+ }
+ if (is_modify_adll == 1) {
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA, reg_addr,
+ ui_prev_adll));
+ }
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("\n"));
+ }
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("\n"));
+ }
+
+ return MV_OK;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Sweep validation
+ */
+int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction,
+ u32 mode)
+{
+ u32 pup = 0, start_pup = 0, end_pup = 0;
+ u32 adll = 0;
+ u32 res[MAX_INTERFACE_NUM] = { 0 };
+ int if_id = 0;
+ u32 adll_value = 0;
+ int reg = (direction == 0) ? WRITE_CENTRALIZATION_PHY_REG :
+ READ_CENTRALIZATION_PHY_REG;
+ enum hws_access_type pup_access;
+ u32 cs;
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ repeat_num = repeat_num;
+
+ if (mode == 1) {
+ /* per pup */
+ start_pup = 0;
+ end_pup = tm->num_of_bus_per_interface - 1;
+ pup_access = ACCESS_TYPE_UNICAST;
+ } else {
+ start_pup = 0;
+ end_pup = 0;
+ pup_access = ACCESS_TYPE_MULTICAST;
+ }
+
+ for (cs = 0; cs < max_cs; cs++) {
+ for (adll = 0; adll < ADLL_LENGTH; adll++) {
+ for (if_id = 0;
+ if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE
+ (tm->if_act_mask,
+ if_id);
+ for (pup = start_pup; pup <= end_pup; pup++) {
+ ctrl_sweepres[adll][if_id][pup] =
+ 0;
+ }
+ }
+ }
+
+ for (adll = 0; adll < (MAX_INTERFACE_NUM * MAX_BUS_NUM); adll++)
+ ctrl_adll[adll] = 0;
+ /* Save DQS value(after algorithm run) */
+ read_adll_value(ctrl_adll,
+ (reg + (cs * CS_REGISTER_ADDR_OFFSET)),
+ MASK_ALL_BITS);
+
+ /*
+ * Sweep ADLL from 0:31 on all I/F on all Pup and perform
+ * BIST on each stage.
+ */
+ for (pup = start_pup; pup <= end_pup; pup++) {
+ for (adll = 0; adll < ADLL_LENGTH; adll++) {
+ adll_value =
+ (direction == 0) ? (adll * 2) : adll;
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, 0,
+ pup_access, pup, DDR_PHY_DATA,
+ reg + CS_REG_VALUE(cs),
+ adll_value));
+ hws_ddr3_run_bist(dev_num, sweep_pattern, res,
+ cs);
+ /* ddr3_tip_reset_fifo_ptr(dev_num); */
+ for (if_id = 0;
+ if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE
+ (tm->if_act_mask,
+ if_id);
+ ctrl_sweepres[adll][if_id][pup]
+ = res[if_id];
+ if (mode == 1) {
+ CHECK_STATUS
+ (ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ pup,
+ DDR_PHY_DATA,
+ reg + CS_REG_VALUE(cs),
+ ctrl_adll[if_id *
+ cs *
+ tm->num_of_bus_per_interface
+ + pup]));
+ }
+ }
+ }
+ }
+ printf("Final, CS %d,%s, Sweep, Result, Adll,", cs,
+ ((direction == 0) ? "TX" : "RX"));
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (mode == 1) {
+ for (pup = start_pup; pup <= end_pup; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ printf("I/F%d-PHY%d , ", if_id, pup);
+ }
+ } else {
+ printf("I/F%d , ", if_id);
+ }
+ }
+ printf("\n");
+
+ for (adll = 0; adll < ADLL_LENGTH; adll++) {
+ adll_value = (direction == 0) ? (adll * 2) : adll;
+ printf("Final,%s, Sweep, Result, %d ,",
+ ((direction == 0) ? "TX" : "RX"), adll_value);
+
+ for (if_id = 0;
+ if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup = start_pup; pup <= end_pup; pup++) {
+ printf("%d , ",
+ ctrl_sweepres[adll][if_id]
+ [pup]);
+ }
+ }
+ printf("\n");
+ }
+
+ /*
+ * Write back to the phy the Rx DQS value, we store in
+ * the beginning.
+ */
+ write_adll_value(ctrl_adll,
+ (reg + cs * CS_REGISTER_ADDR_OFFSET));
+ /* print adll results */
+ read_adll_value(ctrl_adll, (reg + cs * CS_REGISTER_ADDR_OFFSET),
+ MASK_ALL_BITS);
+ printf("%s, DQS, ADLL,,,", (direction == 0) ? "Tx" : "Rx");
+ print_adll(dev_num, ctrl_adll);
+ }
+ ddr3_tip_reset_fifo_ptr(dev_num);
+
+ return 0;
+}
+
+void print_topology(struct hws_topology_map *topology_db)
+{
+ u32 ui, uj;
+
+ printf("\tinterface_mask: 0x%x\n", topology_db->if_act_mask);
+ printf("\tNum Bus: %d\n", topology_db->num_of_bus_per_interface);
+ printf("\tbus_act_mask: 0x%x\n", topology_db->bus_act_mask);
+
+ for (ui = 0; ui < MAX_INTERFACE_NUM; ui++) {
+ VALIDATE_ACTIVE(topology_db->if_act_mask, ui);
+ printf("\n\tInterface ID: %d\n", ui);
+ printf("\t\tDDR Frequency: %s\n",
+ convert_freq(topology_db->
+ interface_params[ui].memory_freq));
+ printf("\t\tSpeed_bin: %d\n",
+ topology_db->interface_params[ui].speed_bin_index);
+ printf("\t\tBus_width: %d\n",
+ (4 << topology_db->interface_params[ui].bus_width));
+ printf("\t\tMem_size: %s\n",
+ convert_mem_size(topology_db->
+ interface_params[ui].memory_size));
+ printf("\t\tCAS-WL: %d\n",
+ topology_db->interface_params[ui].cas_wl);
+ printf("\t\tCAS-L: %d\n",
+ topology_db->interface_params[ui].cas_l);
+ printf("\t\tTemperature: %d\n",
+ topology_db->interface_params[ui].interface_temp);
+ printf("\n");
+ for (uj = 0; uj < 4; uj++) {
+ printf("\t\tBus %d parameters- CS Mask: 0x%x\t", uj,
+ topology_db->interface_params[ui].
+ as_bus_params[uj].cs_bitmask);
+ printf("Mirror: 0x%x\t",
+ topology_db->interface_params[ui].
+ as_bus_params[uj].mirror_enable_bitmask);
+ printf("DQS Swap is %s \t",
+ (topology_db->
+ interface_params[ui].as_bus_params[uj].
+ is_dqs_swap == 1) ? "enabled" : "disabled");
+ printf("Ck Swap:%s\t",
+ (topology_db->
+ interface_params[ui].as_bus_params[uj].
+ is_ck_swap == 1) ? "enabled" : "disabled");
+ printf("\n");
+ }
+ }
+}
+#endif
+
+/*
+ * Execute XSB Test transaction (rd/wr/both)
+ */
+int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type,
+ u32 read_type, u32 burst_length)
+{
+ u32 seq = 0, if_id = 0, addr, cnt;
+ int ret = MV_OK, ret_tmp;
+ u32 data_read[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ addr = mem_addr;
+ for (cnt = 0; cnt <= burst_length; cnt++) {
+ seq = (seq + 1) % 8;
+ if (write_type != 0) {
+ CHECK_STATUS(ddr3_tip_ext_write
+ (dev_num, if_id, addr, 1,
+ xsb_test_table[seq]));
+ }
+ if (read_type != 0) {
+ CHECK_STATUS(ddr3_tip_ext_read
+ (dev_num, if_id, addr, 1,
+ data_read));
+ }
+ if ((read_type != 0) && (write_type != 0)) {
+ ret_tmp =
+ ddr3_tip_compare(if_id,
+ xsb_test_table[seq],
+ data_read,
+ 0xff);
+ addr += (EXT_ACCESS_BURST_LENGTH * 4);
+ ret = (ret != MV_OK) ? ret : ret_tmp;
+ }
+ }
+ }
+
+ return ret;
+}
+
+#else /*EXCLUDE_SWITCH_DEBUG */
+
+u32 rl_version = 1; /* 0 - old RL machine */
+u32 vref = 0x4;
+u32 start_xsb_offset = 0;
+u8 cs_mask_reg[] = {
+ 0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type,
+ u32 read_type, u32 burst_length)
+{
+ return MV_OK;
+}
+
+#endif
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c
new file mode 100644
index 0000000000..560da7ee80
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define REG_READ_DATA_SAMPLE_DELAYS_ADDR 0x1538
+#define REG_READ_DATA_SAMPLE_DELAYS_MASK 0x1f
+#define REG_READ_DATA_SAMPLE_DELAYS_OFFS 8
+
+#define REG_READ_DATA_READY_DELAYS_ADDR 0x153c
+#define REG_READ_DATA_READY_DELAYS_MASK 0x1f
+#define REG_READ_DATA_READY_DELAYS_OFFS 8
+
+int ddr3_if_ecc_enabled(void)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask) ||
+ DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))
+ return 1;
+ else
+ return 0;
+}
+
+int ddr3_pre_algo_config(void)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* Set Bus3 ECC training mode */
+ if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask)) {
+ /* Set Bus3 ECC MUX */
+ CHECK_STATUS(ddr3_tip_if_write
+ (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+ REG_SDRAM_PINS_MUX, 0x100, 0x100));
+ }
+
+ /* Set regular ECC training mode (bus4 and bus 3) */
+ if ((DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask)) ||
+ (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))) {
+ /* Enable ECC Write MUX */
+ CHECK_STATUS(ddr3_tip_if_write
+ (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x100, 0x100));
+ /* General ECC enable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+ REG_SDRAM_CONFIG_ADDR, 0x40000, 0x40000));
+ /* Disable Read Data ECC MUX */
+ CHECK_STATUS(ddr3_tip_if_write
+ (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x0, 0x2));
+ }
+
+ return MV_OK;
+}
+
+int ddr3_post_algo_config(void)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+ int status;
+
+ status = ddr3_post_run_alg();
+ if (MV_OK != status) {
+ printf("DDR3 Post Run Alg - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ /* Un_set ECC training mode */
+ if ((DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask)) ||
+ (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))) {
+ /* Disable ECC Write MUX */
+ CHECK_STATUS(ddr3_tip_if_write
+ (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x0, 0x100));
+ /* General ECC and Bus3 ECC MUX remains enabled */
+ }
+
+ return MV_OK;
+}
+
+int ddr3_hws_hw_training(void)
+{
+ enum hws_algo_type algo_mode = ALGO_TYPE_DYNAMIC;
+ int status;
+ struct init_cntr_param init_param;
+
+ status = ddr3_silicon_pre_init();
+ if (MV_OK != status) {
+ printf("DDR3 Pre silicon Config - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ init_param.do_mrs_phy = 1;
+#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X)
+ init_param.is_ctrl64_bit = 0;
+#else
+ init_param.is_ctrl64_bit = 1;
+#endif
+#if defined(CONFIG_ALLEYCAT3) || defined(CONFIG_ARMADA_38X) || \
+ defined(CONFIG_ARMADA_39X)
+ init_param.init_phy = 1;
+#else
+ init_param.init_phy = 0;
+#endif
+ init_param.msys_init = 1;
+ status = hws_ddr3_tip_init_controller(0, &init_param);
+ if (MV_OK != status) {
+ printf("DDR3 init controller - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ status = ddr3_silicon_post_init();
+ if (MV_OK != status) {
+ printf("DDR3 Post Init - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ status = ddr3_pre_algo_config();
+ if (MV_OK != status) {
+ printf("DDR3 Pre Algo Config - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ /* run algorithm in order to configure the PHY */
+ status = hws_ddr3_tip_run_alg(0, algo_mode);
+ if (MV_OK != status) {
+ printf("DDR3 run algorithm - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ status = ddr3_post_algo_config();
+ if (MV_OK != status) {
+ printf("DDR3 Post Algo Config - FAILED 0x%x\n", status);
+ return status;
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h
new file mode 100644
index 0000000000..17a09530d7
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_HWS_HW_TRAINING_H
+#define _DDR3_HWS_HW_TRAINING_H
+
+/* struct used for DLB configuration array */
+struct dlb_config {
+ u32 reg_addr;
+ u32 reg_data;
+};
+
+/* Topology update structure */
+struct topology_update_info {
+ int update_ecc;
+ u8 ecc;
+ int update_width;
+ u8 width;
+ int update_ecc_pup3_mode;
+ u8 ecc_pup_mode_offset;
+};
+
+/* Topology update defines */
+#define TOPOLOGY_UPDATE_WIDTH_16BIT 1
+#define TOPOLOGY_UPDATE_WIDTH_32BIT 0
+#define TOPOLOGY_UPDATE_WIDTH_32BIT_MASK 0xf
+#define TOPOLOGY_UPDATE_WIDTH_16BIT_MASK 0x3
+
+#define TOPOLOGY_UPDATE_ECC_ON 1
+#define TOPOLOGY_UPDATE_ECC_OFF 0
+#define TOPOLOGY_UPDATE_ECC_OFFSET_PUP4 4
+#define TOPOLOGY_UPDATE_ECC_OFFSET_PUP3 3
+
+/*
+ * 1. L2 filter should be set at binary header to 0xd000000,
+ * to avoid conflict with internal register IO.
+ * 2. U-Boot modifies internal registers base to 0xf100000,
+ * and than should update L2 filter accordingly to 0xf000000 (3.75 GB)
+ */
+/* temporary limit l2 filter to 3GiB (LSP issue) */
+#define L2_FILTER_FOR_MAX_MEMORY_SIZE 0xc0000000
+#define ADDRESS_FILTERING_END_REGISTER 0x8c04
+
+#define SUB_VERSION 0
+
+#endif /* _DDR3_HWS_HW_TRAINING_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h
new file mode 100644
index 0000000000..7500a72403
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_HWS_HW_TRAINING_DEF_H
+#define _DDR3_HWS_HW_TRAINING_DEF_H
+
+#define SAR_DDR3_FREQ_MASK 0xfe00000
+#define SAR_CPU_FAB_GET(cpu, fab) (((cpu & 0x7) << 21) | \
+ ((fab & 0xf) << 24))
+
+#define MAX_CS 4
+
+#define MIN_DIMM_ADDR 0x50
+#define FAR_END_DIMM_ADDR 0x50
+#define MAX_DIMM_ADDR 0x60
+
+#define SDRAM_CS_SIZE 0xfffffff
+#define SDRAM_CS_BASE 0x0
+#define SDRAM_DIMM_SIZE 0x80000000
+
+#define CPU_CONFIGURATION_REG(id) (0x21800 + (id * 0x100))
+#define CPU_MRVL_ID_OFFSET 0x10
+#define SAR1_CPU_CORE_MASK 0x00000018
+#define SAR1_CPU_CORE_OFFSET 3
+
+#define NEW_FABRIC_TWSI_ADDR 0x4e
+#ifdef DB_784MP_GP
+#define BUS_WIDTH_ECC_TWSI_ADDR 0x4e
+#else
+#define BUS_WIDTH_ECC_TWSI_ADDR 0x4f
+#endif
+#define MV_MAX_DDR3_STATIC_SIZE 50
+#define MV_DDR3_MODES_NUMBER 30
+
+#define RESUME_RL_PATTERNS_ADDR 0xfe0000
+#define RESUME_RL_PATTERNS_SIZE 0x100
+#define RESUME_TRAINING_VALUES_ADDR (RESUME_RL_PATTERNS_ADDR + \
+ RESUME_RL_PATTERNS_SIZE)
+#define RESUME_TRAINING_VALUES_MAX 0xcd0
+#define BOOT_INFO_ADDR (RESUME_RL_PATTERNS_ADDR + 0x1000)
+#define CHECKSUM_RESULT_ADDR (BOOT_INFO_ADDR + 0x1000)
+#define NUM_OF_REGISTER_ADDR (CHECKSUM_RESULT_ADDR + 4)
+#define SUSPEND_MAGIC_WORD 0xdeadb002
+#define REGISTER_LIST_END 0xffffffff
+
+/* MISC */
+#define INTER_REGS_BASE SOC_REGS_PHY_BASE
+
+/* DDR */
+#define REG_SDRAM_CONFIG_ADDR 0x1400
+#define REG_SDRAM_CONFIG_MASK 0x9fffffff
+#define REG_SDRAM_CONFIG_RFRS_MASK 0x3fff
+#define REG_SDRAM_CONFIG_WIDTH_OFFS 15
+#define REG_SDRAM_CONFIG_REGDIMM_OFFS 17
+#define REG_SDRAM_CONFIG_ECC_OFFS 18
+#define REG_SDRAM_CONFIG_IERR_OFFS 19
+#define REG_SDRAM_CONFIG_PUPRSTDIV_OFFS 28
+#define REG_SDRAM_CONFIG_RSTRD_OFFS 30
+
+#define REG_SDRAM_PINS_MUX 0x19d4
+
+#define REG_DUNIT_CTRL_LOW_ADDR 0x1404
+#define REG_DUNIT_CTRL_LOW_2T_OFFS 3
+#define REG_DUNIT_CTRL_LOW_2T_MASK 0x3
+#define REG_DUNIT_CTRL_LOW_DPDE_OFFS 14
+
+#define REG_SDRAM_TIMING_LOW_ADDR 0x1408
+#define REG_SDRAM_TIMING_HIGH_ADDR 0x140c
+#define REG_SDRAM_TIMING_H_R2R_OFFS 7
+#define REG_SDRAM_TIMING_H_R2R_MASK 0x3
+#define REG_SDRAM_TIMING_H_R2W_W2R_OFFS 9
+#define REG_SDRAM_TIMING_H_R2W_W2R_MASK 0x3
+#define REG_SDRAM_TIMING_H_W2W_OFFS 11
+#define REG_SDRAM_TIMING_H_W2W_MASK 0x1f
+#define REG_SDRAM_TIMING_H_R2R_H_OFFS 19
+#define REG_SDRAM_TIMING_H_R2R_H_MASK 0x7
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS 22
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_MASK 0x7
+
+#define REG_SDRAM_ADDRESS_CTRL_ADDR 0x1410
+#define REG_SDRAM_ADDRESS_SIZE_OFFS 2
+#define REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS 18
+#define REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS 4
+
+#define REG_SDRAM_OPEN_PAGES_ADDR 0x1414
+#define REG_SDRAM_OPERATION_CS_OFFS 8
+
+#define REG_SDRAM_OPERATION_ADDR 0x1418
+#define REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS 24
+#define REG_SDRAM_OPERATION_CWA_DATA_OFFS 20
+#define REG_SDRAM_OPERATION_CWA_DATA_MASK 0xf
+#define REG_SDRAM_OPERATION_CWA_RC_OFFS 16
+#define REG_SDRAM_OPERATION_CWA_RC_MASK 0xf
+#define REG_SDRAM_OPERATION_CMD_MR0 0xf03
+#define REG_SDRAM_OPERATION_CMD_MR1 0xf04
+#define REG_SDRAM_OPERATION_CMD_MR2 0xf08
+#define REG_SDRAM_OPERATION_CMD_MR3 0xf09
+#define REG_SDRAM_OPERATION_CMD_RFRS 0xf02
+#define REG_SDRAM_OPERATION_CMD_CWA 0xf0e
+#define REG_SDRAM_OPERATION_CMD_RFRS_DONE 0xf
+#define REG_SDRAM_OPERATION_CMD_MASK 0xf
+#define REG_SDRAM_OPERATION_CS_OFFS 8
+
+#define REG_OUDDR3_TIMING_ADDR 0x142c
+
+#define REG_SDRAM_MODE_ADDR 0x141c
+
+#define REG_SDRAM_EXT_MODE_ADDR 0x1420
+
+#define REG_DDR_CONT_HIGH_ADDR 0x1424
+
+#define REG_ODT_TIME_LOW_ADDR 0x1428
+#define REG_ODT_ON_CTL_RD_OFFS 12
+#define REG_ODT_OFF_CTL_RD_OFFS 16
+#define REG_SDRAM_ERROR_ADDR 0x1454
+#define REG_SDRAM_AUTO_PWR_SAVE_ADDR 0x1474
+#define REG_ODT_TIME_HIGH_ADDR 0x147c
+
+#define REG_SDRAM_INIT_CTRL_ADDR 0x1480
+#define REG_SDRAM_INIT_CTRL_OFFS 0
+#define REG_SDRAM_INIT_CKE_ASSERT_OFFS 2
+#define REG_SDRAM_INIT_RESET_DEASSERT_OFFS 3
+#define REG_SDRAM_INIT_RESET_MASK_OFFS 1
+
+#define REG_SDRAM_ODT_CTRL_LOW_ADDR 0x1494
+
+#define REG_SDRAM_ODT_CTRL_HIGH_ADDR 0x1498
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK 0x0
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA 0x3
+
+#define REG_DUNIT_ODT_CTRL_ADDR 0x149c
+#define REG_DUNIT_ODT_CTRL_OVRD_OFFS 8
+#define REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS 9
+
+#define REG_DRAM_FIFO_CTRL_ADDR 0x14a0
+
+#define REG_DRAM_AXI_CTRL_ADDR 0x14a8
+#define REG_DRAM_AXI_CTRL_AXIDATABUSWIDTH_OFFS 0
+
+#define REG_METAL_MASK_ADDR 0x14b0
+#define REG_METAL_MASK_MASK 0xdfffffff
+#define REG_METAL_MASK_RETRY_OFFS 0
+
+#define REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR 0x14c0
+
+#define REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR 0x14c4
+#define REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR 0x14c8
+#define REG_DRAM_MAIN_PADS_CAL_ADDR 0x14cc
+
+#define REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR 0x17c8
+
+#define REG_CS_SIZE_SCRATCH_ADDR 0x1504
+#define REG_DYNAMIC_POWER_SAVE_ADDR 0x1520
+#define REG_DDR_IO_ADDR 0x1524
+#define REG_DDR_IO_CLK_RATIO_OFFS 15
+
+#define REG_DFS_ADDR 0x1528
+#define REG_DFS_DLLNEXTSTATE_OFFS 0
+#define REG_DFS_BLOCK_OFFS 1
+#define REG_DFS_SR_OFFS 2
+#define REG_DFS_ATSR_OFFS 3
+#define REG_DFS_RECONF_OFFS 4
+#define REG_DFS_CL_NEXT_STATE_OFFS 8
+#define REG_DFS_CL_NEXT_STATE_MASK 0xf
+#define REG_DFS_CWL_NEXT_STATE_OFFS 12
+#define REG_DFS_CWL_NEXT_STATE_MASK 0x7
+
+#define REG_READ_DATA_SAMPLE_DELAYS_ADDR 0x1538
+#define REG_READ_DATA_SAMPLE_DELAYS_MASK 0x1f
+#define REG_READ_DATA_SAMPLE_DELAYS_OFFS 8
+
+#define REG_READ_DATA_READY_DELAYS_ADDR 0x153c
+#define REG_READ_DATA_READY_DELAYS_MASK 0x1f
+#define REG_READ_DATA_READY_DELAYS_OFFS 8
+
+#define START_BURST_IN_ADDR 1
+
+#define REG_DRAM_TRAINING_SHADOW_ADDR 0x18488
+#define REG_DRAM_TRAINING_ADDR 0x15b0
+#define REG_DRAM_TRAINING_LOW_FREQ_OFFS 0
+#define REG_DRAM_TRAINING_PATTERNS_OFFS 4
+#define REG_DRAM_TRAINING_MED_FREQ_OFFS 2
+#define REG_DRAM_TRAINING_WL_OFFS 3
+#define REG_DRAM_TRAINING_RL_OFFS 6
+#define REG_DRAM_TRAINING_DQS_RX_OFFS 15
+#define REG_DRAM_TRAINING_DQS_TX_OFFS 16
+#define REG_DRAM_TRAINING_CS_OFFS 20
+#define REG_DRAM_TRAINING_RETEST_OFFS 24
+#define REG_DRAM_TRAINING_DFS_FREQ_OFFS 27
+#define REG_DRAM_TRAINING_DFS_REQ_OFFS 29
+#define REG_DRAM_TRAINING_ERROR_OFFS 30
+#define REG_DRAM_TRAINING_AUTO_OFFS 31
+#define REG_DRAM_TRAINING_RETEST_PAR 0x3
+#define REG_DRAM_TRAINING_RETEST_MASK 0xf8ffffff
+#define REG_DRAM_TRAINING_CS_MASK 0xff0fffff
+#define REG_DRAM_TRAINING_PATTERNS_MASK 0xff0f0000
+
+#define REG_DRAM_TRAINING_1_ADDR 0x15b4
+#define REG_DRAM_TRAINING_1_TRNBPOINT_OFFS 16
+
+#define REG_DRAM_TRAINING_2_ADDR 0x15b8
+#define REG_DRAM_TRAINING_2_OVERRUN_OFFS 17
+#define REG_DRAM_TRAINING_2_FIFO_RST_OFFS 4
+#define REG_DRAM_TRAINING_2_RL_MODE_OFFS 3
+#define REG_DRAM_TRAINING_2_WL_MODE_OFFS 2
+#define REG_DRAM_TRAINING_2_ECC_MUX_OFFS 1
+#define REG_DRAM_TRAINING_2_SW_OVRD_OFFS 0
+
+#define REG_DRAM_TRAINING_PATTERN_BASE_ADDR 0x15bc
+#define REG_DRAM_TRAINING_PATTERN_BASE_OFFS 3
+
+#define REG_TRAINING_DEBUG_2_ADDR 0x15c4
+#define REG_TRAINING_DEBUG_2_OFFS 16
+#define REG_TRAINING_DEBUG_2_MASK 0x3
+
+#define REG_TRAINING_DEBUG_3_ADDR 0x15c8
+#define REG_TRAINING_DEBUG_3_OFFS 3
+#define REG_TRAINING_DEBUG_3_MASK 0x7
+
+#define MR_CS_ADDR_OFFS 4
+
+#define REG_DDR3_MR0_ADDR 0x15d0
+#define REG_DDR3_MR0_CS_ADDR 0x1870
+#define REG_DDR3_MR0_CL_MASK 0x74
+#define REG_DDR3_MR0_CL_OFFS 2
+#define REG_DDR3_MR0_CL_HIGH_OFFS 3
+#define CL_MASK 0xf
+
+#define REG_DDR3_MR1_ADDR 0x15d4
+#define REG_DDR3_MR1_CS_ADDR 0x1874
+#define REG_DDR3_MR1_RTT_MASK 0xfffffdbb
+#define REG_DDR3_MR1_DLL_ENA_OFFS 0
+#define REG_DDR3_MR1_RTT_DISABLED 0x0
+#define REG_DDR3_MR1_RTT_RZQ2 0x40
+#define REG_DDR3_MR1_RTT_RZQ4 0x2
+#define REG_DDR3_MR1_RTT_RZQ6 0x42
+#define REG_DDR3_MR1_RTT_RZQ8 0x202
+#define REG_DDR3_MR1_RTT_RZQ12 0x4
+/* WL-disabled, OB-enabled */
+#define REG_DDR3_MR1_OUTBUF_WL_MASK 0xffffef7f
+/* Output Buffer Disabled */
+#define REG_DDR3_MR1_OUTBUF_DIS_OFFS 12
+#define REG_DDR3_MR1_WL_ENA_OFFS 7
+#define REG_DDR3_MR1_WL_ENA 0x80 /* WL Enabled */
+#define REG_DDR3_MR1_ODT_MASK 0xfffffdbb
+
+#define REG_DDR3_MR2_ADDR 0x15d8
+#define REG_DDR3_MR2_CS_ADDR 0x1878
+#define REG_DDR3_MR2_CWL_OFFS 3
+#define REG_DDR3_MR2_CWL_MASK 0x7
+#define REG_DDR3_MR2_ODT_MASK 0xfffff9ff
+#define REG_DDR3_MR3_ADDR 0x15dc
+#define REG_DDR3_MR3_CS_ADDR 0x187c
+
+#define REG_DDR3_RANK_CTRL_ADDR 0x15e0
+#define REG_DDR3_RANK_CTRL_CS_ENA_MASK 0xf
+#define REG_DDR3_RANK_CTRL_MIRROR_OFFS 4
+
+#define REG_ZQC_CONF_ADDR 0x15e4
+
+#define REG_DRAM_PHY_CONFIG_ADDR 0x15ec
+#define REG_DRAM_PHY_CONFIG_MASK 0x3fffffff
+
+#define REG_ODPG_CNTRL_ADDR 0x1600
+#define REG_ODPG_CNTRL_OFFS 21
+
+#define REG_PHY_LOCK_MASK_ADDR 0x1670
+#define REG_PHY_LOCK_MASK_MASK 0xfffff000
+
+#define REG_PHY_LOCK_STATUS_ADDR 0x1674
+#define REG_PHY_LOCK_STATUS_LOCK_OFFS 9
+#define REG_PHY_LOCK_STATUS_LOCK_MASK 0xfff
+#define REG_PHY_LOCK_APLL_ADLL_STATUS_MASK 0x7ff
+
+#define REG_PHY_REGISTRY_FILE_ACCESS_ADDR 0x16a0
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_WR 0xc0000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_RD 0x80000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE 0x80000000
+#define REG_PHY_BC_OFFS 27
+#define REG_PHY_CNTRL_OFFS 26
+#define REG_PHY_CS_OFFS 16
+#define REG_PHY_DQS_REF_DLY_OFFS 10
+#define REG_PHY_PHASE_OFFS 8
+#define REG_PHY_PUP_OFFS 22
+
+#define REG_TRAINING_WL_ADDR 0x16ac
+#define REG_TRAINING_WL_CS_MASK 0xfffffffc
+#define REG_TRAINING_WL_UPD_OFFS 2
+#define REG_TRAINING_WL_CS_DONE_OFFS 3
+#define REG_TRAINING_WL_RATIO_MASK 0xffffff0f
+#define REG_TRAINING_WL_1TO1 0x50
+#define REG_TRAINING_WL_2TO1 0x10
+#define REG_TRAINING_WL_DELAYEXP_MASK 0x20000000
+#define REG_TRAINING_WL_RESULTS_MASK 0x000001ff
+#define REG_TRAINING_WL_RESULTS_OFFS 20
+
+#define REG_REGISTERED_DRAM_CTRL_ADDR 0x16d0
+#define REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS 15
+#define REG_REGISTERED_DRAM_CTRL_PARITY_MASK 0x3f
+
+/* DLB */
+#define REG_STATIC_DRAM_DLB_CONTROL 0x1700
+#define DLB_BUS_OPTIMIZATION_WEIGHTS_REG 0x1704
+#define DLB_AGING_REGISTER 0x1708
+#define DLB_EVICTION_CONTROL_REG 0x170c
+#define DLB_EVICTION_TIMERS_REGISTER_REG 0x1710
+#define DLB_USER_COMMAND_REG 0x1714
+#define DLB_BUS_WEIGHTS_DIFF_CS 0x1770
+#define DLB_BUS_WEIGHTS_DIFF_BG 0x1774
+#define DLB_BUS_WEIGHTS_SAME_BG 0x1778
+#define DLB_BUS_WEIGHTS_RD_WR 0x177c
+#define DLB_BUS_WEIGHTS_ATTR_SYS_PRIO 0x1780
+#define DLB_MAIN_QUEUE_MAP 0x1784
+#define DLB_LINE_SPLIT 0x1788
+
+#define DLB_ENABLE 0x1
+#define DLB_WRITE_COALESING (0x1 << 2)
+#define DLB_AXI_PREFETCH_EN (0x1 << 3)
+#define DLB_MBUS_PREFETCH_EN (0x1 << 4)
+#define PREFETCH_N_LN_SZ_TR (0x1 << 6)
+#define DLB_INTERJECTION_ENABLE (0x1 << 3)
+
+/* CPU */
+#define REG_BOOTROM_ROUTINE_ADDR 0x182d0
+#define REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS 12
+
+#define REG_DRAM_INIT_CTRL_STATUS_ADDR 0x18488
+#define REG_DRAM_INIT_CTRL_TRN_CLK_OFFS 16
+#define REG_CPU_DIV_CLK_CTRL_0_NEW_RATIO 0x000200ff
+#define REG_DRAM_INIT_CTRL_STATUS_2_ADDR 0x1488
+
+#define REG_CPU_DIV_CLK_CTRL_0_ADDR 0x18700
+
+#define REG_CPU_DIV_CLK_CTRL_1_ADDR 0x18704
+#define REG_CPU_DIV_CLK_CTRL_2_ADDR 0x18708
+
+#define REG_CPU_DIV_CLK_CTRL_3_ADDR 0x1870c
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK 0xffffc0ff
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS 8
+
+#define REG_CPU_DIV_CLK_CTRL_4_ADDR 0x18710
+
+#define REG_CPU_DIV_CLK_STATUS_0_ADDR 0x18718
+#define REG_CPU_DIV_CLK_ALL_STABLE_OFFS 8
+
+#define REG_CPU_PLL_CTRL_0_ADDR 0x1871c
+#define REG_CPU_PLL_STATUS_0_ADDR 0x18724
+#define REG_CORE_DIV_CLK_CTRL_ADDR 0x18740
+#define REG_CORE_DIV_CLK_STATUS_ADDR 0x18744
+#define REG_DDRPHY_APLL_CTRL_ADDR 0x18780
+
+#define REG_DDRPHY_APLL_CTRL_2_ADDR 0x18784
+#define REG_SFABRIC_CLK_CTRL_ADDR 0x20858
+#define REG_SFABRIC_CLK_CTRL_SMPL_OFFS 8
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_19_CTRL_ADDR 0x200e8
+#define REG_XBAR_WIN_4_CTRL_ADDR 0x20040
+#define REG_XBAR_WIN_4_BASE_ADDR 0x20044
+#define REG_XBAR_WIN_4_REMAP_ADDR 0x20048
+#define REG_FASTPATH_WIN_0_CTRL_ADDR 0x20184
+#define REG_XBAR_WIN_7_REMAP_ADDR 0x20078
+
+/* SRAM */
+#define REG_CDI_CONFIG_ADDR 0x20220
+#define REG_SRAM_WINDOW_0_ADDR 0x20240
+#define REG_SRAM_WINDOW_0_ENA_OFFS 0
+#define REG_SRAM_WINDOW_1_ADDR 0x20244
+#define REG_SRAM_L2_ENA_ADDR 0x8500
+#define REG_SRAM_CLEAN_BY_WAY_ADDR 0x87bc
+
+/* Timers */
+#define REG_TIMERS_CTRL_ADDR 0x20300
+#define REG_TIMERS_EVENTS_ADDR 0x20304
+#define REG_TIMER0_VALUE_ADDR 0x20314
+#define REG_TIMER1_VALUE_ADDR 0x2031c
+#define REG_TIMER0_ENABLE_MASK 0x1
+
+#define MV_BOARD_REFCLK_25MHZ 25000000
+#define CNTMR_RELOAD_REG(tmr) (REG_TIMERS_CTRL_ADDR + 0x10 + (tmr * 8))
+#define CNTMR_VAL_REG(tmr) (REG_TIMERS_CTRL_ADDR + 0x14 + (tmr * 8))
+#define CNTMR_CTRL_REG(tmr) (REG_TIMERS_CTRL_ADDR)
+#define CTCR_ARM_TIMER_EN_OFFS(timer) (timer * 2)
+#define CTCR_ARM_TIMER_EN_MASK(timer) (1 << CTCR_ARM_TIMER_EN_OFFS(timer))
+#define CTCR_ARM_TIMER_EN(timer) (1 << CTCR_ARM_TIMER_EN_OFFS(timer))
+
+#define CTCR_ARM_TIMER_AUTO_OFFS(timer) (1 + (timer * 2))
+#define CTCR_ARM_TIMER_AUTO_MASK(timer) (1 << CTCR_ARM_TIMER_EN_OFFS(timer))
+#define CTCR_ARM_TIMER_AUTO_EN(timer) (1 << CTCR_ARM_TIMER_AUTO_OFFS(timer))
+
+/* PMU */
+#define REG_PMU_I_F_CTRL_ADDR 0x1c090
+#define REG_PMU_DUNIT_BLK_OFFS 16
+#define REG_PMU_DUNIT_RFRS_OFFS 20
+#define REG_PMU_DUNIT_ACK_OFFS 24
+
+/* MBUS */
+#define MBUS_UNITS_PRIORITY_CONTROL_REG (MBUS_REGS_OFFSET + 0x420)
+#define FABRIC_UNITS_PRIORITY_CONTROL_REG (MBUS_REGS_OFFSET + 0x424)
+#define MBUS_UNITS_PREFETCH_CONTROL_REG (MBUS_REGS_OFFSET + 0x428)
+#define FABRIC_UNITS_PREFETCH_CONTROL_REG (MBUS_REGS_OFFSET + 0x42c)
+
+#define REG_PM_STAT_MASK_ADDR 0x2210c
+#define REG_PM_STAT_MASK_CPU0_IDLE_MASK_OFFS 16
+
+#define REG_PM_EVENT_STAT_MASK_ADDR 0x22120
+#define REG_PM_EVENT_STAT_MASK_DFS_DONE_OFFS 17
+
+#define REG_PM_CTRL_CONFIG_ADDR 0x22104
+#define REG_PM_CTRL_CONFIG_DFS_REQ_OFFS 18
+
+#define REG_FABRIC_LOCAL_IRQ_MASK_ADDR 0x218c4
+#define REG_FABRIC_LOCAL_IRQ_PMU_MASK_OFFS 18
+
+/* Controller revision info */
+#define PCI_CLASS_CODE_AND_REVISION_ID 0x008
+#define PCCRIR_REVID_OFFS 0 /* Revision ID */
+#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS)
+
+/* Power Management Clock Gating Control Register */
+#define POWER_MNG_CTRL_REG 0x18220
+#define PEX_DEVICE_AND_VENDOR_ID 0x000
+#define PEX_CFG_DIRECT_ACCESS(if, reg) (PEX_IF_REGS_BASE(if) + (reg))
+#define PMC_PEXSTOPCLOCK_OFFS(p) ((p) < 8 ? (5 + (p)) : (18 + (p)))
+#define PMC_PEXSTOPCLOCK_MASK(p) (1 << PMC_PEXSTOPCLOCK_OFFS(p))
+#define PMC_PEXSTOPCLOCK_EN(p) (1 << PMC_PEXSTOPCLOCK_OFFS(p))
+#define PMC_PEXSTOPCLOCK_STOP(p) (0 << PMC_PEXSTOPCLOCK_OFFS(p))
+
+/* TWSI */
+#define TWSI_DATA_ADDR_MASK 0x7
+#define TWSI_DATA_ADDR_OFFS 1
+
+/* General */
+#define MAX_CS 4
+
+/* Frequencies */
+#define FAB_OPT 21
+#define CLK_CPU 12
+#define CLK_VCO (2 * CLK_CPU)
+#define CLK_DDR 12
+
+/* CPU Frequencies: */
+#define CLK_CPU_1000 0
+#define CLK_CPU_1066 1
+#define CLK_CPU_1200 2
+#define CLK_CPU_1333 3
+#define CLK_CPU_1500 4
+#define CLK_CPU_1666 5
+#define CLK_CPU_1800 6
+#define CLK_CPU_2000 7
+#define CLK_CPU_600 8
+#define CLK_CPU_667 9
+#define CLK_CPU_800 0xa
+
+/* Extra Cpu Frequencies: */
+#define CLK_CPU_1600 11
+#define CLK_CPU_2133 12
+#define CLK_CPU_2200 13
+#define CLK_CPU_2400 14
+
+#define SAR1_CPU_CORE_MASK 0x00000018
+#define SAR1_CPU_CORE_OFFSET 3
+
+#endif /* _DDR3_HWS_HW_TRAINING_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h b/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h
new file mode 100644
index 0000000000..544237a276
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_HWS_SIL_TRAINING_H
+#define _DDR3_HWS_SIL_TRAINING_H
+
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_prv_if.h"
+
+int ddr3_silicon_pre_config(void);
+int ddr3_silicon_init(void);
+int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq);
+
+#endif /* _DDR3_HWS_SIL_TRAINING_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_init.c b/drivers/ddr/marvell/a38x/ddr3_init.c
new file mode 100644
index 0000000000..d6ed8e03e9
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_init.c
@@ -0,0 +1,852 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#include "../../../../arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h"
+
+static struct dlb_config ddr3_dlb_config_table[] = {
+ {REG_STATIC_DRAM_DLB_CONTROL, 0x2000005c},
+ {DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x00880000},
+ {DLB_AGING_REGISTER, 0x0f7f007f},
+ {DLB_EVICTION_CONTROL_REG, 0x0000129f},
+ {DLB_EVICTION_TIMERS_REGISTER_REG, 0x00ff0000},
+ {DLB_BUS_WEIGHTS_DIFF_CS, 0x04030802},
+ {DLB_BUS_WEIGHTS_DIFF_BG, 0x00000a02},
+ {DLB_BUS_WEIGHTS_SAME_BG, 0x09000a01},
+ {DLB_BUS_WEIGHTS_RD_WR, 0x00020005},
+ {DLB_BUS_WEIGHTS_ATTR_SYS_PRIO, 0x00060f10},
+ {DLB_MAIN_QUEUE_MAP, 0x00000543},
+ {DLB_LINE_SPLIT, 0x00000000},
+ {DLB_USER_COMMAND_REG, 0x00000000},
+ {0x0, 0x0}
+};
+
+static struct dlb_config ddr3_dlb_config_table_a0[] = {
+ {REG_STATIC_DRAM_DLB_CONTROL, 0x2000005c},
+ {DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x00880000},
+ {DLB_AGING_REGISTER, 0x0f7f007f},
+ {DLB_EVICTION_CONTROL_REG, 0x0000129f},
+ {DLB_EVICTION_TIMERS_REGISTER_REG, 0x00ff0000},
+ {DLB_BUS_WEIGHTS_DIFF_CS, 0x04030802},
+ {DLB_BUS_WEIGHTS_DIFF_BG, 0x00000a02},
+ {DLB_BUS_WEIGHTS_SAME_BG, 0x09000a01},
+ {DLB_BUS_WEIGHTS_RD_WR, 0x00020005},
+ {DLB_BUS_WEIGHTS_ATTR_SYS_PRIO, 0x00060f10},
+ {DLB_MAIN_QUEUE_MAP, 0x00000543},
+ {DLB_LINE_SPLIT, 0x00000000},
+ {DLB_USER_COMMAND_REG, 0x00000000},
+ {0x0, 0x0}
+};
+
+#if defined(CONFIG_ARMADA_38X)
+struct dram_modes {
+ char *mode_name;
+ u8 cpu_freq;
+ u8 fab_freq;
+ u8 chip_id;
+ u8 chip_board_rev;
+ struct reg_data *regs;
+};
+
+struct dram_modes ddr_modes[] = {
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+ /* Conf name, CPUFreq, Fab_freq, Chip ID, Chip/Board, MC regs*/
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+ {"a38x_customer_0_800", DDR_FREQ_800, 0, 0x0, A38X_CUSTOMER_BOARD_ID0,
+ ddr3_customer_800},
+ {"a38x_customer_1_800", DDR_FREQ_800, 0, 0x0, A38X_CUSTOMER_BOARD_ID1,
+ ddr3_customer_800},
+#else
+ {"a38x_533", DDR_FREQ_533, 0, 0x0, MARVELL_BOARD, ddr3_a38x_533},
+ {"a38x_667", DDR_FREQ_667, 0, 0x0, MARVELL_BOARD, ddr3_a38x_667},
+ {"a38x_800", DDR_FREQ_800, 0, 0x0, MARVELL_BOARD, ddr3_a38x_800},
+ {"a38x_933", DDR_FREQ_933, 0, 0x0, MARVELL_BOARD, ddr3_a38x_933},
+#endif
+#endif
+};
+#endif /* defined(CONFIG_ARMADA_38X) */
+
+/* Translates topology map definitions to real memory size in bits */
+u32 mem_size[] = {
+ ADDR_SIZE_512MB, ADDR_SIZE_1GB, ADDR_SIZE_2GB, ADDR_SIZE_4GB,
+ ADDR_SIZE_8GB
+};
+
+static char *ddr_type = "DDR3";
+
+/*
+ * Set 1 to use dynamic DUNIT configuration,
+ * set 0 (supported for A380 and AC3) to configure DUNIT in values set by
+ * ddr3_tip_init_specific_reg_config
+ */
+u8 generic_init_controller = 1;
+
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+static u32 ddr3_get_static_ddr_mode(void);
+#endif
+static int ddr3_hws_tune_training_params(u8 dev_num);
+static int ddr3_update_topology_map(struct hws_topology_map *topology_map);
+
+/* device revision */
+#define DEV_VERSION_ID_REG 0x1823c
+#define REVISON_ID_OFFS 8
+#define REVISON_ID_MASK 0xf00
+
+/* A38x revisions */
+#define MV_88F68XX_Z1_ID 0x0
+#define MV_88F68XX_A0_ID 0x4
+/* A39x revisions */
+#define MV_88F69XX_Z1_ID 0x2
+
+/*
+ * sys_env_device_rev_get - Get Marvell controller device revision number
+ *
+ * DESCRIPTION:
+ * This function returns 8bit describing the device revision as defined
+ * Revision ID Register.
+ *
+ * INPUT:
+ * None.
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * 8bit desscribing Marvell controller revision number
+ */
+u8 sys_env_device_rev_get(void)
+{
+ u32 value;
+
+ value = reg_read(DEV_VERSION_ID_REG);
+ return (value & (REVISON_ID_MASK)) >> REVISON_ID_OFFS;
+}
+
+/*
+ * sys_env_dlb_config_ptr_get
+ *
+ * DESCRIPTION: defines pointer to to DLB COnfiguration table
+ *
+ * INPUT: none
+ *
+ * OUTPUT: pointer to DLB COnfiguration table
+ *
+ * RETURN:
+ * returns pointer to DLB COnfiguration table
+ */
+struct dlb_config *sys_env_dlb_config_ptr_get(void)
+{
+#ifdef CONFIG_ARMADA_39X
+ return &ddr3_dlb_config_table_a0[0];
+#else
+ if (sys_env_device_rev_get() == MV_88F68XX_A0_ID)
+ return &ddr3_dlb_config_table_a0[0];
+ else
+ return &ddr3_dlb_config_table[0];
+#endif
+}
+
+/*
+ * sys_env_get_cs_ena_from_reg
+ *
+ * DESCRIPTION: Get bit mask of enabled CS
+ *
+ * INPUT: None
+ *
+ * OUTPUT: None
+ *
+ * RETURN:
+ * Bit mask of enabled CS, 1 if only CS0 enabled,
+ * 3 if both CS0 and CS1 enabled
+ */
+u32 sys_env_get_cs_ena_from_reg(void)
+{
+ return reg_read(REG_DDR3_RANK_CTRL_ADDR) &
+ REG_DDR3_RANK_CTRL_CS_ENA_MASK;
+}
+
+static void ddr3_restore_and_set_final_windows(u32 *win)
+{
+ u32 win_ctrl_reg, num_of_win_regs;
+ u32 cs_ena = sys_env_get_cs_ena_from_reg();
+ u32 ui;
+
+ win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+ num_of_win_regs = 16;
+
+ /* Return XBAR windows 4-7 or 16-19 init configuration */
+ for (ui = 0; ui < num_of_win_regs; ui++)
+ reg_write((win_ctrl_reg + 0x4 * ui), win[ui]);
+
+ printf("%s Training Sequence - Switching XBAR Window to FastPath Window\n",
+ ddr_type);
+
+#if defined DYNAMIC_CS_SIZE_CONFIG
+ if (ddr3_fast_path_dynamic_cs_size_config(cs_ena) != MV_OK)
+ printf("ddr3_fast_path_dynamic_cs_size_config FAILED\n");
+#else
+ u32 reg, cs;
+ reg = 0x1fffffe1;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= (cs << 2);
+ break;
+ }
+ }
+ /* Open fast path Window to - 0.5G */
+ reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, reg);
+#endif
+}
+
+static int ddr3_save_and_set_training_windows(u32 *win)
+{
+ u32 cs_ena;
+ u32 reg, tmp_count, cs, ui;
+ u32 win_ctrl_reg, win_base_reg, win_remap_reg;
+ u32 num_of_win_regs, win_jump_index;
+ win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+ win_base_reg = REG_XBAR_WIN_4_BASE_ADDR;
+ win_remap_reg = REG_XBAR_WIN_4_REMAP_ADDR;
+ win_jump_index = 0x10;
+ num_of_win_regs = 16;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+#ifdef DISABLE_L2_FILTERING_DURING_DDR_TRAINING
+ /*
+ * Disable L2 filtering during DDR training
+ * (when Cross Bar window is open)
+ */
+ reg_write(ADDRESS_FILTERING_END_REGISTER, 0);
+#endif
+
+ cs_ena = tm->interface_params[0].as_bus_params[0].cs_bitmask;
+
+ /* Close XBAR Window 19 - Not needed */
+ /* {0x000200e8} - Open Mbus Window - 2G */
+ reg_write(REG_XBAR_WIN_19_CTRL_ADDR, 0);
+
+ /* Save XBAR Windows 4-19 init configurations */
+ for (ui = 0; ui < num_of_win_regs; ui++)
+ win[ui] = reg_read(win_ctrl_reg + 0x4 * ui);
+
+ /* Open XBAR Windows 4-7 or 16-19 for other CS */
+ reg = 0;
+ tmp_count = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ switch (cs) {
+ case 0:
+ reg = 0x0e00;
+ break;
+ case 1:
+ reg = 0x0d00;
+ break;
+ case 2:
+ reg = 0x0b00;
+ break;
+ case 3:
+ reg = 0x0700;
+ break;
+ }
+ reg |= (1 << 0);
+ reg |= (SDRAM_CS_SIZE & 0xffff0000);
+
+ reg_write(win_ctrl_reg + win_jump_index * tmp_count,
+ reg);
+ reg = (((SDRAM_CS_SIZE + 1) * (tmp_count)) &
+ 0xffff0000);
+ reg_write(win_base_reg + win_jump_index * tmp_count,
+ reg);
+
+ if (win_remap_reg <= REG_XBAR_WIN_7_REMAP_ADDR)
+ reg_write(win_remap_reg +
+ win_jump_index * tmp_count, 0);
+
+ tmp_count++;
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_init - Main DDR3 Init function
+ * Desc: This routine initialize the DDR3 MC and runs HW training.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+int ddr3_init(void)
+{
+ u32 reg = 0;
+ u32 soc_num;
+ int status;
+ u32 win[16];
+
+ /* SoC/Board special Initializtions */
+ /* Get version from internal library */
+ ddr3_print_version();
+
+ /*Add sub_version string */
+ DEBUG_INIT_C("", SUB_VERSION, 1);
+
+ /* Switching CPU to MRVL ID */
+ soc_num = (reg_read(REG_SAMPLE_RESET_HIGH_ADDR) & SAR1_CPU_CORE_MASK) >>
+ SAR1_CPU_CORE_OFFSET;
+ switch (soc_num) {
+ case 0x3:
+ reg_bit_set(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET);
+ reg_bit_set(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET);
+ case 0x1:
+ reg_bit_set(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET);
+ case 0x0:
+ reg_bit_set(CPU_CONFIGURATION_REG(0), CPU_MRVL_ID_OFFSET);
+ default:
+ break;
+ }
+
+ /*
+ * Set DRAM Reset Mask in case detected GPIO indication of wakeup from
+ * suspend i.e the DRAM values will not be overwritten / reset when
+ * waking from suspend
+ */
+ if (sys_env_suspend_wakeup_check() ==
+ SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED) {
+ reg_bit_set(REG_SDRAM_INIT_CTRL_ADDR,
+ 1 << REG_SDRAM_INIT_RESET_MASK_OFFS);
+ }
+
+ /*
+ * Stage 0 - Set board configuration
+ */
+
+ /* Check if DRAM is already initialized */
+ if (reg_read(REG_BOOTROM_ROUTINE_ADDR) &
+ (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
+ printf("%s Training Sequence - 2nd boot - Skip\n", ddr_type);
+ return MV_OK;
+ }
+
+ /*
+ * Stage 1 - Dunit Setup
+ */
+
+ /* Fix read ready phases for all SOC in reg 0x15c8 */
+ reg = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK);
+ reg |= 0x4; /* Phase 0 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << REG_TRAINING_DEBUG_3_OFFS);
+ reg |= (0x4 << (1 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 1 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (3 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (3 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 3 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (4 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (4 * REG_TRAINING_DEBUG_3_OFFS));
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (5 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (5 * REG_TRAINING_DEBUG_3_OFFS));
+ reg_write(REG_TRAINING_DEBUG_3_ADDR, reg);
+
+ /*
+ * Axi_bresp_mode[8] = Compliant,
+ * Axi_addr_decode_cntrl[11] = Internal,
+ * Axi_data_bus_width[0] = 128bit
+ * */
+ /* 0x14a8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0);
+
+ /*
+ * Stage 2 - Training Values Setup
+ */
+ /* Set X-BAR windows for the training sequence */
+ ddr3_save_and_set_training_windows(win);
+
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+ /*
+ * Load static controller configuration (in case dynamic/generic init
+ * is not enabled
+ */
+ if (generic_init_controller == 0) {
+ ddr3_tip_init_specific_reg_config(0,
+ ddr_modes
+ [ddr3_get_static_ddr_mode
+ ()].regs);
+ }
+#endif
+
+ /* Load topology for New Training IP */
+ status = ddr3_load_topology_map();
+ if (MV_OK != status) {
+ printf("%s Training Sequence topology load - FAILED\n",
+ ddr_type);
+ return status;
+ }
+
+ /* Tune training algo paramteres */
+ status = ddr3_hws_tune_training_params(0);
+ if (MV_OK != status)
+ return status;
+
+ /* Set log level for training lib */
+ ddr3_hws_set_log_level(DEBUG_BLOCK_ALL, DEBUG_LEVEL_ERROR);
+
+ /* Start New Training IP */
+ status = ddr3_hws_hw_training();
+ if (MV_OK != status) {
+ printf("%s Training Sequence - FAILED\n", ddr_type);
+ return status;
+ }
+
+ /*
+ * Stage 3 - Finish
+ */
+ /* Restore and set windows */
+ ddr3_restore_and_set_final_windows(win);
+
+ /* Update DRAM init indication in bootROM register */
+ reg = reg_read(REG_BOOTROM_ROUTINE_ADDR);
+ reg_write(REG_BOOTROM_ROUTINE_ADDR,
+ reg | (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS));
+
+ /* DLB config */
+ ddr3_new_tip_dlb_config();
+
+#if defined(ECC_SUPPORT)
+ if (ddr3_if_ecc_enabled())
+ ddr3_new_tip_ecc_scrub();
+#endif
+
+ printf("%s Training Sequence - Ended Successfully\n", ddr_type);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_get_cpu_freq
+ * Desc: read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_get_cpu_freq(void)
+{
+ return ddr3_tip_get_init_freq();
+}
+
+/*
+ * Name: ddr3_get_fab_opt
+ * Desc: read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_get_fab_opt(void)
+{
+ return 0; /* No fabric */
+}
+
+/*
+ * Name: ddr3_get_static_m_cValue - Init Memory controller with
+ * static parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure.
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1,
+ u32 offset2, u32 mask2)
+{
+ u32 reg, temp;
+
+ reg = reg_read(reg_addr);
+
+ temp = (reg >> offset1) & mask1;
+ if (mask2)
+ temp |= (reg >> offset2) & mask2;
+
+ return temp;
+}
+
+/*
+ * Name: ddr3_get_static_ddr_mode - Init Memory controller with
+ * static parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure.
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+u32 ddr3_get_static_ddr_mode(void)
+{
+ u32 chip_board_rev, i;
+ u32 size;
+
+ /* Valid only for A380 only, MSYS using dynamic controller config */
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+ /*
+ * Customer boards select DDR mode according to
+ * board ID & Sample@Reset
+ */
+ chip_board_rev = mv_board_id_get();
+#else
+ /* Marvell boards select DDR mode according to Sample@Reset only */
+ chip_board_rev = MARVELL_BOARD;
+#endif
+
+ size = ARRAY_SIZE(ddr_modes);
+ for (i = 0; i < size; i++) {
+ if ((ddr3_get_cpu_freq() == ddr_modes[i].cpu_freq) &&
+ (ddr3_get_fab_opt() == ddr_modes[i].fab_freq) &&
+ (chip_board_rev == ddr_modes[i].chip_board_rev))
+ return i;
+ }
+
+ DEBUG_INIT_S("\n*** Error: ddr3_get_static_ddr_mode: No match for requested DDR mode. ***\n\n");
+
+ return 0;
+}
+
+/******************************************************************************
+ * Name: ddr3_get_cs_num_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_num_from_reg(void)
+{
+ u32 cs_ena = sys_env_get_cs_ena_from_reg();
+ u32 cs_count = 0;
+ u32 cs;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ cs_count++;
+ }
+
+ return cs_count;
+}
+
+/*
+ * Name: ddr3_load_topology_map
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+int ddr3_load_topology_map(void)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
+ /* Update topology data */
+ if (MV_OK != ddr3_update_topology_map(tm)) {
+ DEBUG_INIT_FULL_S("Failed update of DDR3 Topology map\n");
+ }
+#endif
+
+ return MV_OK;
+}
+
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps)
+{
+ u32 tmp, hclk = 200;
+
+ switch (freq_mode) {
+ case 4:
+ tmp = 1; /* DDR_400; */
+ hclk = 200;
+ break;
+ case 0x8:
+ tmp = 1; /* DDR_666; */
+ hclk = 333;
+ break;
+ case 0xc:
+ tmp = 1; /* DDR_800; */
+ hclk = 400;
+ break;
+ default:
+ *ddr_freq = 0;
+ *hclk_ps = 0;
+ break;
+ }
+
+ *ddr_freq = tmp; /* DDR freq define */
+ *hclk_ps = 1000000 / hclk; /* values are 1/HCLK in ps */
+
+ return;
+}
+
+void ddr3_new_tip_dlb_config(void)
+{
+ u32 reg, i = 0;
+ struct dlb_config *config_table_ptr = sys_env_dlb_config_ptr_get();
+
+ /* Write the configuration */
+ while (config_table_ptr[i].reg_addr != 0) {
+ reg_write(config_table_ptr[i].reg_addr,
+ config_table_ptr[i].reg_data);
+ i++;
+ }
+
+ /* Enable DLB */
+ reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+ reg |= DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN |
+ DLB_MBUS_PREFETCH_EN | PREFETCH_N_LN_SZ_TR;
+ reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+}
+
+int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena)
+{
+ u32 reg, cs;
+ u32 mem_total_size = 0;
+ u32 cs_mem_size = 0;
+ u32 mem_total_size_c, cs_mem_size_c;
+
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+ u32 physical_mem_size;
+ u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+#endif
+
+ /* Open fast path windows */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ /* get CS size */
+ if (ddr3_calc_mem_cs_size(cs, &cs_mem_size) != MV_OK)
+ return MV_FAIL;
+
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+ /*
+ * if number of address pins doesn't allow to use max
+ * mem size that is defined in topology
+ * mem size is defined by DEVICE_MAX_DRAM_ADDRESS_SIZE
+ */
+ physical_mem_size = mem_size
+ [tm->interface_params[0].memory_size];
+
+ if (ddr3_get_device_width(cs) == 16) {
+ /*
+ * 16bit mem device can be twice more - no need
+ * in less significant pin
+ */
+ max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE * 2;
+ }
+
+ if (physical_mem_size > max_mem_size) {
+ cs_mem_size = max_mem_size *
+ (ddr3_get_bus_width() /
+ ddr3_get_device_width(cs));
+ printf("Updated Physical Mem size is from 0x%x to %x\n",
+ physical_mem_size,
+ DEVICE_MAX_DRAM_ADDRESS_SIZE);
+ }
+#endif
+
+ /* set fast path window control for the cs */
+ reg = 0xffffe1;
+ reg |= (cs << 2);
+ reg |= (cs_mem_size - 1) & 0xffff0000;
+ /*Open fast path Window */
+ reg_write(REG_FASTPATH_WIN_CTRL_ADDR(cs), reg);
+
+ /* Set fast path window base address for the cs */
+ reg = ((cs_mem_size) * cs) & 0xffff0000;
+ /* Set base address */
+ reg_write(REG_FASTPATH_WIN_BASE_ADDR(cs), reg);
+
+ /*
+ * Since memory size may be bigger than 4G the summ may
+ * be more than 32 bit word,
+ * so to estimate the result divide mem_total_size and
+ * cs_mem_size by 0x10000 (it is equal to >> 16)
+ */
+ mem_total_size_c = mem_total_size >> 16;
+ cs_mem_size_c = cs_mem_size >> 16;
+ /* if the sum less than 2 G - calculate the value */
+ if (mem_total_size_c + cs_mem_size_c < 0x10000)
+ mem_total_size += cs_mem_size;
+ else /* put max possible size */
+ mem_total_size = L2_FILTER_FOR_MAX_MEMORY_SIZE;
+ }
+ }
+
+ /* Set L2 filtering to Max Memory size */
+ reg_write(ADDRESS_FILTERING_END_REGISTER, mem_total_size);
+
+ return MV_OK;
+}
+
+u32 ddr3_get_bus_width(void)
+{
+ u32 bus_width;
+
+ bus_width = (reg_read(REG_SDRAM_CONFIG_ADDR) & 0x8000) >>
+ REG_SDRAM_CONFIG_WIDTH_OFFS;
+
+ return (bus_width == 0) ? 16 : 32;
+}
+
+u32 ddr3_get_device_width(u32 cs)
+{
+ u32 device_width;
+
+ device_width = (reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR) &
+ (0x3 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs))) >>
+ (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs);
+
+ return (device_width == 0) ? 8 : 16;
+}
+
+float ddr3_get_device_size(u32 cs)
+{
+ u32 device_size_low, device_size_high, device_size;
+ u32 data, cs_low_offset, cs_high_offset;
+
+ cs_low_offset = REG_SDRAM_ADDRESS_SIZE_OFFS + cs * 4;
+ cs_high_offset = REG_SDRAM_ADDRESS_SIZE_OFFS +
+ REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + cs;
+
+ data = reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR);
+ device_size_low = (data >> cs_low_offset) & 0x3;
+ device_size_high = (data >> cs_high_offset) & 0x1;
+
+ device_size = device_size_low | (device_size_high << 2);
+
+ switch (device_size) {
+ case 0:
+ return 2;
+ case 2:
+ return 0.5;
+ case 3:
+ return 1;
+ case 4:
+ return 4;
+ case 5:
+ return 8;
+ case 1:
+ default:
+ DEBUG_INIT_C("Error: Wrong device size of Cs: ", cs, 1);
+ /*
+ * Small value will give wrong emem size in
+ * ddr3_calc_mem_cs_size
+ */
+ return 0.01;
+ }
+}
+
+int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size)
+{
+ float cs_mem_size;
+
+ /* Calculate in GiB */
+ cs_mem_size = ((ddr3_get_bus_width() / ddr3_get_device_width(cs)) *
+ ddr3_get_device_size(cs)) / 8;
+
+ /*
+ * Multiple controller bus width, 2x for 64 bit
+ * (SoC controller may be 32 or 64 bit,
+ * so bit 15 in 0x1400, that means if whole bus used or only half,
+ * have a differnt meaning
+ */
+ cs_mem_size *= DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER;
+
+ if (cs_mem_size == 0.125) {
+ *cs_size = 128 << 20;
+ } else if (cs_mem_size == 0.25) {
+ *cs_size = 256 << 20;
+ } else if (cs_mem_size == 0.5) {
+ *cs_size = 512 << 20;
+ } else if (cs_mem_size == 1) {
+ *cs_size = 1 << 30;
+ } else if (cs_mem_size == 2) {
+ *cs_size = 2 << 30;
+ } else {
+ DEBUG_INIT_C("Error: Wrong Memory size of Cs: ", cs, 1);
+ return MV_BAD_VALUE;
+ }
+
+ return MV_OK;
+}
+
+#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
+/*
+ * Name: ddr3_update_topology_map
+ * Desc:
+ * Args:
+ * Notes: Update topology map by Sat_r values
+ * Returns:
+ */
+static int ddr3_update_topology_map(struct hws_topology_map *tm)
+{
+ struct topology_update_info topology_update_info;
+
+ topology_update_info.update_width = 0;
+ topology_update_info.update_ecc = 0;
+ topology_update_info.update_ecc_pup3_mode = 0;
+ sys_env_get_topology_update_info(&topology_update_info);
+ if (topology_update_info.update_width) {
+ tm->bus_act_mask &=
+ ~(TOPOLOGY_UPDATE_WIDTH_32BIT_MASK);
+ if (topology_update_info.width == TOPOLOGY_UPDATE_WIDTH_16BIT)
+ tm->bus_act_mask =
+ TOPOLOGY_UPDATE_WIDTH_16BIT_MASK;
+ else
+ tm->bus_act_mask =
+ TOPOLOGY_UPDATE_WIDTH_32BIT_MASK;
+ }
+
+ if (topology_update_info.update_ecc) {
+ if (topology_update_info.ecc == TOPOLOGY_UPDATE_ECC_OFF) {
+ tm->bus_act_mask &=
+ ~(1 << topology_update_info.ecc_pup_mode_offset);
+ } else {
+ tm->bus_act_mask |=
+ topology_update_info.
+ ecc << topology_update_info.ecc_pup_mode_offset;
+ }
+ }
+
+ return MV_OK;
+}
+#endif
+
+/*
+ * Name: ddr3_hws_tune_training_params
+ * Desc:
+ * Args:
+ * Notes: Tune internal training params
+ * Returns:
+ */
+static int ddr3_hws_tune_training_params(u8 dev_num)
+{
+ struct tune_train_params params;
+ int status;
+
+ /* NOTE: do not remove any field initilization */
+ params.ck_delay = TUNE_TRAINING_PARAMS_CK_DELAY;
+ params.ck_delay_16 = TUNE_TRAINING_PARAMS_CK_DELAY_16;
+ params.p_finger = TUNE_TRAINING_PARAMS_PFINGER;
+ params.n_finger = TUNE_TRAINING_PARAMS_NFINGER;
+ params.phy_reg3_val = TUNE_TRAINING_PARAMS_PHYREG3VAL;
+
+ status = ddr3_tip_tune_training_params(dev_num, &params);
+ if (MV_OK != status) {
+ printf("%s Training Sequence - FAILED\n", ddr_type);
+ return status;
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h
new file mode 100644
index 0000000000..e2ff040b00
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_init.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_INIT_H
+#define _DDR3_INIT_H
+
+#if defined(CONFIG_ARMADA_38X)
+#include "ddr3_a38x.h"
+#include "ddr3_a38x_mc_static.h"
+#include "ddr3_a38x_topology.h"
+#endif
+#include "ddr3_hws_hw_training.h"
+#include "ddr3_hws_sil_training.h"
+#include "ddr3_logging_def.h"
+#include "ddr3_training_hw_algo.h"
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_centralization.h"
+#include "ddr3_training_ip_engine.h"
+#include "ddr3_training_ip_flow.h"
+#include "ddr3_training_ip_pbs.h"
+#include "ddr3_training_ip_prv_if.h"
+#include "ddr3_training_ip_static.h"
+#include "ddr3_training_leveling.h"
+#include "xor.h"
+
+/*
+ * MV_DEBUG_INIT need to be defines, otherwise the output of the
+ * DDR2 training code is not complete and misleading
+ */
+#define MV_DEBUG_INIT
+
+#define BIT(x) (1 << (x))
+
+#ifdef MV_DEBUG_INIT
+#define DEBUG_INIT_S(s) puts(s)
+#define DEBUG_INIT_D(d, l) printf("%x", d)
+#define DEBUG_INIT_D_10(d, l) printf("%d", d)
+#else
+#define DEBUG_INIT_S(s)
+#define DEBUG_INIT_D(d, l)
+#define DEBUG_INIT_D_10(d, l)
+#endif
+
+#ifdef MV_DEBUG_INIT_FULL
+#define DEBUG_INIT_FULL_S(s) puts(s)
+#define DEBUG_INIT_FULL_D(d, l) printf("%x", d)
+#define DEBUG_INIT_FULL_D_10(d, l) printf("%d", d)
+#define DEBUG_WR_REG(reg, val) \
+ { DEBUG_INIT_S("Write Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+ DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#define DEBUG_RD_REG(reg, val) \
+ { DEBUG_INIT_S("Read Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+ DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#else
+#define DEBUG_INIT_FULL_S(s)
+#define DEBUG_INIT_FULL_D(d, l)
+#define DEBUG_INIT_FULL_D_10(d, l)
+#define DEBUG_WR_REG(reg, val)
+#define DEBUG_RD_REG(reg, val)
+#endif
+
+#define DEBUG_INIT_FULL_C(s, d, l) \
+ { DEBUG_INIT_FULL_S(s); \
+ DEBUG_INIT_FULL_D(d, l); \
+ DEBUG_INIT_FULL_S("\n"); }
+#define DEBUG_INIT_C(s, d, l) \
+ { DEBUG_INIT_S(s); DEBUG_INIT_D(d, l); DEBUG_INIT_S("\n"); }
+
+/*
+ * Debug (Enable/Disable modules) and Error report
+ */
+
+#ifdef BASIC_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS_RESULTS
+#endif
+
+#ifdef FULL_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS
+
+#define MV_DEBUG_PBS
+#define MV_DEBUG_DFS
+#define MV_DEBUG_MAIN_FULL
+#define MV_DEBUG_DFS_FULL
+#define MV_DEBUG_DQS_FULL
+#define MV_DEBUG_RL_FULL
+#define MV_DEBUG_WL_FULL
+#endif
+
+#if defined(CONFIG_ARMADA_38X)
+#include "ddr3_a38x.h"
+#include "ddr3_a38x_topology.h"
+#endif
+
+/* The following is a list of Marvell status */
+#define MV_ERROR (-1)
+#define MV_OK (0x00) /* Operation succeeded */
+#define MV_FAIL (0x01) /* Operation failed */
+#define MV_BAD_VALUE (0x02) /* Illegal value (general) */
+#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */
+#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */
+#define MV_BAD_PTR (0x05) /* Illegal pointer value */
+#define MV_BAD_SIZE (0x06) /* Illegal size */
+#define MV_BAD_STATE (0x07) /* Illegal state of state machine */
+#define MV_SET_ERROR (0x08) /* Set operation failed */
+#define MV_GET_ERROR (0x09) /* Get operation failed */
+#define MV_CREATE_ERROR (0x0a) /* Fail while creating an item */
+#define MV_NOT_FOUND (0x0b) /* Item not found */
+#define MV_NO_MORE (0x0c) /* No more items found */
+#define MV_NO_SUCH (0x0d) /* No such item */
+#define MV_TIMEOUT (0x0e) /* Time Out */
+#define MV_NO_CHANGE (0x0f) /* Parameter(s) is already in this value */
+#define MV_NOT_SUPPORTED (0x10) /* This request is not support */
+#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented*/
+#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */
+#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */
+#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */
+#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */
+#define MV_INIT_ERROR (0x16) /* Error occured while INIT process */
+#define MV_HW_ERROR (0x17) /* Hardware error */
+#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */
+#define MV_RX_ERROR (0x19) /* Recieve operation not succeeded */
+#define MV_NOT_READY (0x1a) /* The other side is not ready yet */
+#define MV_ALREADY_EXIST (0x1b) /* Tried to create existing item */
+#define MV_OUT_OF_CPU_MEM (0x1c) /* Cpu memory allocation failed. */
+#define MV_NOT_STARTED (0x1d) /* Not started yet */
+#define MV_BUSY (0x1e) /* Item is busy. */
+#define MV_TERMINATE (0x1f) /* Item terminates it's work. */
+#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */
+#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */
+#define MV_WRITE_PROTECT (0x22) /* Write protected */
+#define MV_INVALID (int)(-1)
+
+/* For checking function return values */
+#define CHECK_STATUS(orig_func) \
+ { \
+ int status; \
+ status = orig_func; \
+ if (MV_OK != status) \
+ return status; \
+ }
+
+enum log_level {
+ MV_LOG_LEVEL_0,
+ MV_LOG_LEVEL_1,
+ MV_LOG_LEVEL_2,
+ MV_LOG_LEVEL_3
+};
+
+/* Globals */
+extern u8 debug_training;
+extern u8 is_reg_dump;
+extern u8 generic_init_controller;
+extern u32 freq_val[];
+extern u32 is_pll_old;
+extern struct cl_val_per_freq cas_latency_table[];
+extern struct pattern_info pattern_table[];
+extern struct cl_val_per_freq cas_write_latency_table[];
+extern u8 debug_training;
+extern u8 debug_centralization, debug_training_ip, debug_training_bist,
+ debug_pbs, debug_training_static, debug_leveling;
+extern u32 pipe_multicast_mask;
+extern struct hws_tip_config_func_db config_func_info[];
+extern u8 cs_mask_reg[];
+extern u8 twr_mask_table[];
+extern u8 cl_mask_table[];
+extern u8 cwl_mask_table[];
+extern u16 rfc_table[];
+extern u32 speed_bin_table_t_rc[];
+extern u32 speed_bin_table_t_rcd_t_rp[];
+extern u32 ck_delay, ck_delay_16;
+
+extern u32 g_zpri_data;
+extern u32 g_znri_data;
+extern u32 g_zpri_ctrl;
+extern u32 g_znri_ctrl;
+extern u32 g_zpodt_data;
+extern u32 g_znodt_data;
+extern u32 g_zpodt_ctrl;
+extern u32 g_znodt_ctrl;
+extern u32 g_dic;
+extern u32 g_odt_config;
+extern u32 g_rtt_nom;
+
+extern u8 debug_training_access;
+extern u8 debug_training_a38x;
+extern u32 first_active_if;
+extern enum hws_ddr_freq init_freq;
+extern u32 delay_enable, ck_delay, ck_delay_16, ca_delay;
+extern u32 mask_tune_func;
+extern u32 rl_version;
+extern int rl_mid_freq_wa;
+extern u8 calibration_update_control; /* 2 external only, 1 is internal only */
+extern enum hws_ddr_freq medium_freq;
+
+extern u32 ck_delay, ck_delay_16;
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern u32 first_active_if;
+extern u32 mask_tune_func;
+extern u32 freq_val[];
+extern enum hws_ddr_freq init_freq;
+extern enum hws_ddr_freq low_freq;
+extern enum hws_ddr_freq medium_freq;
+extern u8 generic_init_controller;
+extern enum auto_tune_stage training_stage;
+extern u32 is_pll_before_init;
+extern u32 is_adll_calib_before_init;
+extern u32 is_dfs_in_init;
+extern int wl_debug_delay;
+extern u32 silicon_delay[HWS_MAX_DEVICE_NUM];
+extern u32 p_finger;
+extern u32 n_finger;
+extern u32 freq_val[DDR_FREQ_LIMIT];
+extern u32 start_pattern, end_pattern;
+extern u32 phy_reg0_val;
+extern u32 phy_reg1_val;
+extern u32 phy_reg2_val;
+extern u32 phy_reg3_val;
+extern enum hws_pattern sweep_pattern;
+extern enum hws_pattern pbs_pattern;
+extern u8 is_rzq6;
+extern u32 znri_data_phy_val;
+extern u32 zpri_data_phy_val;
+extern u32 znri_ctrl_phy_val;
+extern u32 zpri_ctrl_phy_val;
+extern u8 debug_training_access;
+extern u32 finger_test, p_finger_start, p_finger_end, n_finger_start,
+ n_finger_end, p_finger_step, n_finger_step;
+extern u32 mode2_t;
+extern u32 xsb_validate_type;
+extern u32 xsb_validation_base_address;
+extern u32 odt_additional;
+extern u32 debug_mode;
+extern u32 delay_enable;
+extern u32 ca_delay;
+extern u32 debug_dunit;
+extern u32 clamp_tbl[];
+extern u32 freq_mask[HWS_MAX_DEVICE_NUM][DDR_FREQ_LIMIT];
+extern u32 start_pattern, end_pattern;
+
+extern u32 maxt_poll_tries;
+extern u32 is_bist_reset_bit;
+extern u8 debug_training_bist;
+
+extern u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+extern u32 debug_mode;
+extern u32 effective_cs;
+extern int ddr3_tip_centr_skip_min_win_check;
+extern u32 *dq_map_table;
+extern enum auto_tune_stage training_stage;
+extern u8 debug_centralization;
+
+extern u32 delay_enable;
+extern u32 start_pattern, end_pattern;
+extern u32 freq_val[DDR_FREQ_LIMIT];
+extern u8 debug_training_hw_alg;
+extern enum auto_tune_stage training_stage;
+
+extern u8 debug_training_ip;
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern enum auto_tune_stage training_stage;
+extern u32 effective_cs;
+
+extern u8 debug_leveling;
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern enum auto_tune_stage training_stage;
+extern u32 rl_version;
+extern struct cl_val_per_freq cas_latency_table[];
+extern u32 start_xsb_offset;
+extern u32 debug_mode;
+extern u32 odt_config;
+extern u32 effective_cs;
+extern u32 phy_reg1_val;
+
+extern u8 debug_pbs;
+extern u32 effective_cs;
+extern u16 mask_results_dq_reg_map[];
+extern enum hws_ddr_freq medium_freq;
+extern u32 freq_val[];
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern enum auto_tune_stage training_stage;
+extern u32 debug_mode;
+extern u32 *dq_map_table;
+
+extern u32 vref;
+extern struct cl_val_per_freq cas_latency_table[];
+extern u32 target_freq;
+extern struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM];
+extern u32 clamp_tbl[];
+extern u32 init_freq;
+/* list of allowed frequency listed in order of enum hws_ddr_freq */
+extern u32 freq_val[];
+extern u8 debug_training_static;
+extern u32 first_active_if;
+
+/* Prototypes */
+int ddr3_tip_enable_init_sequence(u32 dev_num);
+
+int ddr3_tip_init_a38x(u32 dev_num, u32 board_id);
+
+int ddr3_hws_hw_training(void);
+int ddr3_silicon_pre_init(void);
+int ddr3_silicon_post_init(void);
+int ddr3_post_run_alg(void);
+int ddr3_if_ecc_enabled(void);
+void ddr3_new_tip_ecc_scrub(void);
+
+void ddr3_print_version(void);
+void ddr3_new_tip_dlb_config(void);
+struct hws_topology_map *ddr3_get_topology_map(void);
+
+int ddr3_if_ecc_enabled(void);
+int ddr3_tip_reg_write(u32 dev_num, u32 reg_addr, u32 data);
+int ddr3_tip_reg_read(u32 dev_num, u32 reg_addr, u32 *data, u32 reg_mask);
+int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq);
+int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq,
+ struct hws_tip_freq_config_info
+ *freq_config_info);
+int ddr3_a38x_update_topology_map(u32 dev_num,
+ struct hws_topology_map *topology_map);
+int ddr3_tip_a38x_get_init_freq(int dev_num, enum hws_ddr_freq *freq);
+int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq);
+int ddr3_tip_a38x_if_read(u8 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 *data, u32 mask);
+int ddr3_tip_a38x_if_write(u8 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 data, u32 mask);
+int ddr3_tip_a38x_get_device_info(u8 dev_num,
+ struct ddr3_device_info *info_ptr);
+
+int ddr3_tip_init_a38x(u32 dev_num, u32 board_id);
+
+int print_adll(u32 dev_num, u32 adll[MAX_INTERFACE_NUM * MAX_BUS_NUM]);
+int ddr3_tip_restore_dunit_regs(u32 dev_num);
+void print_topology(struct hws_topology_map *topology_db);
+
+u32 mv_board_id_get(void);
+
+int ddr3_load_topology_map(void);
+int ddr3_tip_init_specific_reg_config(u32 dev_num,
+ struct reg_data *reg_config_arr);
+u32 ddr3_tip_get_init_freq(void);
+void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level);
+int ddr3_tip_tune_training_params(u32 dev_num,
+ struct tune_train_params *params);
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena);
+void ddr3_fast_path_static_cs_size_config(u32 cs_ena);
+u32 ddr3_get_device_width(u32 cs);
+u32 mv_board_id_index_get(u32 board_id);
+u32 mv_board_id_get(void);
+u32 ddr3_get_bus_width(void);
+void ddr3_set_log_level(u32 n_log_level);
+int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size);
+
+int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr);
+
+int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode);
+int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode);
+
+int ddr3_tip_static_round_trip_arr_build(u32 dev_num,
+ struct trip_delay_element *table_ptr,
+ int is_wl, u32 *round_trip_delay_arr);
+
+u32 hws_ddr3_tip_max_cs_get(void);
+
+/*
+ * Accessor functions for the registers
+ */
+static inline void reg_write(u32 addr, u32 val)
+{
+ writel(val, INTER_REGS_BASE + addr);
+}
+
+static inline u32 reg_read(u32 addr)
+{
+ return readl(INTER_REGS_BASE + addr);
+}
+
+static inline void reg_bit_set(u32 addr, u32 mask)
+{
+ setbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+static inline void reg_bit_clr(u32 addr, u32 mask)
+{
+ clrbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+#endif /* _DDR3_INIT_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_logging_def.h b/drivers/ddr/marvell/a38x/ddr3_logging_def.h
new file mode 100644
index 0000000000..2de7c4fa31
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_logging_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_LOGGING_CONFIG_H
+#define _DDR3_LOGGING_CONFIG_H
+
+#ifdef SILENT_LIB
+#define DEBUG_TRAINING_BIST_ENGINE(level, s)
+#define DEBUG_TRAINING_IP(level, s)
+#define DEBUG_CENTRALIZATION_ENGINE(level, s)
+#define DEBUG_TRAINING_HW_ALG(level, s)
+#define DEBUG_TRAINING_IP_ENGINE(level, s)
+#define DEBUG_LEVELING(level, s)
+#define DEBUG_PBS_ENGINE(level, s)
+#define DEBUG_TRAINING_STATIC_IP(level, s)
+#define DEBUG_TRAINING_ACCESS(level, s)
+#else
+#ifdef LIB_FUNCTIONAL_DEBUG_ONLY
+#define DEBUG_TRAINING_BIST_ENGINE(level, s)
+#define DEBUG_TRAINING_IP_ENGINE(level, s)
+#define DEBUG_TRAINING_IP(level, s) \
+ if (level >= debug_training) \
+ printf s
+#define DEBUG_CENTRALIZATION_ENGINE(level, s) \
+ if (level >= debug_centralization) \
+ printf s
+#define DEBUG_TRAINING_HW_ALG(level, s) \
+ if (level >= debug_training_hw_alg) \
+ printf s
+#define DEBUG_LEVELING(level, s) \
+ if (level >= debug_leveling) \
+ printf s
+#define DEBUG_PBS_ENGINE(level, s) \
+ if (level >= debug_pbs) \
+ printf s
+#define DEBUG_TRAINING_STATIC_IP(level, s) \
+ if (level >= debug_training_static) \
+ printf s
+#define DEBUG_TRAINING_ACCESS(level, s) \
+ if (level >= debug_training_access) \
+ printf s
+#else
+#define DEBUG_TRAINING_BIST_ENGINE(level, s) \
+ if (level >= debug_training_bist) \
+ printf s
+
+#define DEBUG_TRAINING_IP_ENGINE(level, s) \
+ if (level >= debug_training_ip) \
+ printf s
+#define DEBUG_TRAINING_IP(level, s) \
+ if (level >= debug_training) \
+ printf s
+#define DEBUG_CENTRALIZATION_ENGINE(level, s) \
+ if (level >= debug_centralization) \
+ printf s
+#define DEBUG_TRAINING_HW_ALG(level, s) \
+ if (level >= debug_training_hw_alg) \
+ printf s
+#define DEBUG_LEVELING(level, s) \
+ if (level >= debug_leveling) \
+ printf s
+#define DEBUG_PBS_ENGINE(level, s) \
+ if (level >= debug_pbs) \
+ printf s
+#define DEBUG_TRAINING_STATIC_IP(level, s) \
+ if (level >= debug_training_static) \
+ printf s
+#define DEBUG_TRAINING_ACCESS(level, s) \
+ if (level >= debug_training_access) \
+ printf s
+#endif
+#endif
+
+/* Logging defines */
+#define DEBUG_LEVEL_TRACE 1
+#define DEBUG_LEVEL_INFO 2
+#define DEBUG_LEVEL_ERROR 3
+
+enum ddr_lib_debug_block {
+ DEBUG_BLOCK_STATIC,
+ DEBUG_BLOCK_TRAINING_MAIN,
+ DEBUG_BLOCK_LEVELING,
+ DEBUG_BLOCK_CENTRALIZATION,
+ DEBUG_BLOCK_PBS,
+ DEBUG_BLOCK_IP,
+ DEBUG_BLOCK_BIST,
+ DEBUG_BLOCK_ALG,
+ DEBUG_BLOCK_DEVICE,
+ DEBUG_BLOCK_ACCESS,
+ DEBUG_STAGES_REG_DUMP,
+ /* All excluding IP and REG_DUMP, should be enabled separatelly */
+ DEBUG_BLOCK_ALL
+};
+
+int ddr3_tip_print_log(u32 dev_num, u32 mem_addr);
+int ddr3_tip_print_stability_log(u32 dev_num);
+
+#endif /* _DDR3_LOGGING_CONFIG_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h b/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h
new file mode 100644
index 0000000000..0ce0479a3a
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_PATTERNS_64_H
+#define __DDR3_PATTERNS_64_H
+
+/*
+ * Patterns Declerations
+ */
+
+u32 wl_sup_pattern[LEN_WL_SUP_PATTERN] __aligned(32) = {
+ 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d,
+ 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d,
+ 0x24232221, 0x28272625, 0x2c2b2a29, 0x302f2e2d,
+ 0x34333231, 0x38373635, 0x3c3b3a39, 0x403f3e3d,
+ 0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d,
+ 0x54535251, 0x58575655, 0x5c5b5a59, 0x605f5e5d,
+ 0x64636261, 0x68676665, 0x6c6b6a69, 0x706f6e6d,
+ 0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d
+};
+
+u32 pbs_pattern_32b[2][LEN_PBS_PATTERN] __aligned(32) = {
+ {
+ 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555,
+ 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555,
+ 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555,
+ 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555
+ },
+ {
+ 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa,
+ 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa,
+ 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa,
+ 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa
+ }
+};
+
+u32 pbs_pattern_64b[2][LEN_PBS_PATTERN] __aligned(32) = {
+ {
+ 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555,
+ 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555,
+ 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555,
+ 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555
+ },
+ {
+ 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa,
+ 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa,
+ 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa,
+ 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa
+ }
+};
+
+u32 rl_pattern[LEN_STD_PATTERN] __aligned(32) = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0x01010101, 0x01010101
+};
+
+u32 killer_pattern_32b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+ {
+ 0x01010101, 0x00000000, 0x01010101, 0xffffffff,
+ 0x01010101, 0x00000000, 0x01010101, 0xffffffff,
+ 0xfefefefe, 0xfefefefe, 0x01010101, 0xfefefefe,
+ 0xfefefefe, 0xfefefefe, 0x01010101, 0xfefefefe,
+ 0x01010101, 0xfefefefe, 0x01010101, 0x01010101,
+ 0x01010101, 0xfefefefe, 0x01010101, 0x01010101,
+ 0xfefefefe, 0x01010101, 0xfefefefe, 0x00000000,
+ 0xfefefefe, 0x01010101, 0xfefefefe, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x01010101,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x01010101,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xfefefefe,
+ 0x00000000, 0x00000000, 0x00000000, 0xfefefefe,
+ 0xfefefefe, 0xffffffff, 0x00000000, 0x00000000,
+ 0xfefefefe, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xfefefefe, 0x00000000, 0xfefefefe, 0x00000000,
+ 0xfefefefe, 0x00000000, 0xfefefefe, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x01010101,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x01010101,
+ 0xffffffff, 0xffffffff, 0x01010101, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x01010101, 0x00000000,
+ 0x01010101, 0xffffffff, 0xfefefefe, 0xfefefefe,
+ 0x01010101, 0xffffffff, 0xfefefefe, 0xfefefefe
+ },
+ {
+ 0x02020202, 0x00000000, 0x02020202, 0xffffffff,
+ 0x02020202, 0x00000000, 0x02020202, 0xffffffff,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd,
+ 0x02020202, 0xfdfdfdfd, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfd, 0x02020202, 0x02020202,
+ 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, 0x00000000,
+ 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x02020202,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x02020202,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xfdfdfdfd,
+ 0x00000000, 0x00000000, 0x00000000, 0xfdfdfdfd,
+ 0xfdfdfdfd, 0xffffffff, 0x00000000, 0x00000000,
+ 0xfdfdfdfd, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xfdfdfdfd, 0x00000000, 0xfdfdfdfd, 0x00000000,
+ 0xfdfdfdfd, 0x00000000, 0xfdfdfdfd, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x02020202,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x02020202,
+ 0xffffffff, 0xffffffff, 0x02020202, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x02020202, 0x00000000,
+ 0x02020202, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x02020202, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd
+ },
+ {
+ 0x04040404, 0x00000000, 0x04040404, 0xffffffff,
+ 0x04040404, 0x00000000, 0x04040404, 0xffffffff,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb,
+ 0x04040404, 0xfbfbfbfb, 0x04040404, 0x04040404,
+ 0x04040404, 0xfbfbfbfb, 0x04040404, 0x04040404,
+ 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, 0x00000000,
+ 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x04040404,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x04040404,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xfbfbfbfb,
+ 0x00000000, 0x00000000, 0x00000000, 0xfbfbfbfb,
+ 0xfbfbfbfb, 0xffffffff, 0x00000000, 0x00000000,
+ 0xfbfbfbfb, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xfbfbfbfb, 0x00000000, 0xfbfbfbfb, 0x00000000,
+ 0xfbfbfbfb, 0x00000000, 0xfbfbfbfb, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x04040404,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x04040404,
+ 0xffffffff, 0xffffffff, 0x04040404, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x04040404, 0x00000000,
+ 0x04040404, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x04040404, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb
+ },
+ {
+ 0x08080808, 0x00000000, 0x08080808, 0xffffffff,
+ 0x08080808, 0x00000000, 0x08080808, 0xffffffff,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7,
+ 0x08080808, 0xf7f7f7f7, 0x08080808, 0x08080808,
+ 0x08080808, 0xf7f7f7f7, 0x08080808, 0x08080808,
+ 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, 0x00000000,
+ 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x08080808,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x08080808,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xf7f7f7f7,
+ 0x00000000, 0x00000000, 0x00000000, 0xf7f7f7f7,
+ 0xf7f7f7f7, 0xffffffff, 0x00000000, 0x00000000,
+ 0xf7f7f7f7, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xf7f7f7f7, 0x00000000, 0xf7f7f7f7, 0x00000000,
+ 0xf7f7f7f7, 0x00000000, 0xf7f7f7f7, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x08080808,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x08080808,
+ 0xffffffff, 0xffffffff, 0x08080808, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x08080808, 0x00000000,
+ 0x08080808, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x08080808, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7
+ },
+ {
+ 0x10101010, 0x00000000, 0x10101010, 0xffffffff,
+ 0x10101010, 0x00000000, 0x10101010, 0xffffffff,
+ 0xefefefef, 0xefefefef, 0x10101010, 0xefefefef,
+ 0xefefefef, 0xefefefef, 0x10101010, 0xefefefef,
+ 0x10101010, 0xefefefef, 0x10101010, 0x10101010,
+ 0x10101010, 0xefefefef, 0x10101010, 0x10101010,
+ 0xefefefef, 0x10101010, 0xefefefef, 0x00000000,
+ 0xefefefef, 0x10101010, 0xefefefef, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x10101010,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x10101010,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xefefefef,
+ 0x00000000, 0x00000000, 0x00000000, 0xefefefef,
+ 0xefefefef, 0xffffffff, 0x00000000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xefefefef, 0x00000000, 0xefefefef, 0x00000000,
+ 0xefefefef, 0x00000000, 0xefefefef, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x10101010,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x10101010,
+ 0xffffffff, 0xffffffff, 0x10101010, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x10101010, 0x00000000,
+ 0x10101010, 0xffffffff, 0xefefefef, 0xefefefef,
+ 0x10101010, 0xffffffff, 0xefefefef, 0xefefefef
+ },
+ {
+ 0x20202020, 0x00000000, 0x20202020, 0xffffffff,
+ 0x20202020, 0x00000000, 0x20202020, 0xffffffff,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf,
+ 0x20202020, 0xdfdfdfdf, 0x20202020, 0x20202020,
+ 0x20202020, 0xdfdfdfdf, 0x20202020, 0x20202020,
+ 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, 0x00000000,
+ 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x20202020,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x20202020,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xdfdfdfdf,
+ 0x00000000, 0x00000000, 0x00000000, 0xdfdfdfdf,
+ 0xdfdfdfdf, 0xffffffff, 0x00000000, 0x00000000,
+ 0xdfdfdfdf, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xdfdfdfdf, 0x00000000, 0xdfdfdfdf, 0x00000000,
+ 0xdfdfdfdf, 0x00000000, 0xdfdfdfdf, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x20202020,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x20202020,
+ 0xffffffff, 0xffffffff, 0x20202020, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x20202020, 0x00000000,
+ 0x20202020, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x20202020, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf
+ },
+ {
+ 0x40404040, 0x00000000, 0x40404040, 0xffffffff,
+ 0x40404040, 0x00000000, 0x40404040, 0xffffffff,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf,
+ 0x40404040, 0xbfbfbfbf, 0x40404040, 0x40404040,
+ 0x40404040, 0xbfbfbfbf, 0x40404040, 0x40404040,
+ 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, 0x00000000,
+ 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x40404040,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x40404040,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0xbfbfbfbf,
+ 0x00000000, 0x00000000, 0x00000000, 0xbfbfbfbf,
+ 0xbfbfbfbf, 0xffffffff, 0x00000000, 0x00000000,
+ 0xbfbfbfbf, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xbfbfbfbf, 0x00000000, 0xbfbfbfbf, 0x00000000,
+ 0xbfbfbfbf, 0x00000000, 0xbfbfbfbf, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x40404040,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x40404040,
+ 0xffffffff, 0xffffffff, 0x40404040, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x40404040, 0x00000000,
+ 0x40404040, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x40404040, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf
+ },
+ {
+ 0x80808080, 0x00000000, 0x80808080, 0xffffffff,
+ 0x80808080, 0x00000000, 0x80808080, 0xffffffff,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f,
+ 0x80808080, 0x7f7f7f7f, 0x80808080, 0x80808080,
+ 0x80808080, 0x7f7f7f7f, 0x80808080, 0x80808080,
+ 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, 0x00000000,
+ 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x80808080,
+ 0xffffffff, 0x00000000, 0xffffffff, 0x80808080,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x7f7f7f7f,
+ 0x00000000, 0x00000000, 0x00000000, 0x7f7f7f7f,
+ 0x7f7f7f7f, 0xffffffff, 0x00000000, 0x00000000,
+ 0x7f7f7f7f, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+ 0x7f7f7f7f, 0x00000000, 0x7f7f7f7f, 0x00000000,
+ 0x7f7f7f7f, 0x00000000, 0x7f7f7f7f, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x80808080,
+ 0x00000000, 0xffffffff, 0xffffffff, 0x80808080,
+ 0xffffffff, 0xffffffff, 0x80808080, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x80808080, 0x00000000,
+ 0x80808080, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x80808080, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f
+ }
+};
+
+u32 killer_pattern_64b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+ {
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0xffffffff, 0xffffffff,
+ 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe,
+ 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+ 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+ 0x01010101, 0x01010101, 0x01010101, 0x01010101,
+ 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+ 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x01010101, 0x01010101,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xfefefefe, 0xfefefefe,
+ 0xfefefefe, 0xfefefefe, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000,
+ 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x01010101, 0x01010101,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0xffffffff, 0xffffffff,
+ 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe
+ },
+ {
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0x02020202, 0x02020202, 0xffffffff, 0xffffffff,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x02020202, 0x02020202,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x02020202, 0x02020202,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0x02020202, 0x02020202, 0xffffffff, 0xffffffff,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd
+ },
+ {
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0x04040404, 0x04040404, 0xffffffff, 0xffffffff,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x04040404, 0x04040404,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x04040404, 0x04040404,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0x04040404, 0x04040404, 0xffffffff, 0xffffffff,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb
+ },
+ {
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0x08080808, 0x08080808, 0xffffffff, 0xffffffff,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x08080808, 0x08080808, 0x08080808, 0x08080808,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x08080808, 0x08080808,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x08080808, 0x08080808,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0x08080808, 0x08080808, 0xffffffff, 0xffffffff,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7
+ },
+ {
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0x10101010, 0x10101010, 0xffffffff, 0xffffffff,
+ 0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef,
+ 0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+ 0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010,
+ 0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+ 0xefefefef, 0xefefefef, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x10101010, 0x10101010,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xefefefef, 0xefefefef,
+ 0xefefefef, 0xefefefef, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xefefefef, 0xefefefef, 0x00000000, 0x00000000,
+ 0xefefefef, 0xefefefef, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x10101010, 0x10101010,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0x10101010, 0x10101010, 0xffffffff, 0xffffffff,
+ 0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef
+ },
+ {
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0x20202020, 0x20202020, 0xffffffff, 0xffffffff,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x20202020, 0x20202020,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x20202020, 0x20202020,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0x20202020, 0x20202020, 0xffffffff, 0xffffffff,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf
+ },
+ {
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0x40404040, 0x40404040, 0xffffffff, 0xffffffff,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x40404040, 0x40404040, 0x40404040, 0x40404040,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x40404040, 0x40404040,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x40404040, 0x40404040,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0x40404040, 0x40404040, 0xffffffff, 0xffffffff,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf
+ },
+ {
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0x80808080, 0x80808080, 0xffffffff, 0xffffffff,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x80808080, 0x80808080, 0x80808080, 0x80808080,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x80808080, 0x80808080,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x80808080, 0x80808080,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0x80808080, 0x80808080, 0xffffffff, 0xffffffff,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f
+ }
+};
+
+u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN] __aligned(32) = {
+ {
+ 0x00000000, 0x00000000, 0x01010101, 0x01010101,
+ 0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe,
+ 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+ 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+ 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+ 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+ 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe,
+ 0x00000000, 0x00000000, 0xfefefefe, 0xfefefefe,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x01010101, 0x01010101, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x01010101, 0x01010101,
+ 0x00000000, 0x00000000, 0x01010101, 0x01010101,
+ 0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe,
+ 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202,
+ 0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x00000000, 0x00000000, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x02020202, 0x02020202, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x02020202, 0x02020202,
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202,
+ 0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+ 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x04040404, 0x04040404,
+ 0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+ 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x00000000, 0x00000000, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x04040404, 0x04040404, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x04040404, 0x04040404,
+ 0x00000000, 0x00000000, 0x04040404, 0x04040404,
+ 0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+ 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x08080808, 0x08080808,
+ 0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+ 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x00000000, 0x00000000, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x08080808, 0x08080808, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x08080808, 0x08080808,
+ 0x00000000, 0x00000000, 0x08080808, 0x08080808,
+ 0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+ 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010,
+ 0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef,
+ 0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+ 0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+ 0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+ 0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+ 0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef,
+ 0x00000000, 0x00000000, 0xefefefef, 0xefefefef,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x10101010, 0x10101010, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x10101010, 0x10101010,
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010,
+ 0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef,
+ 0xefefefef, 0xefefefef, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x20202020, 0x20202020,
+ 0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x00000000, 0x00000000, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x20202020, 0x20202020, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x20202020, 0x20202020,
+ 0x00000000, 0x00000000, 0x20202020, 0x20202020,
+ 0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+ 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x40404040, 0x40404040,
+ 0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+ 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x00000000, 0x00000000, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x40404040, 0x40404040, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x40404040, 0x40404040,
+ 0x00000000, 0x00000000, 0x40404040, 0x40404040,
+ 0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+ 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x80808080, 0x80808080,
+ 0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+ 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x00000000, 0x00000000, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x80808080, 0x80808080, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0x80808080, 0x80808080,
+ 0x00000000, 0x00000000, 0x80808080, 0x80808080,
+ 0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+ 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000
+ }
+};
+
+/* Fabric ratios table */
+u32 fabric_ratio[FAB_OPT] = {
+ 0x04010204,
+ 0x04020202,
+ 0x08020306,
+ 0x08020303,
+ 0x04020303,
+ 0x04020204,
+ 0x04010202,
+ 0x08030606,
+ 0x08030505,
+ 0x04020306,
+ 0x0804050a,
+ 0x04030606,
+ 0x04020404,
+ 0x04030306,
+ 0x04020505,
+ 0x08020505,
+ 0x04010303,
+ 0x08050a0a,
+ 0x04030408,
+ 0x04010102,
+ 0x08030306
+};
+
+u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM] = {
+ {3, 2, 5, 7, 1, 0, 6, 4},
+ {2, 3, 6, 7, 1, 0, 4, 5},
+ {1, 3, 5, 6, 0, 2, 4, 7},
+ {0, 2, 4, 7, 1, 3, 5, 6},
+ {3, 0, 4, 6, 1, 2, 5, 7},
+ {0, 3, 5, 7, 1, 2, 4, 6},
+ {2, 3, 5, 7, 1, 0, 4, 6},
+ {0, 2, 5, 4, 1, 3, 6, 7},
+ {2, 3, 4, 7, 0, 1, 5, 6}
+};
+
+#endif /* __DDR3_PATTERNS_64_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_topology_def.h b/drivers/ddr/marvell/a38x/ddr3_topology_def.h
new file mode 100644
index 0000000000..64a0447dd1
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_topology_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TOPOLOGY_DEF_H
+#define _DDR3_TOPOLOGY_DEF_H
+
+/* TOPOLOGY */
+
+enum hws_speed_bin {
+ SPEED_BIN_DDR_800D,
+ SPEED_BIN_DDR_800E,
+ SPEED_BIN_DDR_1066E,
+ SPEED_BIN_DDR_1066F,
+ SPEED_BIN_DDR_1066G,
+ SPEED_BIN_DDR_1333F,
+ SPEED_BIN_DDR_1333G,
+ SPEED_BIN_DDR_1333H,
+ SPEED_BIN_DDR_1333J,
+ SPEED_BIN_DDR_1600G,
+ SPEED_BIN_DDR_1600H,
+ SPEED_BIN_DDR_1600J,
+ SPEED_BIN_DDR_1600K,
+ SPEED_BIN_DDR_1866J,
+ SPEED_BIN_DDR_1866K,
+ SPEED_BIN_DDR_1866L,
+ SPEED_BIN_DDR_1866M,
+ SPEED_BIN_DDR_2133K,
+ SPEED_BIN_DDR_2133L,
+ SPEED_BIN_DDR_2133M,
+ SPEED_BIN_DDR_2133N,
+
+ SPEED_BIN_DDR_1333H_EXT,
+ SPEED_BIN_DDR_1600K_EXT,
+ SPEED_BIN_DDR_1866M_EXT
+};
+
+enum hws_ddr_freq {
+ DDR_FREQ_LOW_FREQ,
+ DDR_FREQ_400,
+ DDR_FREQ_533,
+ DDR_FREQ_667,
+ DDR_FREQ_800,
+ DDR_FREQ_933,
+ DDR_FREQ_1066,
+ DDR_FREQ_311,
+ DDR_FREQ_333,
+ DDR_FREQ_467,
+ DDR_FREQ_850,
+ DDR_FREQ_600,
+ DDR_FREQ_300,
+ DDR_FREQ_900,
+ DDR_FREQ_360,
+ DDR_FREQ_1000,
+ DDR_FREQ_LIMIT
+};
+
+enum speed_bin_table_elements {
+ SPEED_BIN_TRCD,
+ SPEED_BIN_TRP,
+ SPEED_BIN_TRAS,
+ SPEED_BIN_TRC,
+ SPEED_BIN_TRRD1K,
+ SPEED_BIN_TRRD2K,
+ SPEED_BIN_TPD,
+ SPEED_BIN_TFAW1K,
+ SPEED_BIN_TFAW2K,
+ SPEED_BIN_TWTR,
+ SPEED_BIN_TRTP,
+ SPEED_BIN_TWR,
+ SPEED_BIN_TMOD
+};
+
+#endif /* _DDR3_TOPOLOGY_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c
new file mode 100644
index 0000000000..80ef050bdc
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training.c
@@ -0,0 +1,2644 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define GET_MAX_VALUE(x, y) \
+ ((x) > (y)) ? (x) : (y)
+#define CEIL_DIVIDE(x, y) \
+ ((x - (x / y) * y) == 0) ? ((x / y) - 1) : (x / y)
+
+#define TIME_2_CLOCK_CYCLES CEIL_DIVIDE
+
+#define GET_CS_FROM_MASK(mask) (cs_mask2_num[mask])
+#define CS_CBE_VALUE(cs_num) (cs_cbe_reg[cs_num])
+
+u32 window_mem_addr = 0;
+u32 phy_reg0_val = 0;
+u32 phy_reg1_val = 8;
+u32 phy_reg2_val = 0;
+u32 phy_reg3_val = 0xa;
+enum hws_ddr_freq init_freq = DDR_FREQ_667;
+enum hws_ddr_freq low_freq = DDR_FREQ_LOW_FREQ;
+enum hws_ddr_freq medium_freq;
+u32 debug_dunit = 0;
+u32 odt_additional = 1;
+u32 *dq_map_table = NULL;
+u32 odt_config = 1;
+
+#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ALLEYCAT3) || \
+ defined(CONFIG_ARMADA_39X)
+u32 is_pll_before_init = 0, is_adll_calib_before_init = 0, is_dfs_in_init = 0;
+u32 dfs_low_freq = 130;
+#else
+u32 is_pll_before_init = 0, is_adll_calib_before_init = 1, is_dfs_in_init = 0;
+u32 dfs_low_freq = 100;
+#endif
+u32 g_rtt_nom_c_s0, g_rtt_nom_c_s1;
+u8 calibration_update_control; /* 2 external only, 1 is internal only */
+
+enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+enum auto_tune_stage training_stage = INIT_CONTROLLER;
+u32 finger_test = 0, p_finger_start = 11, p_finger_end = 64,
+ n_finger_start = 11, n_finger_end = 64,
+ p_finger_step = 3, n_finger_step = 3;
+u32 clamp_tbl[] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
+
+/* Initiate to 0xff, this variable is define by user in debug mode */
+u32 mode2_t = 0xff;
+u32 xsb_validate_type = 0;
+u32 xsb_validation_base_address = 0xf000;
+u32 first_active_if = 0;
+u32 dfs_low_phy1 = 0x1f;
+u32 multicast_id = 0;
+int use_broadcast = 0;
+struct hws_tip_freq_config_info *freq_info_table = NULL;
+u8 is_cbe_required = 0;
+u32 debug_mode = 0;
+u32 delay_enable = 0;
+int rl_mid_freq_wa = 0;
+
+u32 effective_cs = 0;
+
+u32 mask_tune_func = (SET_MEDIUM_FREQ_MASK_BIT |
+ WRITE_LEVELING_MASK_BIT |
+ LOAD_PATTERN_2_MASK_BIT |
+ READ_LEVELING_MASK_BIT |
+ SET_TARGET_FREQ_MASK_BIT | WRITE_LEVELING_TF_MASK_BIT |
+ READ_LEVELING_TF_MASK_BIT |
+ CENTRALIZATION_RX_MASK_BIT | CENTRALIZATION_TX_MASK_BIT);
+
+void ddr3_print_version(void)
+{
+ printf(DDR3_TIP_VERSION_STRING);
+}
+
+static int ddr3_tip_ddr3_training_main_flow(u32 dev_num);
+static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, u32 cl_value, u32 cwl_value);
+static int ddr3_tip_ddr3_auto_tune(u32 dev_num);
+static int is_bus_access_done(u32 dev_num, u32 if_id,
+ u32 dunit_reg_adrr, u32 bit);
+#ifdef ODT_TEST_SUPPORT
+static int odt_test(u32 dev_num, enum hws_algo_type algo_type);
+#endif
+
+int adll_calibration(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_ddr_freq frequency);
+static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_ddr_freq frequency);
+
+static struct page_element page_param[] = {
+ /*
+ * 8bits 16 bits
+ * page-size(K) page-size(K) mask
+ */
+ { 1, 2, 2},
+ /* 512M */
+ { 1, 2, 3},
+ /* 1G */
+ { 1, 2, 0},
+ /* 2G */
+ { 1, 2, 4},
+ /* 4G */
+ { 2, 2, 5}
+ /* 8G */
+};
+
+static u8 mem_size_config[MEM_SIZE_LAST] = {
+ 0x2, /* 512Mbit */
+ 0x3, /* 1Gbit */
+ 0x0, /* 2Gbit */
+ 0x4, /* 4Gbit */
+ 0x5 /* 8Gbit */
+};
+
+static u8 cs_mask2_num[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
+
+static struct reg_data odpg_default_value[] = {
+ {0x1034, 0x38000, MASK_ALL_BITS},
+ {0x1038, 0x0, MASK_ALL_BITS},
+ {0x10b0, 0x0, MASK_ALL_BITS},
+ {0x10b8, 0x0, MASK_ALL_BITS},
+ {0x10c0, 0x0, MASK_ALL_BITS},
+ {0x10f0, 0x0, MASK_ALL_BITS},
+ {0x10f4, 0x0, MASK_ALL_BITS},
+ {0x10f8, 0xff, MASK_ALL_BITS},
+ {0x10fc, 0xffff, MASK_ALL_BITS},
+ {0x1130, 0x0, MASK_ALL_BITS},
+ {0x1830, 0x2000000, MASK_ALL_BITS},
+ {0x14d0, 0x0, MASK_ALL_BITS},
+ {0x14d4, 0x0, MASK_ALL_BITS},
+ {0x14d8, 0x0, MASK_ALL_BITS},
+ {0x14dc, 0x0, MASK_ALL_BITS},
+ {0x1454, 0x0, MASK_ALL_BITS},
+ {0x1594, 0x0, MASK_ALL_BITS},
+ {0x1598, 0x0, MASK_ALL_BITS},
+ {0x159c, 0x0, MASK_ALL_BITS},
+ {0x15a0, 0x0, MASK_ALL_BITS},
+ {0x15a4, 0x0, MASK_ALL_BITS},
+ {0x15a8, 0x0, MASK_ALL_BITS},
+ {0x15ac, 0x0, MASK_ALL_BITS},
+ {0x1604, 0x0, MASK_ALL_BITS},
+ {0x1608, 0x0, MASK_ALL_BITS},
+ {0x160c, 0x0, MASK_ALL_BITS},
+ {0x1610, 0x0, MASK_ALL_BITS},
+ {0x1614, 0x0, MASK_ALL_BITS},
+ {0x1618, 0x0, MASK_ALL_BITS},
+ {0x1624, 0x0, MASK_ALL_BITS},
+ {0x1690, 0x0, MASK_ALL_BITS},
+ {0x1694, 0x0, MASK_ALL_BITS},
+ {0x1698, 0x0, MASK_ALL_BITS},
+ {0x169c, 0x0, MASK_ALL_BITS},
+ {0x14b8, 0x6f67, MASK_ALL_BITS},
+ {0x1630, 0x0, MASK_ALL_BITS},
+ {0x1634, 0x0, MASK_ALL_BITS},
+ {0x1638, 0x0, MASK_ALL_BITS},
+ {0x163c, 0x0, MASK_ALL_BITS},
+ {0x16b0, 0x0, MASK_ALL_BITS},
+ {0x16b4, 0x0, MASK_ALL_BITS},
+ {0x16b8, 0x0, MASK_ALL_BITS},
+ {0x16bc, 0x0, MASK_ALL_BITS},
+ {0x16c0, 0x0, MASK_ALL_BITS},
+ {0x16c4, 0x0, MASK_ALL_BITS},
+ {0x16c8, 0x0, MASK_ALL_BITS},
+ {0x16cc, 0x1, MASK_ALL_BITS},
+ {0x16f0, 0x1, MASK_ALL_BITS},
+ {0x16f4, 0x0, MASK_ALL_BITS},
+ {0x16f8, 0x0, MASK_ALL_BITS},
+ {0x16fc, 0x0, MASK_ALL_BITS}
+};
+
+static int ddr3_tip_bus_access(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, enum hws_access_type phy_access,
+ u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+ u32 data_value, enum hws_operation oper_type);
+static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id);
+static int ddr3_tip_rank_control(u32 dev_num, u32 if_id);
+
+/*
+ * Update global training parameters by data from user
+ */
+int ddr3_tip_tune_training_params(u32 dev_num,
+ struct tune_train_params *params)
+{
+ if (params->ck_delay != -1)
+ ck_delay = params->ck_delay;
+ if (params->ck_delay_16 != -1)
+ ck_delay_16 = params->ck_delay_16;
+ if (params->phy_reg3_val != -1)
+ phy_reg3_val = params->phy_reg3_val;
+
+ return MV_OK;
+}
+
+/*
+ * Configure CS
+ */
+int ddr3_tip_configure_cs(u32 dev_num, u32 if_id, u32 cs_num, u32 enable)
+{
+ u32 data, addr_hi, data_high;
+ u32 mem_index;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (enable == 1) {
+ data = (tm->interface_params[if_id].bus_width ==
+ BUS_WIDTH_8) ? 0 : 1;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ SDRAM_ACCESS_CONTROL_REG, (data << (cs_num * 4)),
+ 0x3 << (cs_num * 4)));
+ mem_index = tm->interface_params[if_id].memory_size;
+
+ addr_hi = mem_size_config[mem_index] & 0x3;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ SDRAM_ACCESS_CONTROL_REG,
+ (addr_hi << (2 + cs_num * 4)),
+ 0x3 << (2 + cs_num * 4)));
+
+ data_high = (mem_size_config[mem_index] & 0x4) >> 2;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ SDRAM_ACCESS_CONTROL_REG,
+ data_high << (20 + cs_num), 1 << (20 + cs_num)));
+
+ /* Enable Address Select Mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ SDRAM_ACCESS_CONTROL_REG, 1 << (16 + cs_num),
+ 1 << (16 + cs_num)));
+ }
+ switch (cs_num) {
+ case 0:
+ case 1:
+ case 2:
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ DDR_CONTROL_LOW_REG, (enable << (cs_num + 11)),
+ 1 << (cs_num + 11)));
+ break;
+ case 3:
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ DDR_CONTROL_LOW_REG, (enable << 15), 1 << 15));
+ break;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Calculate number of CS
+ */
+static int calc_cs_num(u32 dev_num, u32 if_id, u32 *cs_num)
+{
+ u32 cs;
+ u32 bus_cnt;
+ u32 cs_count;
+ u32 cs_bitmask;
+ u32 curr_cs_num = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ cs_count = 0;
+ cs_bitmask = tm->interface_params[if_id].
+ as_bus_params[bus_cnt].cs_bitmask;
+ for (cs = 0; cs < MAX_CS_NUM; cs++) {
+ if ((cs_bitmask >> cs) & 1)
+ cs_count++;
+ }
+
+ if (curr_cs_num == 0) {
+ curr_cs_num = cs_count;
+ } else if (cs_count != curr_cs_num) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("CS number is different per bus (IF %d BUS %d cs_num %d curr_cs_num %d)\n",
+ if_id, bus_cnt, cs_count,
+ curr_cs_num));
+ return MV_NOT_SUPPORTED;
+ }
+ }
+ *cs_num = curr_cs_num;
+
+ return MV_OK;
+}
+
+/*
+ * Init Controller Flow
+ */
+int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_prm)
+{
+ u32 if_id;
+ u32 cs_num;
+ u32 t_refi = 0, t_hclk = 0, t_ckclk = 0, t_faw = 0, t_pd = 0,
+ t_wr = 0, t2t = 0, txpdll = 0;
+ u32 data_value = 0, bus_width = 0, page_size = 0, cs_cnt = 0,
+ mem_mask = 0, bus_index = 0;
+ enum hws_speed_bin speed_bin_index = SPEED_BIN_DDR_2133N;
+ enum hws_mem_size memory_size = MEM_2G;
+ enum hws_ddr_freq freq = init_freq;
+ u32 cs_mask = 0;
+ u32 cl_value = 0, cwl_val = 0;
+ u32 refresh_interval_cnt = 0, bus_cnt = 0, adll_tap = 0;
+ enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
+ u32 data_read[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("Init_controller, do_mrs_phy=%d, is_ctrl64_bit=%d\n",
+ init_cntr_prm->do_mrs_phy,
+ init_cntr_prm->is_ctrl64_bit));
+
+ if (init_cntr_prm->init_phy == 1) {
+ CHECK_STATUS(ddr3_tip_configure_phy(dev_num));
+ }
+
+ if (generic_init_controller == 1) {
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("active IF %d\n", if_id));
+ mem_mask = 0;
+ for (bus_index = 0;
+ bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ mem_mask |=
+ tm->interface_params[if_id].
+ as_bus_params[bus_index].mirror_enable_bitmask;
+ }
+
+ if (mem_mask != 0) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, CS_ENABLE_REG, 0,
+ 0x8));
+ }
+
+ memory_size =
+ tm->interface_params[if_id].
+ memory_size;
+ speed_bin_index =
+ tm->interface_params[if_id].
+ speed_bin_index;
+ freq = init_freq;
+ t_refi =
+ (tm->interface_params[if_id].
+ interface_temp ==
+ HWS_TEMP_HIGH) ? TREFI_HIGH : TREFI_LOW;
+ t_refi *= 1000; /* psec */
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("memy_size %d speed_bin_ind %d freq %d t_refi %d\n",
+ memory_size, speed_bin_index, freq,
+ t_refi));
+ /* HCLK & CK CLK in 2:1[ps] */
+ /* t_ckclk is external clock */
+ t_ckclk = (MEGA / freq_val[freq]);
+ /* t_hclk is internal clock */
+ t_hclk = 2 * t_ckclk;
+ refresh_interval_cnt = t_refi / t_hclk; /* no units */
+ bus_width =
+ (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask)
+ == 1) ? (16) : (32);
+
+ if (init_cntr_prm->is_ctrl64_bit)
+ bus_width = 64;
+
+ data_value =
+ (refresh_interval_cnt | 0x4000 |
+ ((bus_width ==
+ 32) ? 0x8000 : 0) | 0x1000000) & ~(1 << 26);
+
+ /* Interface Bus Width */
+ /* SRMode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_CONFIGURATION_REG, data_value,
+ 0x100ffff));
+
+ /* Interleave first command pre-charge enable (TBD) */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_OPEN_PAGE_CONTROL_REG, (1 << 10),
+ (1 << 10)));
+
+ /* PHY configuration */
+ /*
+ * Postamble Length = 1.5cc, Addresscntl to clk skew
+ * \BD, Preamble length normal, parralal ADLL enable
+ */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DRAM_PHY_CONFIGURATION, 0x28, 0x3e));
+ if (init_cntr_prm->is_ctrl64_bit) {
+ /* positive edge */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DRAM_PHY_CONFIGURATION, 0x0,
+ 0xff80));
+ }
+
+ /* calibration block disable */
+ /* Xbar Read buffer select (for Internal access) */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ CALIB_MACHINE_CTRL_REG, 0x1200c,
+ 0x7dffe01c));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ CALIB_MACHINE_CTRL_REG,
+ calibration_update_control << 3, 0x3 << 3));
+
+ /* Pad calibration control - enable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ CALIB_MACHINE_CTRL_REG, 0x1, 0x1));
+
+ cs_mask = 0;
+ data_value = 0x7;
+ /*
+ * Address ctrl \96 Part of the Generic code
+ * The next configuration is done:
+ * 1) Memory Size
+ * 2) Bus_width
+ * 3) CS#
+ * 4) Page Number
+ * 5) t_faw
+ * Per Dunit get from the Map_topology the parameters:
+ * Bus_width
+ * t_faw is per Dunit not per CS
+ */
+ page_size =
+ (tm->interface_params[if_id].
+ bus_width ==
+ BUS_WIDTH_8) ? page_param[memory_size].
+ page_size_8bit : page_param[memory_size].
+ page_size_16bit;
+
+ t_faw =
+ (page_size == 1) ? speed_bin_table(speed_bin_index,
+ SPEED_BIN_TFAW1K)
+ : speed_bin_table(speed_bin_index,
+ SPEED_BIN_TFAW2K);
+
+ data_value = TIME_2_CLOCK_CYCLES(t_faw, t_ckclk);
+ data_value = data_value << 24;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_ACCESS_CONTROL_REG, data_value,
+ 0x7f000000));
+
+ data_value =
+ (tm->interface_params[if_id].
+ bus_width == BUS_WIDTH_8) ? 0 : 1;
+
+ /* create merge cs mask for all cs available in dunit */
+ for (bus_cnt = 0;
+ bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ cs_mask |=
+ tm->interface_params[if_id].
+ as_bus_params[bus_cnt].cs_bitmask;
+ }
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("Init_controller IF %d cs_mask %d\n",
+ if_id, cs_mask));
+ /*
+ * Configure the next upon the Map Topology \96 If the
+ * Dunit is CS0 Configure CS0 if it is multi CS
+ * configure them both: The Bust_width it\92s the
+ * Memory Bus width \96 x8 or x16
+ */
+ for (cs_cnt = 0; cs_cnt < NUM_OF_CS; cs_cnt++) {
+ ddr3_tip_configure_cs(dev_num, if_id, cs_cnt,
+ ((cs_mask & (1 << cs_cnt)) ? 1
+ : 0));
+ }
+
+ if (init_cntr_prm->do_mrs_phy) {
+ /*
+ * MR0 \96 Part of the Generic code
+ * The next configuration is done:
+ * 1) Burst Length
+ * 2) CAS Latency
+ * get for each dunit what is it Speed_bin &
+ * Target Frequency. From those both parameters
+ * get the appropriate Cas_l from the CL table
+ */
+ cl_value =
+ tm->interface_params[if_id].
+ cas_l;
+ cwl_val =
+ tm->interface_params[if_id].
+ cas_wl;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("cl_value 0x%x cwl_val 0x%x\n",
+ cl_value, cwl_val));
+
+ data_value =
+ ((cl_mask_table[cl_value] & 0x1) << 2) |
+ ((cl_mask_table[cl_value] & 0xe) << 3);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ MR0_REG, data_value,
+ (0x7 << 4) | (1 << 2)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ MR0_REG, twr_mask_table[t_wr + 1],
+ 0xe00));
+
+ /*
+ * MR1: Set RTT and DIC Design GL values
+ * configured by user
+ */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, MR1_REG,
+ g_dic | g_rtt_nom, 0x266));
+
+ /* MR2 - Part of the Generic code */
+ /*
+ * The next configuration is done:
+ * 1) SRT
+ * 2) CAS Write Latency
+ */
+ data_value = (cwl_mask_table[cwl_val] << 3);
+ data_value |=
+ ((tm->interface_params[if_id].
+ interface_temp ==
+ HWS_TEMP_HIGH) ? (1 << 7) : 0);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ MR2_REG, data_value,
+ (0x7 << 3) | (0x1 << 7) | (0x3 <<
+ 9)));
+ }
+
+ ddr3_tip_write_odt(dev_num, access_type, if_id,
+ cl_value, cwl_val);
+ ddr3_tip_set_timing(dev_num, access_type, if_id, freq);
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DUNIT_CONTROL_HIGH_REG, 0x177,
+ 0x1000177));
+
+ if (init_cntr_prm->is_ctrl64_bit) {
+ /* disable 0.25 cc delay */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DUNIT_CONTROL_HIGH_REG, 0x0,
+ 0x800));
+ }
+
+ /* reset bit 7 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DUNIT_CONTROL_HIGH_REG,
+ (init_cntr_prm->msys_init << 7), (1 << 7)));
+
+ if (mode2_t != 0xff) {
+ t2t = mode2_t;
+ } else {
+ /* calculate number of CS (per interface) */
+ CHECK_STATUS(calc_cs_num
+ (dev_num, if_id, &cs_num));
+ t2t = (cs_num == 1) ? 0 : 1;
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DDR_CONTROL_LOW_REG, t2t << 3,
+ 0x3 << 3));
+ /* move the block to ddr3_tip_set_timing - start */
+ t_pd = GET_MAX_VALUE(t_ckclk * 3,
+ speed_bin_table(speed_bin_index,
+ SPEED_BIN_TPD));
+ t_pd = TIME_2_CLOCK_CYCLES(t_pd, t_ckclk);
+ txpdll = GET_MAX_VALUE(t_ckclk * 10, 24);
+ txpdll = CEIL_DIVIDE((txpdll - 1), t_ckclk);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DDR_TIMING_REG, txpdll << 4,
+ 0x1f << 4));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DDR_TIMING_REG, 0x28 << 9, 0x3f << 9));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DDR_TIMING_REG, 0xa << 21, 0xff << 21));
+
+ /* move the block to ddr3_tip_set_timing - end */
+ /* AUTO_ZQC_TIMING */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ TIMING_REG, (AUTO_ZQC_TIMING | (2 << 20)),
+ 0x3fffff));
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, access_type, if_id,
+ DRAM_PHY_CONFIGURATION, data_read, 0x30));
+ data_value =
+ (data_read[if_id] == 0) ? (1 << 11) : 0;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DUNIT_CONTROL_HIGH_REG, data_value,
+ (1 << 11)));
+
+ /* Set Active control for ODT write transactions */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, 0x1494, g_odt_config,
+ MASK_ALL_BITS));
+ }
+ } else {
+#ifdef STATIC_ALGO_SUPPORT
+ CHECK_STATUS(ddr3_tip_static_init_controller(dev_num));
+#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X)
+ CHECK_STATUS(ddr3_tip_static_phy_init_controller(dev_num));
+#endif
+#endif /* STATIC_ALGO_SUPPORT */
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_rank_control(dev_num, if_id));
+
+ if (init_cntr_prm->do_mrs_phy) {
+ CHECK_STATUS(ddr3_tip_pad_inv(dev_num, if_id));
+ }
+
+ /* Pad calibration control - disable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ CALIB_MACHINE_CTRL_REG, 0x0, 0x1));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ CALIB_MACHINE_CTRL_REG,
+ calibration_update_control << 3, 0x3 << 3));
+ }
+
+ CHECK_STATUS(ddr3_tip_enable_init_sequence(dev_num));
+
+ if (delay_enable != 0) {
+ adll_tap = MEGA / (freq_val[freq] * 64);
+ ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Load Topology map
+ */
+int hws_ddr3_tip_load_topology_map(u32 dev_num, struct hws_topology_map *tm)
+{
+ enum hws_speed_bin speed_bin_index;
+ enum hws_ddr_freq freq = DDR_FREQ_LIMIT;
+ u32 if_id;
+
+ freq_val[DDR_FREQ_LOW_FREQ] = dfs_low_freq;
+ tm = ddr3_get_topology_map();
+ CHECK_STATUS(ddr3_tip_get_first_active_if
+ ((u8)dev_num, tm->if_act_mask,
+ &first_active_if));
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("board IF_Mask=0x%x num_of_bus_per_interface=0x%x\n",
+ tm->if_act_mask,
+ tm->num_of_bus_per_interface));
+
+ /*
+ * if CL, CWL values are missing in topology map, then fill them
+ * according to speedbin tables
+ */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ speed_bin_index =
+ tm->interface_params[if_id].speed_bin_index;
+ /* TBD memory frequency of interface 0 only is used ! */
+ freq = tm->interface_params[first_active_if].memory_freq;
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("speed_bin_index =%d freq=%d cl=%d cwl=%d\n",
+ speed_bin_index, freq_val[freq],
+ tm->interface_params[if_id].
+ cas_l,
+ tm->interface_params[if_id].
+ cas_wl));
+
+ if (tm->interface_params[if_id].cas_l == 0) {
+ tm->interface_params[if_id].cas_l =
+ cas_latency_table[speed_bin_index].cl_val[freq];
+ }
+
+ if (tm->interface_params[if_id].cas_wl == 0) {
+ tm->interface_params[if_id].cas_wl =
+ cas_write_latency_table[speed_bin_index].cl_val[freq];
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * RANK Control Flow
+ */
+static int ddr3_tip_rank_control(u32 dev_num, u32 if_id)
+{
+ u32 data_value = 0, bus_cnt;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (bus_cnt = 1; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ if ((tm->interface_params[if_id].
+ as_bus_params[0].cs_bitmask !=
+ tm->interface_params[if_id].
+ as_bus_params[bus_cnt].cs_bitmask) ||
+ (tm->interface_params[if_id].
+ as_bus_params[0].mirror_enable_bitmask !=
+ tm->interface_params[if_id].
+ as_bus_params[bus_cnt].mirror_enable_bitmask))
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("WARNING:Wrong configuration for pup #%d CS mask and CS mirroring for all pups should be the same\n",
+ bus_cnt));
+ }
+
+ data_value |= tm->interface_params[if_id].
+ as_bus_params[0].cs_bitmask;
+ data_value |= tm->interface_params[if_id].
+ as_bus_params[0].mirror_enable_bitmask << 4;
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, RANK_CTRL_REG,
+ data_value, 0xff));
+
+ return MV_OK;
+}
+
+/*
+ * PAD Inverse Flow
+ */
+static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id)
+{
+ u32 bus_cnt, data_value, ck_swap_pup_ctrl;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ if (tm->interface_params[if_id].
+ as_bus_params[bus_cnt].is_dqs_swap == 1) {
+ /* dqs swap */
+ ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, bus_cnt,
+ DDR_PHY_DATA,
+ PHY_CONTROL_PHY_REG, 0xc0,
+ 0xc0);
+ }
+
+ if (tm->interface_params[if_id].
+ as_bus_params[bus_cnt].is_ck_swap == 1) {
+ if (bus_cnt <= 1)
+ data_value = 0x5 << 2;
+ else
+ data_value = 0xa << 2;
+
+ /* mask equals data */
+ /* ck swap pup is only control pup #0 ! */
+ ck_swap_pup_ctrl = 0;
+ ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ck_swap_pup_ctrl,
+ DDR_PHY_CONTROL,
+ PHY_CONTROL_PHY_REG,
+ data_value, data_value);
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Run Training Flow
+ */
+int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type)
+{
+ int ret = MV_OK, ret_tune = MV_OK;
+
+#ifdef ODT_TEST_SUPPORT
+ if (finger_test == 1)
+ return odt_test(dev_num, algo_type);
+#endif
+
+ if (algo_type == ALGO_TYPE_DYNAMIC) {
+ ret = ddr3_tip_ddr3_auto_tune(dev_num);
+ } else {
+#ifdef STATIC_ALGO_SUPPORT
+ {
+ enum hws_ddr_freq freq;
+ freq = init_freq;
+
+ /* add to mask */
+ if (is_adll_calib_before_init != 0) {
+ printf("with adll calib before init\n");
+ adll_calibration(dev_num, ACCESS_TYPE_MULTICAST,
+ 0, freq);
+ }
+ /*
+ * Frequency per interface is not relevant,
+ * only interface 0
+ */
+ ret = ddr3_tip_run_static_alg(dev_num,
+ freq);
+ }
+#endif
+ }
+
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Run_alg: tuning failed %d\n", ret_tune));
+ }
+
+ return ret;
+}
+
+#ifdef ODT_TEST_SUPPORT
+/*
+ * ODT Test
+ */
+static int odt_test(u32 dev_num, enum hws_algo_type algo_type)
+{
+ int ret = MV_OK, ret_tune = MV_OK;
+ int pfinger_val = 0, nfinger_val;
+
+ for (pfinger_val = p_finger_start; pfinger_val <= p_finger_end;
+ pfinger_val += p_finger_step) {
+ for (nfinger_val = n_finger_start; nfinger_val <= n_finger_end;
+ nfinger_val += n_finger_step) {
+ if (finger_test != 0) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("pfinger_val %d nfinger_val %d\n",
+ pfinger_val, nfinger_val));
+ p_finger = pfinger_val;
+ n_finger = nfinger_val;
+ }
+
+ if (algo_type == ALGO_TYPE_DYNAMIC) {
+ ret = ddr3_tip_ddr3_auto_tune(dev_num);
+ } else {
+ /*
+ * Frequency per interface is not relevant,
+ * only interface 0
+ */
+ ret = ddr3_tip_run_static_alg(dev_num,
+ init_freq);
+ }
+ }
+ }
+
+ if (ret_tune != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Run_alg: tuning failed %d\n", ret_tune));
+ ret = (ret == MV_OK) ? ret_tune : ret;
+ }
+
+ return ret;
+}
+#endif
+
+/*
+ * Select Controller
+ */
+int hws_ddr3_tip_select_ddr_controller(u32 dev_num, int enable)
+{
+ if (config_func_info[dev_num].tip_dunit_mux_select_func != NULL) {
+ return config_func_info[dev_num].
+ tip_dunit_mux_select_func((u8)dev_num, enable);
+ }
+
+ return MV_FAIL;
+}
+
+/*
+ * Dunit Register Write
+ */
+int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 data_value, u32 mask)
+{
+ if (config_func_info[dev_num].tip_dunit_write_func != NULL) {
+ return config_func_info[dev_num].
+ tip_dunit_write_func((u8)dev_num, interface_access,
+ if_id, reg_addr,
+ data_value, mask);
+ }
+
+ return MV_FAIL;
+}
+
+/*
+ * Dunit Register Read
+ */
+int ddr3_tip_if_read(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 *data, u32 mask)
+{
+ if (config_func_info[dev_num].tip_dunit_read_func != NULL) {
+ return config_func_info[dev_num].
+ tip_dunit_read_func((u8)dev_num, interface_access,
+ if_id, reg_addr,
+ data, mask);
+ }
+
+ return MV_FAIL;
+}
+
+/*
+ * Dunit Register Polling
+ */
+int ddr3_tip_if_polling(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, u32 exp_value, u32 mask, u32 offset,
+ u32 poll_tries)
+{
+ u32 poll_cnt = 0, interface_num = 0, start_if, end_if;
+ u32 read_data[MAX_INTERFACE_NUM];
+ int ret;
+ int is_fail = 0, is_if_fail;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (access_type == ACCESS_TYPE_MULTICAST) {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ } else {
+ start_if = if_id;
+ end_if = if_id;
+ }
+
+ for (interface_num = start_if; interface_num <= end_if; interface_num++) {
+ /* polling bit 3 for n times */
+ VALIDATE_ACTIVE(tm->if_act_mask, interface_num);
+
+ is_if_fail = 0;
+ for (poll_cnt = 0; poll_cnt < poll_tries; poll_cnt++) {
+ ret =
+ ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST,
+ interface_num, offset, read_data,
+ mask);
+ if (ret != MV_OK)
+ return ret;
+
+ if (read_data[interface_num] == exp_value)
+ break;
+ }
+
+ if (poll_cnt >= poll_tries) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("max poll IF #%d\n", interface_num));
+ is_fail = 1;
+ is_if_fail = 1;
+ }
+
+ training_result[training_stage][interface_num] =
+ (is_if_fail == 1) ? TEST_FAILED : TEST_SUCCESS;
+ }
+
+ return (is_fail == 0) ? MV_OK : MV_FAIL;
+}
+
+/*
+ * Bus read access
+ */
+int ddr3_tip_bus_read(u32 dev_num, u32 if_id,
+ enum hws_access_type phy_access, u32 phy_id,
+ enum hws_ddr_phy phy_type, u32 reg_addr, u32 *data)
+{
+ u32 bus_index = 0;
+ u32 data_read[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (phy_access == ACCESS_TYPE_MULTICAST) {
+ for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ CHECK_STATUS(ddr3_tip_bus_access
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ bus_index, phy_type, reg_addr, 0,
+ OPERATION_READ));
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ PHY_REG_FILE_ACCESS, data_read,
+ MASK_ALL_BITS));
+ data[bus_index] = (data_read[if_id] & 0xffff);
+ }
+ } else {
+ CHECK_STATUS(ddr3_tip_bus_access
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ phy_access, phy_id, phy_type, reg_addr, 0,
+ OPERATION_READ));
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ PHY_REG_FILE_ACCESS, data_read, MASK_ALL_BITS));
+
+ /*
+ * only 16 lsb bit are valid in Phy (each register is different,
+ * some can actually be less than 16 bits)
+ */
+ *data = (data_read[if_id] & 0xffff);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Bus write access
+ */
+int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, enum hws_access_type phy_access,
+ u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+ u32 data_value)
+{
+ CHECK_STATUS(ddr3_tip_bus_access
+ (dev_num, interface_access, if_id, phy_access,
+ phy_id, phy_type, reg_addr, data_value, OPERATION_WRITE));
+
+ return MV_OK;
+}
+
+/*
+ * Bus access routine (relevant for both read & write)
+ */
+static int ddr3_tip_bus_access(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, enum hws_access_type phy_access,
+ u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+ u32 data_value, enum hws_operation oper_type)
+{
+ u32 addr_low = 0x3f & reg_addr;
+ u32 addr_hi = ((0xc0 & reg_addr) >> 6);
+ u32 data_p1 =
+ (oper_type << 30) + (addr_hi << 28) + (phy_access << 27) +
+ (phy_type << 26) + (phy_id << 22) + (addr_low << 16) +
+ (data_value & 0xffff);
+ u32 data_p2 = data_p1 + (1 << 31);
+ u32 start_if, end_if;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, interface_access, if_id, PHY_REG_FILE_ACCESS,
+ data_p1, MASK_ALL_BITS));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, interface_access, if_id, PHY_REG_FILE_ACCESS,
+ data_p2, MASK_ALL_BITS));
+
+ if (interface_access == ACCESS_TYPE_UNICAST) {
+ start_if = if_id;
+ end_if = if_id;
+ } else {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ }
+
+ /* polling for read/write execution done */
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(is_bus_access_done
+ (dev_num, if_id, PHY_REG_FILE_ACCESS, 31));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Check bus access done
+ */
+static int is_bus_access_done(u32 dev_num, u32 if_id, u32 dunit_reg_adrr,
+ u32 bit)
+{
+ u32 rd_data = 1;
+ u32 cnt = 0;
+ u32 data_read[MAX_INTERFACE_NUM];
+
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, dunit_reg_adrr,
+ data_read, MASK_ALL_BITS));
+ rd_data = data_read[if_id];
+ rd_data &= (1 << bit);
+
+ while (rd_data != 0) {
+ if (cnt++ >= MAX_POLLING_ITERATIONS)
+ break;
+
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ dunit_reg_adrr, data_read, MASK_ALL_BITS));
+ rd_data = data_read[if_id];
+ rd_data &= (1 << bit);
+ }
+
+ if (cnt < MAX_POLLING_ITERATIONS)
+ return MV_OK;
+ else
+ return MV_FAIL;
+}
+
+/*
+ * Phy read-modify-write
+ */
+int ddr3_tip_bus_read_modify_write(u32 dev_num, enum hws_access_type access_type,
+ u32 interface_id, u32 phy_id,
+ enum hws_ddr_phy phy_type, u32 reg_addr,
+ u32 data_value, u32 reg_mask)
+{
+ u32 data_val = 0, if_id, start_if, end_if;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (access_type == ACCESS_TYPE_MULTICAST) {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ } else {
+ start_if = interface_id;
+ end_if = interface_id;
+ }
+
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST, phy_id,
+ phy_type, reg_addr, &data_val));
+ data_value = (data_val & (~reg_mask)) | (data_value & reg_mask);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, phy_id, phy_type, reg_addr,
+ data_value));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * ADLL Calibration
+ */
+int adll_calibration(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_ddr_freq frequency)
+{
+ struct hws_tip_freq_config_info freq_config_info;
+ u32 bus_cnt = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* Reset Diver_b assert -> de-assert */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+ 0, 0x10000000));
+ mdelay(10);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+ 0x10000000, 0x10000000));
+
+ if (config_func_info[dev_num].tip_get_freq_config_info_func != NULL) {
+ CHECK_STATUS(config_func_info[dev_num].
+ tip_get_freq_config_info_func((u8)dev_num, frequency,
+ &freq_config_info));
+ } else {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("tip_get_freq_config_info_func is NULL"));
+ return MV_NOT_INITIALIZED;
+ }
+
+ for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, access_type, if_id, bus_cnt,
+ DDR_PHY_DATA, BW_PHY_REG,
+ freq_config_info.bw_per_freq << 8, 0x700));
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, access_type, if_id, bus_cnt,
+ DDR_PHY_DATA, RATE_PHY_REG,
+ freq_config_info.rate_per_freq, 0x7));
+ }
+
+ /* DUnit to Phy drive post edge, ADLL reset assert de-assert */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DRAM_PHY_CONFIGURATION,
+ 0, (0x80000000 | 0x40000000)));
+ mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ]));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DRAM_PHY_CONFIGURATION,
+ (0x80000000 | 0x40000000), (0x80000000 | 0x40000000)));
+
+ /* polling for ADLL Done */
+ if (ddr3_tip_if_polling(dev_num, access_type, if_id,
+ 0x3ff03ff, 0x3ff03ff, PHY_LOCK_STATUS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Freq_set: DDR3 poll failed(1)"));
+ }
+
+ /* pup data_pup reset assert-> deassert */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+ 0, 0x60000000));
+ mdelay(10);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+ 0x60000000, 0x60000000));
+
+ return MV_OK;
+}
+
+int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_ddr_freq frequency)
+{
+ u32 cl_value = 0, cwl_value = 0, mem_mask = 0, val = 0,
+ bus_cnt = 0, t_hclk = 0, t_wr = 0,
+ refresh_interval_cnt = 0, cnt_id;
+ u32 t_refi = 0, end_if, start_if;
+ u32 bus_index = 0;
+ int is_dll_off = 0;
+ enum hws_speed_bin speed_bin_index = 0;
+ struct hws_tip_freq_config_info freq_config_info;
+ enum hws_result *flow_result = training_result[training_stage];
+ u32 adll_tap = 0;
+ u32 cs_mask[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("dev %d access %d IF %d freq %d\n", dev_num,
+ access_type, if_id, frequency));
+
+ if (frequency == DDR_FREQ_LOW_FREQ)
+ is_dll_off = 1;
+ if (access_type == ACCESS_TYPE_MULTICAST) {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ } else {
+ start_if = if_id;
+ end_if = if_id;
+ }
+
+ /* calculate interface cs mask - Oferb 4/11 */
+ /* speed bin can be different for each interface */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ /* cs enable is active low */
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ cs_mask[if_id] = CS_BIT_MASK;
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+ ddr3_tip_calc_cs_mask(dev_num, if_id, effective_cs,
+ &cs_mask[if_id]);
+ }
+
+ /* speed bin can be different for each interface */
+ /*
+ * moti b - need to remove the loop for multicas access functions
+ * and loop the unicast access functions
+ */
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+ continue;
+
+ flow_result[if_id] = TEST_SUCCESS;
+ speed_bin_index =
+ tm->interface_params[if_id].speed_bin_index;
+ if (tm->interface_params[if_id].memory_freq ==
+ frequency) {
+ cl_value =
+ tm->interface_params[if_id].cas_l;
+ cwl_value =
+ tm->interface_params[if_id].cas_wl;
+ } else {
+ cl_value =
+ cas_latency_table[speed_bin_index].cl_val[frequency];
+ cwl_value =
+ cas_write_latency_table[speed_bin_index].
+ cl_val[frequency];
+ }
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("Freq_set dev 0x%x access 0x%x if 0x%x freq 0x%x speed %d:\n\t",
+ dev_num, access_type, if_id,
+ frequency, speed_bin_index));
+
+ for (cnt_id = 0; cnt_id < DDR_FREQ_LIMIT; cnt_id++) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+ ("%d ",
+ cas_latency_table[speed_bin_index].
+ cl_val[cnt_id]));
+ }
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("\n"));
+ mem_mask = 0;
+ for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ mem_mask |=
+ tm->interface_params[if_id].
+ as_bus_params[bus_index].mirror_enable_bitmask;
+ }
+
+ if (mem_mask != 0) {
+ /* motib redundent in KW28 */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id,
+ CS_ENABLE_REG, 0, 0x8));
+ }
+
+ /* dll state after exiting SR */
+ if (is_dll_off == 1) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DFS_REG, 0x1, 0x1));
+ } else {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DFS_REG, 0, 0x1));
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DUNIT_MMASK_REG, 0, 0x1));
+ /* DFS - block transactions */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DFS_REG, 0x2, 0x2));
+
+ /* disable ODT in case of dll off */
+ if (is_dll_off == 1) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x1874, 0, 0x244));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x1884, 0, 0x244));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x1894, 0, 0x244));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x18a4, 0, 0x244));
+ }
+
+ /* DFS - Enter Self-Refresh */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DFS_REG, 0x4,
+ 0x4));
+ /* polling on self refresh entry */
+ if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, 0x8, 0x8, DFS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Freq_set: DDR3 poll failed on SR entry\n"));
+ }
+
+ /* PLL configuration */
+ if (config_func_info[dev_num].tip_set_freq_divider_func != NULL) {
+ config_func_info[dev_num].
+ tip_set_freq_divider_func(dev_num, if_id,
+ frequency);
+ }
+
+ /* PLL configuration End */
+
+ /* adjust t_refi to new frequency */
+ t_refi = (tm->interface_params[if_id].interface_temp ==
+ HWS_TEMP_HIGH) ? TREFI_LOW : TREFI_HIGH;
+ t_refi *= 1000; /*psec */
+
+ /* HCLK in[ps] */
+ t_hclk = MEGA / (freq_val[frequency] / 2);
+ refresh_interval_cnt = t_refi / t_hclk; /* no units */
+ val = 0x4000 | refresh_interval_cnt;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_CONFIGURATION_REG, val, 0x7fff));
+
+ /* DFS - CL/CWL/WR parameters after exiting SR */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DFS_REG,
+ (cl_mask_table[cl_value] << 8), 0xf00));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DFS_REG,
+ (cwl_mask_table[cwl_value] << 12), 0x7000));
+ t_wr = speed_bin_table(speed_bin_index, SPEED_BIN_TWR);
+ t_wr = (t_wr / 1000);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DFS_REG,
+ (twr_mask_table[t_wr + 1] << 16), 0x70000));
+
+ /* Restore original RTT values if returning from DLL OFF mode */
+ if (is_dll_off == 1) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, 0x1874,
+ g_dic | g_rtt_nom, 0x266));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, 0x1884,
+ g_dic | g_rtt_nom, 0x266));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, 0x1894,
+ g_dic | g_rtt_nom, 0x266));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, 0x18a4,
+ g_dic | g_rtt_nom, 0x266));
+ }
+
+ /* Reset Diver_b assert -> de-assert */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_CONFIGURATION_REG, 0, 0x10000000));
+ mdelay(10);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_CONFIGURATION_REG, 0x10000000, 0x10000000));
+
+ /* Adll configuration function of process and Frequency */
+ if (config_func_info[dev_num].tip_get_freq_config_info_func != NULL) {
+ CHECK_STATUS(config_func_info[dev_num].
+ tip_get_freq_config_info_func(dev_num, frequency,
+ &freq_config_info));
+ }
+ /* TBD check milo5 using device ID ? */
+ for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, bus_cnt, DDR_PHY_DATA,
+ 0x92,
+ freq_config_info.
+ bw_per_freq << 8
+ /*freq_mask[dev_num][frequency] << 8 */
+ , 0x700));
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ bus_cnt, DDR_PHY_DATA, 0x94,
+ freq_config_info.rate_per_freq, 0x7));
+ }
+
+ /* DUnit to Phy drive post edge, ADLL reset assert de-assert */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DRAM_PHY_CONFIGURATION, 0,
+ (0x80000000 | 0x40000000)));
+ mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ]));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ DRAM_PHY_CONFIGURATION, (0x80000000 | 0x40000000),
+ (0x80000000 | 0x40000000)));
+
+ /* polling for ADLL Done */
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x3ff03ff,
+ 0x3ff03ff, PHY_LOCK_STATUS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Freq_set: DDR3 poll failed(1)\n"));
+ }
+
+ /* pup data_pup reset assert-> deassert */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_CONFIGURATION_REG, 0, 0x60000000));
+ mdelay(10);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_CONFIGURATION_REG, 0x60000000, 0x60000000));
+
+ /* Set proper timing params before existing Self-Refresh */
+ ddr3_tip_set_timing(dev_num, access_type, if_id, frequency);
+ if (delay_enable != 0) {
+ adll_tap = MEGA / (freq_val[frequency] * 64);
+ ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap);
+ }
+
+ /* Exit SR */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DFS_REG, 0,
+ 0x4));
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x8, DFS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Freq_set: DDR3 poll failed(2)"));
+ }
+
+ /* Refresh Command */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ SDRAM_OPERATION_REG, 0x2, 0xf1f));
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f,
+ SDRAM_OPERATION_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Freq_set: DDR3 poll failed(3)"));
+ }
+
+ /* Release DFS Block */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DFS_REG, 0,
+ 0x2));
+ /* Controller to MBUS Retry - normal */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, DUNIT_MMASK_REG,
+ 0x1, 0x1));
+
+ /* MRO: Burst Length 8, CL , Auto_precharge 0x16cc */
+ val =
+ ((cl_mask_table[cl_value] & 0x1) << 2) |
+ ((cl_mask_table[cl_value] & 0xe) << 3);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id, MR0_REG,
+ val, (0x7 << 4) | (1 << 2)));
+ /* MR2: CWL = 10 , Auto Self-Refresh - disable */
+ val = (cwl_mask_table[cwl_value] << 3);
+ /*
+ * nklein 24.10.13 - should not be here - leave value as set in
+ * the init configuration val |= (1 << 9);
+ * val |= ((tm->interface_params[if_id].
+ * interface_temp == HWS_TEMP_HIGH) ? (1 << 7) : 0);
+ */
+ /* nklein 24.10.13 - see above comment */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id, MR2_REG,
+ val, (0x7 << 3)));
+
+ /* ODT TIMING */
+ val = ((cl_value - cwl_value + 1) << 4) |
+ ((cl_value - cwl_value + 6) << 8) |
+ ((cl_value - 1) << 12) | ((cl_value + 6) << 16);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id, ODT_TIMING_LOW,
+ val, 0xffff0));
+ val = 0x71 | ((cwl_value - 1) << 8) | ((cwl_value + 5) << 12);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id, ODT_TIMING_HI_REG,
+ val, 0xffff));
+
+ /* ODT Active */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id,
+ DUNIT_ODT_CONTROL_REG,
+ 0xf, 0xf));
+
+ /* re-write CL */
+ val = ((cl_mask_table[cl_value] & 0x1) << 2) |
+ ((cl_mask_table[cl_value] & 0xe) << 3);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ 0, MR0_REG, val,
+ (0x7 << 4) | (1 << 2)));
+
+ /* re-write CWL */
+ val = (cwl_mask_table[cwl_value] << 3);
+ CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask, MRS2_CMD,
+ val, (0x7 << 3)));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ 0, MR2_REG, val, (0x7 << 3)));
+
+ if (mem_mask != 0) {
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id,
+ CS_ENABLE_REG,
+ 1 << 3, 0x8));
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Set ODT values
+ */
+static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, u32 cl_value, u32 cwl_value)
+{
+ /* ODT TIMING */
+ u32 val = (cl_value - cwl_value + 6);
+
+ val = ((cl_value - cwl_value + 1) << 4) | ((val & 0xf) << 8) |
+ (((cl_value - 1) & 0xf) << 12) |
+ (((cl_value + 6) & 0xf) << 16) | (((val & 0x10) >> 4) << 21);
+ val |= (((cl_value - 1) >> 4) << 22) | (((cl_value + 6) >> 4) << 23);
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODT_TIMING_LOW, val, 0xffff0));
+ val = 0x71 | ((cwl_value - 1) << 8) | ((cwl_value + 5) << 12);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODT_TIMING_HI_REG, val, 0xffff));
+ if (odt_additional == 1) {
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+ if_id,
+ SDRAM_ODT_CONTROL_HIGH_REG,
+ 0xf, 0xf));
+ }
+
+ /* ODT Active */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ DUNIT_ODT_CONTROL_REG, 0xf, 0xf));
+
+ return MV_OK;
+}
+
+/*
+ * Set Timing values for training
+ */
+static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_ddr_freq frequency)
+{
+ u32 t_ckclk = 0, t_ras = 0;
+ u32 t_rcd = 0, t_rp = 0, t_wr = 0, t_wtr = 0, t_rrd = 0, t_rtp = 0,
+ t_rfc = 0, t_mod = 0;
+ u32 val = 0, page_size = 0;
+ enum hws_speed_bin speed_bin_index;
+ enum hws_mem_size memory_size = MEM_2G;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ speed_bin_index = tm->interface_params[if_id].speed_bin_index;
+ memory_size = tm->interface_params[if_id].memory_size;
+ page_size =
+ (tm->interface_params[if_id].bus_width ==
+ BUS_WIDTH_8) ? page_param[memory_size].
+ page_size_8bit : page_param[memory_size].page_size_16bit;
+ t_ckclk = (MEGA / freq_val[frequency]);
+ t_rrd = (page_size == 1) ? speed_bin_table(speed_bin_index,
+ SPEED_BIN_TRRD1K) :
+ speed_bin_table(speed_bin_index, SPEED_BIN_TRRD2K);
+ t_rrd = GET_MAX_VALUE(t_ckclk * 4, t_rrd);
+ t_rtp = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index,
+ SPEED_BIN_TRTP));
+ t_wtr = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index,
+ SPEED_BIN_TWTR));
+ t_ras = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+ SPEED_BIN_TRAS),
+ t_ckclk);
+ t_rcd = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+ SPEED_BIN_TRCD),
+ t_ckclk);
+ t_rp = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+ SPEED_BIN_TRP),
+ t_ckclk);
+ t_wr = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+ SPEED_BIN_TWR),
+ t_ckclk);
+ t_wtr = TIME_2_CLOCK_CYCLES(t_wtr, t_ckclk);
+ t_rrd = TIME_2_CLOCK_CYCLES(t_rrd, t_ckclk);
+ t_rtp = TIME_2_CLOCK_CYCLES(t_rtp, t_ckclk);
+ t_rfc = TIME_2_CLOCK_CYCLES(rfc_table[memory_size] * 1000, t_ckclk);
+ t_mod = GET_MAX_VALUE(t_ckclk * 24, 15000);
+ t_mod = TIME_2_CLOCK_CYCLES(t_mod, t_ckclk);
+
+ /* SDRAM Timing Low */
+ val = (t_ras & 0xf) | (t_rcd << 4) | (t_rp << 8) | (t_wr << 12) |
+ (t_wtr << 16) | (((t_ras & 0x30) >> 4) << 20) | (t_rrd << 24) |
+ (t_rtp << 28);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_LOW_REG, val, 0xff3fffff));
+
+ /* SDRAM Timing High */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ t_rfc & 0x7f, 0x7f));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ 0x180, 0x180));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ 0x600, 0x600));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ 0x1800, 0xf800));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ ((t_rfc & 0x380) >> 7) << 16, 0x70000));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG, 0,
+ 0x380000));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ (t_mod & 0xf) << 25, 0x1e00000));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ (t_mod >> 4) << 30, 0xc0000000));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ 0x16000000, 0x1e000000));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG,
+ 0x40000000, 0xc0000000));
+
+ return MV_OK;
+}
+
+/*
+ * Mode Read
+ */
+int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info)
+{
+ u32 ret;
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ MR0_REG, mode_info->reg_mr0, MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ MR1_REG, mode_info->reg_mr1, MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ MR2_REG, mode_info->reg_mr2, MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ MR3_REG, mode_info->reg_mr2, MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ READ_DATA_SAMPLE_DELAY, mode_info->read_data_sample,
+ MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ READ_DATA_READY_DELAY, mode_info->read_data_ready,
+ MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+
+ return MV_OK;
+}
+
+/*
+ * Get first active IF
+ */
+int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask,
+ u32 *interface_id)
+{
+ u32 if_id;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (interface_mask & (1 << if_id)) {
+ *interface_id = if_id;
+ break;
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Write CS Result
+ */
+int ddr3_tip_write_cs_result(u32 dev_num, u32 offset)
+{
+ u32 if_id, bus_num, cs_bitmask, data_val, cs_num;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_num = 0; bus_num < tm->num_of_bus_per_interface;
+ bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+ cs_bitmask =
+ tm->interface_params[if_id].
+ as_bus_params[bus_num].cs_bitmask;
+ if (cs_bitmask != effective_cs) {
+ cs_num = GET_CS_FROM_MASK(cs_bitmask);
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_num,
+ DDR_PHY_DATA,
+ offset +
+ CS_REG_VALUE(effective_cs),
+ &data_val);
+ ddr3_tip_bus_write(dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_num, DDR_PHY_DATA,
+ offset +
+ CS_REG_VALUE(cs_num),
+ data_val);
+ }
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Write MRS
+ */
+int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, u32 cmd,
+ u32 data, u32 mask)
+{
+ u32 if_id, reg;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ reg = (cmd == MRS1_CMD) ? MR1_REG : MR2_REG;
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, reg, data, mask));
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ SDRAM_OPERATION_REG,
+ (cs_mask_arr[if_id] << 8) | cmd, 0xf1f));
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+ 0x1f, SDRAM_OPERATION_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("write_mrs_cmd: Poll cmd fail"));
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Reset XSB Read FIFO
+ */
+int ddr3_tip_reset_fifo_ptr(u32 dev_num)
+{
+ u32 if_id = 0;
+
+ /* Configure PHY reset value to 0 in order to "clean" the FIFO */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, 0x15c8, 0, 0xff000000));
+ /*
+ * Move PHY to RL mode (only in RL mode the PHY overrides FIFO values
+ * during FIFO reset)
+ */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, TRAINING_SW_2_REG,
+ 0x1, 0x9));
+ /* In order that above configuration will influence the PHY */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, 0x15b0,
+ 0x80000000, 0x80000000));
+ /* Reset read fifo assertion */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, 0x1400, 0, 0x40000000));
+ /* Reset read fifo deassertion */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, 0x1400,
+ 0x40000000, 0x40000000));
+ /* Move PHY back to functional mode */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, TRAINING_SW_2_REG,
+ 0x8, 0x9));
+ /* Stop training machine */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, 0x15b4, 0x10000, 0x10000));
+
+ return MV_OK;
+}
+
+/*
+ * Reset Phy registers
+ */
+int ddr3_tip_ddr3_reset_phy_regs(u32 dev_num)
+{
+ u32 if_id, phy_id, cs;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (phy_id = 0; phy_id < tm->num_of_bus_per_interface;
+ phy_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, phy_id);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ phy_id, DDR_PHY_DATA,
+ WL_PHY_REG +
+ CS_REG_VALUE(effective_cs),
+ phy_reg0_val));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA,
+ RL_PHY_REG + CS_REG_VALUE(effective_cs),
+ phy_reg2_val));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA,
+ READ_CENTRALIZATION_PHY_REG +
+ CS_REG_VALUE(effective_cs), phy_reg3_val));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ CS_REG_VALUE(effective_cs), phy_reg3_val));
+ }
+ }
+
+ /* Set Receiver Calibration value */
+ for (cs = 0; cs < MAX_CS_NUM; cs++) {
+ /* PHY register 0xdb bits[5:0] - configure to 63 */
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ DDR_PHY_DATA, CSN_IOB_VREF_REG(cs), 63));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Restore Dunit registers
+ */
+int ddr3_tip_restore_dunit_regs(u32 dev_num)
+{
+ u32 index_cnt;
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, CALIB_MACHINE_CTRL_REG,
+ 0x1, 0x1));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, CALIB_MACHINE_CTRL_REG,
+ calibration_update_control << 3,
+ 0x3 << 3));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ ODPG_WRITE_READ_MODE_ENABLE_REG,
+ 0xffff, MASK_ALL_BITS));
+
+ for (index_cnt = 0; index_cnt < ARRAY_SIZE(odpg_default_value);
+ index_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ odpg_default_value[index_cnt].reg_addr,
+ odpg_default_value[index_cnt].reg_data,
+ odpg_default_value[index_cnt].reg_mask));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Auto tune main flow
+ */
+static int ddr3_tip_ddr3_training_main_flow(u32 dev_num)
+{
+ enum hws_ddr_freq freq = init_freq;
+ struct init_cntr_param init_cntr_prm;
+ int ret = MV_OK;
+ u32 if_id;
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+ if (debug_training == DEBUG_LEVEL_TRACE) {
+ CHECK_STATUS(print_device_info((u8)dev_num));
+ }
+#endif
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ CHECK_STATUS(ddr3_tip_ddr3_reset_phy_regs(dev_num));
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ freq = init_freq;
+ if (is_pll_before_init != 0) {
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ config_func_info[dev_num].tip_set_freq_divider_func(
+ (u8)dev_num, if_id, freq);
+ }
+ }
+
+ if (is_adll_calib_before_init != 0) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("with adll calib before init\n"));
+ adll_calibration(dev_num, ACCESS_TYPE_MULTICAST, 0, freq);
+ }
+
+ if (is_reg_dump != 0) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("Dump before init controller\n"));
+ ddr3_tip_reg_dump(dev_num);
+ }
+
+ if (mask_tune_func & INIT_CONTROLLER_MASK_BIT) {
+ training_stage = INIT_CONTROLLER;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("INIT_CONTROLLER_MASK_BIT\n"));
+ init_cntr_prm.do_mrs_phy = 1;
+ init_cntr_prm.is_ctrl64_bit = 0;
+ init_cntr_prm.init_phy = 1;
+ init_cntr_prm.msys_init = 0;
+ ret = hws_ddr3_tip_init_controller(dev_num, &init_cntr_prm);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("hws_ddr3_tip_init_controller failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+#ifdef STATIC_ALGO_SUPPORT
+ if (mask_tune_func & STATIC_LEVELING_MASK_BIT) {
+ training_stage = STATIC_LEVELING;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("STATIC_LEVELING_MASK_BIT\n"));
+ ret = ddr3_tip_run_static_alg(dev_num, freq);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_run_static_alg failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+#endif
+
+ if (mask_tune_func & SET_LOW_FREQ_MASK_BIT) {
+ training_stage = SET_LOW_FREQ;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("SET_LOW_FREQ_MASK_BIT %d\n",
+ freq_val[low_freq]));
+ ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, low_freq);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_freq_set failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & LOAD_PATTERN_MASK_BIT) {
+ training_stage = LOAD_PATTERN;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("LOAD_PATTERN_MASK_BIT #%d\n",
+ effective_cs));
+ ret = ddr3_tip_load_all_pattern_to_mem(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_load_all_pattern_to_mem failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ if (mask_tune_func & SET_MEDIUM_FREQ_MASK_BIT) {
+ training_stage = SET_MEDIUM_FREQ;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("SET_MEDIUM_FREQ_MASK_BIT %d\n",
+ freq_val[medium_freq]));
+ ret =
+ ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, medium_freq);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_freq_set failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ if (mask_tune_func & WRITE_LEVELING_MASK_BIT) {
+ training_stage = WRITE_LEVELING;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("WRITE_LEVELING_MASK_BIT\n"));
+ if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) {
+ ret = ddr3_tip_dynamic_write_leveling(dev_num);
+ } else {
+ /* Use old WL */
+ ret = ddr3_tip_legacy_dynamic_write_leveling(dev_num);
+ }
+
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_dynamic_write_leveling failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & LOAD_PATTERN_2_MASK_BIT) {
+ training_stage = LOAD_PATTERN_2;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("LOAD_PATTERN_2_MASK_BIT CS #%d\n",
+ effective_cs));
+ ret = ddr3_tip_load_all_pattern_to_mem(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_load_all_pattern_to_mem failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ if (mask_tune_func & READ_LEVELING_MASK_BIT) {
+ training_stage = READ_LEVELING;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("READ_LEVELING_MASK_BIT\n"));
+ if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) {
+ ret = ddr3_tip_dynamic_read_leveling(dev_num, medium_freq);
+ } else {
+ /* Use old RL */
+ ret = ddr3_tip_legacy_dynamic_read_leveling(dev_num);
+ }
+
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_dynamic_read_leveling failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ if (mask_tune_func & WRITE_LEVELING_SUPP_MASK_BIT) {
+ training_stage = WRITE_LEVELING_SUPP;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("WRITE_LEVELING_SUPP_MASK_BIT\n"));
+ ret = ddr3_tip_dynamic_write_leveling_supp(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_dynamic_write_leveling_supp failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & PBS_RX_MASK_BIT) {
+ training_stage = PBS_RX;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("PBS_RX_MASK_BIT CS #%d\n",
+ effective_cs));
+ ret = ddr3_tip_pbs_rx(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_pbs_rx failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & PBS_TX_MASK_BIT) {
+ training_stage = PBS_TX;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("PBS_TX_MASK_BIT CS #%d\n",
+ effective_cs));
+ ret = ddr3_tip_pbs_tx(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_pbs_tx failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) {
+ training_stage = SET_TARGET_FREQ;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("SET_TARGET_FREQ_MASK_BIT %d\n",
+ freq_val[tm->
+ interface_params[first_active_if].
+ memory_freq]));
+ ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ tm->interface_params[first_active_if].
+ memory_freq);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_freq_set failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ if (mask_tune_func & WRITE_LEVELING_TF_MASK_BIT) {
+ training_stage = WRITE_LEVELING_TF;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("WRITE_LEVELING_TF_MASK_BIT\n"));
+ ret = ddr3_tip_dynamic_write_leveling(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_dynamic_write_leveling TF failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ if (mask_tune_func & LOAD_PATTERN_HIGH_MASK_BIT) {
+ training_stage = LOAD_PATTERN_HIGH;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("LOAD_PATTERN_HIGH\n"));
+ ret = ddr3_tip_load_all_pattern_to_mem(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_load_all_pattern_to_mem failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ if (mask_tune_func & READ_LEVELING_TF_MASK_BIT) {
+ training_stage = READ_LEVELING_TF;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("READ_LEVELING_TF_MASK_BIT\n"));
+ ret = ddr3_tip_dynamic_read_leveling(dev_num, tm->
+ interface_params[first_active_if].
+ memory_freq);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_dynamic_read_leveling TF failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ if (mask_tune_func & DM_PBS_TX_MASK_BIT) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("DM_PBS_TX_MASK_BIT\n"));
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & VREF_CALIBRATION_MASK_BIT) {
+ training_stage = VREF_CALIBRATION;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("VREF\n"));
+ ret = ddr3_tip_vref(dev_num);
+ if (is_reg_dump != 0) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("VREF Dump\n"));
+ ddr3_tip_reg_dump(dev_num);
+ }
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_vref failure\n"));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & CENTRALIZATION_RX_MASK_BIT) {
+ training_stage = CENTRALIZATION_RX;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("CENTRALIZATION_RX_MASK_BIT CS #%d\n",
+ effective_cs));
+ ret = ddr3_tip_centralization_rx(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_centralization_rx failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) {
+ training_stage = WRITE_LEVELING_SUPP_TF;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("WRITE_LEVELING_SUPP_TF_MASK_BIT CS #%d\n",
+ effective_cs));
+ ret = ddr3_tip_dynamic_write_leveling_supp(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_dynamic_write_leveling_supp TF failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) {
+ training_stage = CENTRALIZATION_TX;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("CENTRALIZATION_TX_MASK_BIT CS #%d\n",
+ effective_cs));
+ ret = ddr3_tip_centralization_tx(dev_num);
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_centralization_tx failure CS #%d\n",
+ effective_cs));
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("restore registers to default\n"));
+ /* restore register values */
+ CHECK_STATUS(ddr3_tip_restore_dunit_regs(dev_num));
+
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+
+ return MV_OK;
+}
+
+/*
+ * DDR3 Dynamic training flow
+ */
+static int ddr3_tip_ddr3_auto_tune(u32 dev_num)
+{
+ u32 if_id, stage, ret;
+ int is_if_fail = 0, is_auto_tune_fail = 0;
+
+ training_stage = INIT_CONTROLLER;
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ for (stage = 0; stage < MAX_STAGE_LIMIT; stage++)
+ training_result[stage][if_id] = NO_TEST_DONE;
+ }
+
+ ret = ddr3_tip_ddr3_training_main_flow(dev_num);
+
+ /* activate XSB test */
+ if (xsb_validate_type != 0) {
+ run_xsb_test(dev_num, xsb_validation_base_address, 1, 1,
+ 0x1024);
+ }
+
+ if (is_reg_dump != 0)
+ ddr3_tip_reg_dump(dev_num);
+
+ /* print log */
+ CHECK_STATUS(ddr3_tip_print_log(dev_num, window_mem_addr));
+
+ if (ret != MV_OK) {
+ CHECK_STATUS(ddr3_tip_print_stability_log(dev_num));
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ is_if_fail = 0;
+ for (stage = 0; stage < MAX_STAGE_LIMIT; stage++) {
+ if (training_result[stage][if_id] == TEST_FAILED)
+ is_if_fail = 1;
+ }
+ if (is_if_fail == 1) {
+ is_auto_tune_fail = 1;
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+ ("Auto Tune failed for IF %d\n",
+ if_id));
+ }
+ }
+
+ if ((ret == MV_FAIL) || (is_auto_tune_fail == 1))
+ return MV_FAIL;
+ else
+ return MV_OK;
+}
+
+/*
+ * Enable init sequence
+ */
+int ddr3_tip_enable_init_sequence(u32 dev_num)
+{
+ int is_fail = 0;
+ u32 if_id = 0, mem_mask = 0, bus_index = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* Enable init sequence */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, 0,
+ SDRAM_INIT_CONTROL_REG, 0x1, 0x1));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1,
+ SDRAM_INIT_CONTROL_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("polling failed IF %d\n",
+ if_id));
+ is_fail = 1;
+ continue;
+ }
+
+ mem_mask = 0;
+ for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ mem_mask |=
+ tm->interface_params[if_id].
+ as_bus_params[bus_index].mirror_enable_bitmask;
+ }
+
+ if (mem_mask != 0) {
+ /* Disable Multi CS */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ if_id, CS_ENABLE_REG, 1 << 3,
+ 1 << 3));
+ }
+ }
+
+ return (is_fail == 0) ? MV_OK : MV_FAIL;
+}
+
+int ddr3_tip_register_dq_table(u32 dev_num, u32 *table)
+{
+ dq_map_table = table;
+
+ return MV_OK;
+}
+
+/*
+ * Check if pup search is locked
+ */
+int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode)
+{
+ u32 bit_start = 0, bit_end = 0, bit_id;
+
+ if (read_mode == RESULT_PER_BIT) {
+ bit_start = 0;
+ bit_end = BUS_WIDTH_IN_BITS - 1;
+ } else {
+ bit_start = 0;
+ bit_end = 0;
+ }
+
+ for (bit_id = bit_start; bit_id <= bit_end; bit_id++) {
+ if (GET_LOCK_RESULT(pup_buf[bit_id]) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Get minimum buffer value
+ */
+u8 ddr3_tip_get_buf_min(u8 *buf_ptr)
+{
+ u8 min_val = 0xff;
+ u8 cnt = 0;
+
+ for (cnt = 0; cnt < BUS_WIDTH_IN_BITS; cnt++) {
+ if (buf_ptr[cnt] < min_val)
+ min_val = buf_ptr[cnt];
+ }
+
+ return min_val;
+}
+
+/*
+ * Get maximum buffer value
+ */
+u8 ddr3_tip_get_buf_max(u8 *buf_ptr)
+{
+ u8 max_val = 0;
+ u8 cnt = 0;
+
+ for (cnt = 0; cnt < BUS_WIDTH_IN_BITS; cnt++) {
+ if (buf_ptr[cnt] > max_val)
+ max_val = buf_ptr[cnt];
+ }
+
+ return max_val;
+}
+
+/*
+ * The following functions return memory parameters:
+ * bus and device width, device size
+ */
+
+u32 hws_ddr3_get_bus_width(void)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ return (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) ==
+ 1) ? 16 : 32;
+}
+
+u32 hws_ddr3_get_device_width(u32 if_id)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ return (tm->interface_params[if_id].bus_width ==
+ BUS_WIDTH_8) ? 8 : 16;
+}
+
+u32 hws_ddr3_get_device_size(u32 if_id)
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (tm->interface_params[if_id].memory_size >=
+ MEM_SIZE_LAST) {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Error: Wrong device size of Cs: %d",
+ tm->interface_params[if_id].memory_size));
+ return 0;
+ } else {
+ return 1 << tm->interface_params[if_id].memory_size;
+ }
+}
+
+int hws_ddr3_calc_mem_cs_size(u32 if_id, u32 cs, u32 *cs_size)
+{
+ u32 cs_mem_size, dev_size;
+
+ dev_size = hws_ddr3_get_device_size(if_id);
+ if (dev_size != 0) {
+ cs_mem_size = ((hws_ddr3_get_bus_width() /
+ hws_ddr3_get_device_width(if_id)) * dev_size);
+
+ /* the calculated result in Gbytex16 to avoid float using */
+
+ if (cs_mem_size == 2) {
+ *cs_size = _128M;
+ } else if (cs_mem_size == 4) {
+ *cs_size = _256M;
+ } else if (cs_mem_size == 8) {
+ *cs_size = _512M;
+ } else if (cs_mem_size == 16) {
+ *cs_size = _1G;
+ } else if (cs_mem_size == 32) {
+ *cs_size = _2G;
+ } else {
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Error: Wrong Memory size of Cs: %d", cs));
+ return MV_FAIL;
+ }
+ return MV_OK;
+ } else {
+ return MV_FAIL;
+ }
+}
+
+int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr)
+{
+ u32 cs_mem_size = 0;
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+ u32 physical_mem_size;
+ u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE;
+#endif
+
+ if (hws_ddr3_calc_mem_cs_size(if_id, cs, &cs_mem_size) != MV_OK)
+ return MV_FAIL;
+
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+ /*
+ * if number of address pins doesn't allow to use max mem size that
+ * is defined in topology mem size is defined by
+ * DEVICE_MAX_DRAM_ADDRESS_SIZE
+ */
+ physical_mem_size =
+ mv_hwsmem_size[tm->interface_params[0].memory_size];
+
+ if (hws_ddr3_get_device_width(cs) == 16) {
+ /*
+ * 16bit mem device can be twice more - no need in less
+ * significant pin
+ */
+ max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE * 2;
+ }
+
+ if (physical_mem_size > max_mem_size) {
+ cs_mem_size = max_mem_size *
+ (hws_ddr3_get_bus_width() /
+ hws_ddr3_get_device_width(if_id));
+ DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+ ("Updated Physical Mem size is from 0x%x to %x\n",
+ physical_mem_size,
+ DEVICE_MAX_DRAM_ADDRESS_SIZE));
+ }
+#endif
+
+ /* calculate CS base addr */
+ *cs_base_addr = ((cs_mem_size) * cs) & 0xffff0000;
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_bist.c b/drivers/ddr/marvell/a38x/ddr3_training_bist.c
new file mode 100644
index 0000000000..bd0e26068e
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_bist.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+static u32 bist_offset = 32;
+enum hws_pattern sweep_pattern = PATTERN_KILLER_DQ0;
+
+static int ddr3_tip_bist_operation(u32 dev_num,
+ enum hws_access_type access_type,
+ u32 if_id,
+ enum hws_bist_operation oper_type);
+
+/*
+ * BIST activate
+ */
+int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern,
+ enum hws_access_type access_type, u32 if_num,
+ enum hws_dir direction,
+ enum hws_stress_jump addr_stress_jump,
+ enum hws_pattern_duration duration,
+ enum hws_bist_operation oper_type,
+ u32 offset, u32 cs_num, u32 pattern_addr_length)
+{
+ u32 tx_burst_size;
+ u32 delay_between_burst;
+ u32 rd_mode, val;
+ u32 poll_cnt = 0, max_poll = 1000, i, start_if, end_if;
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+ u32 read_data[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* ODPG Write enable from BIST */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+ ODPG_DATA_CONTROL_REG, 0x1, 0x1));
+ /* ODPG Read enable/disable from BIST */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+ ODPG_DATA_CONTROL_REG,
+ (direction == OPER_READ) ?
+ 0x2 : 0, 0x2));
+ CHECK_STATUS(ddr3_tip_load_pattern_to_odpg(dev_num, access_type, if_num,
+ pattern, offset));
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+ ODPG_DATA_BUF_SIZE_REG,
+ pattern_addr_length, MASK_ALL_BITS));
+ tx_burst_size = (direction == OPER_WRITE) ?
+ pattern_table[pattern].tx_burst_size : 0;
+ delay_between_burst = (direction == OPER_WRITE) ? 2 : 0;
+ rd_mode = (direction == OPER_WRITE) ? 1 : 0;
+ CHECK_STATUS(ddr3_tip_configure_odpg
+ (dev_num, access_type, if_num, direction,
+ pattern_table[pattern].num_of_phases_tx, tx_burst_size,
+ pattern_table[pattern].num_of_phases_rx,
+ delay_between_burst,
+ rd_mode, cs_num, addr_stress_jump, duration));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+ ODPG_PATTERN_ADDR_OFFSET_REG,
+ offset, MASK_ALL_BITS));
+ if (oper_type == BIST_STOP) {
+ CHECK_STATUS(ddr3_tip_bist_operation(dev_num, access_type,
+ if_num, BIST_STOP));
+ } else {
+ CHECK_STATUS(ddr3_tip_bist_operation(dev_num, access_type,
+ if_num, BIST_START));
+ if (duration != DURATION_CONT) {
+ /*
+ * This pdelay is a WA, becuase polling fives "done"
+ * also the odpg did nmot finish its task
+ */
+ if (access_type == ACCESS_TYPE_MULTICAST) {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ } else {
+ start_if = if_num;
+ end_if = if_num;
+ }
+
+ for (i = start_if; i <= end_if; i++) {
+ VALIDATE_ACTIVE(tm->
+ if_act_mask, i);
+
+ for (poll_cnt = 0; poll_cnt < max_poll;
+ poll_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_num, ODPG_BIST_DONE,
+ read_data,
+ MASK_ALL_BITS));
+ val = read_data[i];
+ if ((val & 0x1) == 0x0) {
+ /*
+ * In SOC type devices this bit
+ * is self clear so, if it was
+ * cleared all good
+ */
+ break;
+ }
+ }
+
+ if (poll_cnt >= max_poll) {
+ DEBUG_TRAINING_BIST_ENGINE
+ (DEBUG_LEVEL_ERROR,
+ ("Bist poll failure 2\n"));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_num,
+ ODPG_DATA_CONTROL_REG, 0,
+ MASK_ALL_BITS));
+ return MV_FAIL;
+ }
+ }
+
+ CHECK_STATUS(ddr3_tip_bist_operation
+ (dev_num, access_type, if_num, BIST_STOP));
+ }
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+ ODPG_DATA_CONTROL_REG, 0,
+ MASK_ALL_BITS));
+
+ return MV_OK;
+}
+
+/*
+ * BIST read result
+ */
+int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id,
+ struct bist_result *pst_bist_result)
+{
+ int ret;
+ u32 read_data[MAX_INTERFACE_NUM];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+ return MV_NOT_SUPPORTED;
+ DEBUG_TRAINING_BIST_ENGINE(DEBUG_LEVEL_TRACE,
+ ("ddr3_tip_bist_read_result if_id %d\n",
+ if_id));
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_BIST_FAILED_DATA_HI_REG, read_data,
+ MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+ pst_bist_result->bist_fail_high = read_data[if_id];
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_BIST_FAILED_DATA_LOW_REG, read_data,
+ MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+ pst_bist_result->bist_fail_low = read_data[if_id];
+
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_BIST_LAST_FAIL_ADDR_REG, read_data,
+ MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+ pst_bist_result->bist_last_fail_addr = read_data[if_id];
+ ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_BIST_DATA_ERROR_COUNTER_REG, read_data,
+ MASK_ALL_BITS);
+ if (ret != MV_OK)
+ return ret;
+ pst_bist_result->bist_error_cnt = read_data[if_id];
+
+ return MV_OK;
+}
+
+/*
+ * BIST flow - Activate & read result
+ */
+int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result,
+ u32 cs_num)
+{
+ int ret;
+ u32 i = 0;
+ u32 win_base;
+ struct bist_result st_bist_result;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, i);
+ hws_ddr3_cs_base_adr_calc(i, cs_num, &win_base);
+ ret = ddr3_tip_bist_activate(dev_num, pattern,
+ ACCESS_TYPE_UNICAST,
+ i, OPER_WRITE, STRESS_NONE,
+ DURATION_SINGLE, BIST_START,
+ bist_offset + win_base,
+ cs_num, 15);
+ if (ret != MV_OK) {
+ printf("ddr3_tip_bist_activate failed (0x%x)\n", ret);
+ return ret;
+ }
+
+ ret = ddr3_tip_bist_activate(dev_num, pattern,
+ ACCESS_TYPE_UNICAST,
+ i, OPER_READ, STRESS_NONE,
+ DURATION_SINGLE, BIST_START,
+ bist_offset + win_base,
+ cs_num, 15);
+ if (ret != MV_OK) {
+ printf("ddr3_tip_bist_activate failed (0x%x)\n", ret);
+ return ret;
+ }
+
+ ret = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result);
+ if (ret != MV_OK) {
+ printf("ddr3_tip_bist_read_result failed\n");
+ return ret;
+ }
+ result[i] = st_bist_result.bist_error_cnt;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Set BIST Operation
+ */
+
+static int ddr3_tip_bist_operation(u32 dev_num,
+ enum hws_access_type access_type,
+ u32 if_id, enum hws_bist_operation oper_type)
+{
+ if (oper_type == BIST_STOP) {
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODPG_BIST_DONE, 1 << 8, 1 << 8));
+ } else {
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODPG_BIST_DONE, 1, 1));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Print BIST result
+ */
+void ddr3_tip_print_bist_res(void)
+{
+ u32 dev_num = 0;
+ u32 i;
+ struct bist_result st_bist_result[MAX_INTERFACE_NUM];
+ int res;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+ if (IS_ACTIVE(tm->if_act_mask, i) == 0)
+ continue;
+
+ res = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result[i]);
+ if (res != MV_OK) {
+ DEBUG_TRAINING_BIST_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_bist_read_result failed\n"));
+ return;
+ }
+ }
+
+ DEBUG_TRAINING_BIST_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("interface | error_cnt | fail_low | fail_high | fail_addr\n"));
+
+ for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+ if (IS_ACTIVE(tm->if_act_mask, i) ==
+ 0)
+ continue;
+
+ DEBUG_TRAINING_BIST_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("%d | 0x%08x | 0x%08x | 0x%08x | 0x%08x\n",
+ i, st_bist_result[i].bist_error_cnt,
+ st_bist_result[i].bist_fail_low,
+ st_bist_result[i].bist_fail_high,
+ st_bist_result[i].bist_last_fail_addr));
+ }
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
new file mode 100644
index 0000000000..9d216da96d
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define VALIDATE_WIN_LENGTH(e1, e2, maxsize) \
+ (((e2) + 1 > (e1) + (u8)MIN_WINDOW_SIZE) && \
+ ((e2) + 1 < (e1) + (u8)maxsize))
+#define IS_WINDOW_OUT_BOUNDARY(e1, e2, maxsize) \
+ (((e1) == 0 && (e2) != 0) || \
+ ((e1) != (maxsize - 1) && (e2) == (maxsize - 1)))
+#define CENTRAL_TX 0
+#define CENTRAL_RX 1
+#define NUM_OF_CENTRAL_TYPES 2
+
+u32 start_pattern = PATTERN_KILLER_DQ0, end_pattern = PATTERN_KILLER_DQ7;
+u32 start_if = 0, end_if = (MAX_INTERFACE_NUM - 1);
+u8 bus_end_window[NUM_OF_CENTRAL_TYPES][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 bus_start_window[NUM_OF_CENTRAL_TYPES][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 centralization_state[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+static u8 ddr3_tip_special_rx_run_once_flag;
+
+static int ddr3_tip_centralization(u32 dev_num, u32 mode);
+
+/*
+ * Centralization RX Flow
+ */
+int ddr3_tip_centralization_rx(u32 dev_num)
+{
+ CHECK_STATUS(ddr3_tip_special_rx(dev_num));
+ CHECK_STATUS(ddr3_tip_centralization(dev_num, CENTRAL_RX));
+
+ return MV_OK;
+}
+
+/*
+ * Centralization TX Flow
+ */
+int ddr3_tip_centralization_tx(u32 dev_num)
+{
+ CHECK_STATUS(ddr3_tip_centralization(dev_num, CENTRAL_TX));
+
+ return MV_OK;
+}
+
+/*
+ * Centralization Flow
+ */
+static int ddr3_tip_centralization(u32 dev_num, u32 mode)
+{
+ enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
+ u32 if_id, pattern_id, bit_id;
+ u8 bus_id;
+ u8 cur_start_win[BUS_WIDTH_IN_BITS];
+ u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
+ u8 cur_end_win[BUS_WIDTH_IN_BITS];
+ u8 current_window[BUS_WIDTH_IN_BITS];
+ u8 opt_window, waste_window, start_window_skew, end_window_skew;
+ u8 final_pup_window[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+ enum hws_training_result result_type = RESULT_PER_BIT;
+ enum hws_dir direction;
+ u32 *result[HWS_SEARCH_DIR_LIMIT];
+ u32 reg_phy_off, reg;
+ u8 max_win_size;
+ int lock_success = 1;
+ u8 cur_end_win_min, cur_start_win_max;
+ u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
+ int is_if_fail = 0;
+ enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage);
+ u32 pup_win_length = 0;
+ enum hws_search_dir search_dir_id;
+ u8 cons_tap = (mode == CENTRAL_TX) ? (64) : (0);
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* save current cs enable reg val */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS));
+ /* enable single cs */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, (1 << 3), (1 << 3)));
+ }
+
+ if (mode == CENTRAL_TX) {
+ max_win_size = MAX_WINDOW_SIZE_TX;
+ reg_phy_off = WRITE_CENTRALIZATION_PHY_REG + (effective_cs * 4);
+ direction = OPER_WRITE;
+ } else {
+ max_win_size = MAX_WINDOW_SIZE_RX;
+ reg_phy_off = READ_CENTRALIZATION_PHY_REG + (effective_cs * 4);
+ direction = OPER_READ;
+ }
+
+ /* DB initialization */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0;
+ bus_id < tm->num_of_bus_per_interface; bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ centralization_state[if_id][bus_id] = 0;
+ bus_end_window[mode][if_id][bus_id] =
+ (max_win_size - 1) + cons_tap;
+ bus_start_window[mode][if_id][bus_id] = 0;
+ centralization_result[if_id][bus_id] = 0;
+ }
+ }
+
+ /* start flow */
+ for (pattern_id = start_pattern; pattern_id <= end_pattern;
+ pattern_id++) {
+ ddr3_tip_ip_training_wrapper(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, result_type,
+ HWS_CONTROL_ELEMENT_ADLL,
+ PARAM_NOT_CARE, direction,
+ tm->
+ if_act_mask, 0x0,
+ max_win_size - 1,
+ max_win_size - 1,
+ pattern_id, EDGE_FPF, CS_SINGLE,
+ PARAM_NOT_CARE, training_result);
+
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0;
+ bus_id <= tm->num_of_bus_per_interface - 1;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+
+ for (search_dir_id = HWS_LOW2HIGH;
+ search_dir_id <= HWS_HIGH2LOW;
+ search_dir_id++) {
+ CHECK_STATUS
+ (ddr3_tip_read_training_result
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ ALL_BITS_PER_PUP,
+ search_dir_id,
+ direction, result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ CS_SINGLE,
+ &result[search_dir_id],
+ 1, 0, 0));
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("%s pat %d IF %d pup %d Regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ ((mode ==
+ CENTRAL_TX) ? "TX" : "RX"),
+ pattern_id, if_id, bus_id,
+ result[search_dir_id][0],
+ result[search_dir_id][1],
+ result[search_dir_id][2],
+ result[search_dir_id][3],
+ result[search_dir_id][4],
+ result[search_dir_id][5],
+ result[search_dir_id][6],
+ result[search_dir_id][7]));
+ }
+
+ for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
+ bit_id++) {
+ /* check if this code is valid for 2 edge, probably not :( */
+ cur_start_win[bit_id] =
+ GET_TAP_RESULT(result
+ [HWS_LOW2HIGH]
+ [bit_id],
+ EDGE_1);
+ cur_end_win[bit_id] =
+ GET_TAP_RESULT(result
+ [HWS_HIGH2LOW]
+ [bit_id],
+ EDGE_1);
+ /* window length */
+ current_window[bit_id] =
+ cur_end_win[bit_id] -
+ cur_start_win[bit_id] + 1;
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_TRACE,
+ ("cs %x patern %d IF %d pup %d cur_start_win %d cur_end_win %d current_window %d\n",
+ effective_cs, pattern_id,
+ if_id, bus_id,
+ cur_start_win[bit_id],
+ cur_end_win[bit_id],
+ current_window[bit_id]));
+ }
+
+ if ((ddr3_tip_is_pup_lock
+ (result[HWS_LOW2HIGH], result_type)) &&
+ (ddr3_tip_is_pup_lock
+ (result[HWS_HIGH2LOW], result_type))) {
+ /* read result success */
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("Pup locked, pat %d IF %d pup %d\n",
+ pattern_id, if_id, bus_id));
+ } else {
+ /* read result failure */
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("fail Lock, pat %d IF %d pup %d\n",
+ pattern_id, if_id, bus_id));
+ if (centralization_state[if_id][bus_id]
+ == 1) {
+ /* continue with next pup */
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_TRACE,
+ ("continue to next pup %d %d\n",
+ if_id, bus_id));
+ continue;
+ }
+
+ for (bit_id = 0;
+ bit_id < BUS_WIDTH_IN_BITS;
+ bit_id++) {
+ /*
+ * the next check is relevant
+ * only when using search
+ * machine 2 edges
+ */
+ if (cur_start_win[bit_id] > 0 &&
+ cur_end_win[bit_id] == 0) {
+ cur_end_win
+ [bit_id] =
+ max_win_size - 1;
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_TRACE,
+ ("fail, IF %d pup %d bit %d fail #1\n",
+ if_id, bus_id,
+ bit_id));
+ /* the next bit */
+ continue;
+ } else {
+ centralization_state
+ [if_id][bus_id] = 1;
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_TRACE,
+ ("fail, IF %d pup %d bit %d fail #2\n",
+ if_id, bus_id,
+ bit_id));
+ }
+ }
+
+ if (centralization_state[if_id][bus_id]
+ == 1) {
+ /* going to next pup */
+ continue;
+ }
+ } /*bit */
+
+ opt_window =
+ ddr3_tip_get_buf_min(current_window);
+ /* final pup window length */
+ final_pup_window[if_id][bus_id] =
+ ddr3_tip_get_buf_min(cur_end_win) -
+ ddr3_tip_get_buf_max(cur_start_win) +
+ 1;
+ waste_window =
+ opt_window -
+ final_pup_window[if_id][bus_id];
+ start_window_skew =
+ ddr3_tip_get_buf_max(cur_start_win) -
+ ddr3_tip_get_buf_min(
+ cur_start_win);
+ end_window_skew =
+ ddr3_tip_get_buf_max(
+ cur_end_win) -
+ ddr3_tip_get_buf_min(
+ cur_end_win);
+ /* min/max updated with pattern change */
+ cur_end_win_min =
+ ddr3_tip_get_buf_min(
+ cur_end_win);
+ cur_start_win_max =
+ ddr3_tip_get_buf_max(
+ cur_start_win);
+ bus_end_window[mode][if_id][bus_id] =
+ GET_MIN(bus_end_window[mode][if_id]
+ [bus_id],
+ cur_end_win_min);
+ bus_start_window[mode][if_id][bus_id] =
+ GET_MAX(bus_start_window[mode][if_id]
+ [bus_id],
+ cur_start_win_max);
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("pat %d IF %d pup %d opt_win %d final_win %d waste_win %d st_win_skew %d end_win_skew %d cur_st_win_max %d cur_end_win_min %d bus_st_win %d bus_end_win %d\n",
+ pattern_id, if_id, bus_id, opt_window,
+ final_pup_window[if_id][bus_id],
+ waste_window, start_window_skew,
+ end_window_skew,
+ cur_start_win_max,
+ cur_end_win_min,
+ bus_start_window[mode][if_id][bus_id],
+ bus_end_window[mode][if_id][bus_id]));
+
+ /* check if window is valid */
+ if (ddr3_tip_centr_skip_min_win_check == 0) {
+ if ((VALIDATE_WIN_LENGTH
+ (bus_start_window[mode][if_id]
+ [bus_id],
+ bus_end_window[mode][if_id]
+ [bus_id],
+ max_win_size) == 1) ||
+ (IS_WINDOW_OUT_BOUNDARY
+ (bus_start_window[mode][if_id]
+ [bus_id],
+ bus_end_window[mode][if_id]
+ [bus_id],
+ max_win_size) == 1)) {
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("win valid, pat %d IF %d pup %d\n",
+ pattern_id, if_id,
+ bus_id));
+ /* window is valid */
+ } else {
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("fail win, pat %d IF %d pup %d bus_st_win %d bus_end_win %d\n",
+ pattern_id, if_id, bus_id,
+ bus_start_window[mode]
+ [if_id][bus_id],
+ bus_end_window[mode]
+ [if_id][bus_id]));
+ centralization_state[if_id]
+ [bus_id] = 1;
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ } /* ddr3_tip_centr_skip_min_win_check */
+ } /* pup */
+ } /* interface */
+ } /* pattern */
+
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+ continue;
+
+ is_if_fail = 0;
+ flow_result[if_id] = TEST_SUCCESS;
+
+ for (bus_id = 0;
+ bus_id <= (tm->num_of_bus_per_interface - 1); bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+
+ /* continue only if lock */
+ if (centralization_state[if_id][bus_id] != 1) {
+ if (ddr3_tip_centr_skip_min_win_check == 0) {
+ if ((bus_end_window
+ [mode][if_id][bus_id] ==
+ (max_win_size - 1)) &&
+ ((bus_end_window
+ [mode][if_id][bus_id] -
+ bus_start_window[mode][if_id]
+ [bus_id]) < MIN_WINDOW_SIZE) &&
+ ((bus_end_window[mode][if_id]
+ [bus_id] - bus_start_window
+ [mode][if_id][bus_id]) > 2)) {
+ /* prevent false lock */
+ /* TBD change to enum */
+ centralization_state
+ [if_id][bus_id] = 2;
+ }
+
+ if ((bus_end_window[mode][if_id][bus_id]
+ == 0) &&
+ ((bus_end_window[mode][if_id]
+ [bus_id] -
+ bus_start_window[mode][if_id]
+ [bus_id]) < MIN_WINDOW_SIZE) &&
+ ((bus_end_window[mode][if_id]
+ [bus_id] -
+ bus_start_window[mode][if_id]
+ [bus_id]) > 2))
+ /*prevent false lock */
+ centralization_state[if_id]
+ [bus_id] = 3;
+ }
+
+ if ((bus_end_window[mode][if_id][bus_id] >
+ (max_win_size - 1)) && direction ==
+ OPER_WRITE) {
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("Tx special pattern\n"));
+ cons_tap = 64;
+ }
+ }
+
+ /* check states */
+ if (centralization_state[if_id][bus_id] == 3) {
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("SSW - TBD IF %d pup %d\n",
+ if_id, bus_id));
+ lock_success = 1;
+ } else if (centralization_state[if_id][bus_id] == 2) {
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("SEW - TBD IF %d pup %d\n",
+ if_id, bus_id));
+ lock_success = 1;
+ } else if (centralization_state[if_id][bus_id] == 0) {
+ lock_success = 1;
+ } else {
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("fail, IF %d pup %d\n",
+ if_id, bus_id));
+ lock_success = 0;
+ }
+
+ if (lock_success == 1) {
+ centralization_result[if_id][bus_id] =
+ (bus_end_window[mode][if_id][bus_id] +
+ bus_start_window[mode][if_id][bus_id])
+ / 2 - cons_tap;
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_TRACE,
+ (" bus_id %d Res= %d\n", bus_id,
+ centralization_result[if_id][bus_id]));
+ /* copy results to registers */
+ pup_win_length =
+ bus_end_window[mode][if_id][bus_id] -
+ bus_start_window[mode][if_id][bus_id] +
+ 1;
+
+ ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA,
+ RESULT_DB_PHY_REG_ADDR +
+ effective_cs, &reg);
+ reg = (reg & (~0x1f <<
+ ((mode == CENTRAL_TX) ?
+ (RESULT_DB_PHY_REG_TX_OFFSET) :
+ (RESULT_DB_PHY_REG_RX_OFFSET))))
+ | pup_win_length <<
+ ((mode == CENTRAL_TX) ?
+ (RESULT_DB_PHY_REG_TX_OFFSET) :
+ (RESULT_DB_PHY_REG_RX_OFFSET));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ RESULT_DB_PHY_REG_ADDR +
+ effective_cs, reg));
+
+ /* offset per CS is calculated earlier */
+ CHECK_STATUS(
+ ddr3_tip_bus_write(dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_id,
+ DDR_PHY_DATA,
+ reg_phy_off,
+ centralization_result
+ [if_id]
+ [bus_id]));
+ } else {
+ is_if_fail = 1;
+ }
+ }
+
+ if (is_if_fail == 1)
+ flow_result[if_id] = TEST_FAILED;
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ /* restore cs enable value */
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, CS_ENABLE_REG,
+ cs_enable_reg_val[if_id],
+ MASK_ALL_BITS));
+ }
+
+ return is_if_fail;
+}
+
+/*
+ * Centralization Flow
+ */
+int ddr3_tip_special_rx(u32 dev_num)
+{
+ enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
+ u32 if_id, pup_id, pattern_id, bit_id;
+ u8 cur_start_win[BUS_WIDTH_IN_BITS];
+ u8 cur_end_win[BUS_WIDTH_IN_BITS];
+ enum hws_training_result result_type = RESULT_PER_BIT;
+ enum hws_dir direction;
+ enum hws_search_dir search_dir_id;
+ u32 *result[HWS_SEARCH_DIR_LIMIT];
+ u32 max_win_size;
+ u8 cur_end_win_min, cur_start_win_max;
+ u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
+ u32 temp = 0;
+ int pad_num = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (ddr3_tip_special_rx_run_once_flag != 0)
+ return MV_OK;
+
+ ddr3_tip_special_rx_run_once_flag = 1;
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* save current cs enable reg val */
+ CHECK_STATUS(ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, CS_ENABLE_REG,
+ cs_enable_reg_val,
+ MASK_ALL_BITS));
+ /* enable single cs */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, CS_ENABLE_REG,
+ (1 << 3), (1 << 3)));
+ }
+
+ max_win_size = MAX_WINDOW_SIZE_RX;
+ direction = OPER_READ;
+ pattern_id = PATTERN_VREF;
+
+ /* start flow */
+ ddr3_tip_ip_training_wrapper(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, result_type,
+ HWS_CONTROL_ELEMENT_ADLL,
+ PARAM_NOT_CARE, direction,
+ tm->if_act_mask, 0x0,
+ max_win_size - 1, max_win_size - 1,
+ pattern_id, EDGE_FPF, CS_SINGLE,
+ PARAM_NOT_CARE, training_result);
+
+ for (if_id = start_if; if_id <= end_if; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup_id = 0;
+ pup_id <= tm->num_of_bus_per_interface; pup_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+
+ for (search_dir_id = HWS_LOW2HIGH;
+ search_dir_id <= HWS_HIGH2LOW;
+ search_dir_id++) {
+ CHECK_STATUS(ddr3_tip_read_training_result
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup_id,
+ ALL_BITS_PER_PUP, search_dir_id,
+ direction, result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ CS_SINGLE, &result[search_dir_id],
+ 1, 0, 0));
+ DEBUG_CENTRALIZATION_ENGINE(DEBUG_LEVEL_INFO,
+ ("Special: pat %d IF %d pup %d Regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pattern_id, if_id,
+ pup_id,
+ result
+ [search_dir_id][0],
+ result
+ [search_dir_id][1],
+ result
+ [search_dir_id][2],
+ result
+ [search_dir_id][3],
+ result
+ [search_dir_id][4],
+ result
+ [search_dir_id][5],
+ result
+ [search_dir_id][6],
+ result
+ [search_dir_id]
+ [7]));
+ }
+
+ for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; bit_id++) {
+ /*
+ * check if this code is valid for 2 edge,
+ * probably not :(
+ */
+ cur_start_win[bit_id] =
+ GET_TAP_RESULT(result[HWS_LOW2HIGH]
+ [bit_id], EDGE_1);
+ cur_end_win[bit_id] =
+ GET_TAP_RESULT(result[HWS_HIGH2LOW]
+ [bit_id], EDGE_1);
+ }
+ if (!((ddr3_tip_is_pup_lock
+ (result[HWS_LOW2HIGH], result_type)) &&
+ (ddr3_tip_is_pup_lock
+ (result[HWS_HIGH2LOW], result_type)))) {
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("Special: Pup lock fail, pat %d IF %d pup %d\n",
+ pattern_id, if_id, pup_id));
+ return MV_FAIL;
+ }
+
+ cur_end_win_min =
+ ddr3_tip_get_buf_min(cur_end_win);
+ cur_start_win_max =
+ ddr3_tip_get_buf_max(cur_start_win);
+
+ if (cur_start_win_max <= 1) { /* Align left */
+ for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
+ bit_id++) {
+ pad_num =
+ dq_map_table[bit_id +
+ pup_id *
+ BUS_WIDTH_IN_BITS +
+ if_id *
+ BUS_WIDTH_IN_BITS *
+ tm->
+ num_of_bus_per_interface];
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST,
+ pup_id, DDR_PHY_DATA,
+ PBS_RX_PHY_REG + pad_num,
+ &temp));
+ temp = (temp + 0xa > 31) ?
+ (31) : (temp + 0xa);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ pup_id, DDR_PHY_DATA,
+ PBS_RX_PHY_REG + pad_num,
+ temp));
+ }
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("Special: PBS:: I/F# %d , Bus# %d fix align to the Left\n",
+ if_id, pup_id));
+ }
+
+ if (cur_end_win_min > 30) { /* Align right */
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup_id,
+ DDR_PHY_DATA, PBS_RX_PHY_REG + 4,
+ &temp));
+ temp += 0xa;
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ pup_id, DDR_PHY_DATA,
+ PBS_RX_PHY_REG + 4, temp));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup_id,
+ DDR_PHY_DATA, PBS_RX_PHY_REG + 5,
+ &temp));
+ temp += 0xa;
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ pup_id, DDR_PHY_DATA,
+ PBS_RX_PHY_REG + 5, temp));
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("Special: PBS:: I/F# %d , Bus# %d fix align to the right\n",
+ if_id, pup_id));
+ }
+
+ vref_window_size[if_id][pup_id] =
+ cur_end_win_min -
+ cur_start_win_max + 1;
+ DEBUG_CENTRALIZATION_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("Special: Winsize I/F# %d , Bus# %d is %d\n",
+ if_id, pup_id, vref_window_size
+ [if_id][pup_id]));
+ } /* pup */
+ } /* end of interface */
+
+ return MV_OK;
+}
+
+/*
+ * Print Centralization Result
+ */
+int ddr3_tip_print_centralization_result(u32 dev_num)
+{
+ u32 if_id = 0, bus_id = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ dev_num = dev_num;
+
+ printf("Centralization Results\n");
+ printf("I/F0 Result[0 - success 1-fail 2 - state_2 3 - state_3] ...\n");
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ printf("%d ,\n", centralization_state[if_id][bus_id]);
+ }
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_db.c b/drivers/ddr/marvell/a38x/ddr3_training_db.c
new file mode 100644
index 0000000000..861dfb19c3
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_db.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+/* List of allowed frequency listed in order of enum hws_ddr_freq */
+u32 freq_val[DDR_FREQ_LIMIT] = {
+ 0, /*DDR_FREQ_LOW_FREQ */
+ 400, /*DDR_FREQ_400, */
+ 533, /*DDR_FREQ_533, */
+ 666, /*DDR_FREQ_667, */
+ 800, /*DDR_FREQ_800, */
+ 933, /*DDR_FREQ_933, */
+ 1066, /*DDR_FREQ_1066, */
+ 311, /*DDR_FREQ_311, */
+ 333, /*DDR_FREQ_333, */
+ 467, /*DDR_FREQ_467, */
+ 850, /*DDR_FREQ_850, */
+ 600, /*DDR_FREQ_600 */
+ 300, /*DDR_FREQ_300 */
+ 900, /*DDR_FREQ_900 */
+ 360, /*DDR_FREQ_360 */
+ 1000 /*DDR_FREQ_1000 */
+};
+
+/* Table for CL values per frequency for each speed bin index */
+struct cl_val_per_freq cas_latency_table[] = {
+ /*
+ * 400M 667M 933M 311M 467M 600M 360
+ * 100M 533M 800M 1066M 333M 850M 900
+ * 1000 (the order is 100, 400, 533 etc.)
+ */
+ /* DDR3-800D */
+ { {6, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
+ /* DDR3-800E */
+ { {6, 6, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 6, 0, 6, 0} },
+ /* DDR3-1066E */
+ { {6, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 0, 5, 0, 5, 0} },
+ /* DDR3-1066F */
+ { {6, 6, 7, 0, 0, 0, 0, 6, 6, 7, 0, 0, 6, 0, 6, 0} },
+ /* DDR3-1066G */
+ { {6, 6, 8, 0, 0, 0, 0, 6, 6, 8, 0, 0, 6, 0, 6, 0} },
+ /* DDR3-1333F* */
+ { {6, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1333G */
+ { {6, 5, 7, 8, 0, 0, 0, 5, 5, 7, 0, 8, 5, 0, 5, 0} },
+ /* DDR3-1333H */
+ { {6, 6, 8, 9, 0, 0, 0, 6, 6, 8, 0, 9, 6, 0, 6, 0} },
+ /* DDR3-1333J* */
+ { {6, 6, 8, 10, 0, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6, 0}
+ /* DDR3-1600G* */},
+ { {6, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1600H */
+ { {6, 5, 6, 8, 9, 0, 0, 5, 5, 6, 0, 8, 5, 0, 5, 0} },
+ /* DDR3-1600J */
+ { {6, 5, 7, 9, 10, 0, 0, 5, 5, 7, 0, 9, 5, 0, 5, 0} },
+ /* DDR3-1600K */
+ { {6, 6, 8, 10, 11, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6, 0 } },
+ /* DDR3-1866J* */
+ { {6, 5, 6, 8, 9, 11, 0, 5, 5, 6, 11, 8, 5, 0, 5, 0} },
+ /* DDR3-1866K */
+ { {6, 5, 7, 8, 10, 11, 0, 5, 5, 7, 11, 8, 5, 11, 5, 11} },
+ /* DDR3-1866L */
+ { {6, 6, 7, 9, 11, 12, 0, 6, 6, 7, 12, 9, 6, 12, 6, 12} },
+ /* DDR3-1866M* */
+ { {6, 6, 8, 10, 11, 13, 0, 6, 6, 8, 13, 10, 6, 13, 6, 13} },
+ /* DDR3-2133K* */
+ { {6, 5, 6, 7, 9, 10, 11, 5, 5, 6, 10, 7, 5, 11, 5, 11} },
+ /* DDR3-2133L */
+ { {6, 5, 6, 8, 9, 11, 12, 5, 5, 6, 11, 8, 5, 12, 5, 12} },
+ /* DDR3-2133M */
+ { {6, 5, 7, 9, 10, 12, 13, 5, 5, 7, 12, 9, 5, 13, 5, 13} },
+ /* DDR3-2133N* */
+ { {6, 6, 7, 9, 11, 13, 14, 6, 6, 7, 13, 9, 6, 14, 6, 14} },
+ /* DDR3-1333H-ext */
+ { {6, 6, 7, 9, 0, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} },
+ /* DDR3-1600K-ext */
+ { {6, 6, 7, 9, 11, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} },
+ /* DDR3-1866M-ext */
+ { {6, 6, 7, 9, 11, 13, 0, 6, 6, 7, 13, 9, 6, 13, 6, 13} },
+};
+
+/* Table for CWL values per speedbin index */
+struct cl_val_per_freq cas_write_latency_table[] = {
+ /*
+ * 400M 667M 933M 311M 467M 600M 360
+ * 100M 533M 800M 1066M 333M 850M 900
+ * (the order is 100, 400, 533 etc.)
+ */
+ /* DDR3-800D */
+ { {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
+ /* DDR3-800E */
+ { {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
+ /* DDR3-1066E */
+ { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1066F */
+ { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1066G */
+ { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1333F* */
+ { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1333G */
+ { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1333H */
+ { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1333J* */
+ { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1600G* */
+ { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1600H */
+ { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1600J */
+ { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1600K */
+ { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1866J* */
+ { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} },
+ /* DDR3-1866K */
+ { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} },
+ /* DDR3-1866L */
+ { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
+ /* DDR3-1866M* */
+ { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
+ /* DDR3-2133K* */
+ { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+ /* DDR3-2133L */
+ { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+ /* DDR3-2133M */
+ { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+ /* DDR3-2133N* */
+ { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+ /* DDR3-1333H-ext */
+ { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1600K-ext */
+ { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+ /* DDR3-1866M-ext */
+ { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
+};
+
+u8 twr_mask_table[] = {
+ 10,
+ 10,
+ 10,
+ 10,
+ 10,
+ 1, /*5 */
+ 2, /*6 */
+ 3, /*7 */
+ 10,
+ 10,
+ 5, /*10 */
+ 10,
+ 6, /*12 */
+ 10,
+ 7, /*14 */
+ 10,
+ 0 /*16 */
+};
+
+u8 cl_mask_table[] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x2,
+ 0x4,
+ 0x6,
+ 0x8,
+ 0xa,
+ 0xc,
+ 0xe,
+ 0x1,
+ 0x3,
+ 0x5,
+ 0x5
+};
+
+u8 cwl_mask_table[] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x1,
+ 0x2,
+ 0x3,
+ 0x4,
+ 0x5,
+ 0x6,
+ 0x7,
+ 0x8,
+ 0x9,
+ 0x9
+};
+
+/* RFC values (in ns) */
+u16 rfc_table[] = {
+ 90, /* 512M */
+ 110, /* 1G */
+ 160, /* 2G */
+ 260, /* 4G */
+ 350 /* 8G */
+};
+
+u32 speed_bin_table_t_rc[] = {
+ 50000,
+ 52500,
+ 48750,
+ 50625,
+ 52500,
+ 46500,
+ 48000,
+ 49500,
+ 51000,
+ 45000,
+ 46250,
+ 47500,
+ 48750,
+ 44700,
+ 45770,
+ 46840,
+ 47910,
+ 43285,
+ 44220,
+ 45155,
+ 46900
+};
+
+u32 speed_bin_table_t_rcd_t_rp[] = {
+ 12500,
+ 15000,
+ 11250,
+ 13125,
+ 15000,
+ 10500,
+ 12000,
+ 13500,
+ 15000,
+ 10000,
+ 11250,
+ 12500,
+ 13750,
+ 10700,
+ 11770,
+ 12840,
+ 13910,
+ 10285,
+ 11022,
+ 12155,
+ 13090,
+};
+
+enum {
+ PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR = 0,
+ PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM
+};
+
+static u8 pattern_killer_pattern_table_map[KILLER_PATTERN_LENGTH * 2][2] = {
+ /*Aggressor / Victim */
+ {1, 0},
+ {0, 0},
+ {1, 0},
+ {1, 1},
+ {0, 1},
+ {0, 1},
+ {1, 0},
+ {0, 1},
+ {1, 0},
+ {0, 1},
+ {1, 0},
+ {1, 0},
+ {0, 1},
+ {1, 0},
+ {0, 1},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {1, 0},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 1},
+ {0, 1},
+ {1, 1},
+ {0, 0},
+ {0, 0},
+ {1, 1},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {1, 1},
+ {0, 0},
+ {0, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {0, 1},
+ {0, 0},
+ {0, 1},
+ {0, 1},
+ {0, 0},
+ {1, 1},
+ {1, 1},
+ {1, 0},
+ {1, 0},
+ {1, 1},
+ {1, 1},
+ {1, 1},
+ {1, 1},
+ {1, 1},
+ {1, 1},
+ {1, 1}
+};
+
+static u8 pattern_vref_pattern_table_map[] = {
+ /* 1 means 0xffffffff, 0 is 0x0 */
+ 0xb8,
+ 0x52,
+ 0x55,
+ 0x8a,
+ 0x33,
+ 0xa6,
+ 0x6d,
+ 0xfe
+};
+
+/* Return speed Bin value for selected index and t* element */
+u32 speed_bin_table(u8 index, enum speed_bin_table_elements element)
+{
+ u32 result = 0;
+
+ switch (element) {
+ case SPEED_BIN_TRCD:
+ case SPEED_BIN_TRP:
+ result = speed_bin_table_t_rcd_t_rp[index];
+ break;
+ case SPEED_BIN_TRAS:
+ if (index < 6)
+ result = 37500;
+ else if (index < 10)
+ result = 36000;
+ else if (index < 14)
+ result = 35000;
+ else if (index < 18)
+ result = 34000;
+ else
+ result = 33000;
+ break;
+ case SPEED_BIN_TRC:
+ result = speed_bin_table_t_rc[index];
+ break;
+ case SPEED_BIN_TRRD1K:
+ if (index < 3)
+ result = 10000;
+ else if (index < 6)
+ result = 7005;
+ else if (index < 14)
+ result = 6000;
+ else
+ result = 5000;
+ break;
+ case SPEED_BIN_TRRD2K:
+ if (index < 6)
+ result = 10000;
+ else if (index < 14)
+ result = 7005;
+ else
+ result = 6000;
+ break;
+ case SPEED_BIN_TPD:
+ if (index < 3)
+ result = 7500;
+ else if (index < 10)
+ result = 5625;
+ else
+ result = 5000;
+ break;
+ case SPEED_BIN_TFAW1K:
+ if (index < 3)
+ result = 40000;
+ else if (index < 6)
+ result = 37500;
+ else if (index < 14)
+ result = 30000;
+ else if (index < 18)
+ result = 27000;
+ else
+ result = 25000;
+ break;
+ case SPEED_BIN_TFAW2K:
+ if (index < 6)
+ result = 50000;
+ else if (index < 10)
+ result = 45000;
+ else if (index < 14)
+ result = 40000;
+ else
+ result = 35000;
+ break;
+ case SPEED_BIN_TWTR:
+ result = 7500;
+ break;
+ case SPEED_BIN_TRTP:
+ result = 7500;
+ break;
+ case SPEED_BIN_TWR:
+ result = 15000;
+ break;
+ case SPEED_BIN_TMOD:
+ result = 15000;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static inline u32 pattern_table_get_killer_word(u8 dqs, u8 index)
+{
+ u8 i, byte = 0;
+ u8 role;
+
+ for (i = 0; i < 8; i++) {
+ role = (i == dqs) ?
+ (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
+ (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
+ byte |= pattern_killer_pattern_table_map[index][role] << i;
+ }
+
+ return byte | (byte << 8) | (byte << 16) | (byte << 24);
+}
+
+static inline u32 pattern_table_get_killer_word16(u8 dqs, u8 index)
+{
+ u8 i, byte0 = 0, byte1 = 0;
+ u8 role;
+
+ for (i = 0; i < 8; i++) {
+ role = (i == dqs) ?
+ (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
+ (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
+ byte0 |= pattern_killer_pattern_table_map[index * 2][role] << i;
+ }
+
+ for (i = 0; i < 8; i++) {
+ role = (i == dqs) ?
+ (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
+ (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
+ byte1 |= pattern_killer_pattern_table_map
+ [index * 2 + 1][role] << i;
+ }
+
+ return byte0 | (byte0 << 8) | (byte1 << 16) | (byte1 << 24);
+}
+
+static inline u32 pattern_table_get_sso_word(u8 sso, u8 index)
+{
+ u8 step = sso + 1;
+
+ if (0 == ((index / step) & 1))
+ return 0x0;
+ else
+ return 0xffffffff;
+}
+
+static inline u32 pattern_table_get_vref_word(u8 index)
+{
+ if (0 == ((pattern_vref_pattern_table_map[index / 8] >>
+ (index % 8)) & 1))
+ return 0x0;
+ else
+ return 0xffffffff;
+}
+
+static inline u32 pattern_table_get_vref_word16(u8 index)
+{
+ if (0 == pattern_killer_pattern_table_map
+ [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
+ 0 == pattern_killer_pattern_table_map
+ [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
+ return 0x00000000;
+ else if (1 == pattern_killer_pattern_table_map
+ [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
+ 0 == pattern_killer_pattern_table_map
+ [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
+ return 0xffff0000;
+ else if (0 == pattern_killer_pattern_table_map
+ [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
+ 1 == pattern_killer_pattern_table_map
+ [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
+ return 0x0000ffff;
+ else
+ return 0xffffffff;
+}
+
+static inline u32 pattern_table_get_static_pbs_word(u8 index)
+{
+ u16 temp;
+
+ temp = ((0x00ff << (index / 3)) & 0xff00) >> 8;
+
+ return temp | (temp << 8) | (temp << 16) | (temp << 24);
+}
+
+inline u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index)
+{
+ u32 pattern;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0) {
+ /* 32bit patterns */
+ switch (type) {
+ case PATTERN_PBS1:
+ case PATTERN_PBS2:
+ if (index == 0 || index == 2 || index == 5 ||
+ index == 7)
+ pattern = PATTERN_55;
+ else
+ pattern = PATTERN_AA;
+ break;
+ case PATTERN_PBS3:
+ if (0 == (index & 1))
+ pattern = PATTERN_55;
+ else
+ pattern = PATTERN_AA;
+ break;
+ case PATTERN_RL:
+ if (index < 6)
+ pattern = PATTERN_00;
+ else
+ pattern = PATTERN_80;
+ break;
+ case PATTERN_STATIC_PBS:
+ pattern = pattern_table_get_static_pbs_word(index);
+ break;
+ case PATTERN_KILLER_DQ0:
+ case PATTERN_KILLER_DQ1:
+ case PATTERN_KILLER_DQ2:
+ case PATTERN_KILLER_DQ3:
+ case PATTERN_KILLER_DQ4:
+ case PATTERN_KILLER_DQ5:
+ case PATTERN_KILLER_DQ6:
+ case PATTERN_KILLER_DQ7:
+ pattern = pattern_table_get_killer_word(
+ (u8)(type - PATTERN_KILLER_DQ0), index);
+ break;
+ case PATTERN_RL2:
+ if (index < 6)
+ pattern = PATTERN_00;
+ else
+ pattern = PATTERN_01;
+ break;
+ case PATTERN_TEST:
+ if (index > 1 && index < 6)
+ pattern = PATTERN_20;
+ else
+ pattern = PATTERN_00;
+ break;
+ case PATTERN_FULL_SSO0:
+ case PATTERN_FULL_SSO1:
+ case PATTERN_FULL_SSO2:
+ case PATTERN_FULL_SSO3:
+ pattern = pattern_table_get_sso_word(
+ (u8)(type - PATTERN_FULL_SSO0), index);
+ break;
+ case PATTERN_VREF:
+ pattern = pattern_table_get_vref_word(index);
+ break;
+ default:
+ pattern = 0;
+ break;
+ }
+ } else {
+ /* 16bit patterns */
+ switch (type) {
+ case PATTERN_PBS1:
+ case PATTERN_PBS2:
+ case PATTERN_PBS3:
+ pattern = PATTERN_55AA;
+ break;
+ case PATTERN_RL:
+ if (index < 3)
+ pattern = PATTERN_00;
+ else
+ pattern = PATTERN_80;
+ break;
+ case PATTERN_STATIC_PBS:
+ pattern = PATTERN_00FF;
+ break;
+ case PATTERN_KILLER_DQ0:
+ case PATTERN_KILLER_DQ1:
+ case PATTERN_KILLER_DQ2:
+ case PATTERN_KILLER_DQ3:
+ case PATTERN_KILLER_DQ4:
+ case PATTERN_KILLER_DQ5:
+ case PATTERN_KILLER_DQ6:
+ case PATTERN_KILLER_DQ7:
+ pattern = pattern_table_get_killer_word16(
+ (u8)(type - PATTERN_KILLER_DQ0), index);
+ break;
+ case PATTERN_RL2:
+ if (index < 3)
+ pattern = PATTERN_00;
+ else
+ pattern = PATTERN_01;
+ break;
+ case PATTERN_TEST:
+ pattern = PATTERN_0080;
+ break;
+ case PATTERN_FULL_SSO0:
+ pattern = 0x0000ffff;
+ break;
+ case PATTERN_FULL_SSO1:
+ case PATTERN_FULL_SSO2:
+ case PATTERN_FULL_SSO3:
+ pattern = pattern_table_get_sso_word(
+ (u8)(type - PATTERN_FULL_SSO1), index);
+ break;
+ case PATTERN_VREF:
+ pattern = pattern_table_get_vref_word16(index);
+ break;
+ default:
+ pattern = 0;
+ break;
+ }
+ }
+
+ return pattern;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
new file mode 100644
index 0000000000..56fce174d4
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define VREF_INITIAL_STEP 3
+#define VREF_SECOND_STEP 1
+#define VREF_MAX_INDEX 7
+#define MAX_VALUE (1024 - 1)
+#define MIN_VALUE (-MAX_VALUE)
+#define GET_RD_SAMPLE_DELAY(data, cs) ((data >> rd_sample_mask[cs]) & 0xf)
+
+u32 ck_delay = (u32)-1, ck_delay_16 = (u32)-1;
+u32 ca_delay;
+int ddr3_tip_centr_skip_min_win_check = 0;
+u8 current_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u8 last_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u16 current_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u16 last_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u8 lim_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u8 interface_state[MAX_INTERFACE_NUM];
+u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 vref_window_size_th = 12;
+
+static u8 pup_st[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+
+static u32 rd_sample_mask[] = {
+ 0,
+ 8,
+ 16,
+ 24
+};
+
+#define VREF_STEP_1 0
+#define VREF_STEP_2 1
+#define VREF_CONVERGE 2
+
+/*
+ * ODT additional timing
+ */
+int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id)
+{
+ u32 cs_num = 0, max_read_sample = 0, min_read_sample = 0;
+ u32 data_read[MAX_INTERFACE_NUM] = { 0 };
+ u32 read_sample[MAX_CS_NUM];
+ u32 val;
+ u32 pup_index;
+ int max_phase = MIN_VALUE, current_phase;
+ enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ DUNIT_ODT_CONTROL_REG,
+ 0 << 8, 0x3 << 8));
+ CHECK_STATUS(ddr3_tip_if_read(dev_num, access_type, if_id,
+ READ_DATA_SAMPLE_DELAY,
+ data_read, MASK_ALL_BITS));
+ val = data_read[if_id];
+
+ for (cs_num = 0; cs_num < MAX_CS_NUM; cs_num++) {
+ read_sample[cs_num] = GET_RD_SAMPLE_DELAY(val, cs_num);
+
+ /* find maximum of read_samples */
+ if (read_sample[cs_num] >= max_read_sample) {
+ if (read_sample[cs_num] == max_read_sample)
+ max_phase = MIN_VALUE;
+ else
+ max_read_sample = read_sample[cs_num];
+
+ for (pup_index = 0;
+ pup_index < tm->num_of_bus_per_interface;
+ pup_index++) {
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup_index,
+ DDR_PHY_DATA,
+ RL_PHY_REG + CS_REG_VALUE(cs_num),
+ &val));
+
+ current_phase = ((int)val & 0xe0) >> 6;
+ if (current_phase >= max_phase)
+ max_phase = current_phase;
+ }
+ }
+
+ /* find minimum */
+ if (read_sample[cs_num] < min_read_sample)
+ min_read_sample = read_sample[cs_num];
+ }
+
+ min_read_sample = min_read_sample - 1;
+ max_read_sample = max_read_sample + 4 + (max_phase + 1) / 2 + 1;
+ if (min_read_sample >= 0xf)
+ min_read_sample = 0xf;
+ if (max_read_sample >= 0x1f)
+ max_read_sample = 0x1f;
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODT_TIMING_LOW,
+ ((min_read_sample - 1) << 12),
+ 0xf << 12));
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODT_TIMING_LOW,
+ (max_read_sample << 16),
+ 0x1f << 16));
+
+ return MV_OK;
+}
+
+int get_valid_win_rx(u32 dev_num, u32 if_id, u8 res[4])
+{
+ u32 reg_pup = RESULT_DB_PHY_REG_ADDR;
+ u32 reg_data;
+ u32 cs_num;
+ int i;
+
+ cs_num = 0;
+
+ /* TBD */
+ reg_pup += cs_num;
+
+ for (i = 0; i < 4; i++) {
+ CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id,
+ ACCESS_TYPE_UNICAST, i,
+ DDR_PHY_DATA, reg_pup,
+ &reg_data));
+ res[i] = (reg_data >> RESULT_DB_PHY_REG_RX_OFFSET) & 0x1f;
+ }
+
+ return 0;
+}
+
+/*
+ * This algorithm deals with the vertical optimum from Voltage point of view
+ * of the sample signal.
+ * Voltage sample point can improve the Eye / window size of the bit and the
+ * pup.
+ * The problem is that it is tune for all DQ the same so there isn't any
+ * PBS like code.
+ * It is more like centralization.
+ * But because we don't have The training SM support we do it a bit more
+ * smart search to save time.
+ */
+int ddr3_tip_vref(u32 dev_num)
+{
+ /*
+ * The Vref register have non linear order. Need to check what will be
+ * in future projects.
+ */
+ u32 vref_map[8] = {
+ 1, 2, 3, 4, 5, 6, 7, 0
+ };
+ /* State and parameter definitions */
+ u32 initial_step = VREF_INITIAL_STEP;
+ /* need to be assign with minus ????? */
+ u32 second_step = VREF_SECOND_STEP;
+ u32 algo_run_flag = 0, currrent_vref = 0;
+ u32 while_count = 0;
+ u32 pup = 0, if_id = 0, num_pup = 0, rep = 0;
+ u32 val = 0;
+ u32 reg_addr = 0xa8;
+ u32 copy_start_pattern, copy_end_pattern;
+ enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage);
+ u8 res[4];
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ CHECK_STATUS(ddr3_tip_special_rx(dev_num));
+
+ /* save start/end pattern */
+ copy_start_pattern = start_pattern;
+ copy_end_pattern = end_pattern;
+
+ /* set vref as centralization pattern */
+ start_pattern = PATTERN_VREF;
+ end_pattern = PATTERN_VREF;
+
+ /* init params */
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup = 0;
+ pup < tm->num_of_bus_per_interface; pup++) {
+ current_vref[pup][if_id] = 0;
+ last_vref[pup][if_id] = 0;
+ lim_vref[pup][if_id] = 0;
+ current_valid_window[pup][if_id] = 0;
+ last_valid_window[pup][if_id] = 0;
+ if (vref_window_size[if_id][pup] >
+ vref_window_size_th) {
+ pup_st[pup][if_id] = VREF_CONVERGE;
+ DEBUG_TRAINING_HW_ALG(
+ DEBUG_LEVEL_INFO,
+ ("VREF config, IF[ %d ]pup[ %d ] - Vref tune not requered (%d)\n",
+ if_id, pup, __LINE__));
+ } else {
+ pup_st[pup][if_id] = VREF_STEP_1;
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr, &val));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ pup, DDR_PHY_DATA, reg_addr,
+ (val & (~0xf)) | vref_map[0]));
+ DEBUG_TRAINING_HW_ALG(
+ DEBUG_LEVEL_INFO,
+ ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+ if_id, pup,
+ (val & (~0xf)) | vref_map[0],
+ __LINE__));
+ }
+ }
+ interface_state[if_id] = 0;
+ }
+
+ /* TODO: Set number of active interfaces */
+ num_pup = tm->num_of_bus_per_interface * MAX_INTERFACE_NUM;
+
+ while ((algo_run_flag <= num_pup) & (while_count < 10)) {
+ while_count++;
+ for (rep = 1; rep < 4; rep++) {
+ ddr3_tip_centr_skip_min_win_check = 1;
+ ddr3_tip_centralization_rx(dev_num);
+ ddr3_tip_centr_skip_min_win_check = 0;
+
+ /* Read Valid window results only for non converge pups */
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (interface_state[if_id] != 4) {
+ get_valid_win_rx(dev_num, if_id, res);
+ for (pup = 0;
+ pup < tm->num_of_bus_per_interface;
+ pup++) {
+ VALIDATE_ACTIVE
+ (tm->bus_act_mask, pup);
+ if (pup_st[pup]
+ [if_id] ==
+ VREF_CONVERGE)
+ continue;
+
+ current_valid_window[pup]
+ [if_id] =
+ (current_valid_window[pup]
+ [if_id] * (rep - 1) +
+ 1000 * res[pup]) / rep;
+ }
+ }
+ }
+ }
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ DEBUG_TRAINING_HW_ALG(
+ DEBUG_LEVEL_TRACE,
+ ("current_valid_window: IF[ %d ] - ", if_id));
+
+ for (pup = 0;
+ pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
+ ("%d ",
+ current_valid_window
+ [pup][if_id]));
+ }
+ DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, ("\n"));
+ }
+
+ /* Compare results and respond as function of state */
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup = 0;
+ pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
+ ("I/F[ %d ], pup[ %d ] STATE #%d (%d)\n",
+ if_id, pup,
+ pup_st[pup]
+ [if_id], __LINE__));
+
+ if (pup_st[pup][if_id] == VREF_CONVERGE)
+ continue;
+
+ DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
+ ("I/F[ %d ], pup[ %d ] CHECK progress - Current %d Last %d, limit VREF %d (%d)\n",
+ if_id, pup,
+ current_valid_window[pup]
+ [if_id],
+ last_valid_window[pup]
+ [if_id], lim_vref[pup]
+ [if_id], __LINE__));
+
+ /*
+ * The -1 is for solution resolution +/- 1 tap
+ * of ADLL
+ */
+ if (current_valid_window[pup][if_id] + 200 >=
+ (last_valid_window[pup][if_id])) {
+ if (pup_st[pup][if_id] == VREF_STEP_1) {
+ /*
+ * We stay in the same state and
+ * step just update the window
+ * size (take the max) and Vref
+ */
+ if (current_vref[pup]
+ [if_id] == VREF_MAX_INDEX) {
+ /*
+ * If we step to the end
+ * and didn't converge
+ * to some particular
+ * better Vref value
+ * define the pup as
+ * converge and step
+ * back to nominal
+ * Vref.
+ */
+ pup_st[pup]
+ [if_id] =
+ VREF_CONVERGE;
+ algo_run_flag++;
+ interface_state
+ [if_id]++;
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+ if_id, pup,
+ current_vref[pup]
+ [if_id],
+ __LINE__));
+ } else {
+ /* continue to update the Vref index */
+ current_vref[pup]
+ [if_id] =
+ ((current_vref[pup]
+ [if_id] +
+ initial_step) >
+ VREF_MAX_INDEX) ?
+ VREF_MAX_INDEX
+ : (current_vref[pup]
+ [if_id] +
+ initial_step);
+ if (current_vref[pup]
+ [if_id] ==
+ VREF_MAX_INDEX) {
+ pup_st[pup]
+ [if_id]
+ =
+ VREF_STEP_2;
+ }
+ lim_vref[pup]
+ [if_id] =
+ last_vref[pup]
+ [if_id] =
+ current_vref[pup]
+ [if_id];
+ }
+
+ last_valid_window[pup]
+ [if_id] =
+ GET_MAX(current_valid_window
+ [pup][if_id],
+ last_valid_window
+ [pup]
+ [if_id]);
+
+ /* update the Vref for next stage */
+ currrent_vref =
+ current_vref[pup]
+ [if_id];
+ CHECK_STATUS
+ (ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ &val));
+ CHECK_STATUS
+ (ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ (val & (~0xf)) |
+ vref_map[currrent_vref]));
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+ if_id, pup,
+ (val & (~0xf)) |
+ vref_map[currrent_vref],
+ __LINE__));
+ } else if (pup_st[pup][if_id]
+ == VREF_STEP_2) {
+ /*
+ * We keep on search back with
+ * the same step size.
+ */
+ last_valid_window[pup]
+ [if_id] =
+ GET_MAX(current_valid_window
+ [pup][if_id],
+ last_valid_window
+ [pup]
+ [if_id]);
+ last_vref[pup][if_id] =
+ current_vref[pup]
+ [if_id];
+
+ /* we finish all search space */
+ if ((current_vref[pup]
+ [if_id] - second_step) == lim_vref[pup][if_id]) {
+ /*
+ * If we step to the end
+ * and didn't converge
+ * to some particular
+ * better Vref value
+ * define the pup as
+ * converge and step
+ * back to nominal
+ * Vref.
+ */
+ pup_st[pup]
+ [if_id] =
+ VREF_CONVERGE;
+ algo_run_flag++;
+
+ interface_state
+ [if_id]++;
+
+ current_vref[pup]
+ [if_id] =
+ (current_vref[pup]
+ [if_id] -
+ second_step);
+
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+ if_id, pup,
+ current_vref[pup]
+ [if_id],
+ __LINE__));
+ } else
+ /* we finish all search space */
+ if (current_vref[pup]
+ [if_id] ==
+ lim_vref[pup]
+ [if_id]) {
+ /*
+ * If we step to the end
+ * and didn't converge
+ * to some particular
+ * better Vref value
+ * define the pup as
+ * converge and step
+ * back to nominal
+ * Vref.
+ */
+ pup_st[pup]
+ [if_id] =
+ VREF_CONVERGE;
+
+ algo_run_flag++;
+ interface_state
+ [if_id]++;
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+ if_id, pup,
+ current_vref[pup]
+ [if_id],
+ __LINE__));
+ } else {
+ current_vref[pup]
+ [if_id] =
+ current_vref[pup]
+ [if_id] -
+ second_step;
+ }
+
+ /* Update the Vref for next stage */
+ currrent_vref =
+ current_vref[pup]
+ [if_id];
+ CHECK_STATUS
+ (ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ &val));
+ CHECK_STATUS
+ (ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ (val & (~0xf)) |
+ vref_map[currrent_vref]));
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+ if_id, pup,
+ (val & (~0xf)) |
+ vref_map[currrent_vref],
+ __LINE__));
+ }
+ } else {
+ /* we change state and change step */
+ if (pup_st[pup][if_id] == VREF_STEP_1) {
+ pup_st[pup][if_id] =
+ VREF_STEP_2;
+ lim_vref[pup][if_id] =
+ current_vref[pup]
+ [if_id] - initial_step;
+ last_valid_window[pup]
+ [if_id] =
+ current_valid_window[pup]
+ [if_id];
+ last_vref[pup][if_id] =
+ current_vref[pup]
+ [if_id];
+ current_vref[pup][if_id] =
+ last_vref[pup][if_id] -
+ second_step;
+
+ /* Update the Vref for next stage */
+ CHECK_STATUS
+ (ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ &val));
+ CHECK_STATUS
+ (ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ (val & (~0xf)) |
+ vref_map[current_vref[pup]
+ [if_id]]));
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+ if_id, pup,
+ (val & (~0xf)) |
+ vref_map[current_vref[pup]
+ [if_id]],
+ __LINE__));
+
+ } else if (pup_st[pup][if_id] == VREF_STEP_2) {
+ /*
+ * The last search was the max
+ * point set value and exit
+ */
+ CHECK_STATUS
+ (ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ &val));
+ CHECK_STATUS
+ (ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ (val & (~0xf)) |
+ vref_map[last_vref[pup]
+ [if_id]]));
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+ if_id, pup,
+ (val & (~0xf)) |
+ vref_map[last_vref[pup]
+ [if_id]],
+ __LINE__));
+ pup_st[pup][if_id] =
+ VREF_CONVERGE;
+ algo_run_flag++;
+ interface_state[if_id]++;
+ DEBUG_TRAINING_HW_ALG
+ (DEBUG_LEVEL_TRACE,
+ ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+ if_id, pup,
+ current_vref[pup]
+ [if_id], __LINE__));
+ }
+ }
+ }
+ }
+ }
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup = 0;
+ pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr, &val));
+ DEBUG_TRAINING_HW_ALG(
+ DEBUG_LEVEL_INFO,
+ ("FINAL values: I/F[ %d ], pup[ %d ] - Vref = %X (%d)\n",
+ if_id, pup, val, __LINE__));
+ }
+ }
+
+ flow_result[if_id] = TEST_SUCCESS;
+
+ /* restore start/end pattern */
+ start_pattern = copy_start_pattern;
+ end_pattern = copy_end_pattern;
+
+ return 0;
+}
+
+/*
+ * CK/CA Delay
+ */
+int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap)
+{
+ u32 if_id = 0;
+ u32 ck_num_adll_tap = 0, ca_num_adll_tap = 0, data = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * ck_delay_table is delaying the of the clock signal only.
+ * (to overcome timing issues between_c_k & command/address signals)
+ */
+ /*
+ * ca_delay is delaying the of the entire command & Address signals
+ * (include Clock signal to overcome DGL error on the Clock versus
+ * the DQS).
+ */
+
+ /* Calc ADLL Tap */
+ if ((ck_delay == -1) || (ck_delay_16 == -1)) {
+ DEBUG_TRAINING_HW_ALG(
+ DEBUG_LEVEL_ERROR,
+ ("ERROR: One of ck_delay values not initialized!!!\n"));
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* Calc delay ps in ADLL tap */
+ if (tm->interface_params[if_id].bus_width ==
+ BUS_WIDTH_16)
+ ck_num_adll_tap = ck_delay_16 / adll_tap;
+ else
+ ck_num_adll_tap = ck_delay / adll_tap;
+
+ ca_num_adll_tap = ca_delay / adll_tap;
+ data = (ck_num_adll_tap & 0x3f) +
+ ((ca_num_adll_tap & 0x3f) << 10);
+
+ /*
+ * Set the ADLL number to the CK ADLL for Interfaces for
+ * all Pup
+ */
+ DEBUG_TRAINING_HW_ALG(
+ DEBUG_LEVEL_TRACE,
+ ("ck_num_adll_tap %d ca_num_adll_tap %d adll_tap %d\n",
+ ck_num_adll_tap, ca_num_adll_tap, adll_tap));
+
+ CHECK_STATUS(ddr3_tip_bus_write(dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, DDR_PHY_CONTROL,
+ 0x0, data));
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h
new file mode 100644
index 0000000000..6e1bab260d
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_HW_ALGO_H_
+#define _DDR3_TRAINING_HW_ALGO_H_
+
+int ddr3_tip_vref(u32 dev_num);
+int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id);
+int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap);
+
+#endif /* _DDR3_TRAINING_HW_ALGO_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip.h b/drivers/ddr/marvell/a38x/ddr3_training_ip.h
new file mode 100644
index 0000000000..76a1b6a06d
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_H_
+#define _DDR3_TRAINING_IP_H_
+
+#include "ddr3_training_ip_def.h"
+#include "ddr_topology_def.h"
+#include "ddr_training_ip_db.h"
+
+#define DDR3_TIP_VERSION_STRING "DDR3 Training Sequence - Ver TIP-1.29."
+
+#define MAX_CS_NUM 4
+#define MAX_TOTAL_BUS_NUM (MAX_INTERFACE_NUM * MAX_BUS_NUM)
+#define MAX_DQ_NUM 40
+
+#define GET_MIN(arg1, arg2) ((arg1) < (arg2)) ? (arg1) : (arg2)
+#define GET_MAX(arg1, arg2) ((arg1) < (arg2)) ? (arg2) : (arg1)
+
+#define INIT_CONTROLLER_MASK_BIT 0x00000001
+#define STATIC_LEVELING_MASK_BIT 0x00000002
+#define SET_LOW_FREQ_MASK_BIT 0x00000004
+#define LOAD_PATTERN_MASK_BIT 0x00000008
+#define SET_MEDIUM_FREQ_MASK_BIT 0x00000010
+#define WRITE_LEVELING_MASK_BIT 0x00000020
+#define LOAD_PATTERN_2_MASK_BIT 0x00000040
+#define READ_LEVELING_MASK_BIT 0x00000080
+#define SW_READ_LEVELING_MASK_BIT 0x00000100
+#define WRITE_LEVELING_SUPP_MASK_BIT 0x00000200
+#define PBS_RX_MASK_BIT 0x00000400
+#define PBS_TX_MASK_BIT 0x00000800
+#define SET_TARGET_FREQ_MASK_BIT 0x00001000
+#define ADJUST_DQS_MASK_BIT 0x00002000
+#define WRITE_LEVELING_TF_MASK_BIT 0x00004000
+#define LOAD_PATTERN_HIGH_MASK_BIT 0x00008000
+#define READ_LEVELING_TF_MASK_BIT 0x00010000
+#define WRITE_LEVELING_SUPP_TF_MASK_BIT 0x00020000
+#define DM_PBS_TX_MASK_BIT 0x00040000
+#define CENTRALIZATION_RX_MASK_BIT 0x00100000
+#define CENTRALIZATION_TX_MASK_BIT 0x00200000
+#define TX_EMPHASIS_MASK_BIT 0x00400000
+#define PER_BIT_READ_LEVELING_TF_MASK_BIT 0x00800000
+#define VREF_CALIBRATION_MASK_BIT 0x01000000
+
+enum hws_result {
+ TEST_FAILED = 0,
+ TEST_SUCCESS = 1,
+ NO_TEST_DONE = 2
+};
+
+enum hws_training_result {
+ RESULT_PER_BIT,
+ RESULT_PER_BYTE
+};
+
+enum auto_tune_stage {
+ INIT_CONTROLLER,
+ STATIC_LEVELING,
+ SET_LOW_FREQ,
+ LOAD_PATTERN,
+ SET_MEDIUM_FREQ,
+ WRITE_LEVELING,
+ LOAD_PATTERN_2,
+ READ_LEVELING,
+ WRITE_LEVELING_SUPP,
+ PBS_RX,
+ PBS_TX,
+ SET_TARGET_FREQ,
+ ADJUST_DQS,
+ WRITE_LEVELING_TF,
+ READ_LEVELING_TF,
+ WRITE_LEVELING_SUPP_TF,
+ DM_PBS_TX,
+ VREF_CALIBRATION,
+ CENTRALIZATION_RX,
+ CENTRALIZATION_TX,
+ TX_EMPHASIS,
+ LOAD_PATTERN_HIGH,
+ PER_BIT_READ_LEVELING_TF,
+ MAX_STAGE_LIMIT
+};
+
+enum hws_access_type {
+ ACCESS_TYPE_UNICAST = 0,
+ ACCESS_TYPE_MULTICAST = 1
+};
+
+enum hws_algo_type {
+ ALGO_TYPE_DYNAMIC,
+ ALGO_TYPE_STATIC
+};
+
+struct init_cntr_param {
+ int is_ctrl64_bit;
+ int do_mrs_phy;
+ int init_phy;
+ int msys_init;
+};
+
+struct pattern_info {
+ u8 num_of_phases_tx;
+ u8 tx_burst_size;
+ u8 delay_between_bursts;
+ u8 num_of_phases_rx;
+ u32 start_addr;
+ u8 pattern_len;
+};
+
+/* CL value for each frequency */
+struct cl_val_per_freq {
+ u8 cl_val[DDR_FREQ_LIMIT];
+};
+
+struct cs_element {
+ u8 cs_num;
+ u8 num_of_cs;
+};
+
+struct mode_info {
+ /* 32 bits representing MRS bits */
+ u32 reg_mr0[MAX_INTERFACE_NUM];
+ u32 reg_mr1[MAX_INTERFACE_NUM];
+ u32 reg_mr2[MAX_INTERFACE_NUM];
+ u32 reg_m_r3[MAX_INTERFACE_NUM];
+ /*
+ * Each element in array represent read_data_sample register delay for
+ * a specific interface.
+ * Each register, 4 bits[0+CS*8 to 4+CS*8] represent Number of DDR
+ * cycles from read command until data is ready to be fetched from
+ * the PHY, when accessing CS.
+ */
+ u32 read_data_sample[MAX_INTERFACE_NUM];
+ /*
+ * Each element in array represent read_data_sample register delay for
+ * a specific interface.
+ * Each register, 4 bits[0+CS*8 to 4+CS*8] represent the total delay
+ * from read command until opening the read mask, when accessing CS.
+ * This field defines the delay in DDR cycles granularity.
+ */
+ u32 read_data_ready[MAX_INTERFACE_NUM];
+};
+
+struct hws_tip_freq_config_info {
+ u8 is_supported;
+ u8 bw_per_freq;
+ u8 rate_per_freq;
+};
+
+struct hws_cs_config_info {
+ u32 cs_reg_value;
+ u32 cs_cbe_value;
+};
+
+struct dfx_access {
+ u8 pipe;
+ u8 client;
+};
+
+struct hws_xsb_info {
+ struct dfx_access *dfx_table;
+};
+
+int ddr3_tip_register_dq_table(u32 dev_num, u32 *table);
+int hws_ddr3_tip_select_ddr_controller(u32 dev_num, int enable);
+int hws_ddr3_tip_init_controller(u32 dev_num,
+ struct init_cntr_param *init_cntr_prm);
+int hws_ddr3_tip_load_topology_map(u32 dev_num,
+ struct hws_topology_map *topology);
+int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type);
+int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info);
+int hws_ddr3_tip_read_training_result(u32 dev_num,
+ enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]);
+int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode);
+u8 ddr3_tip_get_buf_min(u8 *buf_ptr);
+u8 ddr3_tip_get_buf_max(u8 *buf_ptr);
+
+#endif /* _DDR3_TRAINING_IP_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h
new file mode 100644
index 0000000000..5c9bfe98a0
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_BIST_H_
+#define _DDR3_TRAINING_IP_BIST_H_
+
+#include "ddr3_training_ip.h"
+
+enum hws_bist_operation {
+ BIST_STOP = 0,
+ BIST_START = 1
+};
+
+enum hws_stress_jump {
+ STRESS_NONE = 0,
+ STRESS_ENABLE = 1
+};
+
+enum hws_pattern_duration {
+ DURATION_SINGLE = 0,
+ DURATION_STOP_AT_FAIL = 1,
+ DURATION_ADDRESS = 2,
+ DURATION_CONT = 4
+};
+
+struct bist_result {
+ u32 bist_error_cnt;
+ u32 bist_fail_low;
+ u32 bist_fail_high;
+ u32 bist_last_fail_addr;
+};
+
+int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id,
+ struct bist_result *pst_bist_result);
+int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern,
+ enum hws_access_type access_type,
+ u32 if_num, enum hws_dir direction,
+ enum hws_stress_jump addr_stress_jump,
+ enum hws_pattern_duration duration,
+ enum hws_bist_operation oper_type,
+ u32 offset, u32 cs_num, u32 pattern_addr_length);
+int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result,
+ u32 cs_num);
+int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction,
+ u32 mode);
+int ddr3_tip_print_regs(u32 dev_num);
+int ddr3_tip_reg_dump(u32 dev_num);
+int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type, u32 read_type,
+ u32 burst_length);
+
+#endif /* _DDR3_TRAINING_IP_BIST_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h
new file mode 100644
index 0000000000..7c57603947
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_CENTRALIZATION_H
+#define _DDR3_TRAINING_IP_CENTRALIZATION_H
+
+int ddr3_tip_centralization_tx(u32 dev_num);
+int ddr3_tip_centralization_rx(u32 dev_num);
+int ddr3_tip_print_centralization_result(u32 dev_num);
+int ddr3_tip_special_rx(u32 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_CENTRALIZATION_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h
new file mode 100644
index 0000000000..c0afa7742e
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_DB_H_
+#define _DDR3_TRAINING_IP_DB_H_
+
+enum hws_pattern {
+ PATTERN_PBS1,
+ PATTERN_PBS2,
+ PATTERN_RL,
+ PATTERN_STATIC_PBS,
+ PATTERN_KILLER_DQ0,
+ PATTERN_KILLER_DQ1,
+ PATTERN_KILLER_DQ2,
+ PATTERN_KILLER_DQ3,
+ PATTERN_KILLER_DQ4,
+ PATTERN_KILLER_DQ5,
+ PATTERN_KILLER_DQ6,
+ PATTERN_KILLER_DQ7,
+ PATTERN_PBS3,
+ PATTERN_RL2,
+ PATTERN_TEST,
+ PATTERN_FULL_SSO0,
+ PATTERN_FULL_SSO1,
+ PATTERN_FULL_SSO2,
+ PATTERN_FULL_SSO3,
+ PATTERN_VREF,
+ PATTERN_LIMIT
+};
+
+#endif /* _DDR3_TRAINING_IP_DB_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h
new file mode 100644
index 0000000000..51a66d8491
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_DEF_H
+#define _DDR3_TRAINING_IP_DEF_H
+
+#include "silicon_if.h"
+
+#define PATTERN_55 0x55555555
+#define PATTERN_AA 0xaaaaaaaa
+#define PATTERN_80 0x80808080
+#define PATTERN_20 0x20202020
+#define PATTERN_01 0x01010101
+#define PATTERN_FF 0xffffffff
+#define PATTERN_00 0x00000000
+
+/* 16bit bus width patterns */
+#define PATTERN_55AA 0x5555aaaa
+#define PATTERN_00FF 0x0000ffff
+#define PATTERN_0080 0x00008080
+
+#define INVALID_VALUE 0xffffffff
+#define MAX_NUM_OF_DUNITS 32
+/*
+ * length *2 = length in words of pattern, first low address,
+ * second high address
+ */
+#define TEST_PATTERN_LENGTH 4
+#define KILLER_PATTERN_DQ_NUMBER 8
+#define SSO_DQ_NUMBER 4
+#define PATTERN_MAXIMUM_LENGTH 64
+#define ADLL_TX_LENGTH 64
+#define ADLL_RX_LENGTH 32
+
+#define PARAM_NOT_CARE 0
+
+#define READ_LEVELING_PHY_OFFSET 2
+#define WRITE_LEVELING_PHY_OFFSET 0
+
+#define MASK_ALL_BITS 0xffffffff
+
+#define CS_BIT_MASK 0xf
+
+/* DFX access */
+#define BROADCAST_ID 28
+#define MULTICAST_ID 29
+
+#define XSB_BASE_ADDR 0x00004000
+#define XSB_CTRL_0_REG 0x00000000
+#define XSB_CTRL_1_REG 0x00000004
+#define XSB_CMD_REG 0x00000008
+#define XSB_ADDRESS_REG 0x0000000c
+#define XSB_DATA_REG 0x00000010
+#define PIPE_ENABLE_ADDR 0x000f8000
+#define ENABLE_DDR_TUNING_ADDR 0x000f829c
+
+#define CLIENT_BASE_ADDR 0x00002000
+#define CLIENT_CTRL_REG 0x00000000
+
+#define TARGET_INT 0x1801
+#define TARGET_EXT 0x180e
+#define BYTE_EN 0
+#define CMD_READ 0
+#define CMD_WRITE 1
+
+#define INTERNAL_ACCESS_PORT 1
+#define EXECUTING 1
+#define ACCESS_EXT 1
+#define CS2_EXIST_BIT 2
+#define TRAINING_ID 0xf
+#define EXT_TRAINING_ID 1
+#define EXT_MODE 0x4
+
+#define GET_RESULT_STATE(res) (res)
+#define SET_RESULT_STATE(res, state) (res = state)
+
+#define _1K 0x00000400
+#define _4K 0x00001000
+#define _8K 0x00002000
+#define _16K 0x00004000
+#define _32K 0x00008000
+#define _64K 0x00010000
+#define _128K 0x00020000
+#define _256K 0x00040000
+#define _512K 0x00080000
+
+#define _1M 0x00100000
+#define _2M 0x00200000
+#define _4M 0x00400000
+#define _8M 0x00800000
+#define _16M 0x01000000
+#define _32M 0x02000000
+#define _64M 0x04000000
+#define _128M 0x08000000
+#define _256M 0x10000000
+#define _512M 0x20000000
+
+#define _1G 0x40000000
+#define _2G 0x80000000
+
+#define ADDR_SIZE_512MB 0x04000000
+#define ADDR_SIZE_1GB 0x08000000
+#define ADDR_SIZE_2GB 0x10000000
+#define ADDR_SIZE_4GB 0x20000000
+#define ADDR_SIZE_8GB 0x40000000
+
+enum hws_edge_compare {
+ EDGE_PF,
+ EDGE_FP,
+ EDGE_FPF,
+ EDGE_PFP
+};
+
+enum hws_control_element {
+ HWS_CONTROL_ELEMENT_ADLL, /* per bit 1 edge */
+ HWS_CONTROL_ELEMENT_DQ_SKEW,
+ HWS_CONTROL_ELEMENT_DQS_SKEW
+};
+
+enum hws_search_dir {
+ HWS_LOW2HIGH,
+ HWS_HIGH2LOW,
+ HWS_SEARCH_DIR_LIMIT
+};
+
+enum hws_page_size {
+ PAGE_SIZE_1K,
+ PAGE_SIZE_2K
+};
+
+enum hws_operation {
+ OPERATION_READ = 0,
+ OPERATION_WRITE = 1
+};
+
+enum hws_training_ip_stat {
+ HWS_TRAINING_IP_STATUS_FAIL,
+ HWS_TRAINING_IP_STATUS_SUCCESS,
+ HWS_TRAINING_IP_STATUS_TIMEOUT
+};
+
+enum hws_ddr_cs {
+ CS_SINGLE,
+ CS_NON_SINGLE
+};
+
+enum hws_ddr_phy {
+ DDR_PHY_DATA = 0,
+ DDR_PHY_CONTROL = 1
+};
+
+enum hws_dir {
+ OPER_WRITE,
+ OPER_READ,
+ OPER_WRITE_AND_READ
+};
+
+enum hws_wl_supp {
+ PHASE_SHIFT,
+ CLOCK_SHIFT,
+ ALIGN_SHIFT
+};
+
+struct reg_data {
+ u32 reg_addr;
+ u32 reg_data;
+ u32 reg_mask;
+};
+
+#endif /* _DDR3_TRAINING_IP_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c
new file mode 100644
index 0000000000..011824ab42
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c
@@ -0,0 +1,1354 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define PATTERN_1 0x55555555
+#define PATTERN_2 0xaaaaaaaa
+
+#define VALIDATE_TRAINING_LIMIT(e1, e2) \
+ ((((e2) - (e1) + 1) > 33) && ((e1) < 67))
+
+u32 phy_reg_bk[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS];
+
+u32 training_res[MAX_INTERFACE_NUM * MAX_BUS_NUM * BUS_WIDTH_IN_BITS *
+ HWS_SEARCH_DIR_LIMIT];
+
+u16 mask_results_dq_reg_map[] = {
+ RESULT_CONTROL_PUP_0_BIT_0_REG, RESULT_CONTROL_PUP_0_BIT_1_REG,
+ RESULT_CONTROL_PUP_0_BIT_2_REG, RESULT_CONTROL_PUP_0_BIT_3_REG,
+ RESULT_CONTROL_PUP_0_BIT_4_REG, RESULT_CONTROL_PUP_0_BIT_5_REG,
+ RESULT_CONTROL_PUP_0_BIT_6_REG, RESULT_CONTROL_PUP_0_BIT_7_REG,
+ RESULT_CONTROL_PUP_1_BIT_0_REG, RESULT_CONTROL_PUP_1_BIT_1_REG,
+ RESULT_CONTROL_PUP_1_BIT_2_REG, RESULT_CONTROL_PUP_1_BIT_3_REG,
+ RESULT_CONTROL_PUP_1_BIT_4_REG, RESULT_CONTROL_PUP_1_BIT_5_REG,
+ RESULT_CONTROL_PUP_1_BIT_6_REG, RESULT_CONTROL_PUP_1_BIT_7_REG,
+ RESULT_CONTROL_PUP_2_BIT_0_REG, RESULT_CONTROL_PUP_2_BIT_1_REG,
+ RESULT_CONTROL_PUP_2_BIT_2_REG, RESULT_CONTROL_PUP_2_BIT_3_REG,
+ RESULT_CONTROL_PUP_2_BIT_4_REG, RESULT_CONTROL_PUP_2_BIT_5_REG,
+ RESULT_CONTROL_PUP_2_BIT_6_REG, RESULT_CONTROL_PUP_2_BIT_7_REG,
+ RESULT_CONTROL_PUP_3_BIT_0_REG, RESULT_CONTROL_PUP_3_BIT_1_REG,
+ RESULT_CONTROL_PUP_3_BIT_2_REG, RESULT_CONTROL_PUP_3_BIT_3_REG,
+ RESULT_CONTROL_PUP_3_BIT_4_REG, RESULT_CONTROL_PUP_3_BIT_5_REG,
+ RESULT_CONTROL_PUP_3_BIT_6_REG, RESULT_CONTROL_PUP_3_BIT_7_REG,
+ RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG,
+ RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG,
+ RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG,
+ RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG,
+};
+
+u16 mask_results_pup_reg_map[] = {
+ RESULT_CONTROL_BYTE_PUP_0_REG, RESULT_CONTROL_BYTE_PUP_1_REG,
+ RESULT_CONTROL_BYTE_PUP_2_REG, RESULT_CONTROL_BYTE_PUP_3_REG,
+ RESULT_CONTROL_BYTE_PUP_4_REG
+};
+
+u16 mask_results_dq_reg_map_pup3_ecc[] = {
+ RESULT_CONTROL_PUP_0_BIT_0_REG, RESULT_CONTROL_PUP_0_BIT_1_REG,
+ RESULT_CONTROL_PUP_0_BIT_2_REG, RESULT_CONTROL_PUP_0_BIT_3_REG,
+ RESULT_CONTROL_PUP_0_BIT_4_REG, RESULT_CONTROL_PUP_0_BIT_5_REG,
+ RESULT_CONTROL_PUP_0_BIT_6_REG, RESULT_CONTROL_PUP_0_BIT_7_REG,
+ RESULT_CONTROL_PUP_1_BIT_0_REG, RESULT_CONTROL_PUP_1_BIT_1_REG,
+ RESULT_CONTROL_PUP_1_BIT_2_REG, RESULT_CONTROL_PUP_1_BIT_3_REG,
+ RESULT_CONTROL_PUP_1_BIT_4_REG, RESULT_CONTROL_PUP_1_BIT_5_REG,
+ RESULT_CONTROL_PUP_1_BIT_6_REG, RESULT_CONTROL_PUP_1_BIT_7_REG,
+ RESULT_CONTROL_PUP_2_BIT_0_REG, RESULT_CONTROL_PUP_2_BIT_1_REG,
+ RESULT_CONTROL_PUP_2_BIT_2_REG, RESULT_CONTROL_PUP_2_BIT_3_REG,
+ RESULT_CONTROL_PUP_2_BIT_4_REG, RESULT_CONTROL_PUP_2_BIT_5_REG,
+ RESULT_CONTROL_PUP_2_BIT_6_REG, RESULT_CONTROL_PUP_2_BIT_7_REG,
+ RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG,
+ RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG,
+ RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG,
+ RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG,
+ RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG,
+ RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG,
+ RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG,
+ RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG,
+};
+
+u16 mask_results_pup_reg_map_pup3_ecc[] = {
+ RESULT_CONTROL_BYTE_PUP_0_REG, RESULT_CONTROL_BYTE_PUP_1_REG,
+ RESULT_CONTROL_BYTE_PUP_2_REG, RESULT_CONTROL_BYTE_PUP_4_REG,
+ RESULT_CONTROL_BYTE_PUP_4_REG
+};
+
+struct pattern_info pattern_table_16[] = {
+ /*
+ * num tx phases, tx burst, delay between, rx pattern,
+ * start_address, pattern_len
+ */
+ {1, 1, 2, 1, 0x0080, 2}, /* PATTERN_PBS1 */
+ {1, 1, 2, 1, 0x00c0, 2}, /* PATTERN_PBS2 */
+ {1, 1, 2, 1, 0x0100, 2}, /* PATTERN_RL */
+ {0xf, 0x7, 2, 0x7, 0x0140, 16}, /* PATTERN_STATIC_PBS */
+ {0xf, 0x7, 2, 0x7, 0x0190, 16}, /* PATTERN_KILLER_DQ0 */
+ {0xf, 0x7, 2, 0x7, 0x01d0, 16}, /* PATTERN_KILLER_DQ1 */
+ {0xf, 0x7, 2, 0x7, 0x0210, 16}, /* PATTERN_KILLER_DQ2 */
+ {0xf, 0x7, 2, 0x7, 0x0250, 16}, /* PATTERN_KILLER_DQ3 */
+ {0xf, 0x7, 2, 0x7, 0x0290, 16}, /* PATTERN_KILLER_DQ4 */
+ {0xf, 0x7, 2, 0x7, 0x02d0, 16}, /* PATTERN_KILLER_DQ5 */
+ {0xf, 0x7, 2, 0x7, 0x0310, 16}, /* PATTERN_KILLER_DQ6 */
+ {0xf, 0x7, 2, 0x7, 0x0350, 16}, /* PATTERN_KILLER_DQ7 */
+ {1, 1, 2, 1, 0x0380, 2}, /* PATTERN_PBS3 */
+ {1, 1, 2, 1, 0x0000, 2}, /* PATTERN_RL2 */
+ {1, 1, 2, 1, 0x0040, 2}, /* PATTERN_TEST */
+ {0xf, 0x7, 2, 0x7, 0x03c0, 16}, /* PATTERN_FULL_SSO_1T */
+ {0xf, 0x7, 2, 0x7, 0x0400, 16}, /* PATTERN_FULL_SSO_2T */
+ {0xf, 0x7, 2, 0x7, 0x0440, 16}, /* PATTERN_FULL_SSO_3T */
+ {0xf, 0x7, 2, 0x7, 0x0480, 16}, /* PATTERN_FULL_SSO_4T */
+ {0xf, 0x7, 2, 0x7, 0x04c0, 16} /* PATTERN_VREF */
+ /*Note: actual start_address is <<3 of defined addess */
+};
+
+struct pattern_info pattern_table_32[] = {
+ /*
+ * num tx phases, tx burst, delay between, rx pattern,
+ * start_address, pattern_len
+ */
+ {3, 3, 2, 3, 0x0080, 4}, /* PATTERN_PBS1 */
+ {3, 3, 2, 3, 0x00c0, 4}, /* PATTERN_PBS2 */
+ {3, 3, 2, 3, 0x0100, 4}, /* PATTERN_RL */
+ {0x1f, 0xf, 2, 0xf, 0x0140, 32}, /* PATTERN_STATIC_PBS */
+ {0x1f, 0xf, 2, 0xf, 0x0190, 32}, /* PATTERN_KILLER_DQ0 */
+ {0x1f, 0xf, 2, 0xf, 0x01d0, 32}, /* PATTERN_KILLER_DQ1 */
+ {0x1f, 0xf, 2, 0xf, 0x0210, 32}, /* PATTERN_KILLER_DQ2 */
+ {0x1f, 0xf, 2, 0xf, 0x0250, 32}, /* PATTERN_KILLER_DQ3 */
+ {0x1f, 0xf, 2, 0xf, 0x0290, 32}, /* PATTERN_KILLER_DQ4 */
+ {0x1f, 0xf, 2, 0xf, 0x02d0, 32}, /* PATTERN_KILLER_DQ5 */
+ {0x1f, 0xf, 2, 0xf, 0x0310, 32}, /* PATTERN_KILLER_DQ6 */
+ {0x1f, 0xf, 2, 0xf, 0x0350, 32}, /* PATTERN_KILLER_DQ7 */
+ {3, 3, 2, 3, 0x0380, 4}, /* PATTERN_PBS3 */
+ {3, 3, 2, 3, 0x0000, 4}, /* PATTERN_RL2 */
+ {3, 3, 2, 3, 0x0040, 4}, /* PATTERN_TEST */
+ {0x1f, 0xf, 2, 0xf, 0x03c0, 32}, /* PATTERN_FULL_SSO_1T */
+ {0x1f, 0xf, 2, 0xf, 0x0400, 32}, /* PATTERN_FULL_SSO_2T */
+ {0x1f, 0xf, 2, 0xf, 0x0440, 32}, /* PATTERN_FULL_SSO_3T */
+ {0x1f, 0xf, 2, 0xf, 0x0480, 32}, /* PATTERN_FULL_SSO_4T */
+ {0x1f, 0xf, 2, 0xf, 0x04c0, 32} /* PATTERN_VREF */
+ /*Note: actual start_address is <<3 of defined addess */
+};
+
+u32 train_dev_num;
+enum hws_ddr_cs traintrain_cs_type;
+u32 train_pup_num;
+enum hws_training_result train_result_type;
+enum hws_control_element train_control_element;
+enum hws_search_dir traine_search_dir;
+enum hws_dir train_direction;
+u32 train_if_select;
+u32 train_init_value;
+u32 train_number_iterations;
+enum hws_pattern train_pattern;
+enum hws_edge_compare train_edge_compare;
+u32 train_cs_num;
+u32 train_if_acess, train_if_id, train_pup_access;
+u32 max_polling_for_done = 1000000;
+
+u32 *ddr3_tip_get_buf_ptr(u32 dev_num, enum hws_search_dir search,
+ enum hws_training_result result_type,
+ u32 interface_num)
+{
+ u32 *buf_ptr = NULL;
+
+ buf_ptr = &training_res
+ [MAX_INTERFACE_NUM * MAX_BUS_NUM * BUS_WIDTH_IN_BITS * search +
+ interface_num * MAX_BUS_NUM * BUS_WIDTH_IN_BITS];
+
+ return buf_ptr;
+}
+
+/*
+ * IP Training search
+ * Note: for one edge search only from fail to pass, else jitter can
+ * be be entered into solution.
+ */
+int ddr3_tip_ip_training(u32 dev_num, enum hws_access_type access_type,
+ u32 interface_num,
+ enum hws_access_type pup_access_type,
+ u32 pup_num, enum hws_training_result result_type,
+ enum hws_control_element control_element,
+ enum hws_search_dir search_dir, enum hws_dir direction,
+ u32 interface_mask, u32 init_value, u32 num_iter,
+ enum hws_pattern pattern,
+ enum hws_edge_compare edge_comp,
+ enum hws_ddr_cs cs_type, u32 cs_num,
+ enum hws_training_ip_stat *train_status)
+{
+ u32 mask_dq_num_of_regs, mask_pup_num_of_regs, index_cnt, poll_cnt,
+ reg_data, pup_id;
+ u32 tx_burst_size;
+ u32 delay_between_burst;
+ u32 rd_mode;
+ u32 read_data[MAX_INTERFACE_NUM];
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (pup_num >= tm->num_of_bus_per_interface) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("pup_num %d not valid\n", pup_num));
+ }
+ if (interface_num >= MAX_INTERFACE_NUM) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("if_id %d not valid\n",
+ interface_num));
+ }
+ if (train_status == NULL) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("error param 4\n"));
+ return MV_BAD_PARAM;
+ }
+
+ /* load pattern */
+ if (cs_type == CS_SINGLE) {
+ /* All CSs to CS0 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ CS_ENABLE_REG, 1 << 3, 1 << 3));
+ /* All CSs to CS0 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ ODPG_DATA_CONTROL_REG,
+ (0x3 | (effective_cs << 26)), 0xc000003));
+ } else {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ CS_ENABLE_REG, 0, 1 << 3));
+ /* CS select */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ ODPG_DATA_CONTROL_REG, 0x3 | cs_num << 26,
+ 0x3 | 3 << 26));
+ }
+
+ /* load pattern to ODPG */
+ ddr3_tip_load_pattern_to_odpg(dev_num, access_type, interface_num,
+ pattern,
+ pattern_table[pattern].start_addr);
+ tx_burst_size = (direction == OPER_WRITE) ?
+ pattern_table[pattern].tx_burst_size : 0;
+ delay_between_burst = (direction == OPER_WRITE) ? 2 : 0;
+ rd_mode = (direction == OPER_WRITE) ? 1 : 0;
+ CHECK_STATUS(ddr3_tip_configure_odpg
+ (dev_num, access_type, interface_num, direction,
+ pattern_table[pattern].num_of_phases_tx, tx_burst_size,
+ pattern_table[pattern].num_of_phases_rx,
+ delay_between_burst, rd_mode, effective_cs, STRESS_NONE,
+ DURATION_SINGLE));
+ reg_data = (direction == OPER_READ) ? 0 : (0x3 << 30);
+ reg_data |= (direction == OPER_READ) ? 0x60 : 0xfa;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ ODPG_WRITE_READ_MODE_ENABLE_REG, reg_data,
+ MASK_ALL_BITS));
+ reg_data = (edge_comp == EDGE_PF || edge_comp == EDGE_FP) ? 0 : 1 << 6;
+ reg_data |= (edge_comp == EDGE_PF || edge_comp == EDGE_PFP) ?
+ (1 << 7) : 0;
+
+ /* change from Pass to Fail will lock the result */
+ if (pup_access_type == ACCESS_TYPE_MULTICAST)
+ reg_data |= 0xe << 14;
+ else
+ reg_data |= pup_num << 14;
+
+ if (edge_comp == EDGE_FP) {
+ /* don't search for readl edge change, only the state */
+ reg_data |= (0 << 20);
+ } else if (edge_comp == EDGE_FPF) {
+ reg_data |= (0 << 20);
+ } else {
+ reg_data |= (3 << 20);
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ ODPG_TRAINING_CONTROL_REG,
+ reg_data | (0x7 << 8) | (0x7 << 11),
+ (0x3 | (0x3 << 2) | (0x3 << 6) | (1 << 5) | (0x7 << 8) |
+ (0x7 << 11) | (0xf << 14) | (0x3 << 18) | (3 << 20))));
+ reg_data = (search_dir == HWS_LOW2HIGH) ? 0 : (1 << 8);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num, ODPG_OBJ1_OPCODE_REG,
+ 1 | reg_data | init_value << 9 | (1 << 25) | (1 << 26),
+ 0xff | (1 << 8) | (0xffff << 9) | (1 << 25) | (1 << 26)));
+
+ /*
+ * Write2_dunit(0x10b4, Number_iteration , [15:0])
+ * Max number of iterations
+ */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, interface_num,
+ ODPG_OBJ1_ITER_CNT_REG, num_iter,
+ 0xffff));
+ if (control_element == HWS_CONTROL_ELEMENT_DQ_SKEW &&
+ direction == OPER_READ) {
+ /*
+ * Write2_dunit(0x10c0, 0x5f , [7:0])
+ * MC PBS Reg Address at DDR PHY
+ */
+ reg_data = 0x5f +
+ effective_cs * CALIBRATED_OBJECTS_REG_ADDR_OFFSET;
+ } else if (control_element == HWS_CONTROL_ELEMENT_DQ_SKEW &&
+ direction == OPER_WRITE) {
+ reg_data = 0x1f +
+ effective_cs * CALIBRATED_OBJECTS_REG_ADDR_OFFSET;
+ } else if (control_element == HWS_CONTROL_ELEMENT_ADLL &&
+ direction == OPER_WRITE) {
+ /*
+ * LOOP 0x00000001 + 4*n:
+ * where n (0-3) represents M_CS number
+ */
+ /*
+ * Write2_dunit(0x10c0, 0x1 , [7:0])
+ * ADLL WR Reg Address at DDR PHY
+ */
+ reg_data = 1 + effective_cs * CS_REGISTER_ADDR_OFFSET;
+ } else if (control_element == HWS_CONTROL_ELEMENT_ADLL &&
+ direction == OPER_READ) {
+ /* ADLL RD Reg Address at DDR PHY */
+ reg_data = 3 + effective_cs * CS_REGISTER_ADDR_OFFSET;
+ } else if (control_element == HWS_CONTROL_ELEMENT_DQS_SKEW &&
+ direction == OPER_WRITE) {
+ /* TBD not defined in 0.5.0 requirement */
+ } else if (control_element == HWS_CONTROL_ELEMENT_DQS_SKEW &&
+ direction == OPER_READ) {
+ /* TBD not defined in 0.5.0 requirement */
+ }
+
+ reg_data |= (0x6 << 28);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num, CALIB_OBJ_PRFA_REG,
+ reg_data | (init_value << 8),
+ 0xff | (0xffff << 8) | (0xf << 24) | (u32) (0xf << 28)));
+
+ mask_dq_num_of_regs = tm->num_of_bus_per_interface * BUS_WIDTH_IN_BITS;
+ mask_pup_num_of_regs = tm->num_of_bus_per_interface;
+
+ if (result_type == RESULT_PER_BIT) {
+ for (index_cnt = 0; index_cnt < mask_dq_num_of_regs;
+ index_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ mask_results_dq_reg_map[index_cnt], 0,
+ 1 << 24));
+ }
+
+ /* Mask disabled buses */
+ for (pup_id = 0; pup_id < tm->num_of_bus_per_interface;
+ pup_id++) {
+ if (IS_ACTIVE(tm->bus_act_mask, pup_id) == 1)
+ continue;
+
+ for (index_cnt = (mask_dq_num_of_regs - pup_id * 8);
+ index_cnt <
+ (mask_dq_num_of_regs - (pup_id + 1) * 8);
+ index_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type,
+ interface_num,
+ mask_results_dq_reg_map
+ [index_cnt], (1 << 24), 1 << 24));
+ }
+ }
+
+ for (index_cnt = 0; index_cnt < mask_pup_num_of_regs;
+ index_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ mask_results_pup_reg_map[index_cnt],
+ (1 << 24), 1 << 24));
+ }
+ } else if (result_type == RESULT_PER_BYTE) {
+ /* write to adll */
+ for (index_cnt = 0; index_cnt < mask_pup_num_of_regs;
+ index_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ mask_results_pup_reg_map[index_cnt], 0,
+ 1 << 24));
+ }
+ for (index_cnt = 0; index_cnt < mask_dq_num_of_regs;
+ index_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, interface_num,
+ mask_results_dq_reg_map[index_cnt],
+ (1 << 24), (1 << 24)));
+ }
+ }
+
+ /* Start Training Trigger */
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, interface_num,
+ ODPG_TRAINING_TRIGGER_REG, 1, 1));
+ /* wait for all RFU tests to finish (or timeout) */
+ /* WA for 16 bit mode, more investigation needed */
+ mdelay(1);
+
+ /* Training "Done ?" */
+ for (index_cnt = 0; index_cnt < MAX_INTERFACE_NUM; index_cnt++) {
+ if (IS_ACTIVE(tm->if_act_mask, index_cnt) == 0)
+ continue;
+
+ if (interface_mask & (1 << index_cnt)) {
+ /* need to check results for this Dunit */
+ for (poll_cnt = 0; poll_cnt < max_polling_for_done;
+ poll_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ index_cnt,
+ ODPG_TRAINING_STATUS_REG,
+ &reg_data, MASK_ALL_BITS));
+ if ((reg_data & 0x2) != 0) {
+ /*done */
+ train_status[index_cnt] =
+ HWS_TRAINING_IP_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ if (poll_cnt == max_polling_for_done) {
+ train_status[index_cnt] =
+ HWS_TRAINING_IP_STATUS_TIMEOUT;
+ }
+ }
+ /* Be sure that ODPG done */
+ CHECK_STATUS(is_odpg_access_done(dev_num, index_cnt));
+ }
+
+ /* Write ODPG done in Dunit */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_STATUS_DONE_REG, 0, 0x1));
+
+ /* wait for all Dunit tests to finish (or timeout) */
+ /* Training "Done ?" */
+ /* Training "Pass ?" */
+ for (index_cnt = 0; index_cnt < MAX_INTERFACE_NUM; index_cnt++) {
+ if (IS_ACTIVE(tm->if_act_mask, index_cnt) == 0)
+ continue;
+
+ if (interface_mask & (1 << index_cnt)) {
+ /* need to check results for this Dunit */
+ for (poll_cnt = 0; poll_cnt < max_polling_for_done;
+ poll_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ index_cnt,
+ ODPG_TRAINING_TRIGGER_REG,
+ read_data, MASK_ALL_BITS));
+ reg_data = read_data[index_cnt];
+ if ((reg_data & 0x2) != 0) {
+ /* done */
+ if ((reg_data & 0x4) == 0) {
+ train_status[index_cnt] =
+ HWS_TRAINING_IP_STATUS_SUCCESS;
+ } else {
+ train_status[index_cnt] =
+ HWS_TRAINING_IP_STATUS_FAIL;
+ }
+ break;
+ }
+ }
+
+ if (poll_cnt == max_polling_for_done) {
+ train_status[index_cnt] =
+ HWS_TRAINING_IP_STATUS_TIMEOUT;
+ }
+ }
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+ return MV_OK;
+}
+
+/*
+ * Load expected Pattern to ODPG
+ */
+int ddr3_tip_load_pattern_to_odpg(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_pattern pattern,
+ u32 load_addr)
+{
+ u32 pattern_length_cnt = 0;
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+
+ for (pattern_length_cnt = 0;
+ pattern_length_cnt < pattern_table[pattern].pattern_len;
+ pattern_length_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ ODPG_PATTERN_DATA_LOW_REG,
+ pattern_table_get_word(dev_num, pattern,
+ (u8) (pattern_length_cnt *
+ 2)), MASK_ALL_BITS));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ ODPG_PATTERN_DATA_HI_REG,
+ pattern_table_get_word(dev_num, pattern,
+ (u8) (pattern_length_cnt *
+ 2 + 1)),
+ MASK_ALL_BITS));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ ODPG_PATTERN_ADDR_REG, pattern_length_cnt,
+ MASK_ALL_BITS));
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ ODPG_PATTERN_ADDR_OFFSET_REG, load_addr, MASK_ALL_BITS));
+
+ return MV_OK;
+}
+
+/*
+ * Configure ODPG
+ */
+int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_dir direction, u32 tx_phases,
+ u32 tx_burst_size, u32 rx_phases,
+ u32 delay_between_burst, u32 rd_mode, u32 cs_num,
+ u32 addr_stress_jump, u32 single_pattern)
+{
+ u32 data_value = 0;
+ int ret;
+
+ data_value = ((single_pattern << 2) | (tx_phases << 5) |
+ (tx_burst_size << 11) | (delay_between_burst << 15) |
+ (rx_phases << 21) | (rd_mode << 25) | (cs_num << 26) |
+ (addr_stress_jump << 29));
+ ret = ddr3_tip_if_write(dev_num, access_type, if_id,
+ ODPG_DATA_CONTROL_REG, data_value, 0xaffffffc);
+ if (ret != MV_OK)
+ return ret;
+
+ return MV_OK;
+}
+
+int ddr3_tip_process_result(u32 *ar_result, enum hws_edge e_edge,
+ enum hws_edge_search e_edge_search,
+ u32 *edge_result)
+{
+ u32 i, res;
+ int tap_val, max_val = -10000, min_val = 10000;
+ int lock_success = 1;
+
+ for (i = 0; i < BUS_WIDTH_IN_BITS; i++) {
+ res = GET_LOCK_RESULT(ar_result[i]);
+ if (res == 0) {
+ lock_success = 0;
+ break;
+ }
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("lock failed for bit %d\n", i));
+ }
+
+ if (lock_success == 1) {
+ for (i = 0; i < BUS_WIDTH_IN_BITS; i++) {
+ tap_val = GET_TAP_RESULT(ar_result[i], e_edge);
+ if (tap_val > max_val)
+ max_val = tap_val;
+ if (tap_val < min_val)
+ min_val = tap_val;
+ if (e_edge_search == TRAINING_EDGE_MAX)
+ *edge_result = (u32) max_val;
+ else
+ *edge_result = (u32) min_val;
+
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("i %d ar_result[i] 0x%x tap_val %d max_val %d min_val %d Edge_result %d\n",
+ i, ar_result[i], tap_val,
+ max_val, min_val,
+ *edge_result));
+ }
+ } else {
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Read training search result
+ */
+int ddr3_tip_read_training_result(u32 dev_num, u32 if_id,
+ enum hws_access_type pup_access_type,
+ u32 pup_num, u32 bit_num,
+ enum hws_search_dir search,
+ enum hws_dir direction,
+ enum hws_training_result result_type,
+ enum hws_training_load_op operation,
+ u32 cs_num_type, u32 **load_res,
+ int is_read_from_db, u8 cons_tap,
+ int is_check_result_validity)
+{
+ u32 reg_offset, pup_cnt, start_pup, end_pup, start_reg, end_reg;
+ u32 *interface_train_res = NULL;
+ u16 *reg_addr = NULL;
+ u32 read_data[MAX_INTERFACE_NUM];
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * Agreed assumption: all CS mask contain same number of bits,
+ * i.e. in multi CS, the number of CS per memory is the same for
+ * all pups
+ */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, CS_ENABLE_REG,
+ (cs_num_type == 0) ? 1 << 3 : 0, (1 << 3)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_DATA_CONTROL_REG, (cs_num_type << 26), (3 << 26)));
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_TRACE,
+ ("Read_from_d_b %d cs_type %d oper %d result_type %d direction %d search %d pup_num %d if_id %d pup_access_type %d\n",
+ is_read_from_db, cs_num_type, operation,
+ result_type, direction, search, pup_num,
+ if_id, pup_access_type));
+
+ if ((load_res == NULL) && (is_read_from_db == 1)) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("ddr3_tip_read_training_result load_res = NULL"));
+ return MV_FAIL;
+ }
+ if (pup_num >= tm->num_of_bus_per_interface) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("pup_num %d not valid\n", pup_num));
+ }
+ if (if_id >= MAX_INTERFACE_NUM) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("if_id %d not valid\n", if_id));
+ }
+ if (result_type == RESULT_PER_BIT)
+ reg_addr = mask_results_dq_reg_map;
+ else
+ reg_addr = mask_results_pup_reg_map;
+ if (pup_access_type == ACCESS_TYPE_UNICAST) {
+ start_pup = pup_num;
+ end_pup = pup_num;
+ } else { /*pup_access_type == ACCESS_TYPE_MULTICAST) */
+
+ start_pup = 0;
+ end_pup = tm->num_of_bus_per_interface - 1;
+ }
+
+ for (pup_cnt = start_pup; pup_cnt <= end_pup; pup_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup_cnt);
+ DEBUG_TRAINING_IP_ENGINE(
+ DEBUG_LEVEL_TRACE,
+ ("if_id %d start_pup %d end_pup %d pup_cnt %d\n",
+ if_id, start_pup, end_pup, pup_cnt));
+ if (result_type == RESULT_PER_BIT) {
+ if (bit_num == ALL_BITS_PER_PUP) {
+ start_reg = pup_cnt * BUS_WIDTH_IN_BITS;
+ end_reg = (pup_cnt + 1) * BUS_WIDTH_IN_BITS - 1;
+ } else {
+ start_reg =
+ pup_cnt * BUS_WIDTH_IN_BITS + bit_num;
+ end_reg = pup_cnt * BUS_WIDTH_IN_BITS + bit_num;
+ }
+ } else {
+ start_reg = pup_cnt;
+ end_reg = pup_cnt;
+ }
+
+ interface_train_res =
+ ddr3_tip_get_buf_ptr(dev_num, search, result_type,
+ if_id);
+ DEBUG_TRAINING_IP_ENGINE(
+ DEBUG_LEVEL_TRACE,
+ ("start_reg %d end_reg %d interface %p\n",
+ start_reg, end_reg, interface_train_res));
+ if (interface_train_res == NULL) {
+ DEBUG_TRAINING_IP_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("interface_train_res is NULL\n"));
+ return MV_FAIL;
+ }
+
+ for (reg_offset = start_reg; reg_offset <= end_reg;
+ reg_offset++) {
+ if (operation == TRAINING_LOAD_OPERATION_UNLOAD) {
+ if (is_read_from_db == 0) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ reg_addr[reg_offset],
+ read_data,
+ MASK_ALL_BITS));
+ if (is_check_result_validity == 1) {
+ if ((read_data[if_id] &
+ 0x02000000) == 0) {
+ interface_train_res
+ [reg_offset] =
+ 0x02000000 +
+ 64 + cons_tap;
+ } else {
+ interface_train_res
+ [reg_offset] =
+ read_data
+ [if_id] +
+ cons_tap;
+ }
+ } else {
+ interface_train_res[reg_offset]
+ = read_data[if_id] +
+ cons_tap;
+ }
+ DEBUG_TRAINING_IP_ENGINE
+ (DEBUG_LEVEL_TRACE,
+ ("reg_offset %d value 0x%x addr %p\n",
+ reg_offset,
+ interface_train_res
+ [reg_offset],
+ &interface_train_res
+ [reg_offset]));
+ } else {
+ *load_res =
+ &interface_train_res[start_reg];
+ DEBUG_TRAINING_IP_ENGINE
+ (DEBUG_LEVEL_TRACE,
+ ("*load_res %p\n", *load_res));
+ }
+ } else {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_TRACE,
+ ("not supported\n"));
+ }
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Load all pattern to memory using ODPG
+ */
+int ddr3_tip_load_all_pattern_to_mem(u32 dev_num)
+{
+ u32 pattern = 0, if_id;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* enable single cs */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, (1 << 3), (1 << 3)));
+ }
+
+ for (pattern = 0; pattern < PATTERN_LIMIT; pattern++)
+ ddr3_tip_load_pattern_to_mem(dev_num, pattern);
+
+ return MV_OK;
+}
+
+/*
+ * Wait till ODPG access is ready
+ */
+int is_odpg_access_done(u32 dev_num, u32 if_id)
+{
+ u32 poll_cnt = 0, data_value;
+ u32 read_data[MAX_INTERFACE_NUM];
+
+ for (poll_cnt = 0; poll_cnt < MAX_POLLING_ITERATIONS; poll_cnt++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_BIST_DONE, read_data, MASK_ALL_BITS));
+ data_value = read_data[if_id];
+ if (((data_value >> ODPG_BIST_DONE_BIT_OFFS) & 0x1) ==
+ ODPG_BIST_DONE_BIT_VALUE) {
+ data_value = data_value & 0xfffffffe;
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ODPG_BIST_DONE, data_value,
+ MASK_ALL_BITS));
+ break;
+ }
+ }
+
+ if (poll_cnt >= MAX_POLLING_ITERATIONS) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("Bist Activate: poll failure 2\n"));
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Load specific pattern to memory using ODPG
+ */
+int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern pattern)
+{
+ u32 reg_data, if_id;
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* load pattern to memory */
+ /*
+ * Write Tx mode, CS0, phases, Tx burst size, delay between burst,
+ * rx pattern phases
+ */
+ reg_data =
+ 0x1 | (pattern_table[pattern].num_of_phases_tx << 5) |
+ (pattern_table[pattern].tx_burst_size << 11) |
+ (pattern_table[pattern].delay_between_bursts << 15) |
+ (pattern_table[pattern].num_of_phases_rx << 21) | (0x1 << 25) |
+ (effective_cs << 26);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, reg_data, MASK_ALL_BITS));
+ /* ODPG Write enable from BIST */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, (0x1 | (effective_cs << 26)),
+ 0xc000003));
+ /* disable error injection */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_WRITE_DATA_ERROR_REG, 0, 0x1));
+ /* load pattern to ODPG */
+ ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, pattern,
+ pattern_table[pattern].start_addr);
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+ continue;
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1498,
+ 0x3, 0xf));
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_ENABLE_REG, 0x1 << ODPG_ENABLE_OFFS,
+ (0x1 << ODPG_ENABLE_OFFS)));
+
+ mdelay(1);
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(is_odpg_access_done(dev_num, if_id));
+ }
+
+ /* Disable ODPG and stop write to memory */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, (0x1 << 30), (u32) (0x3 << 30)));
+
+ /* return to default */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+ /* Disable odt0 for CS0 training - need to adjust for multy CS */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x1498,
+ 0x0, 0xf));
+
+ /* temporary added */
+ mdelay(1);
+
+ return MV_OK;
+}
+
+/*
+ * Load specific pattern to memory using CPU
+ */
+int ddr3_tip_load_pattern_to_mem_by_cpu(u32 dev_num, enum hws_pattern pattern,
+ u32 offset)
+{
+ /* eranba - TBD */
+ return MV_OK;
+}
+
+/*
+ * Training search routine
+ */
+int ddr3_tip_ip_training_wrapper_int(u32 dev_num,
+ enum hws_access_type access_type,
+ u32 if_id,
+ enum hws_access_type pup_access_type,
+ u32 pup_num, u32 bit_num,
+ enum hws_training_result result_type,
+ enum hws_control_element control_element,
+ enum hws_search_dir search_dir,
+ enum hws_dir direction,
+ u32 interface_mask, u32 init_value_l2h,
+ u32 init_value_h2l, u32 num_iter,
+ enum hws_pattern pattern,
+ enum hws_edge_compare edge_comp,
+ enum hws_ddr_cs train_cs_type, u32 cs_num,
+ enum hws_training_ip_stat *train_status)
+{
+ u32 interface_num = 0, start_if, end_if, init_value_used;
+ enum hws_search_dir search_dir_id, start_search, end_search;
+ enum hws_edge_compare edge_comp_used;
+ u8 cons_tap = (direction == OPER_WRITE) ? (64) : (0);
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (train_status == NULL) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("train_status is NULL\n"));
+ return MV_FAIL;
+ }
+
+ if ((train_cs_type > CS_NON_SINGLE) ||
+ (edge_comp >= EDGE_PFP) ||
+ (pattern >= PATTERN_LIMIT) ||
+ (direction > OPER_WRITE_AND_READ) ||
+ (search_dir > HWS_HIGH2LOW) ||
+ (control_element > HWS_CONTROL_ELEMENT_DQS_SKEW) ||
+ (result_type > RESULT_PER_BYTE) ||
+ (pup_num >= tm->num_of_bus_per_interface) ||
+ (pup_access_type > ACCESS_TYPE_MULTICAST) ||
+ (if_id > 11) || (access_type > ACCESS_TYPE_MULTICAST)) {
+ DEBUG_TRAINING_IP_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("wrong parameter train_cs_type %d edge_comp %d pattern %d direction %d search_dir %d control_element %d result_type %d pup_num %d pup_access_type %d if_id %d access_type %d\n",
+ train_cs_type, edge_comp, pattern, direction,
+ search_dir, control_element, result_type, pup_num,
+ pup_access_type, if_id, access_type));
+ return MV_FAIL;
+ }
+
+ if (edge_comp == EDGE_FPF) {
+ start_search = HWS_LOW2HIGH;
+ end_search = HWS_HIGH2LOW;
+ edge_comp_used = EDGE_FP;
+ } else {
+ start_search = search_dir;
+ end_search = search_dir;
+ edge_comp_used = edge_comp;
+ }
+
+ for (search_dir_id = start_search; search_dir_id <= end_search;
+ search_dir_id++) {
+ init_value_used = (search_dir_id == HWS_LOW2HIGH) ?
+ init_value_l2h : init_value_h2l;
+ DEBUG_TRAINING_IP_ENGINE(
+ DEBUG_LEVEL_TRACE,
+ ("dev_num %d, access_type %d, if_id %d, pup_access_type %d,pup_num %d, result_type %d, control_element %d search_dir_id %d, direction %d, interface_mask %d,init_value_used %d, num_iter %d, pattern %d, edge_comp_used %d, train_cs_type %d, cs_num %d\n",
+ dev_num, access_type, if_id, pup_access_type, pup_num,
+ result_type, control_element, search_dir_id,
+ direction, interface_mask, init_value_used, num_iter,
+ pattern, edge_comp_used, train_cs_type, cs_num));
+
+ ddr3_tip_ip_training(dev_num, access_type, if_id,
+ pup_access_type, pup_num, result_type,
+ control_element, search_dir_id, direction,
+ interface_mask, init_value_used, num_iter,
+ pattern, edge_comp_used, train_cs_type,
+ cs_num, train_status);
+ if (access_type == ACCESS_TYPE_MULTICAST) {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ } else {
+ start_if = if_id;
+ end_if = if_id;
+ }
+
+ for (interface_num = start_if; interface_num <= end_if;
+ interface_num++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, interface_num);
+ cs_num = 0;
+ CHECK_STATUS(ddr3_tip_read_training_result
+ (dev_num, interface_num, pup_access_type,
+ pup_num, bit_num, search_dir_id,
+ direction, result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ train_cs_type, NULL, 0, cons_tap,
+ 0));
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Training search & read result routine
+ */
+int ddr3_tip_ip_training_wrapper(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id,
+ enum hws_access_type pup_access_type,
+ u32 pup_num,
+ enum hws_training_result result_type,
+ enum hws_control_element control_element,
+ enum hws_search_dir search_dir,
+ enum hws_dir direction, u32 interface_mask,
+ u32 init_value_l2h, u32 init_value_h2l,
+ u32 num_iter, enum hws_pattern pattern,
+ enum hws_edge_compare edge_comp,
+ enum hws_ddr_cs train_cs_type, u32 cs_num,
+ enum hws_training_ip_stat *train_status)
+{
+ u8 e1, e2;
+ u32 interface_cnt, bit_id, start_if, end_if, bit_end = 0;
+ u32 *result[HWS_SEARCH_DIR_LIMIT] = { 0 };
+ u8 cons_tap = (direction == OPER_WRITE) ? (64) : (0);
+ u8 bit_bit_mask[MAX_BUS_NUM] = { 0 }, bit_bit_mask_active = 0;
+ u8 pup_id;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (pup_num >= tm->num_of_bus_per_interface) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("pup_num %d not valid\n", pup_num));
+ }
+
+ if (if_id >= MAX_INTERFACE_NUM) {
+ DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+ ("if_id %d not valid\n", if_id));
+ }
+
+ CHECK_STATUS(ddr3_tip_ip_training_wrapper_int
+ (dev_num, access_type, if_id, pup_access_type, pup_num,
+ ALL_BITS_PER_PUP, result_type, control_element,
+ search_dir, direction, interface_mask, init_value_l2h,
+ init_value_h2l, num_iter, pattern, edge_comp,
+ train_cs_type, cs_num, train_status));
+
+ if (access_type == ACCESS_TYPE_MULTICAST) {
+ start_if = 0;
+ end_if = MAX_INTERFACE_NUM - 1;
+ } else {
+ start_if = if_id;
+ end_if = if_id;
+ }
+
+ for (interface_cnt = start_if; interface_cnt <= end_if;
+ interface_cnt++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, interface_cnt);
+ for (pup_id = 0;
+ pup_id <= (tm->num_of_bus_per_interface - 1); pup_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+ if (result_type == RESULT_PER_BIT)
+ bit_end = BUS_WIDTH_IN_BITS - 1;
+ else
+ bit_end = 0;
+
+ bit_bit_mask[pup_id] = 0;
+ for (bit_id = 0; bit_id <= bit_end; bit_id++) {
+ enum hws_search_dir search_dir_id;
+ for (search_dir_id = HWS_LOW2HIGH;
+ search_dir_id <= HWS_HIGH2LOW;
+ search_dir_id++) {
+ CHECK_STATUS
+ (ddr3_tip_read_training_result
+ (dev_num, interface_cnt,
+ ACCESS_TYPE_UNICAST, pup_id,
+ bit_id, search_dir_id,
+ direction, result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ CS_SINGLE,
+ &result[search_dir_id],
+ 1, 0, 0));
+ }
+ e1 = GET_TAP_RESULT(result[HWS_LOW2HIGH][0],
+ EDGE_1);
+ e2 = GET_TAP_RESULT(result[HWS_HIGH2LOW][0],
+ EDGE_1);
+ DEBUG_TRAINING_IP_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("wrapper if_id %d pup_id %d bit %d l2h 0x%x (e1 0x%x) h2l 0x%x (e2 0x%x)\n",
+ interface_cnt, pup_id, bit_id,
+ result[HWS_LOW2HIGH][0], e1,
+ result[HWS_HIGH2LOW][0], e2));
+ /* TBD validate is valid only for tx */
+ if (VALIDATE_TRAINING_LIMIT(e1, e2) == 1 &&
+ GET_LOCK_RESULT(result[HWS_LOW2HIGH][0]) &&
+ GET_LOCK_RESULT(result[HWS_LOW2HIGH][0])) {
+ /* Mark problem bits */
+ bit_bit_mask[pup_id] |= 1 << bit_id;
+ bit_bit_mask_active = 1;
+ }
+ } /* For all bits */
+ } /* For all PUPs */
+
+ /* Fix problem bits */
+ if (bit_bit_mask_active != 0) {
+ u32 *l2h_if_train_res = NULL;
+ u32 *h2l_if_train_res = NULL;
+ l2h_if_train_res =
+ ddr3_tip_get_buf_ptr(dev_num, HWS_LOW2HIGH,
+ result_type,
+ interface_cnt);
+ h2l_if_train_res =
+ ddr3_tip_get_buf_ptr(dev_num, HWS_HIGH2LOW,
+ result_type,
+ interface_cnt);
+
+ ddr3_tip_ip_training(dev_num, ACCESS_TYPE_UNICAST,
+ interface_cnt,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, result_type,
+ control_element, HWS_LOW2HIGH,
+ direction, interface_mask,
+ num_iter / 2, num_iter / 2,
+ pattern, EDGE_FP, train_cs_type,
+ cs_num, train_status);
+
+ for (pup_id = 0;
+ pup_id <= (tm->num_of_bus_per_interface - 1);
+ pup_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+
+ if (bit_bit_mask[pup_id] == 0)
+ continue;
+
+ for (bit_id = 0; bit_id <= bit_end; bit_id++) {
+ if ((bit_bit_mask[pup_id] &
+ (1 << bit_id)) == 0)
+ continue;
+ CHECK_STATUS
+ (ddr3_tip_read_training_result
+ (dev_num, interface_cnt,
+ ACCESS_TYPE_UNICAST, pup_id,
+ bit_id, HWS_LOW2HIGH,
+ direction,
+ result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ CS_SINGLE, &l2h_if_train_res,
+ 0, 0, 1));
+ }
+ }
+
+ ddr3_tip_ip_training(dev_num, ACCESS_TYPE_UNICAST,
+ interface_cnt,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, result_type,
+ control_element, HWS_HIGH2LOW,
+ direction, interface_mask,
+ num_iter / 2, num_iter / 2,
+ pattern, EDGE_FP, train_cs_type,
+ cs_num, train_status);
+
+ for (pup_id = 0;
+ pup_id <= (tm->num_of_bus_per_interface - 1);
+ pup_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+
+ if (bit_bit_mask[pup_id] == 0)
+ continue;
+
+ for (bit_id = 0; bit_id <= bit_end; bit_id++) {
+ if ((bit_bit_mask[pup_id] &
+ (1 << bit_id)) == 0)
+ continue;
+ CHECK_STATUS
+ (ddr3_tip_read_training_result
+ (dev_num, interface_cnt,
+ ACCESS_TYPE_UNICAST, pup_id,
+ bit_id, HWS_HIGH2LOW, direction,
+ result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ CS_SINGLE, &h2l_if_train_res,
+ 0, cons_tap, 1));
+ }
+ }
+ } /* if bit_bit_mask_active */
+ } /* For all Interfacess */
+
+ return MV_OK;
+}
+
+/*
+ * Load phy values
+ */
+int ddr3_tip_load_phy_values(int b_load)
+{
+ u32 bus_cnt = 0, if_id, dev_num = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ if (b_load == 1) {
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_cnt,
+ DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ (effective_cs *
+ CS_REGISTER_ADDR_OFFSET),
+ &phy_reg_bk[if_id][bus_cnt]
+ [0]));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_cnt,
+ DDR_PHY_DATA,
+ RL_PHY_REG +
+ (effective_cs *
+ CS_REGISTER_ADDR_OFFSET),
+ &phy_reg_bk[if_id][bus_cnt]
+ [1]));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, bus_cnt,
+ DDR_PHY_DATA,
+ READ_CENTRALIZATION_PHY_REG +
+ (effective_cs *
+ CS_REGISTER_ADDR_OFFSET),
+ &phy_reg_bk[if_id][bus_cnt]
+ [2]));
+ } else {
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ (effective_cs *
+ CS_REGISTER_ADDR_OFFSET),
+ phy_reg_bk[if_id][bus_cnt]
+ [0]));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA,
+ RL_PHY_REG +
+ (effective_cs *
+ CS_REGISTER_ADDR_OFFSET),
+ phy_reg_bk[if_id][bus_cnt]
+ [1]));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST,
+ bus_cnt, DDR_PHY_DATA,
+ READ_CENTRALIZATION_PHY_REG +
+ (effective_cs *
+ CS_REGISTER_ADDR_OFFSET),
+ phy_reg_bk[if_id][bus_cnt]
+ [2]));
+ }
+ }
+ }
+
+ return MV_OK;
+}
+
+int ddr3_tip_training_ip_test(u32 dev_num, enum hws_training_result result_type,
+ enum hws_search_dir search_dir,
+ enum hws_dir direction,
+ enum hws_edge_compare edge,
+ u32 init_val1, u32 init_val2,
+ u32 num_of_iterations,
+ u32 start_pattern, u32 end_pattern)
+{
+ u32 pattern, if_id, pup_id;
+ enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM];
+ u32 *res = NULL;
+ u32 search_state = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ ddr3_tip_load_phy_values(1);
+
+ for (pattern = start_pattern; pattern <= end_pattern; pattern++) {
+ for (search_state = 0; search_state < HWS_SEARCH_DIR_LIMIT;
+ search_state++) {
+ ddr3_tip_ip_training_wrapper(dev_num,
+ ACCESS_TYPE_MULTICAST, 0,
+ ACCESS_TYPE_MULTICAST, 0,
+ result_type,
+ HWS_CONTROL_ELEMENT_ADLL,
+ search_dir, direction,
+ 0xfff, init_val1,
+ init_val2,
+ num_of_iterations, pattern,
+ edge, CS_SINGLE,
+ PARAM_NOT_CARE,
+ train_status);
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup_id = 0; pup_id <
+ tm->num_of_bus_per_interface;
+ pup_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask,
+ pup_id);
+ CHECK_STATUS
+ (ddr3_tip_read_training_result
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup_id,
+ ALL_BITS_PER_PUP,
+ search_state,
+ direction, result_type,
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ CS_SINGLE, &res, 1, 0,
+ 0));
+ if (result_type == RESULT_PER_BYTE) {
+ DEBUG_TRAINING_IP_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("search_state %d if_id %d pup_id %d 0x%x\n",
+ search_state, if_id,
+ pup_id, res[0]));
+ } else {
+ DEBUG_TRAINING_IP_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("search_state %d if_id %d pup_id %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ search_state, if_id,
+ pup_id, res[0],
+ res[1], res[2],
+ res[3], res[4],
+ res[5], res[6],
+ res[7]));
+ }
+ }
+ } /* interface */
+ } /* search */
+ } /* pattern */
+
+ ddr3_tip_load_phy_values(0);
+
+ return MV_OK;
+}
+
+struct pattern_info *ddr3_tip_get_pattern_table()
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0)
+ return pattern_table_32;
+ else
+ return pattern_table_16;
+}
+
+u16 *ddr3_tip_get_mask_results_dq_reg()
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))
+ return mask_results_dq_reg_map_pup3_ecc;
+ else
+ return mask_results_dq_reg_map;
+}
+
+u16 *ddr3_tip_get_mask_results_pup_reg_map()
+{
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))
+ return mask_results_pup_reg_map_pup3_ecc;
+ else
+ return mask_results_pup_reg_map;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h
new file mode 100644
index 0000000000..25b146216e
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_ENGINE_H_
+#define _DDR3_TRAINING_IP_ENGINE_H_
+
+#include "ddr3_training_ip_def.h"
+#include "ddr3_training_ip_flow.h"
+
+#define EDGE_1 0
+#define EDGE_2 1
+#define ALL_PUP_TRAINING 0xe
+#define PUP_RESULT_EDGE_1_MASK 0xff
+#define PUP_RESULT_EDGE_2_MASK (0xff << 8)
+#define PUP_LOCK_RESULT_BIT 25
+
+#define GET_TAP_RESULT(reg, edge) \
+ (((edge) == EDGE_1) ? ((reg) & PUP_RESULT_EDGE_1_MASK) : \
+ (((reg) & PUP_RESULT_EDGE_2_MASK) >> 8));
+#define GET_LOCK_RESULT(reg) \
+ (((reg) & (1<<PUP_LOCK_RESULT_BIT)) >> PUP_LOCK_RESULT_BIT)
+
+#define EDGE_FAILURE 128
+#define ALL_BITS_PER_PUP 128
+
+#define MIN_WINDOW_SIZE 6
+#define MAX_WINDOW_SIZE_RX 32
+#define MAX_WINDOW_SIZE_TX 64
+
+int ddr3_tip_training_ip_test(u32 dev_num, enum hws_training_result result_type,
+ enum hws_search_dir search_dir,
+ enum hws_dir direction,
+ enum hws_edge_compare edge,
+ u32 init_val1, u32 init_val2,
+ u32 num_of_iterations, u32 start_pattern,
+ u32 end_pattern);
+int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern pattern);
+int ddr3_tip_load_pattern_to_mem_by_cpu(u32 dev_num, enum hws_pattern pattern,
+ u32 offset);
+int ddr3_tip_load_all_pattern_to_mem(u32 dev_num);
+int ddr3_tip_read_training_result(u32 dev_num, u32 if_id,
+ enum hws_access_type pup_access_type,
+ u32 pup_num, u32 bit_num,
+ enum hws_search_dir search,
+ enum hws_dir direction,
+ enum hws_training_result result_type,
+ enum hws_training_load_op operation,
+ u32 cs_num_type, u32 **load_res,
+ int is_read_from_db, u8 cons_tap,
+ int is_check_result_validity);
+int ddr3_tip_ip_training(u32 dev_num, enum hws_access_type access_type,
+ u32 interface_num,
+ enum hws_access_type pup_access_type,
+ u32 pup_num, enum hws_training_result result_type,
+ enum hws_control_element control_element,
+ enum hws_search_dir search_dir, enum hws_dir direction,
+ u32 interface_mask, u32 init_value, u32 num_iter,
+ enum hws_pattern pattern,
+ enum hws_edge_compare edge_comp,
+ enum hws_ddr_cs cs_type, u32 cs_num,
+ enum hws_training_ip_stat *train_status);
+int ddr3_tip_ip_training_wrapper(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id,
+ enum hws_access_type pup_access_type,
+ u32 pup_num,
+ enum hws_training_result result_type,
+ enum hws_control_element control_element,
+ enum hws_search_dir search_dir,
+ enum hws_dir direction,
+ u32 interface_mask, u32 init_value1,
+ u32 init_value2, u32 num_iter,
+ enum hws_pattern pattern,
+ enum hws_edge_compare edge_comp,
+ enum hws_ddr_cs train_cs_type, u32 cs_num,
+ enum hws_training_ip_stat *train_status);
+int is_odpg_access_done(u32 dev_num, u32 if_id);
+void ddr3_tip_print_bist_res(void);
+struct pattern_info *ddr3_tip_get_pattern_table(void);
+u16 *ddr3_tip_get_mask_results_dq_reg(void);
+u16 *ddr3_tip_get_mask_results_pup_reg_map(void);
+
+#endif /* _DDR3_TRAINING_IP_ENGINE_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h
new file mode 100644
index 0000000000..22d7ce23e6
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_FLOW_H_
+#define _DDR3_TRAINING_IP_FLOW_H_
+
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_pbs.h"
+
+#define MRS0_CMD 0x3
+#define MRS1_CMD 0x4
+#define MRS2_CMD 0x8
+#define MRS3_CMD 0x9
+
+/*
+ * Definitions of INTERFACE registers
+ */
+
+#define READ_BUFFER_SELECT 0x14a4
+
+/*
+ * Definitions of PHY registers
+ */
+
+#define KILLER_PATTERN_LENGTH 32
+#define EXT_ACCESS_BURST_LENGTH 8
+
+#define IS_ACTIVE(if_mask , if_id) \
+ ((if_mask) & (1 << (if_id)))
+#define VALIDATE_ACTIVE(mask, id) \
+ { \
+ if (IS_ACTIVE(mask, id) == 0) \
+ continue; \
+ }
+
+#define GET_TOPOLOGY_NUM_OF_BUSES() \
+ (ddr3_get_topology_map()->num_of_bus_per_interface)
+
+#define DDR3_IS_ECC_PUP3_MODE(if_mask) \
+ (((if_mask) == 0xb) ? 1 : 0)
+#define DDR3_IS_ECC_PUP4_MODE(if_mask) \
+ (((((if_mask) & 0x10) == 0)) ? 0 : 1)
+#define DDR3_IS_16BIT_DRAM_MODE(mask) \
+ (((((mask) & 0x4) == 0)) ? 1 : 0)
+
+#define MEGA 1000000
+#define BUS_WIDTH_IN_BITS 8
+
+/*
+ * DFX address Space
+ * Table 2: DFX address space
+ * Address Bits Value Description
+ * [31 : 20] 0x? DFX base address bases PCIe mapping
+ * [19 : 15] 0...Number_of_client-1 Client Index inside pipe.
+ * See also Table 1 Multi_cast = 29 Broadcast = 28
+ * [14 : 13] 2'b01 Access to Client Internal Register
+ * [12 : 0] Client Internal Register offset See related Client Registers
+ * [14 : 13] 2'b00 Access to Ram Wrappers Internal Register
+ * [12 : 6] 0 Number_of_rams-1 Ram Index inside Client
+ * [5 : 0] Ram Wrapper Internal Register offset See related Ram Wrappers
+ * Registers
+ */
+
+/* nsec */
+#define TREFI_LOW 7800
+#define TREFI_HIGH 3900
+
+#define TR2R_VALUE_REG 0x180
+#define TR2R_MASK_REG 0x180
+#define TRFC_MASK_REG 0x7f
+#define TR2W_MASK_REG 0x600
+#define TW2W_HIGH_VALUE_REG 0x1800
+#define TW2W_HIGH_MASK_REG 0xf800
+#define TRFC_HIGH_VALUE_REG 0x20000
+#define TRFC_HIGH_MASK_REG 0x70000
+#define TR2R_HIGH_VALUE_REG 0x0
+#define TR2R_HIGH_MASK_REG 0x380000
+#define TMOD_VALUE_REG 0x16000000
+#define TMOD_MASK_REG 0x1e000000
+#define T_VALUE_REG 0x40000000
+#define T_MASK_REG 0xc0000000
+#define AUTO_ZQC_TIMING 15384
+#define WRITE_XBAR_PORT1 0xc03f8077
+#define READ_XBAR_PORT1 0xc03f8073
+#define DISABLE_DDR_TUNING_DATA 0x02294285
+#define ENABLE_DDR_TUNING_DATA 0x12294285
+
+#define ODPG_TRAINING_STATUS_REG 0x18488
+#define ODPG_TRAINING_TRIGGER_REG 0x1030
+#define ODPG_STATUS_DONE_REG 0x16fc
+#define ODPG_ENABLE_REG 0x186d4
+#define ODPG_ENABLE_OFFS 0
+#define ODPG_DISABLE_OFFS 8
+
+#define ODPG_TRAINING_CONTROL_REG 0x1034
+#define ODPG_OBJ1_OPCODE_REG 0x103c
+#define ODPG_OBJ1_ITER_CNT_REG 0x10b4
+#define CALIB_OBJ_PRFA_REG 0x10c4
+#define ODPG_WRITE_LEVELING_DONE_CNTR_REG 0x10f8
+#define ODPG_WRITE_READ_MODE_ENABLE_REG 0x10fc
+#define TRAINING_OPCODE_1_REG 0x10b4
+#define SDRAM_CONFIGURATION_REG 0x1400
+#define DDR_CONTROL_LOW_REG 0x1404
+#define SDRAM_TIMING_LOW_REG 0x1408
+#define SDRAM_TIMING_HIGH_REG 0x140c
+#define SDRAM_ACCESS_CONTROL_REG 0x1410
+#define SDRAM_OPEN_PAGE_CONTROL_REG 0x1414
+#define SDRAM_OPERATION_REG 0x1418
+#define DUNIT_CONTROL_HIGH_REG 0x1424
+#define ODT_TIMING_LOW 0x1428
+#define DDR_TIMING_REG 0x142c
+#define ODT_TIMING_HI_REG 0x147c
+#define SDRAM_INIT_CONTROL_REG 0x1480
+#define SDRAM_ODT_CONTROL_HIGH_REG 0x1498
+#define DUNIT_ODT_CONTROL_REG 0x149c
+#define READ_BUFFER_SELECT_REG 0x14a4
+#define DUNIT_MMASK_REG 0x14b0
+#define CALIB_MACHINE_CTRL_REG 0x14cc
+#define DRAM_DLL_TIMING_REG 0x14e0
+#define DRAM_ZQ_INIT_TIMIMG_REG 0x14e4
+#define DRAM_ZQ_TIMING_REG 0x14e8
+#define DFS_REG 0x1528
+#define READ_DATA_SAMPLE_DELAY 0x1538
+#define READ_DATA_READY_DELAY 0x153c
+#define TRAINING_REG 0x15b0
+#define TRAINING_SW_1_REG 0x15b4
+#define TRAINING_SW_2_REG 0x15b8
+#define TRAINING_PATTERN_BASE_ADDRESS_REG 0x15bc
+#define TRAINING_DBG_1_REG 0x15c0
+#define TRAINING_DBG_2_REG 0x15c4
+#define TRAINING_DBG_3_REG 0x15c8
+#define RANK_CTRL_REG 0x15e0
+#define TIMING_REG 0x15e4
+#define DRAM_PHY_CONFIGURATION 0x15ec
+#define MR0_REG 0x15d0
+#define MR1_REG 0x15d4
+#define MR2_REG 0x15d8
+#define MR3_REG 0x15dc
+#define TIMING_REG 0x15e4
+#define ODPG_CTRL_CONTROL_REG 0x1600
+#define ODPG_DATA_CONTROL_REG 0x1630
+#define ODPG_PATTERN_ADDR_OFFSET_REG 0x1638
+#define ODPG_DATA_BUF_SIZE_REG 0x163c
+#define PHY_LOCK_STATUS_REG 0x1674
+#define PHY_REG_FILE_ACCESS 0x16a0
+#define TRAINING_WRITE_LEVELING_REG 0x16ac
+#define ODPG_PATTERN_ADDR_REG 0x16b0
+#define ODPG_PATTERN_DATA_HI_REG 0x16b4
+#define ODPG_PATTERN_DATA_LOW_REG 0x16b8
+#define ODPG_BIST_LAST_FAIL_ADDR_REG 0x16bc
+#define ODPG_BIST_DATA_ERROR_COUNTER_REG 0x16c0
+#define ODPG_BIST_FAILED_DATA_HI_REG 0x16c4
+#define ODPG_BIST_FAILED_DATA_LOW_REG 0x16c8
+#define ODPG_WRITE_DATA_ERROR_REG 0x16cc
+#define CS_ENABLE_REG 0x16d8
+#define WR_LEVELING_DQS_PATTERN_REG 0x16dc
+
+#define ODPG_BIST_DONE 0x186d4
+#define ODPG_BIST_DONE_BIT_OFFS 0
+#define ODPG_BIST_DONE_BIT_VALUE 0
+
+#define RESULT_CONTROL_BYTE_PUP_0_REG 0x1830
+#define RESULT_CONTROL_BYTE_PUP_1_REG 0x1834
+#define RESULT_CONTROL_BYTE_PUP_2_REG 0x1838
+#define RESULT_CONTROL_BYTE_PUP_3_REG 0x183c
+#define RESULT_CONTROL_BYTE_PUP_4_REG 0x18b0
+
+#define RESULT_CONTROL_PUP_0_BIT_0_REG 0x18b4
+#define RESULT_CONTROL_PUP_0_BIT_1_REG 0x18b8
+#define RESULT_CONTROL_PUP_0_BIT_2_REG 0x18bc
+#define RESULT_CONTROL_PUP_0_BIT_3_REG 0x18c0
+#define RESULT_CONTROL_PUP_0_BIT_4_REG 0x18c4
+#define RESULT_CONTROL_PUP_0_BIT_5_REG 0x18c8
+#define RESULT_CONTROL_PUP_0_BIT_6_REG 0x18cc
+#define RESULT_CONTROL_PUP_0_BIT_7_REG 0x18f0
+#define RESULT_CONTROL_PUP_1_BIT_0_REG 0x18f4
+#define RESULT_CONTROL_PUP_1_BIT_1_REG 0x18f8
+#define RESULT_CONTROL_PUP_1_BIT_2_REG 0x18fc
+#define RESULT_CONTROL_PUP_1_BIT_3_REG 0x1930
+#define RESULT_CONTROL_PUP_1_BIT_4_REG 0x1934
+#define RESULT_CONTROL_PUP_1_BIT_5_REG 0x1938
+#define RESULT_CONTROL_PUP_1_BIT_6_REG 0x193c
+#define RESULT_CONTROL_PUP_1_BIT_7_REG 0x19b0
+#define RESULT_CONTROL_PUP_2_BIT_0_REG 0x19b4
+#define RESULT_CONTROL_PUP_2_BIT_1_REG 0x19b8
+#define RESULT_CONTROL_PUP_2_BIT_2_REG 0x19bc
+#define RESULT_CONTROL_PUP_2_BIT_3_REG 0x19c0
+#define RESULT_CONTROL_PUP_2_BIT_4_REG 0x19c4
+#define RESULT_CONTROL_PUP_2_BIT_5_REG 0x19c8
+#define RESULT_CONTROL_PUP_2_BIT_6_REG 0x19cc
+#define RESULT_CONTROL_PUP_2_BIT_7_REG 0x19f0
+#define RESULT_CONTROL_PUP_3_BIT_0_REG 0x19f4
+#define RESULT_CONTROL_PUP_3_BIT_1_REG 0x19f8
+#define RESULT_CONTROL_PUP_3_BIT_2_REG 0x19fc
+#define RESULT_CONTROL_PUP_3_BIT_3_REG 0x1a30
+#define RESULT_CONTROL_PUP_3_BIT_4_REG 0x1a34
+#define RESULT_CONTROL_PUP_3_BIT_5_REG 0x1a38
+#define RESULT_CONTROL_PUP_3_BIT_6_REG 0x1a3c
+#define RESULT_CONTROL_PUP_3_BIT_7_REG 0x1ab0
+#define RESULT_CONTROL_PUP_4_BIT_0_REG 0x1ab4
+#define RESULT_CONTROL_PUP_4_BIT_1_REG 0x1ab8
+#define RESULT_CONTROL_PUP_4_BIT_2_REG 0x1abc
+#define RESULT_CONTROL_PUP_4_BIT_3_REG 0x1ac0
+#define RESULT_CONTROL_PUP_4_BIT_4_REG 0x1ac4
+#define RESULT_CONTROL_PUP_4_BIT_5_REG 0x1ac8
+#define RESULT_CONTROL_PUP_4_BIT_6_REG 0x1acc
+#define RESULT_CONTROL_PUP_4_BIT_7_REG 0x1af0
+
+#define WL_PHY_REG 0x0
+#define WRITE_CENTRALIZATION_PHY_REG 0x1
+#define RL_PHY_REG 0x2
+#define READ_CENTRALIZATION_PHY_REG 0x3
+#define PBS_RX_PHY_REG 0x50
+#define PBS_TX_PHY_REG 0x10
+#define PHY_CONTROL_PHY_REG 0x90
+#define BW_PHY_REG 0x92
+#define RATE_PHY_REG 0x94
+#define CMOS_CONFIG_PHY_REG 0xa2
+#define PAD_ZRI_CALIB_PHY_REG 0xa4
+#define PAD_ODT_CALIB_PHY_REG 0xa6
+#define PAD_CONFIG_PHY_REG 0xa8
+#define PAD_PRE_DISABLE_PHY_REG 0xa9
+#define TEST_ADLL_REG 0xbf
+#define CSN_IOB_VREF_REG(cs) (0xdb + (cs * 12))
+#define CSN_IO_BASE_VREF_REG(cs) (0xd0 + (cs * 12))
+
+#define RESULT_DB_PHY_REG_ADDR 0xc0
+#define RESULT_DB_PHY_REG_RX_OFFSET 5
+#define RESULT_DB_PHY_REG_TX_OFFSET 0
+
+/* TBD - for NP5 use only CS 0 */
+#define PHY_WRITE_DELAY(cs) WL_PHY_REG
+/*( ( _cs_ == 0 ) ? 0x0 : 0x4 )*/
+/* TBD - for NP5 use only CS 0 */
+#define PHY_READ_DELAY(cs) RL_PHY_REG
+
+#define DDR0_ADDR_1 0xf8258
+#define DDR0_ADDR_2 0xf8254
+#define DDR1_ADDR_1 0xf8270
+#define DDR1_ADDR_2 0xf8270
+#define DDR2_ADDR_1 0xf825c
+#define DDR2_ADDR_2 0xf825c
+#define DDR3_ADDR_1 0xf8264
+#define DDR3_ADDR_2 0xf8260
+#define DDR4_ADDR_1 0xf8274
+#define DDR4_ADDR_2 0xf8274
+
+#define GENERAL_PURPOSE_RESERVED0_REG 0x182e0
+
+#define GET_BLOCK_ID_MAX_FREQ(dev_num, block_id) 800000
+#define CS0_RD_LVL_REF_DLY_OFFS 0
+#define CS0_RD_LVL_REF_DLY_LEN 0
+#define CS0_RD_LVL_PH_SEL_OFFS 0
+#define CS0_RD_LVL_PH_SEL_LEN 0
+
+#define CS_REGISTER_ADDR_OFFSET 4
+#define CALIBRATED_OBJECTS_REG_ADDR_OFFSET 0x10
+
+#define MAX_POLLING_ITERATIONS 100000
+
+#define PHASE_REG_OFFSET 32
+#define NUM_BYTES_IN_BURST 31
+#define NUM_OF_CS 4
+#define CS_REG_VALUE(cs_num) (cs_mask_reg[cs_num])
+#define ADLL_LENGTH 32
+
+struct write_supp_result {
+ enum hws_wl_supp stage;
+ int is_pup_fail;
+};
+
+struct page_element {
+ enum hws_page_size page_size_8bit;
+ /* page size in 8 bits bus width */
+ enum hws_page_size page_size_16bit;
+ /* page size in 16 bits bus width */
+ u32 ui_page_mask;
+ /* Mask used in register */
+};
+
+int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id,
+ enum hws_ddr_freq frequency,
+ u32 *round_trip_delay_arr);
+int ddr3_tip_read_leveling_static_config(u32 dev_num, u32 if_id,
+ enum hws_ddr_freq frequency,
+ u32 *total_round_trip_delay_arr);
+int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 data_value, u32 mask);
+int ddr3_tip_if_polling(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, u32 exp_value, u32 mask, u32 offset,
+ u32 poll_tries);
+int ddr3_tip_if_read(u32 dev_num, enum hws_access_type interface_access,
+ u32 if_id, u32 reg_addr, u32 *data, u32 mask);
+int ddr3_tip_bus_read_modify_write(u32 dev_num,
+ enum hws_access_type access_type,
+ u32 if_id, u32 phy_id,
+ enum hws_ddr_phy phy_type,
+ u32 reg_addr, u32 data_value, u32 reg_mask);
+int ddr3_tip_bus_read(u32 dev_num, u32 if_id, enum hws_access_type phy_access,
+ u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+ u32 *data);
+int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type e_interface_access,
+ u32 if_id, enum hws_access_type e_phy_access, u32 phy_id,
+ enum hws_ddr_phy e_phy_type, u32 reg_addr,
+ u32 data_value);
+int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type e_access, u32 if_id,
+ enum hws_ddr_freq memory_freq);
+int ddr3_tip_adjust_dqs(u32 dev_num);
+int ddr3_tip_init_controller(u32 dev_num);
+int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr,
+ u32 num_of_bursts, u32 *addr);
+int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr,
+ u32 num_of_bursts, u32 *addr);
+int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 ui_freq);
+int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num);
+int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 ui_freq);
+int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num);
+int ddr3_tip_dynamic_write_leveling(u32 dev_num);
+int ddr3_tip_dynamic_write_leveling_supp(u32 dev_num);
+int ddr3_tip_static_init_controller(u32 dev_num);
+int ddr3_tip_configure_phy(u32 dev_num);
+int ddr3_tip_load_pattern_to_odpg(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_pattern pattern,
+ u32 load_addr);
+int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern e_pattern);
+int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum hws_dir direction, u32 tx_phases,
+ u32 tx_burst_size, u32 rx_phases,
+ u32 delay_between_burst, u32 rd_mode, u32 cs_num,
+ u32 addr_stress_jump, u32 single_pattern);
+int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value);
+int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, u32 cmd, u32 data,
+ u32 mask);
+int ddr3_tip_write_cs_result(u32 dev_num, u32 offset);
+int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask, u32 *if_id);
+int ddr3_tip_reset_fifo_ptr(u32 dev_num);
+int read_pup_value(int pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+ int reg_addr, u32 mask);
+int read_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+ int reg_addr, u32 mask);
+int write_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+ int reg_addr);
+int ddr3_tip_tune_training_params(u32 dev_num,
+ struct tune_train_params *params);
+
+#endif /* _DDR3_TRAINING_IP_FLOW_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h
new file mode 100644
index 0000000000..c6be67c40a
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_PBS_H_
+#define _DDR3_TRAINING_IP_PBS_H_
+
+enum {
+ EBA_CONFIG,
+ EEBA_CONFIG,
+ SBA_CONFIG
+};
+
+enum hws_training_load_op {
+ TRAINING_LOAD_OPERATION_UNLOAD,
+ TRAINING_LOAD_OPERATION_LOAD
+};
+
+enum hws_edge {
+ TRAINING_EDGE_1,
+ TRAINING_EDGE_2
+};
+
+enum hws_edge_search {
+ TRAINING_EDGE_MAX,
+ TRAINING_EDGE_MIN
+};
+
+enum pbs_dir {
+ PBS_TX_MODE = 0,
+ PBS_RX_MODE,
+ NUM_OF_PBS_MODES
+};
+
+int ddr3_tip_pbs_rx(u32 dev_num);
+int ddr3_tip_print_all_pbs_result(u32 dev_num);
+int ddr3_tip_pbs_tx(u32 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_PBS_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h
new file mode 100644
index 0000000000..724b106275
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_PRV_IF_H
+#define _DDR3_TRAINING_IP_PRV_IF_H
+
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_flow.h"
+#include "ddr3_training_ip_bist.h"
+
+enum hws_static_config_type {
+ WRITE_LEVELING_STATIC,
+ READ_LEVELING_STATIC
+};
+
+struct ddr3_device_info {
+ u32 device_id;
+ u32 ck_delay;
+};
+
+typedef int (*HWS_TIP_DUNIT_MUX_SELECT_FUNC_PTR)(u8 dev_num, int enable);
+typedef int (*HWS_TIP_DUNIT_REG_READ_FUNC_PTR)(
+ u8 dev_num, enum hws_access_type interface_access, u32 if_id,
+ u32 offset, u32 *data, u32 mask);
+typedef int (*HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR)(
+ u8 dev_num, enum hws_access_type interface_access, u32 if_id,
+ u32 offset, u32 data, u32 mask);
+typedef int (*HWS_TIP_GET_FREQ_CONFIG_INFO)(
+ u8 dev_num, enum hws_ddr_freq freq,
+ struct hws_tip_freq_config_info *freq_config_info);
+typedef int (*HWS_TIP_GET_DEVICE_INFO)(
+ u8 dev_num, struct ddr3_device_info *info_ptr);
+typedef int (*HWS_GET_CS_CONFIG_FUNC_PTR)(
+ u8 dev_num, u32 cs_mask, struct hws_cs_config_info *cs_info);
+typedef int (*HWS_SET_FREQ_DIVIDER_FUNC_PTR)(
+ u8 dev_num, u32 if_id, enum hws_ddr_freq freq);
+typedef int (*HWS_GET_INIT_FREQ)(u8 dev_num, enum hws_ddr_freq *freq);
+typedef int (*HWS_TRAINING_IP_IF_WRITE_FUNC_PTR)(
+ u32 dev_num, enum hws_access_type access_type, u32 dunit_id,
+ u32 reg_addr, u32 data, u32 mask);
+typedef int (*HWS_TRAINING_IP_IF_READ_FUNC_PTR)(
+ u32 dev_num, enum hws_access_type access_type, u32 dunit_id,
+ u32 reg_addr, u32 *data, u32 mask);
+typedef int (*HWS_TRAINING_IP_BUS_WRITE_FUNC_PTR)(
+ u32 dev_num, enum hws_access_type dunit_access_type, u32 if_id,
+ enum hws_access_type phy_access_type, u32 phy_id,
+ enum hws_ddr_phy phy_type, u32 reg_addr, u32 data);
+typedef int (*HWS_TRAINING_IP_BUS_READ_FUNC_PTR)(
+ u32 dev_num, u32 if_id, enum hws_access_type phy_access_type,
+ u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, u32 *data);
+typedef int (*HWS_TRAINING_IP_ALGO_RUN_FUNC_PTR)(
+ u32 dev_num, enum hws_algo_type algo_type);
+typedef int (*HWS_TRAINING_IP_SET_FREQ_FUNC_PTR)(
+ u32 dev_num, enum hws_access_type access_type, u32 if_id,
+ enum hws_ddr_freq frequency);
+typedef int (*HWS_TRAINING_IP_INIT_CONTROLLER_FUNC_PTR)(
+ u32 dev_num, struct init_cntr_param *init_cntr_prm);
+typedef int (*HWS_TRAINING_IP_PBS_RX_FUNC_PTR)(u32 dev_num);
+typedef int (*HWS_TRAINING_IP_PBS_TX_FUNC_PTR)(u32 dev_num);
+typedef int (*HWS_TRAINING_IP_SELECT_CONTROLLER_FUNC_PTR)(
+ u32 dev_num, int enable);
+typedef int (*HWS_TRAINING_IP_TOPOLOGY_MAP_LOAD_FUNC_PTR)(
+ u32 dev_num, struct hws_topology_map *topology_map);
+typedef int (*HWS_TRAINING_IP_STATIC_CONFIG_FUNC_PTR)(
+ u32 dev_num, enum hws_ddr_freq frequency,
+ enum hws_static_config_type static_config_type, u32 if_id);
+typedef int (*HWS_TRAINING_IP_EXTERNAL_READ_PTR)(
+ u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data);
+typedef int (*HWS_TRAINING_IP_EXTERNAL_WRITE_PTR)(
+ u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data);
+typedef int (*HWS_TRAINING_IP_BIST_ACTIVATE)(
+ u32 dev_num, enum hws_pattern pattern, enum hws_access_type access_type,
+ u32 if_num, enum hws_dir direction,
+ enum hws_stress_jump addr_stress_jump,
+ enum hws_pattern_duration duration,
+ enum hws_bist_operation oper_type, u32 offset, u32 cs_num,
+ u32 pattern_addr_length);
+typedef int (*HWS_TRAINING_IP_BIST_READ_RESULT)(
+ u32 dev_num, u32 if_id, struct bist_result *pst_bist_result);
+typedef int (*HWS_TRAINING_IP_LOAD_TOPOLOGY)(u32 dev_num, u32 config_num);
+typedef int (*HWS_TRAINING_IP_READ_LEVELING)(u32 dev_num, u32 config_num);
+typedef int (*HWS_TRAINING_IP_WRITE_LEVELING)(u32 dev_num, u32 config_num);
+typedef u32 (*HWS_TRAINING_IP_GET_TEMP)(u8 dev_num);
+
+struct hws_tip_config_func_db {
+ HWS_TIP_DUNIT_MUX_SELECT_FUNC_PTR tip_dunit_mux_select_func;
+ HWS_TIP_DUNIT_REG_READ_FUNC_PTR tip_dunit_read_func;
+ HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR tip_dunit_write_func;
+ HWS_TIP_GET_FREQ_CONFIG_INFO tip_get_freq_config_info_func;
+ HWS_TIP_GET_DEVICE_INFO tip_get_device_info_func;
+ HWS_SET_FREQ_DIVIDER_FUNC_PTR tip_set_freq_divider_func;
+ HWS_GET_CS_CONFIG_FUNC_PTR tip_get_cs_config_info;
+ HWS_TRAINING_IP_GET_TEMP tip_get_temperature;
+};
+
+int ddr3_tip_init_config_func(u32 dev_num,
+ struct hws_tip_config_func_db *config_func);
+int ddr3_tip_register_xsb_info(u32 dev_num,
+ struct hws_xsb_info *xsb_info_table);
+enum hws_result *ddr3_tip_get_result_ptr(u32 stage);
+int ddr3_set_freq_config_info(struct hws_tip_freq_config_info *table);
+int print_device_info(u8 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_PRV_IF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h
new file mode 100644
index 0000000000..878068b24d
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_STATIC_H_
+#define _DDR3_TRAINING_IP_STATIC_H_
+
+#include "ddr3_training_ip_def.h"
+#include "ddr3_training_ip.h"
+
+struct trip_delay_element {
+ u32 dqs_delay; /* DQS delay (m_sec) */
+ u32 ck_delay; /* CK Delay (m_sec) */
+};
+
+struct hws_tip_static_config_info {
+ u32 silicon_delay;
+ struct trip_delay_element *package_trace_arr;
+ struct trip_delay_element *board_trace_arr;
+};
+
+int ddr3_tip_run_static_alg(u32 dev_num, enum hws_ddr_freq freq);
+int ddr3_tip_init_static_config_db(
+ u32 dev_num, struct hws_tip_static_config_info *static_config_info);
+int ddr3_tip_init_specific_reg_config(u32 dev_num,
+ struct reg_data *reg_config_arr);
+int ddr3_tip_static_phy_init_controller(u32 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_STATIC_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.c b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c
new file mode 100644
index 0000000000..3c40f198e7
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c
@@ -0,0 +1,1836 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define WL_ITERATION_NUM 10
+#define ONE_CLOCK_ERROR_SHIFT 2
+#define ALIGN_ERROR_SHIFT -2
+
+static u32 pup_mask_table[] = {
+ 0x000000ff,
+ 0x0000ff00,
+ 0x00ff0000,
+ 0xff000000
+};
+
+static struct write_supp_result wr_supp_res[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+
+static int ddr3_tip_dynamic_write_leveling_seq(u32 dev_num);
+static int ddr3_tip_dynamic_read_leveling_seq(u32 dev_num);
+static int ddr3_tip_dynamic_per_bit_read_leveling_seq(u32 dev_num);
+static int ddr3_tip_wl_supp_align_err_shift(u32 dev_num, u32 if_id, u32 bus_id,
+ u32 bus_id_delta);
+static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id,
+ u32 bus_id, u32 offset,
+ u32 bus_id_delta);
+static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id,
+ u32 edge_offset, u32 bus_id_delta);
+static int ddr3_tip_wl_supp_one_clk_err_shift(u32 dev_num, u32 if_id,
+ u32 bus_id, u32 bus_id_delta);
+
+u32 hws_ddr3_tip_max_cs_get(void)
+{
+ u32 c_cs;
+ static u32 max_cs;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (!max_cs) {
+ for (c_cs = 0; c_cs < NUM_OF_CS; c_cs++) {
+ VALIDATE_ACTIVE(tm->
+ interface_params[0].as_bus_params[0].
+ cs_bitmask, c_cs);
+ max_cs++;
+ }
+ }
+
+ return max_cs;
+}
+
+/*****************************************************************************
+Dynamic read leveling
+******************************************************************************/
+int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 freq)
+{
+ u32 data, mask;
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ u32 bus_num, if_id, cl_val;
+ enum hws_speed_bin speed_bin_index;
+ /* save current CS value */
+ u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 };
+ int is_any_pup_fail = 0;
+ u32 data_read[MAX_INTERFACE_NUM + 1] = { 0 };
+ u8 rl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM];
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ if (rl_version == 0) {
+ /* OLD RL machine */
+ data = 0x40;
+ data |= (1 << 20);
+
+ /* TBD multi CS */
+ CHECK_STATUS(ddr3_tip_if_write(
+ dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, TRAINING_REG,
+ data, 0x11ffff));
+ CHECK_STATUS(ddr3_tip_if_write(
+ dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ TRAINING_PATTERN_BASE_ADDRESS_REG,
+ 0, 0xfffffff8));
+ CHECK_STATUS(ddr3_tip_if_write(
+ dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, TRAINING_REG,
+ (u32)(1 << 31), (u32)(1 << 31)));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+ (u32)(1 << 31), TRAINING_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("RL: DDR3 poll failed(1) IF %d\n",
+ if_id));
+ training_result[training_stage][if_id] =
+ TEST_FAILED;
+
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ /* read read-leveling result */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_REG, data_read, 1 << 30));
+ /* exit read leveling mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x8, 0x9));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_1_REG, 1 << 16, 1 << 16));
+
+ /* disable RL machine all Trn_CS[3:0] , [16:0] */
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_REG, 0, 0xf1ffff));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if ((data_read[if_id] & (1 << 30)) == 0) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("\n_read Leveling failed for IF %d\n",
+ if_id));
+ training_result[training_stage][if_id] =
+ TEST_FAILED;
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ return MV_OK;
+ }
+
+ /* NEW RL machine */
+ for (effective_cs = 0; effective_cs < NUM_OF_CS; effective_cs++)
+ for (bus_num = 0; bus_num < MAX_BUS_NUM; bus_num++)
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++)
+ rl_values[effective_cs][bus_num][if_id] = 0;
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+
+ /* save current cs enable reg val */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val,
+ MASK_ALL_BITS));
+ /* enable single cs */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, (1 << 3), (1 << 3)));
+ }
+
+ ddr3_tip_reset_fifo_ptr(dev_num);
+
+ /*
+ * Phase 1: Load pattern (using ODPG)
+ *
+ * enter Read Leveling mode
+ * only 27 bits are masked
+ * assuming non multi-CS configuration
+ * write to CS = 0 for the non multi CS configuration, note
+ * that the results shall be read back to the required CS !!!
+ */
+
+ /* BUS count is 0 shifted 26 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0x3, 0x3));
+ CHECK_STATUS(ddr3_tip_configure_odpg
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0,
+ pattern_table[PATTERN_RL].num_of_phases_tx, 0,
+ pattern_table[PATTERN_RL].num_of_phases_rx, 0, 0,
+ effective_cs, STRESS_NONE, DURATION_SINGLE));
+
+ /* load pattern to ODPG */
+ ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, PATTERN_RL,
+ pattern_table[PATTERN_RL].
+ start_addr);
+
+ /*
+ * Phase 2: ODPG to Read Leveling mode
+ */
+
+ /* General Training Opcode register */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_WRITE_READ_MODE_ENABLE_REG, 0,
+ MASK_ALL_BITS));
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_CONTROL_REG,
+ (0x301b01 | effective_cs << 2), 0x3c3fef));
+
+ /* Object1 opcode register 0 & 1 */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ speed_bin_index =
+ tm->interface_params[if_id].speed_bin_index;
+ cl_val =
+ cas_latency_table[speed_bin_index].cl_val[freq];
+ data = (cl_val << 17) | (0x3 << 25);
+ mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_OBJ1_OPCODE_REG, data, mask));
+ }
+
+ /* Set iteration count to max value */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_OPCODE_1_REG, 0xd00, 0xd00));
+
+ /*
+ * Phase 2: Mask config
+ */
+
+ ddr3_tip_dynamic_read_leveling_seq(dev_num);
+
+ /*
+ * Phase 3: Read Leveling execution
+ */
+
+ /* temporary jira dunit=14751 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_DBG_1_REG, 0, (u32)(1 << 31)));
+ /* configure phy reset value */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_DBG_3_REG, (0x7f << 24),
+ (u32)(0xff << 24)));
+ /* data pup rd reset enable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ SDRAM_CONFIGURATION_REG, 0, (1 << 30)));
+ /* data pup rd reset disable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ SDRAM_CONFIGURATION_REG, (1 << 30), (1 << 30)));
+ /* training SW override & training RL mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x1, 0x9));
+ /* training enable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_REG, (1 << 24) | (1 << 20),
+ (1 << 24) | (1 << 20)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_REG, (u32)(1 << 31), (u32)(1 << 31)));
+
+ /********* trigger training *******************/
+ /* Trigger, poll on status and disable ODPG */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_STATUS_REG, 0x1, 0x1));
+
+ /* check for training done + results pass */
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x2, 0x2,
+ ODPG_TRAINING_STATUS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("Training Done Failed\n"));
+ return MV_FAIL;
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id,
+ ODPG_TRAINING_TRIGGER_REG, data_read,
+ 0x4));
+ data = data_read[if_id];
+ if (data != 0x0) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("Training Result Failed\n"));
+ }
+ }
+
+ /*disable ODPG - Back to functional mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_ENABLE_REG, 0x1 << ODPG_DISABLE_OFFS,
+ (0x1 << ODPG_DISABLE_OFFS)));
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x0, 0x1,
+ ODPG_ENABLE_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("ODPG disable failed "));
+ return MV_FAIL;
+ }
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+ /* double loop on bus, pup */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* check training done */
+ is_any_pup_fail = 0;
+ for (bus_num = 0;
+ bus_num < tm->num_of_bus_per_interface;
+ bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, (1 << 25), (1 << 25),
+ mask_results_pup_reg_map[bus_num],
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("\n_r_l: DDR3 poll failed(2) for bus %d",
+ bus_num));
+ is_any_pup_fail = 1;
+ } else {
+ /* read result per pup */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ mask_results_pup_reg_map
+ [bus_num], data_read,
+ 0xff));
+ rl_values[effective_cs][bus_num]
+ [if_id] = (u8)data_read[if_id];
+ }
+ }
+
+ if (is_any_pup_fail == 1) {
+ training_result[training_stage][if_id] =
+ TEST_FAILED;
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+
+ DEBUG_LEVELING(DEBUG_LEVEL_INFO, ("RL exit read leveling\n"));
+
+ /*
+ * Phase 3: Exit Read Leveling
+ */
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, (1 << 3), (1 << 3)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_1_REG, (1 << 16), (1 << 16)));
+ /* set ODPG to functional */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+
+ /*
+ * Copy the result from the effective CS search to the
+ * real Functional CS
+ */
+ /*ddr3_tip_write_cs_result(dev_num, RL_PHY_REG); */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ /* double loop on bus, pup */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_num = 0;
+ bus_num < tm->num_of_bus_per_interface;
+ bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+ /* read result per pup from arry */
+ data = rl_values[effective_cs][bus_num][if_id];
+ data = (data & 0x1f) |
+ (((data & 0xe0) >> 5) << 6);
+ ddr3_tip_bus_write(dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_num, DDR_PHY_DATA,
+ RL_PHY_REG +
+ ((effective_cs ==
+ 0) ? 0x0 : 0x4), data);
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* restore cs enable value */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val[if_id],
+ MASK_ALL_BITS));
+ if (odt_config != 0) {
+ CHECK_STATUS(ddr3_tip_write_additional_odt_setting
+ (dev_num, if_id));
+ }
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (training_result[training_stage][if_id] == TEST_FAILED)
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Legacy Dynamic write leveling
+ */
+int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num)
+{
+ u32 c_cs, if_id, cs_mask = 0;
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * In TRAINIUNG reg (0x15b0) write 0x80000008 | cs_mask:
+ * Trn_start
+ * cs_mask = 0x1 <<20 Trn_CS0 - CS0 is included in the DDR3 training
+ * cs_mask = 0x1 <<21 Trn_CS1 - CS1 is included in the DDR3 training
+ * cs_mask = 0x1 <<22 Trn_CS2 - CS2 is included in the DDR3 training
+ * cs_mask = 0x1 <<23 Trn_CS3 - CS3 is included in the DDR3 training
+ * Trn_auto_seq = write leveling
+ */
+ for (c_cs = 0; c_cs < max_cs; c_cs++)
+ cs_mask = cs_mask | 1 << (20 + c_cs);
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, 0,
+ TRAINING_REG, (0x80000008 | cs_mask),
+ 0xffffffff));
+ mdelay(20);
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+ (u32)0x80000000, TRAINING_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("polling failed for Old WL result\n"));
+ return MV_FAIL;
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Legacy Dynamic read leveling
+ */
+int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num)
+{
+ u32 c_cs, if_id, cs_mask = 0;
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * In TRAINIUNG reg (0x15b0) write 0x80000040 | cs_mask:
+ * Trn_start
+ * cs_mask = 0x1 <<20 Trn_CS0 - CS0 is included in the DDR3 training
+ * cs_mask = 0x1 <<21 Trn_CS1 - CS1 is included in the DDR3 training
+ * cs_mask = 0x1 <<22 Trn_CS2 - CS2 is included in the DDR3 training
+ * cs_mask = 0x1 <<23 Trn_CS3 - CS3 is included in the DDR3 training
+ * Trn_auto_seq = Read Leveling using training pattern
+ */
+ for (c_cs = 0; c_cs < max_cs; c_cs++)
+ cs_mask = cs_mask | 1 << (20 + c_cs);
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, 0, TRAINING_REG,
+ (0x80000040 | cs_mask), 0xffffffff));
+ mdelay(100);
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+ (u32)0x80000000, TRAINING_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("polling failed for Old RL result\n"));
+ return MV_FAIL;
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Dynamic per bit read leveling
+ */
+int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 freq)
+{
+ u32 data, mask;
+ u32 bus_num, if_id, cl_val, bit_num;
+ u32 curr_numb, curr_min_delay;
+ int adll_array[3] = { 0, -0xa, 0x14 };
+ u32 phyreg3_arr[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+ enum hws_speed_bin speed_bin_index;
+ int is_any_pup_fail = 0;
+ int break_loop = 0;
+ u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; /* save current CS value */
+ u32 data_read[MAX_INTERFACE_NUM];
+ int per_bit_rl_pup_status[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+ u32 data2_write[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_num = 0;
+ bus_num <= tm->num_of_bus_per_interface; bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+ per_bit_rl_pup_status[if_id][bus_num] = 0;
+ data2_write[if_id][bus_num] = 0;
+ /* read current value of phy register 0x3 */
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_num, DDR_PHY_DATA,
+ READ_CENTRALIZATION_PHY_REG,
+ &phyreg3_arr[if_id][bus_num]));
+ }
+ }
+
+ /* NEW RL machine */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+
+ /* save current cs enable reg val */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, &cs_enable_reg_val[if_id],
+ MASK_ALL_BITS));
+ /* enable single cs */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, (1 << 3), (1 << 3)));
+ }
+
+ ddr3_tip_reset_fifo_ptr(dev_num);
+ for (curr_numb = 0; curr_numb < 3; curr_numb++) {
+ /*
+ * Phase 1: Load pattern (using ODPG)
+ *
+ * enter Read Leveling mode
+ * only 27 bits are masked
+ * assuming non multi-CS configuration
+ * write to CS = 0 for the non multi CS configuration, note that
+ * the results shall be read back to the required CS !!!
+ */
+
+ /* BUS count is 0 shifted 26 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0x3, 0x3));
+ CHECK_STATUS(ddr3_tip_configure_odpg
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0,
+ pattern_table[PATTERN_TEST].num_of_phases_tx, 0,
+ pattern_table[PATTERN_TEST].num_of_phases_rx, 0,
+ 0, 0, STRESS_NONE, DURATION_SINGLE));
+
+ /* load pattern to ODPG */
+ ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, PATTERN_TEST,
+ pattern_table[PATTERN_TEST].
+ start_addr);
+
+ /*
+ * Phase 2: ODPG to Read Leveling mode
+ */
+
+ /* General Training Opcode register */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_WRITE_READ_MODE_ENABLE_REG, 0,
+ MASK_ALL_BITS));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_CONTROL_REG, 0x301b01, 0x3c3fef));
+
+ /* Object1 opcode register 0 & 1 */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ speed_bin_index =
+ tm->interface_params[if_id].speed_bin_index;
+ cl_val =
+ cas_latency_table[speed_bin_index].cl_val[freq];
+ data = (cl_val << 17) | (0x3 << 25);
+ mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ODPG_OBJ1_OPCODE_REG, data, mask));
+ }
+
+ /* Set iteration count to max value */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_OPCODE_1_REG, 0xd00, 0xd00));
+
+ /*
+ * Phase 2: Mask config
+ */
+
+ ddr3_tip_dynamic_per_bit_read_leveling_seq(dev_num);
+
+ /*
+ * Phase 3: Read Leveling execution
+ */
+
+ /* temporary jira dunit=14751 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_DBG_1_REG, 0, (u32)(1 << 31)));
+ /* configure phy reset value */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_DBG_3_REG, (0x7f << 24),
+ (u32)(0xff << 24)));
+ /* data pup rd reset enable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ SDRAM_CONFIGURATION_REG, 0, (1 << 30)));
+ /* data pup rd reset disable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ SDRAM_CONFIGURATION_REG, (1 << 30), (1 << 30)));
+ /* training SW override & training RL mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x1, 0x9));
+ /* training enable */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_REG, (1 << 24) | (1 << 20),
+ (1 << 24) | (1 << 20)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_REG, (u32)(1 << 31), (u32)(1 << 31)));
+
+ /********* trigger training *******************/
+ /* Trigger, poll on status and disable ODPG */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_STATUS_REG, 0x1, 0x1));
+
+ /*check for training done + results pass */
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x2, 0x2,
+ ODPG_TRAINING_STATUS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("Training Done Failed\n"));
+ return MV_FAIL;
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id,
+ ODPG_TRAINING_TRIGGER_REG, data_read,
+ 0x4));
+ data = data_read[if_id];
+ if (data != 0x0) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("Training Result Failed\n"));
+ }
+ }
+
+ /*disable ODPG - Back to functional mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_ENABLE_REG, 0x1 << ODPG_DISABLE_OFFS,
+ (0x1 << ODPG_DISABLE_OFFS)));
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x0, 0x1,
+ ODPG_ENABLE_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("ODPG disable failed "));
+ return MV_FAIL;
+ }
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+ /* double loop on bus, pup */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* check training done */
+ for (bus_num = 0;
+ bus_num < tm->num_of_bus_per_interface;
+ bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+
+ if (per_bit_rl_pup_status[if_id][bus_num]
+ == 0) {
+ curr_min_delay = 0;
+ for (bit_num = 0; bit_num < 8;
+ bit_num++) {
+ if (ddr3_tip_if_polling
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id, (1 << 25),
+ (1 << 25),
+ mask_results_dq_reg_map
+ [bus_num * 8 + bit_num],
+ MAX_POLLING_ITERATIONS) !=
+ MV_OK) {
+ DEBUG_LEVELING
+ (DEBUG_LEVEL_ERROR,
+ ("\n_r_l: DDR3 poll failed(2) for bus %d bit %d\n",
+ bus_num,
+ bit_num));
+ } else {
+ /* read result per pup */
+ CHECK_STATUS
+ (ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ mask_results_dq_reg_map
+ [bus_num * 8 +
+ bit_num],
+ data_read,
+ MASK_ALL_BITS));
+ data =
+ (data_read
+ [if_id] &
+ 0x1f) |
+ ((data_read
+ [if_id] &
+ 0xe0) << 1);
+ if (curr_min_delay == 0)
+ curr_min_delay =
+ data;
+ else if (data <
+ curr_min_delay)
+ curr_min_delay =
+ data;
+ if (data > data2_write[if_id][bus_num])
+ data2_write
+ [if_id]
+ [bus_num] =
+ data;
+ }
+ }
+
+ if (data2_write[if_id][bus_num] <=
+ (curr_min_delay +
+ MAX_DQ_READ_LEVELING_DELAY)) {
+ per_bit_rl_pup_status[if_id]
+ [bus_num] = 1;
+ }
+ }
+ }
+ }
+
+ /* check if there is need to search new phyreg3 value */
+ if (curr_numb < 2) {
+ /* if there is DLL that is not checked yet */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_num = 0;
+ bus_num < tm->num_of_bus_per_interface;
+ bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask,
+ bus_num);
+ if (per_bit_rl_pup_status[if_id]
+ [bus_num] != 1) {
+ /* go to next ADLL value */
+ CHECK_STATUS
+ (ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_num, DDR_PHY_DATA,
+ READ_CENTRALIZATION_PHY_REG,
+ (phyreg3_arr[if_id]
+ [bus_num] +
+ adll_array[curr_numb])));
+ break_loop = 1;
+ break;
+ }
+ }
+ if (break_loop)
+ break;
+ }
+ } /* if (curr_numb < 2) */
+ if (!break_loop)
+ break;
+ } /* for ( curr_numb = 0; curr_numb <3; curr_numb++) */
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_num = 0; bus_num < tm->num_of_bus_per_interface;
+ bus_num++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+ if (per_bit_rl_pup_status[if_id][bus_num] == 1)
+ ddr3_tip_bus_write(dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_num, DDR_PHY_DATA,
+ RL_PHY_REG +
+ CS_REG_VALUE(effective_cs),
+ data2_write[if_id]
+ [bus_num]);
+ else
+ is_any_pup_fail = 1;
+ }
+
+ /* TBD flow does not support multi CS */
+ /*
+ * cs_bitmask = tm->interface_params[if_id].
+ * as_bus_params[bus_num].cs_bitmask;
+ */
+ /* divide by 4 is used for retrieving the CS number */
+ /*
+ * TBD BC2 - what is the PHY address for other
+ * CS ddr3_tip_write_cs_result() ???
+ */
+ /*
+ * find what should be written to PHY
+ * - max delay that is less than threshold
+ */
+ if (is_any_pup_fail == 1) {
+ training_result[training_stage][if_id] = TEST_FAILED;
+ if (debug_mode == 0)
+ return MV_FAIL;
+ }
+ }
+ DEBUG_LEVELING(DEBUG_LEVEL_INFO, ("RL exit read leveling\n"));
+
+ /*
+ * Phase 3: Exit Read Leveling
+ */
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, (1 << 3), (1 << 3)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_1_REG, (1 << 16), (1 << 16)));
+ /* set ODPG to functional */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+ /*
+ * Copy the result from the effective CS search to the real
+ * Functional CS
+ */
+ ddr3_tip_write_cs_result(dev_num, RL_PHY_REG);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* restore cs enable value */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val[if_id],
+ MASK_ALL_BITS));
+ if (odt_config != 0) {
+ CHECK_STATUS(ddr3_tip_write_additional_odt_setting
+ (dev_num, if_id));
+ }
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (training_result[training_stage][if_id] == TEST_FAILED)
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs,
+ u32 *cs_mask)
+{
+ u32 all_bus_cs = 0, same_bus_cs;
+ u32 bus_cnt;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ *cs_mask = same_bus_cs = CS_BIT_MASK;
+
+ /*
+ * In some of the devices (such as BC2), the CS is per pup and there
+ * for mixed mode is valid on like other devices where CS configuration
+ * is per interface.
+ * In order to know that, we do 'Or' and 'And' operation between all
+ * CS (of the pups).
+ * If they are they are not the same then it's mixed mode so all CS
+ * should be configured (when configuring the MRS)
+ */
+ for (bus_cnt = 0; bus_cnt < tm->num_of_bus_per_interface; bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+
+ all_bus_cs |= tm->interface_params[if_id].
+ as_bus_params[bus_cnt].cs_bitmask;
+ same_bus_cs &= tm->interface_params[if_id].
+ as_bus_params[bus_cnt].cs_bitmask;
+
+ /* cs enable is active low */
+ *cs_mask &= ~tm->interface_params[if_id].
+ as_bus_params[bus_cnt].cs_bitmask;
+ }
+
+ if (all_bus_cs == same_bus_cs)
+ *cs_mask = (*cs_mask | (~(1 << effective_cs))) & CS_BIT_MASK;
+
+ return MV_OK;
+}
+
+/*
+ * Dynamic write leveling
+ */
+int ddr3_tip_dynamic_write_leveling(u32 dev_num)
+{
+ u32 reg_data = 0, iter, if_id, bus_cnt;
+ u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 };
+ u32 cs_mask[MAX_INTERFACE_NUM];
+ u32 read_data_sample_delay_vals[MAX_INTERFACE_NUM] = { 0 };
+ u32 read_data_ready_delay_vals[MAX_INTERFACE_NUM] = { 0 };
+ /* 0 for failure */
+ u32 res_values[MAX_INTERFACE_NUM * MAX_BUS_NUM] = { 0 };
+ u32 test_res = 0; /* 0 - success for all pup */
+ u32 data_read[MAX_INTERFACE_NUM];
+ u8 wl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM];
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ u32 cs_mask0[MAX_INTERFACE_NUM] = { 0 };
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+
+ /* save Read Data Sample Delay */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ READ_DATA_SAMPLE_DELAY,
+ read_data_sample_delay_vals, MASK_ALL_BITS));
+ /* save Read Data Ready Delay */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ READ_DATA_READY_DELAY, read_data_ready_delay_vals,
+ MASK_ALL_BITS));
+ /* save current cs reg val */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS));
+ }
+
+ /*
+ * Phase 1: DRAM 2 Write Leveling mode
+ */
+
+ /*Assert 10 refresh commands to DRAM to all CS */
+ for (iter = 0; iter < WL_ITERATION_NUM; iter++) {
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, SDRAM_OPERATION_REG,
+ (u32)((~(0xf) << 8) | 0x2), 0xf1f));
+ }
+ }
+ /* check controller back to normal */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f,
+ SDRAM_OPERATION_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("WL: DDR3 poll failed(3)"));
+ }
+ }
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ /*enable write leveling to all cs - Q off , WL n */
+ /* calculate interface cs mask */
+ CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask0, MRS1_CMD,
+ 0x1000, 0x1080));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* cs enable is active low */
+ ddr3_tip_calc_cs_mask(dev_num, if_id, effective_cs,
+ &cs_mask[if_id]);
+ }
+
+ /* Enable Output buffer to relevant CS - Q on , WL on */
+ CHECK_STATUS(ddr3_tip_write_mrs_cmd
+ (dev_num, cs_mask, MRS1_CMD, 0x80, 0x1080));
+
+ /*enable odt for relevant CS */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ 0x1498, (0x3 << (effective_cs * 2)), 0xf));
+
+ /*
+ * Phase 2: Set training IP to write leveling mode
+ */
+
+ CHECK_STATUS(ddr3_tip_dynamic_write_leveling_seq(dev_num));
+
+ /*
+ * Phase 3: Trigger training
+ */
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1));
+
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ /* training done */
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ (1 << 1), (1 << 1), ODPG_TRAINING_STATUS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("WL: DDR3 poll (4) failed (Data: 0x%x)\n",
+ reg_data));
+ }
+#if !defined(CONFIG_ARMADA_38X) /*Disabled. JIRA #1498 */
+ else {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id,
+ ODPG_TRAINING_TRIGGER_REG,
+ &reg_data, (1 << 2)));
+ if (reg_data != 0) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("WL: WL failed IF %d reg_data=0x%x\n",
+ if_id, reg_data));
+ }
+ }
+#endif
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* training done */
+ if (ddr3_tip_if_polling
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ (1 << 1), (1 << 1), ODPG_TRAINING_STATUS_REG,
+ MAX_POLLING_ITERATIONS) != MV_OK) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("WL: DDR3 poll (4) failed (Data: 0x%x)\n",
+ reg_data));
+ } else {
+#if !defined(CONFIG_ARMADA_38X) /*Disabled. JIRA #1498 */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id,
+ ODPG_TRAINING_STATUS_REG,
+ data_read, (1 << 2)));
+ reg_data = data_read[if_id];
+ if (reg_data != 0) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("WL: WL failed IF %d reg_data=0x%x\n",
+ if_id, reg_data));
+ }
+#endif
+
+ /* check for training completion per bus */
+ for (bus_cnt = 0;
+ bus_cnt < tm->num_of_bus_per_interface;
+ bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask,
+ bus_cnt);
+ /* training status */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ mask_results_pup_reg_map
+ [bus_cnt], data_read,
+ (1 << 25)));
+ reg_data = data_read[if_id];
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL: IF %d BUS %d reg 0x%x\n",
+ if_id, bus_cnt, reg_data));
+ if (reg_data == 0) {
+ res_values[
+ (if_id *
+ tm->num_of_bus_per_interface)
+ + bus_cnt] = 1;
+ }
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ mask_results_pup_reg_map
+ [bus_cnt], data_read,
+ 0xff));
+ /*
+ * Save the read value that should be
+ * write to PHY register
+ */
+ wl_values[effective_cs]
+ [bus_cnt][if_id] =
+ (u8)data_read[if_id];
+ }
+ }
+ }
+
+ /*
+ * Phase 4: Exit write leveling mode
+ */
+
+ /* disable DQs toggling */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ WR_LEVELING_DQS_PATTERN_REG, 0x0, 0x1));
+
+ /* Update MRS 1 (WL off) */
+ CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask0, MRS1_CMD,
+ 0x1000, 0x1080));
+
+ /* Update MRS 1 (return to functional mode - Q on , WL off) */
+ CHECK_STATUS(ddr3_tip_write_mrs_cmd
+ (dev_num, cs_mask0, MRS1_CMD, 0x0, 0x1080));
+
+ /* set phy to normal mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x5, 0x7));
+
+ /* exit sw override mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x4, 0x7));
+ }
+
+ /*
+ * Phase 5: Load WL values to each PHY
+ */
+
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ test_res = 0;
+ for (bus_cnt = 0;
+ bus_cnt < tm->num_of_bus_per_interface;
+ bus_cnt++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+ /* check if result == pass */
+ if (res_values
+ [(if_id *
+ tm->num_of_bus_per_interface) +
+ bus_cnt] == 0) {
+ /*
+ * read result control register
+ * according to pup
+ */
+ reg_data =
+ wl_values[effective_cs][bus_cnt]
+ [if_id];
+ /*
+ * Write into write leveling register
+ * ([4:0] ADLL, [8:6] Phase, [15:10]
+ * (centralization) ADLL + 0x10)
+ */
+ reg_data =
+ (reg_data & 0x1f) |
+ (((reg_data & 0xe0) >> 5) << 6) |
+ (((reg_data & 0x1f) +
+ phy_reg1_val) << 10);
+ ddr3_tip_bus_write(
+ dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST,
+ bus_cnt,
+ DDR_PHY_DATA,
+ WL_PHY_REG +
+ effective_cs *
+ CS_REGISTER_ADDR_OFFSET,
+ reg_data);
+ } else {
+ test_res = 1;
+ /*
+ * read result control register
+ * according to pup
+ */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ mask_results_pup_reg_map
+ [bus_cnt], data_read,
+ 0xff));
+ reg_data = data_read[if_id];
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("WL: IF %d BUS %d failed, reg 0x%x\n",
+ if_id, bus_cnt, reg_data));
+ }
+ }
+
+ if (test_res != 0) {
+ training_result[training_stage][if_id] =
+ TEST_FAILED;
+ }
+ }
+ }
+ /* Set to 0 after each loop to avoid illegal value may be used */
+ effective_cs = 0;
+
+ /*
+ * Copy the result from the effective CS search to the real
+ * Functional CS
+ */
+ /* ddr3_tip_write_cs_result(dev_num, WL_PHY_REG); */
+ /* restore saved values */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* restore Read Data Sample Delay */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ READ_DATA_SAMPLE_DELAY,
+ read_data_sample_delay_vals[if_id],
+ MASK_ALL_BITS));
+
+ /* restore Read Data Ready Delay */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ READ_DATA_READY_DELAY,
+ read_data_ready_delay_vals[if_id],
+ MASK_ALL_BITS));
+
+ /* enable multi cs */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val[if_id],
+ MASK_ALL_BITS));
+ }
+
+ /* Disable modt0 for CS0 training - need to adjust for multy CS */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x1498,
+ 0x0, 0xf));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (training_result[training_stage][if_id] == TEST_FAILED)
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Dynamic write leveling supplementary
+ */
+int ddr3_tip_dynamic_write_leveling_supp(u32 dev_num)
+{
+ int adll_offset;
+ u32 if_id, bus_id, data, data_tmp;
+ int is_if_fail = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ is_if_fail = 0;
+
+ for (bus_id = 0; bus_id < GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ wr_supp_res[if_id][bus_id].is_pup_fail = 1;
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ effective_cs * CS_REGISTER_ADDR_OFFSET,
+ &data));
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL Supp: adll_offset=0 data delay = %d\n",
+ data));
+ if (ddr3_tip_wl_supp_align_phase_shift
+ (dev_num, if_id, bus_id, 0, 0) == MV_OK) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL Supp: IF %d bus_id %d adll_offset=0 Success !\n",
+ if_id, bus_id));
+ continue;
+ }
+
+ /* change adll */
+ adll_offset = 5;
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, bus_id, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ effective_cs * CS_REGISTER_ADDR_OFFSET,
+ data + adll_offset));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ effective_cs * CS_REGISTER_ADDR_OFFSET,
+ &data_tmp));
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL Supp: adll_offset= %d data delay = %d\n",
+ adll_offset, data_tmp));
+
+ if (ddr3_tip_wl_supp_align_phase_shift
+ (dev_num, if_id, bus_id, adll_offset, 0) == MV_OK) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL Supp: IF %d bus_id %d adll_offset= %d Success !\n",
+ if_id, bus_id, adll_offset));
+ continue;
+ }
+
+ /* change adll */
+ adll_offset = -5;
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, bus_id, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ effective_cs * CS_REGISTER_ADDR_OFFSET,
+ data + adll_offset));
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA,
+ WRITE_CENTRALIZATION_PHY_REG +
+ effective_cs * CS_REGISTER_ADDR_OFFSET,
+ &data_tmp));
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL Supp: adll_offset= %d data delay = %d\n",
+ adll_offset, data_tmp));
+ if (ddr3_tip_wl_supp_align_phase_shift
+ (dev_num, if_id, bus_id, adll_offset, 0) == MV_OK) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("WL Supp: IF %d bus_id %d adll_offset= %d Success !\n",
+ if_id, bus_id, adll_offset));
+ continue;
+ } else {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_ERROR,
+ ("WL Supp: IF %d bus_id %d Failed !\n",
+ if_id, bus_id));
+ is_if_fail = 1;
+ }
+ }
+ DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+ ("WL Supp: IF %d bus_id %d is_pup_fail %d\n",
+ if_id, bus_id, is_if_fail));
+
+ if (is_if_fail == 1) {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("WL Supp: IF %d failed\n", if_id));
+ training_result[training_stage][if_id] = TEST_FAILED;
+ } else {
+ training_result[training_stage][if_id] = TEST_SUCCESS;
+ }
+ }
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (training_result[training_stage][if_id] == TEST_FAILED)
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Phase Shift
+ */
+static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id,
+ u32 bus_id, u32 offset,
+ u32 bus_id_delta)
+{
+ wr_supp_res[if_id][bus_id].stage = PHASE_SHIFT;
+ if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id,
+ 0, bus_id_delta) == MV_OK) {
+ wr_supp_res[if_id][bus_id].is_pup_fail = 0;
+ return MV_OK;
+ } else if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id,
+ ONE_CLOCK_ERROR_SHIFT,
+ bus_id_delta) == MV_OK) {
+ /* 1 clock error */
+ wr_supp_res[if_id][bus_id].stage = CLOCK_SHIFT;
+ DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+ ("Supp: 1 error clock for if %d pup %d with ofsset %d success\n",
+ if_id, bus_id, offset));
+ ddr3_tip_wl_supp_one_clk_err_shift(dev_num, if_id, bus_id, 0);
+ wr_supp_res[if_id][bus_id].is_pup_fail = 0;
+ return MV_OK;
+ } else if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id,
+ ALIGN_ERROR_SHIFT,
+ bus_id_delta) == MV_OK) {
+ /* align error */
+ DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+ ("Supp: align error for if %d pup %d with ofsset %d success\n",
+ if_id, bus_id, offset));
+ wr_supp_res[if_id][bus_id].stage = ALIGN_SHIFT;
+ ddr3_tip_wl_supp_align_err_shift(dev_num, if_id, bus_id, 0);
+ wr_supp_res[if_id][bus_id].is_pup_fail = 0;
+ return MV_OK;
+ } else {
+ wr_supp_res[if_id][bus_id].is_pup_fail = 1;
+ return MV_FAIL;
+ }
+}
+
+/*
+ * Compare Test
+ */
+static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id,
+ u32 edge_offset, u32 bus_id_delta)
+{
+ u32 num_of_succ_byte_compare, word_in_pattern, abs_offset;
+ u32 word_offset, i;
+ u32 read_pattern[TEST_PATTERN_LENGTH * 2];
+ struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+ u32 pattern_test_pattern_table[8];
+
+ for (i = 0; i < 8; i++) {
+ pattern_test_pattern_table[i] =
+ pattern_table_get_word(dev_num, PATTERN_TEST, (u8)i);
+ }
+
+ /* extern write, than read and compare */
+ CHECK_STATUS(ddr3_tip_ext_write
+ (dev_num, if_id,
+ (pattern_table[PATTERN_TEST].start_addr +
+ ((SDRAM_CS_SIZE + 1) * effective_cs)), 1,
+ pattern_test_pattern_table));
+
+ CHECK_STATUS(ddr3_tip_reset_fifo_ptr(dev_num));
+
+ CHECK_STATUS(ddr3_tip_ext_read
+ (dev_num, if_id,
+ (pattern_table[PATTERN_TEST].start_addr +
+ ((SDRAM_CS_SIZE + 1) * effective_cs)), 1, read_pattern));
+
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("XSB-compt: IF %d bus_id %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ if_id, bus_id, read_pattern[0], read_pattern[1],
+ read_pattern[2], read_pattern[3], read_pattern[4],
+ read_pattern[5], read_pattern[6], read_pattern[7]));
+
+ /* compare byte per pup */
+ num_of_succ_byte_compare = 0;
+ for (word_in_pattern = start_xsb_offset;
+ word_in_pattern < (TEST_PATTERN_LENGTH * 2); word_in_pattern++) {
+ word_offset = word_in_pattern + edge_offset;
+ if ((word_offset > (TEST_PATTERN_LENGTH * 2 - 1)) ||
+ (word_offset < 0))
+ continue;
+
+ if ((read_pattern[word_in_pattern] & pup_mask_table[bus_id]) ==
+ (pattern_test_pattern_table[word_offset] &
+ pup_mask_table[bus_id]))
+ num_of_succ_byte_compare++;
+ }
+
+ abs_offset = (edge_offset > 0) ? edge_offset : -edge_offset;
+ if (num_of_succ_byte_compare == ((TEST_PATTERN_LENGTH * 2) -
+ abs_offset - start_xsb_offset)) {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Success\n",
+ if_id, bus_id, num_of_succ_byte_compare));
+ return MV_OK;
+ } else {
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Fail !\n",
+ if_id, bus_id, num_of_succ_byte_compare));
+
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("XSB-compt: expected 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pattern_test_pattern_table[0],
+ pattern_test_pattern_table[1],
+ pattern_test_pattern_table[2],
+ pattern_test_pattern_table[3],
+ pattern_test_pattern_table[4],
+ pattern_test_pattern_table[5],
+ pattern_test_pattern_table[6],
+ pattern_test_pattern_table[7]));
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("XSB-compt: recieved 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ read_pattern[0], read_pattern[1],
+ read_pattern[2], read_pattern[3],
+ read_pattern[4], read_pattern[5],
+ read_pattern[6], read_pattern[7]));
+
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Fail !\n",
+ if_id, bus_id, num_of_succ_byte_compare));
+
+ return MV_FAIL;
+ }
+}
+
+/*
+ * Clock error shift - function moves the write leveling delay 1cc forward
+ */
+static int ddr3_tip_wl_supp_one_clk_err_shift(u32 dev_num, u32 if_id,
+ u32 bus_id, u32 bus_id_delta)
+{
+ int phase, adll;
+ u32 data;
+ DEBUG_LEVELING(DEBUG_LEVEL_TRACE, ("One_clk_err_shift\n"));
+
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id, ACCESS_TYPE_UNICAST, bus_id,
+ DDR_PHY_DATA, WL_PHY_REG, &data));
+ phase = ((data >> 6) & 0x7);
+ adll = data & 0x1f;
+ DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+ ("One_clk_err_shift: IF %d bus_id %d phase %d adll %d\n",
+ if_id, bus_id, phase, adll));
+
+ if ((phase == 0) || (phase == 1)) {
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, bus_id,
+ DDR_PHY_DATA, 0, (phase + 2), 0x1f));
+ } else if (phase == 2) {
+ if (adll < 6) {
+ data = (3 << 6) + (0x1f);
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ bus_id, DDR_PHY_DATA, 0, data,
+ (0x7 << 6 | 0x1f)));
+ data = 0x2f;
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ bus_id, DDR_PHY_DATA, 1, data, 0x3f));
+ }
+ } else {
+ /* phase 3 */
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Align error shift
+ */
+static int ddr3_tip_wl_supp_align_err_shift(u32 dev_num, u32 if_id,
+ u32 bus_id, u32 bus_id_delta)
+{
+ int phase, adll;
+ u32 data;
+
+ /* Shift WL result 1 phase back */
+ CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id, ACCESS_TYPE_UNICAST,
+ bus_id, DDR_PHY_DATA, WL_PHY_REG,
+ &data));
+ phase = ((data >> 6) & 0x7);
+ adll = data & 0x1f;
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_TRACE,
+ ("Wl_supp_align_err_shift: IF %d bus_id %d phase %d adll %d\n",
+ if_id, bus_id, phase, adll));
+
+ if (phase < 2) {
+ if (adll > 0x1a) {
+ if (phase == 0)
+ return MV_FAIL;
+
+ if (phase == 1) {
+ data = 0;
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, bus_id, DDR_PHY_DATA,
+ 0, data, (0x7 << 6 | 0x1f)));
+ data = 0xf;
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, bus_id, DDR_PHY_DATA,
+ 1, data, 0x1f));
+ return MV_OK;
+ }
+ } else {
+ return MV_FAIL;
+ }
+ } else if ((phase == 2) || (phase == 3)) {
+ phase = phase - 2;
+ data = (phase << 6) + (adll & 0x1f);
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id, bus_id,
+ DDR_PHY_DATA, 0, data, (0x7 << 6 | 0x1f)));
+ return MV_OK;
+ } else {
+ DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+ ("Wl_supp_align_err_shift: unexpected phase\n"));
+
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Dynamic write leveling sequence
+ */
+static int ddr3_tip_dynamic_write_leveling_seq(u32 dev_num)
+{
+ u32 bus_id, dq_id;
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_SW_2_REG, 0x1, 0x5));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_WRITE_LEVELING_REG, 0x50, 0xff));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_WRITE_LEVELING_REG, 0x5c, 0xff));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_TRAINING_CONTROL_REG, 0x381b82, 0x3c3faf));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_OBJ1_OPCODE_REG, (0x3 << 25), (0x3ffff << 9)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_OBJ1_ITER_CNT_REG, 0x80, 0xffff));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_WRITE_LEVELING_DONE_CNTR_REG, 0x14, 0xff));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ TRAINING_WRITE_LEVELING_REG, 0xff5c, 0xffff));
+
+ /* mask PBS */
+ for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_dq_reg_map[dq_id], 0x1 << 24,
+ 0x1 << 24));
+ }
+
+ /* Mask all results */
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_pup_reg_map[bus_id], 0x1 << 24,
+ 0x1 << 24));
+ }
+
+ /* Unmask only wanted */
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_pup_reg_map[bus_id], 0, 0x1 << 24));
+ }
+
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ WR_LEVELING_DQS_PATTERN_REG, 0x1, 0x1));
+
+ return MV_OK;
+}
+
+/*
+ * Dynamic read leveling sequence
+ */
+static int ddr3_tip_dynamic_read_leveling_seq(u32 dev_num)
+{
+ u32 bus_id, dq_id;
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* mask PBS */
+ for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_dq_reg_map[dq_id], 0x1 << 24,
+ 0x1 << 24));
+ }
+
+ /* Mask all results */
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_pup_reg_map[bus_id], 0x1 << 24,
+ 0x1 << 24));
+ }
+
+ /* Unmask only wanted */
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_pup_reg_map[bus_id], 0, 0x1 << 24));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Dynamic read leveling sequence
+ */
+static int ddr3_tip_dynamic_per_bit_read_leveling_seq(u32 dev_num)
+{
+ u32 bus_id, dq_id;
+ u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* mask PBS */
+ for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_dq_reg_map[dq_id], 0x1 << 24,
+ 0x1 << 24));
+ }
+
+ /* Mask all results */
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_pup_reg_map[bus_id], 0x1 << 24,
+ 0x1 << 24));
+ }
+
+ /* Unmask only wanted */
+ for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, dq_id / 8);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ mask_results_dq_reg_map[dq_id], 0x0 << 24,
+ 0x1 << 24));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Print write leveling supplementary results
+ */
+int ddr3_tip_print_wl_supp_result(u32 dev_num)
+{
+ u32 bus_id = 0, if_id = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ DEBUG_LEVELING(DEBUG_LEVEL_INFO,
+ ("I/F0 PUP0 Result[0 - success, 1-fail] ...\n"));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ DEBUG_LEVELING(DEBUG_LEVEL_INFO,
+ ("%d ,", wr_supp_res[if_id]
+ [bus_id].is_pup_fail));
+ }
+ }
+ DEBUG_LEVELING(
+ DEBUG_LEVEL_INFO,
+ ("I/F0 PUP0 Stage[0-phase_shift, 1-clock_shift, 2-align_shift] ...\n"));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+ bus_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+ DEBUG_LEVELING(DEBUG_LEVEL_INFO,
+ ("%d ,", wr_supp_res[if_id]
+ [bus_id].stage));
+ }
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.h b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h
new file mode 100644
index 0000000000..f2b4177082
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_LEVELING_H_
+#define _DDR3_TRAINING_LEVELING_H_
+
+#define MAX_DQ_READ_LEVELING_DELAY 15
+
+int ddr3_tip_print_wl_supp_result(u32 dev_num);
+int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs,
+ u32 *cs_mask);
+u32 hws_ddr3_tip_max_cs_get(void);
+
+#endif /* _DDR3_TRAINING_LEVELING_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_pbs.c b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c
new file mode 100644
index 0000000000..2b4a58fb9f
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c
@@ -0,0 +1,995 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define TYPICAL_PBS_VALUE 12
+
+u32 nominal_adll[MAX_INTERFACE_NUM * MAX_BUS_NUM];
+enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM];
+u8 result_mat[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS];
+u8 result_mat_rx_dqs[MAX_INTERFACE_NUM][MAX_BUS_NUM][MAX_CS_NUM];
+/* 4-EEWA, 3-EWA, 2-SWA, 1-Fail, 0-Pass */
+u8 result_all_bit[MAX_BUS_NUM * BUS_WIDTH_IN_BITS * MAX_INTERFACE_NUM];
+u8 max_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 min_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 max_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 min_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u32 pbsdelay_per_pup[NUM_OF_PBS_MODES][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 adll_shift_lock[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 adll_shift_val[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+enum hws_pattern pbs_pattern = PATTERN_VREF;
+static u8 pup_state[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+
+/*
+ * Name: ddr3_tip_pbs
+ * Desc: PBS
+ * Args: TBD
+ * Notes:
+ * Returns: OK if success, other error code if fail.
+ */
+int ddr3_tip_pbs(u32 dev_num, enum pbs_dir pbs_mode)
+{
+ u32 res0[MAX_INTERFACE_NUM];
+ int adll_tap = MEGA / freq_val[medium_freq] / 64;
+ int pad_num = 0;
+ enum hws_search_dir search_dir =
+ (pbs_mode == PBS_RX_MODE) ? HWS_HIGH2LOW : HWS_LOW2HIGH;
+ enum hws_dir dir = (pbs_mode == PBS_RX_MODE) ? OPER_READ : OPER_WRITE;
+ int iterations = (pbs_mode == PBS_RX_MODE) ? 31 : 63;
+ u32 res_valid_mask = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
+ int init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations;
+ enum hws_edge_compare search_edge = EDGE_FP;
+ u32 pup = 0, bit = 0, if_id = 0, all_lock = 0, cs_num = 0;
+ int reg_addr = 0;
+ u32 validation_val = 0;
+ u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
+ u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+ u8 temp = 0;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /* save current cs enable reg val */
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ /* save current cs enable reg val */
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS));
+
+ /* enable single cs */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, (1 << 3), (1 << 3)));
+ }
+
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (READ_CENTRALIZATION_PHY_REG +
+ (effective_cs * CS_REGISTER_ADDR_OFFSET)) :
+ (WRITE_CENTRALIZATION_PHY_REG +
+ (effective_cs * CS_REGISTER_ADDR_OFFSET));
+ read_adll_value(nominal_adll, reg_addr, MASK_ALL_BITS);
+
+ /* stage 1 shift ADLL */
+ ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, RESULT_PER_BIT,
+ HWS_CONTROL_ELEMENT_ADLL, search_dir, dir,
+ tm->if_act_mask, init_val, iterations,
+ pbs_pattern, search_edge, CS_SINGLE, cs_num,
+ train_status);
+ validation_val = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0;
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ min_adll_per_pup[if_id][pup] =
+ (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
+ pup_state[if_id][pup] = 0x3;
+ adll_shift_lock[if_id][pup] = 1;
+ max_adll_per_pup[if_id][pup] = 0x0;
+ }
+ }
+
+ /* EBA */
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ mask_results_dq_reg_map[
+ bit + pup * BUS_WIDTH_IN_BITS],
+ res0, MASK_ALL_BITS));
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+ if_id, bit, pup,
+ res0[if_id]));
+ if (pup_state[if_id][pup] != 3)
+ continue;
+ /* if not EBA state than move to next pup */
+
+ if ((res0[if_id] & 0x2000000) == 0) {
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("-- Fail Training IP\n"));
+ /* training machine failed */
+ pup_state[if_id][pup] = 1;
+ adll_shift_lock[if_id][pup] = 0;
+ continue;
+ }
+
+ else if ((res0[if_id] & res_valid_mask) ==
+ validation_val) {
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("-- FAIL EBA %d %d %d %d\n",
+ if_id, bit, pup,
+ res0[if_id]));
+ pup_state[if_id][pup] = 4;
+ /* this pup move to EEBA */
+ adll_shift_lock[if_id][pup] = 0;
+ continue;
+ } else {
+ /*
+ * The search ended in Pass we need
+ * Fail
+ */
+ res0[if_id] =
+ (pbs_mode == PBS_RX_MODE) ?
+ ((res0[if_id] &
+ res_valid_mask) + 1) :
+ ((res0[if_id] &
+ res_valid_mask) - 1);
+ max_adll_per_pup[if_id][pup] =
+ (max_adll_per_pup[if_id][pup] <
+ res0[if_id]) ?
+ (u8)res0[if_id] :
+ max_adll_per_pup[if_id][pup];
+ min_adll_per_pup[if_id][pup] =
+ (res0[if_id] >
+ min_adll_per_pup[if_id][pup]) ?
+ min_adll_per_pup[if_id][pup] :
+ (u8)
+ res0[if_id];
+ /*
+ * vs the Rx we are searching for the
+ * smallest value of DQ shift so all
+ * Bus would fail
+ */
+ adll_shift_val[if_id][pup] =
+ (pbs_mode == PBS_RX_MODE) ?
+ max_adll_per_pup[if_id][pup] :
+ min_adll_per_pup[if_id][pup];
+ }
+ }
+ }
+ }
+
+ /* EEBA */
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ if (pup_state[if_id][pup] != 4)
+ continue;
+ /*
+ * if pup state different from EEBA than move to
+ * next pup
+ */
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x54 + effective_cs * 0x10) :
+ (0x14 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
+ reg_addr, 0x1f));
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x55 + effective_cs * 0x10) :
+ (0x15 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
+ reg_addr, 0x1f));
+ /* initialize the Edge2 Max. */
+ adll_shift_val[if_id][pup] = 0;
+ min_adll_per_pup[if_id][pup] =
+ (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
+ max_adll_per_pup[if_id][pup] = 0x0;
+
+ ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, RESULT_PER_BIT,
+ HWS_CONTROL_ELEMENT_ADLL,
+ search_dir, dir,
+ tm->if_act_mask, init_val,
+ iterations, pbs_pattern,
+ search_edge, CS_SINGLE, cs_num,
+ train_status);
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ ("ADLL shift results:\n"));
+
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ mask_results_dq_reg_map[
+ bit + pup *
+ BUS_WIDTH_IN_BITS],
+ res0, MASK_ALL_BITS));
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+ if_id, bit, pup,
+ res0[if_id]));
+
+ if ((res0[if_id] & 0x2000000) == 0) {
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ (" -- EEBA Fail\n"));
+ bit = BUS_WIDTH_IN_BITS;
+ /* exit bit loop */
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("-- EEBA Fail Training IP\n"));
+ /*
+ * training machine failed but pass
+ * before in the EBA so maybe the DQS
+ * shift change env.
+ */
+ pup_state[if_id][pup] = 2;
+ adll_shift_lock[if_id][pup] = 0;
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x54 + effective_cs * 0x10) :
+ (0x14 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ 0x0));
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x55 + effective_cs * 0x10) :
+ (0x15 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ 0x0));
+ continue;
+ } else if ((res0[if_id] & res_valid_mask) ==
+ validation_val) {
+ /* exit bit loop */
+ bit = BUS_WIDTH_IN_BITS;
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("-- FAIL EEBA\n"));
+ /* this pup move to SBA */
+ pup_state[if_id][pup] = 2;
+ adll_shift_lock[if_id][pup] = 0;
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x54 + effective_cs * 0x10) :
+ (0x14 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ 0x0));
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x55 + effective_cs * 0x10) :
+ (0x15 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num,
+ ACCESS_TYPE_UNICAST,
+ if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ 0x0));
+ continue;
+ } else {
+ adll_shift_lock[if_id][pup] = 1;
+ /*
+ * The search ended in Pass we need
+ * Fail
+ */
+ res0[if_id] =
+ (pbs_mode == PBS_RX_MODE) ?
+ ((res0[if_id] &
+ res_valid_mask) + 1) :
+ ((res0[if_id] &
+ res_valid_mask) - 1);
+ max_adll_per_pup[if_id][pup] =
+ (max_adll_per_pup[if_id][pup] <
+ res0[if_id]) ?
+ (u8)res0[if_id] :
+ max_adll_per_pup[if_id][pup];
+ min_adll_per_pup[if_id][pup] =
+ (res0[if_id] >
+ min_adll_per_pup[if_id][pup]) ?
+ min_adll_per_pup[if_id][pup] :
+ (u8)res0[if_id];
+ /*
+ * vs the Rx we are searching for the
+ * smallest value of DQ shift so all Bus
+ * would fail
+ */
+ adll_shift_val[if_id][pup] =
+ (pbs_mode == PBS_RX_MODE) ?
+ max_adll_per_pup[if_id][pup] :
+ min_adll_per_pup[if_id][pup];
+ }
+ }
+ }
+ }
+
+ /* Print Stage result */
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("FP I/F %d, ADLL Shift for EBA: pup[%d] Lock status = %d Lock Val = %d,%d\n",
+ if_id, pup,
+ adll_shift_lock[if_id][pup],
+ max_adll_per_pup[if_id][pup],
+ min_adll_per_pup[if_id][pup]));
+ }
+ }
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ ("Update ADLL Shift of all pups:\n"));
+
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (adll_shift_lock[if_id][pup] != 1)
+ continue;
+ /* if pup not locked continue to next pup */
+
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x3 + effective_cs * 4) :
+ (0x1 + effective_cs * 4);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
+ reg_addr, adll_shift_val[if_id][pup]));
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+ ("FP I/F %d, Pup[%d] = %d\n", if_id,
+ pup, adll_shift_val[if_id][pup]));
+ }
+ }
+
+ /* PBS EEBA&EBA */
+ /* Start the Per Bit Skew search */
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ max_pbs_per_pup[if_id][pup] = 0x0;
+ min_pbs_per_pup[if_id][pup] = 0x1f;
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ /* reset result for PBS */
+ result_all_bit[bit + pup * BUS_WIDTH_IN_BITS +
+ if_id * MAX_BUS_NUM *
+ BUS_WIDTH_IN_BITS] = 0;
+ }
+ }
+ }
+
+ iterations = 31;
+ search_dir = HWS_LOW2HIGH;
+ /* !!!!! ran sh (search_dir == HWS_LOW2HIGH)?0:iterations; */
+ init_val = 0;
+
+ ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ RESULT_PER_BIT, HWS_CONTROL_ELEMENT_DQ_SKEW,
+ search_dir, dir, tm->if_act_mask, init_val,
+ iterations, pbs_pattern, search_edge,
+ CS_SINGLE, cs_num, train_status);
+
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (adll_shift_lock[if_id][pup] != 1) {
+ /* if pup not lock continue to next pup */
+ continue;
+ }
+
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ mask_results_dq_reg_map[
+ bit +
+ pup * BUS_WIDTH_IN_BITS],
+ res0, MASK_ALL_BITS));
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ ("Per Bit Skew search, FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+ if_id, bit, pup,
+ res0[if_id]));
+ if ((res0[if_id] & 0x2000000) == 0) {
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ ("--EBA PBS Fail - Training IP machine\n"));
+ /* exit the bit loop */
+ bit = BUS_WIDTH_IN_BITS;
+ /*
+ * ADLL is no long in lock need new
+ * search
+ */
+ adll_shift_lock[if_id][pup] = 0;
+ /* Move to SBA */
+ pup_state[if_id][pup] = 2;
+ max_pbs_per_pup[if_id][pup] = 0x0;
+ min_pbs_per_pup[if_id][pup] = 0x1f;
+ continue;
+ } else {
+ temp = (u8)(res0[if_id] &
+ res_valid_mask);
+ max_pbs_per_pup[if_id][pup] =
+ (temp >
+ max_pbs_per_pup[if_id][pup]) ?
+ temp :
+ max_pbs_per_pup[if_id][pup];
+ min_pbs_per_pup[if_id][pup] =
+ (temp <
+ min_pbs_per_pup[if_id][pup]) ?
+ temp :
+ min_pbs_per_pup[if_id][pup];
+ result_all_bit[bit +
+ pup * BUS_WIDTH_IN_BITS +
+ if_id * MAX_BUS_NUM *
+ BUS_WIDTH_IN_BITS] =
+ temp;
+ }
+ }
+ }
+ }
+
+ /* Check all Pup lock */
+ all_lock = 1;
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ all_lock = all_lock * adll_shift_lock[if_id][pup];
+ }
+ }
+
+ /* Only if not all Pups Lock */
+ if (all_lock == 0) {
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ ("##########ADLL shift for SBA###########\n"));
+
+ /* ADLL shift for SBA */
+ search_dir = (pbs_mode == PBS_RX_MODE) ? HWS_LOW2HIGH :
+ HWS_HIGH2LOW;
+ init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations;
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ if (adll_shift_lock[if_id][pup] == 1) {
+ /*if pup lock continue to next pup */
+ continue;
+ }
+ /*init the var altogth init before */
+ adll_shift_lock[if_id][pup] = 0;
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x54 + effective_cs * 0x10) :
+ (0x14 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr, 0));
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x55 + effective_cs * 0x10) :
+ (0x15 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr, 0));
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x5f + effective_cs * 0x10) :
+ (0x1f + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr, 0));
+ /* initilaze the Edge2 Max. */
+ adll_shift_val[if_id][pup] = 0;
+ min_adll_per_pup[if_id][pup] = 0x1f;
+ max_adll_per_pup[if_id][pup] = 0x0;
+
+ ddr3_tip_ip_training(dev_num,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ RESULT_PER_BIT,
+ HWS_CONTROL_ELEMENT_ADLL,
+ search_dir, dir,
+ tm->if_act_mask,
+ init_val, iterations,
+ pbs_pattern,
+ search_edge, CS_SINGLE,
+ cs_num, train_status);
+
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ mask_results_dq_reg_map
+ [bit +
+ pup *
+ BUS_WIDTH_IN_BITS],
+ res0, MASK_ALL_BITS));
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+ if_id, bit, pup, res0[if_id]));
+ if ((res0[if_id] & 0x2000000) == 0) {
+ /* exit the bit loop */
+ bit = BUS_WIDTH_IN_BITS;
+ /* Fail SBA --> Fail PBS */
+ pup_state[if_id][pup] = 1;
+ DEBUG_PBS_ENGINE
+ (DEBUG_LEVEL_INFO,
+ (" SBA Fail\n"));
+ continue;
+ } else {
+ /*
+ * - increment to get all
+ * 8 bit lock.
+ */
+ adll_shift_lock[if_id][pup]++;
+ /*
+ * The search ended in Pass
+ * we need Fail
+ */
+ res0[if_id] =
+ (pbs_mode == PBS_RX_MODE) ?
+ ((res0[if_id] & res_valid_mask) + 1) :
+ ((res0[if_id] & res_valid_mask) - 1);
+ max_adll_per_pup[if_id][pup] =
+ (max_adll_per_pup[if_id]
+ [pup] < res0[if_id]) ?
+ (u8)res0[if_id] :
+ max_adll_per_pup[if_id][pup];
+ min_adll_per_pup[if_id][pup] =
+ (res0[if_id] >
+ min_adll_per_pup[if_id]
+ [pup]) ?
+ min_adll_per_pup[if_id][pup] :
+ (u8)res0[if_id];
+ /*
+ * vs the Rx we are searching for
+ * the smallest value of DQ shift
+ * so all Bus would fail
+ */
+ adll_shift_val[if_id][pup] =
+ (pbs_mode == PBS_RX_MODE) ?
+ max_adll_per_pup[if_id][pup] :
+ min_adll_per_pup[if_id][pup];
+ }
+ }
+ /* 1 is lock */
+ adll_shift_lock[if_id][pup] =
+ (adll_shift_lock[if_id][pup] == 8) ?
+ 1 : 0;
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x3 + effective_cs * 4) :
+ (0x1 + effective_cs * 4);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ adll_shift_val[if_id][pup]));
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("adll_shift_lock[%x][%x] = %x\n",
+ if_id, pup,
+ adll_shift_lock[if_id][pup]));
+ }
+ }
+
+ /* End ADLL Shift for SBA */
+ /* Start the Per Bit Skew search */
+ /* The ADLL shift finished with a Pass */
+ search_edge = (pbs_mode == PBS_RX_MODE) ? EDGE_PF : EDGE_FP;
+ search_dir = (pbs_mode == PBS_RX_MODE) ?
+ HWS_LOW2HIGH : HWS_HIGH2LOW;
+ iterations = 0x1f;
+ /* - The initial value is different in Rx and Tx mode */
+ init_val = (pbs_mode == PBS_RX_MODE) ? 0 : iterations;
+
+ ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE, RESULT_PER_BIT,
+ HWS_CONTROL_ELEMENT_DQ_SKEW,
+ search_dir, dir, tm->if_act_mask,
+ init_val, iterations, pbs_pattern,
+ search_edge, CS_SINGLE, cs_num,
+ train_status);
+
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num,
+ ACCESS_TYPE_MULTICAST,
+ PARAM_NOT_CARE,
+ mask_results_dq_reg_map
+ [bit +
+ pup *
+ BUS_WIDTH_IN_BITS],
+ res0, MASK_ALL_BITS));
+ if (pup_state[if_id][pup] != 2) {
+ /*
+ * if pup is not SBA continue
+ * to next pup
+ */
+ bit = BUS_WIDTH_IN_BITS;
+ continue;
+ }
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("Per Bit Skew search, PF I/F %d, bit:%d, pup:%d res0 0x%x\n",
+ if_id, bit, pup, res0[if_id]));
+ if ((res0[if_id] & 0x2000000) == 0) {
+ DEBUG_PBS_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("SBA Fail\n"));
+
+ max_pbs_per_pup[if_id][pup] =
+ 0x1f;
+ result_all_bit[
+ bit + pup *
+ BUS_WIDTH_IN_BITS +
+ if_id * MAX_BUS_NUM *
+ BUS_WIDTH_IN_BITS] =
+ 0x1f;
+ } else {
+ temp = (u8)(res0[if_id] &
+ res_valid_mask);
+ max_pbs_per_pup[if_id][pup] =
+ (temp >
+ max_pbs_per_pup[if_id]
+ [pup]) ? temp :
+ max_pbs_per_pup
+ [if_id][pup];
+ min_pbs_per_pup[if_id][pup] =
+ (temp <
+ min_pbs_per_pup[if_id]
+ [pup]) ? temp :
+ min_pbs_per_pup
+ [if_id][pup];
+ result_all_bit[
+ bit + pup *
+ BUS_WIDTH_IN_BITS +
+ if_id * MAX_BUS_NUM *
+ BUS_WIDTH_IN_BITS] =
+ temp;
+ adll_shift_lock[if_id][pup] = 1;
+ }
+ }
+ }
+ }
+
+ /* Check all Pup state */
+ all_lock = 1;
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ /*
+ * DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ * ("pup_state[%d][%d] = %d\n",if_id,pup,pup_state
+ * [if_id][pup]));
+ */
+ }
+ }
+
+ /* END OF SBA */
+ /* Norm */
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+ if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /* if pup not lock continue to next pup */
+ if (adll_shift_lock[if_id][pup] != 1) {
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("PBS failed for IF #%d\n",
+ if_id));
+ training_result[training_stage][if_id]
+ = TEST_FAILED;
+
+ result_mat[if_id][pup][bit] = 0;
+ max_pbs_per_pup[if_id][pup] = 0;
+ min_pbs_per_pup[if_id][pup] = 0;
+ } else {
+ training_result[
+ training_stage][if_id] =
+ (training_result[training_stage]
+ [if_id] == TEST_FAILED) ?
+ TEST_FAILED : TEST_SUCCESS;
+ result_mat[if_id][pup][bit] =
+ result_all_bit[
+ bit + pup *
+ BUS_WIDTH_IN_BITS +
+ if_id * MAX_BUS_NUM *
+ BUS_WIDTH_IN_BITS] -
+ min_pbs_per_pup[if_id][pup];
+ }
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("The abs min_pbs[%d][%d] = %d\n",
+ if_id, pup,
+ min_pbs_per_pup[if_id][pup]));
+ }
+ }
+ }
+
+ /* Clean all results */
+ ddr3_tip_clean_pbs_result(dev_num, pbs_mode);
+
+ /* DQ PBS register update with the final result */
+ for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_INFO,
+ ("Final Results: if_id %d, pup %d, Pup State: %d\n",
+ if_id, pup, pup_state[if_id][pup]));
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ if (dq_map_table == NULL) {
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_ERROR,
+ ("dq_map_table not initialized\n"));
+ return MV_FAIL;
+ }
+ pad_num = dq_map_table[
+ bit + pup * BUS_WIDTH_IN_BITS +
+ if_id * BUS_WIDTH_IN_BITS *
+ tm->num_of_bus_per_interface];
+ DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+ ("result_mat: %d ",
+ result_mat[if_id][pup]
+ [bit]));
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (PBS_RX_PHY_REG + effective_cs * 0x10) :
+ (PBS_TX_PHY_REG + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr + pad_num,
+ result_mat[if_id][pup][bit]));
+ }
+ pbsdelay_per_pup[pbs_mode][if_id][pup] =
+ (max_pbs_per_pup[if_id][pup] ==
+ min_pbs_per_pup[if_id][pup]) ?
+ TYPICAL_PBS_VALUE :
+ ((max_adll_per_pup[if_id][pup] -
+ min_adll_per_pup[if_id][pup]) * adll_tap /
+ (max_pbs_per_pup[if_id][pup] -
+ min_pbs_per_pup[if_id][pup]));
+
+ /* RX results ready, write RX also */
+ if (pbs_mode == PBS_TX_MODE) {
+ /* Write TX results */
+ reg_addr = (0x14 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ (max_pbs_per_pup[if_id][pup] -
+ min_pbs_per_pup[if_id][pup]) /
+ 2));
+ reg_addr = (0x15 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ (max_pbs_per_pup[if_id][pup] -
+ min_pbs_per_pup[if_id][pup]) /
+ 2));
+
+ /* Write previously stored RX results */
+ reg_addr = (0x54 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ result_mat_rx_dqs[if_id][pup]
+ [effective_cs]));
+ reg_addr = (0x55 + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr,
+ result_mat_rx_dqs[if_id][pup]
+ [effective_cs]));
+ } else {
+ /*
+ * RX results may affect RL results correctess,
+ * so just store the results that will written
+ * in TX stage
+ */
+ result_mat_rx_dqs[if_id][pup][effective_cs] =
+ (max_pbs_per_pup[if_id][pup] -
+ min_pbs_per_pup[if_id][pup]) / 2;
+ }
+ DEBUG_PBS_ENGINE(
+ DEBUG_LEVEL_INFO,
+ (", PBS tap=%d [psec] ==> skew observed = %d\n",
+ pbsdelay_per_pup[pbs_mode][if_id][pup],
+ ((max_pbs_per_pup[if_id][pup] -
+ min_pbs_per_pup[if_id][pup]) *
+ pbsdelay_per_pup[pbs_mode][if_id][pup])));
+ }
+ }
+
+ /* Write back to the phy the default values */
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (READ_CENTRALIZATION_PHY_REG + effective_cs * 4) :
+ (WRITE_CENTRALIZATION_PHY_REG + effective_cs * 4);
+ write_adll_value(nominal_adll, reg_addr);
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (0x5a + effective_cs * 0x10) :
+ (0x1a + effective_cs * 0x10);
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, reg_addr,
+ 0));
+
+ /* restore cs enable value */
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ CS_ENABLE_REG, cs_enable_reg_val[if_id],
+ MASK_ALL_BITS));
+ }
+
+ /* exit test mode */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ODPG_WRITE_READ_MODE_ENABLE_REG, 0xffff, MASK_ALL_BITS));
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ /*
+ * meaning that there is no VW exist at all (No lock at
+ * the EBA ADLL shift at EBS)
+ */
+ if (pup_state[if_id][pup] == 1)
+ return MV_FAIL;
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tip_pbs_rx.
+ * Desc: PBS TX
+ * Args: TBD
+ * Notes:
+ * Returns: OK if success, other error code if fail.
+ */
+int ddr3_tip_pbs_rx(u32 uidev_num)
+{
+ return ddr3_tip_pbs(uidev_num, PBS_RX_MODE);
+}
+
+/*
+ * Name: ddr3_tip_pbs_tx.
+ * Desc: PBS TX
+ * Args: TBD
+ * Notes:
+ * Returns: OK if success, other error code if fail.
+ */
+int ddr3_tip_pbs_tx(u32 uidev_num)
+{
+ return ddr3_tip_pbs(uidev_num, PBS_TX_MODE);
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Print PBS Result
+ */
+int ddr3_tip_print_all_pbs_result(u32 dev_num)
+{
+ u32 curr_cs;
+ u32 max_cs = hws_ddr3_tip_max_cs_get();
+
+ for (curr_cs = 0; curr_cs < max_cs; curr_cs++) {
+ ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_RX_MODE);
+ ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_TX_MODE);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Print PBS Result
+ */
+int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode)
+{
+ u32 data_value = 0, bit = 0, if_id = 0, pup = 0;
+ u32 reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (PBS_RX_PHY_REG + cs_num * 0x10) :
+ (PBS_TX_PHY_REG + cs_num * 0x10);
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ printf("CS%d, %s ,PBS\n", cs_num,
+ (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx");
+
+ for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+ printf("%s, DQ", (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx");
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ printf("%d ,PBS,,, ", bit);
+ for (pup = 0; pup <= tm->num_of_bus_per_interface;
+ pup++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+ CHECK_STATUS(ddr3_tip_bus_read
+ (dev_num, if_id,
+ ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr + bit,
+ &data_value));
+ printf("%d , ", data_value);
+ }
+ }
+ printf("\n");
+ }
+ printf("\n");
+
+ return MV_OK;
+}
+#endif
+
+/*
+ * Fixup PBS Result
+ */
+int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode)
+{
+ u32 if_id, pup, bit;
+ u32 reg_addr = (pbs_mode == PBS_RX_MODE) ?
+ (PBS_RX_PHY_REG + effective_cs * 0x10) :
+ (PBS_TX_PHY_REG + effective_cs * 0x10);
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (pup = 0; pup <= tm->num_of_bus_per_interface; pup++) {
+ for (bit = 0; bit <= BUS_WIDTH_IN_BITS + 3; bit++) {
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, ACCESS_TYPE_UNICAST, pup,
+ DDR_PHY_DATA, reg_addr + bit, 0));
+ }
+ }
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_static.c b/drivers/ddr/marvell/a38x/ddr3_training_static.c
new file mode 100644
index 0000000000..5101f3f383
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_static.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+/* Design Guidelines parameters */
+u32 g_zpri_data = 123; /* controller data - P drive strength */
+u32 g_znri_data = 123; /* controller data - N drive strength */
+u32 g_zpri_ctrl = 74; /* controller C/A - P drive strength */
+u32 g_znri_ctrl = 74; /* controller C/A - N drive strength */
+u32 g_zpodt_data = 45; /* controller data - P ODT */
+u32 g_znodt_data = 45; /* controller data - N ODT */
+u32 g_zpodt_ctrl = 45; /* controller data - P ODT */
+u32 g_znodt_ctrl = 45; /* controller data - N ODT */
+u32 g_odt_config = 0x120012;
+u32 g_rtt_nom = 0x44;
+u32 g_dic = 0x2;
+
+#ifdef STATIC_ALGO_SUPPORT
+
+#define PARAM_NOT_CARE 0
+#define MAX_STATIC_SEQ 48
+
+u32 silicon_delay[HWS_MAX_DEVICE_NUM];
+struct hws_tip_static_config_info static_config[HWS_MAX_DEVICE_NUM];
+static reg_data *static_init_controller_config[HWS_MAX_DEVICE_NUM];
+
+/* debug delay in write leveling */
+int wl_debug_delay = 0;
+/* pup register #3 for functional board */
+int function_reg_value = 8;
+u32 silicon;
+
+u32 read_ready_delay_phase_offset[] = { 4, 4, 4, 4, 6, 6, 6, 6 };
+
+static struct cs_element chip_select_map[] = {
+ /* CS Value (single only) Num_CS */
+ {0, 0},
+ {0, 1},
+ {1, 1},
+ {0, 2},
+ {2, 1},
+ {0, 2},
+ {0, 2},
+ {0, 3},
+ {3, 1},
+ {0, 2},
+ {0, 2},
+ {0, 3},
+ {0, 2},
+ {0, 3},
+ {0, 3},
+ {0, 4}
+};
+
+/*
+ * Register static init controller DB
+ */
+int ddr3_tip_init_specific_reg_config(u32 dev_num, reg_data *reg_config_arr)
+{
+ static_init_controller_config[dev_num] = reg_config_arr;
+ return MV_OK;
+}
+
+/*
+ * Register static info DB
+ */
+int ddr3_tip_init_static_config_db(
+ u32 dev_num, struct hws_tip_static_config_info *static_config_info)
+{
+ static_config[dev_num].board_trace_arr =
+ static_config_info->board_trace_arr;
+ static_config[dev_num].package_trace_arr =
+ static_config_info->package_trace_arr;
+ silicon_delay[dev_num] = static_config_info->silicon_delay;
+
+ return MV_OK;
+}
+
+/*
+ * Static round trip flow - Calculates the total round trip delay.
+ */
+int ddr3_tip_static_round_trip_arr_build(u32 dev_num,
+ struct trip_delay_element *table_ptr,
+ int is_wl, u32 *round_trip_delay_arr)
+{
+ u32 bus_index, global_bus;
+ u32 if_id;
+ u32 bus_per_interface;
+ int sign;
+ u32 temp;
+ u32 board_trace;
+ struct trip_delay_element *pkg_delay_ptr;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ /*
+ * In WL we calc the diff between Clock to DQs in RL we sum the round
+ * trip of Clock and DQs
+ */
+ sign = (is_wl) ? -1 : 1;
+
+ bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES();
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ for (bus_index = 0; bus_index < bus_per_interface;
+ bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ global_bus = (if_id * bus_per_interface) + bus_index;
+
+ /* calculate total trip delay (package and board) */
+ board_trace = (table_ptr[global_bus].dqs_delay * sign) +
+ table_ptr[global_bus].ck_delay;
+ temp = (board_trace * 163) / 1000;
+
+ /* Convert the length to delay in psec units */
+ pkg_delay_ptr =
+ static_config[dev_num].package_trace_arr;
+ round_trip_delay_arr[global_bus] = temp +
+ (int)(pkg_delay_ptr[global_bus].dqs_delay *
+ sign) +
+ (int)pkg_delay_ptr[global_bus].ck_delay +
+ (int)((is_wl == 1) ? wl_debug_delay :
+ (int)silicon_delay[dev_num]);
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_TRACE,
+ ("Round Trip Build round_trip_delay_arr[0x%x]: 0x%x temp 0x%x\n",
+ global_bus, round_trip_delay_arr[global_bus],
+ temp));
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Write leveling for static flow - calculating the round trip delay of the
+ * DQS signal.
+ */
+int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id,
+ enum hws_ddr_freq frequency,
+ u32 *round_trip_delay_arr)
+{
+ u32 bus_index; /* index to the bus loop */
+ u32 bus_start_index;
+ u32 bus_per_interface;
+ u32 phase = 0;
+ u32 adll = 0, adll_cen, adll_inv, adll_final;
+ u32 adll_period = MEGA / freq_val[frequency] / 64;
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("ddr3_tip_write_leveling_static_config\n"));
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_TRACE,
+ ("dev_num 0x%x IF 0x%x freq %d (adll_period 0x%x)\n",
+ dev_num, if_id, frequency, adll_period));
+
+ bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES();
+ bus_start_index = if_id * bus_per_interface;
+ for (bus_index = bus_start_index;
+ bus_index < (bus_start_index + bus_per_interface); bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ phase = round_trip_delay_arr[bus_index] / (32 * adll_period);
+ adll = (round_trip_delay_arr[bus_index] -
+ (phase * 32 * adll_period)) / adll_period;
+ adll = (adll > 31) ? 31 : adll;
+ adll_cen = 16 + adll;
+ adll_inv = adll_cen / 32;
+ adll_final = adll_cen - (adll_inv * 32);
+ adll_final = (adll_final > 31) ? 31 : adll_final;
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("\t%d - phase 0x%x adll 0x%x\n",
+ bus_index, phase, adll));
+ /*
+ * Writing to all 4 phy of Interface number,
+ * bit 0 \96 4 \96 ADLL, bit 6-8 phase
+ */
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ (bus_index % 4), DDR_PHY_DATA,
+ PHY_WRITE_DELAY(cs),
+ ((phase << 6) + (adll & 0x1f)), 0x1df));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ACCESS_TYPE_UNICAST, (bus_index % 4),
+ DDR_PHY_DATA, WRITE_CENTRALIZATION_PHY_REG,
+ ((adll_inv & 0x1) << 5) + adll_final));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Read leveling for static flow
+ */
+int ddr3_tip_read_leveling_static_config(u32 dev_num,
+ u32 if_id,
+ enum hws_ddr_freq frequency,
+ u32 *total_round_trip_delay_arr)
+{
+ u32 cs, data0, data1, data3 = 0;
+ u32 bus_index; /* index to the bus loop */
+ u32 bus_start_index;
+ u32 phase0, phase1, max_phase;
+ u32 adll0, adll1;
+ u32 cl_value;
+ u32 min_delay;
+ u32 sdr_period = MEGA / freq_val[frequency];
+ u32 ddr_period = MEGA / freq_val[frequency] / 2;
+ u32 adll_period = MEGA / freq_val[frequency] / 64;
+ enum hws_speed_bin speed_bin_index;
+ u32 rd_sample_dly[MAX_CS_NUM] = { 0 };
+ u32 rd_ready_del[MAX_CS_NUM] = { 0 };
+ u32 bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES();
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("ddr3_tip_read_leveling_static_config\n"));
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("dev_num 0x%x ifc 0x%x freq %d\n", dev_num,
+ if_id, frequency));
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_TRACE,
+ ("Sdr_period 0x%x Ddr_period 0x%x adll_period 0x%x\n",
+ sdr_period, ddr_period, adll_period));
+
+ if (tm->interface_params[first_active_if].memory_freq ==
+ frequency) {
+ cl_value = tm->interface_params[first_active_if].cas_l;
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("cl_value 0x%x\n", cl_value));
+ } else {
+ speed_bin_index = tm->interface_params[if_id].speed_bin_index;
+ cl_value = cas_latency_table[speed_bin_index].cl_val[frequency];
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("cl_value 0x%x speed_bin_index %d\n",
+ cl_value, speed_bin_index));
+ }
+
+ bus_start_index = if_id * bus_per_interface;
+
+ for (bus_index = bus_start_index;
+ bus_index < (bus_start_index + bus_per_interface);
+ bus_index += 2) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ cs = chip_select_map[
+ tm->interface_params[if_id].as_bus_params[
+ (bus_index % 4)].cs_bitmask].cs_num;
+
+ /* read sample delay calculation */
+ min_delay = (total_round_trip_delay_arr[bus_index] <
+ total_round_trip_delay_arr[bus_index + 1]) ?
+ total_round_trip_delay_arr[bus_index] :
+ total_round_trip_delay_arr[bus_index + 1];
+ /* round down */
+ rd_sample_dly[cs] = 2 * (min_delay / (sdr_period * 2));
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_TRACE,
+ ("\t%d - min_delay 0x%x cs 0x%x rd_sample_dly[cs] 0x%x\n",
+ bus_index, min_delay, cs, rd_sample_dly[cs]));
+
+ /* phase calculation */
+ phase0 = (total_round_trip_delay_arr[bus_index] -
+ (sdr_period * rd_sample_dly[cs])) / (ddr_period);
+ phase1 = (total_round_trip_delay_arr[bus_index + 1] -
+ (sdr_period * rd_sample_dly[cs])) / (ddr_period);
+ max_phase = (phase0 > phase1) ? phase0 : phase1;
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_TRACE,
+ ("\tphase0 0x%x phase1 0x%x max_phase 0x%x\n",
+ phase0, phase1, max_phase));
+
+ /* ADLL calculation */
+ adll0 = (u32)((total_round_trip_delay_arr[bus_index] -
+ (sdr_period * rd_sample_dly[cs]) -
+ (ddr_period * phase0)) / adll_period);
+ adll0 = (adll0 > 31) ? 31 : adll0;
+ adll1 = (u32)((total_round_trip_delay_arr[bus_index + 1] -
+ (sdr_period * rd_sample_dly[cs]) -
+ (ddr_period * phase1)) / adll_period);
+ adll1 = (adll1 > 31) ? 31 : adll1;
+
+ /* The Read delay close the Read FIFO */
+ rd_ready_del[cs] = rd_sample_dly[cs] +
+ read_ready_delay_phase_offset[max_phase];
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_TRACE,
+ ("\tadll0 0x%x adll1 0x%x rd_ready_del[cs] 0x%x\n",
+ adll0, adll1, rd_ready_del[cs]));
+
+ /*
+ * Write to the phy of Interface (bit 0 \96 4 \96 ADLL,
+ * bit 6-8 phase)
+ */
+ data0 = ((phase0 << 6) + (adll0 & 0x1f));
+ data1 = ((phase1 << 6) + (adll1 & 0x1f));
+
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ (bus_index % 4), DDR_PHY_DATA, PHY_READ_DELAY(cs),
+ data0, 0x1df));
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ ((bus_index + 1) % 4), DDR_PHY_DATA,
+ PHY_READ_DELAY(cs), data1, 0x1df));
+ }
+
+ for (bus_index = 0; bus_index < bus_per_interface; bus_index++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ bus_index, DDR_PHY_DATA, 0x3, data3, 0x1f));
+ }
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ READ_DATA_SAMPLE_DELAY,
+ (rd_sample_dly[0] + cl_value) + (rd_sample_dly[1] << 8),
+ MASK_ALL_BITS));
+
+ /* Read_ready_del0 bit 0-4 , CS bits 8-12 */
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_UNICAST, if_id,
+ READ_DATA_READY_DELAY,
+ rd_ready_del[0] + (rd_ready_del[1] << 8) + cl_value,
+ MASK_ALL_BITS));
+
+ return MV_OK;
+}
+
+/*
+ * DDR3 Static flow
+ */
+int ddr3_tip_run_static_alg(u32 dev_num, enum hws_ddr_freq freq)
+{
+ u32 if_id = 0;
+ struct trip_delay_element *table_ptr;
+ u32 wl_total_round_trip_delay_arr[MAX_TOTAL_BUS_NUM];
+ u32 rl_total_round_trip_delay_arr[MAX_TOTAL_BUS_NUM];
+ struct init_cntr_param init_cntr_prm;
+ int ret;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("ddr3_tip_run_static_alg"));
+
+ init_cntr_prm.do_mrs_phy = 1;
+ init_cntr_prm.is_ctrl64_bit = 0;
+ init_cntr_prm.init_phy = 1;
+ ret = hws_ddr3_tip_init_controller(dev_num, &init_cntr_prm);
+ if (ret != MV_OK) {
+ DEBUG_TRAINING_STATIC_IP(
+ DEBUG_LEVEL_ERROR,
+ ("hws_ddr3_tip_init_controller failure\n"));
+ }
+
+ /* calculate the round trip delay for Write Leveling */
+ table_ptr = static_config[dev_num].board_trace_arr;
+ CHECK_STATUS(ddr3_tip_static_round_trip_arr_build
+ (dev_num, table_ptr, 1,
+ wl_total_round_trip_delay_arr));
+ /* calculate the round trip delay for Read Leveling */
+ CHECK_STATUS(ddr3_tip_static_round_trip_arr_build
+ (dev_num, table_ptr, 0,
+ rl_total_round_trip_delay_arr));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ /* check if the interface is enabled */
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+ /*
+ * Static frequency is defined according to init-frequency
+ * (not target)
+ */
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Static IF %d freq %d\n",
+ if_id, freq));
+ CHECK_STATUS(ddr3_tip_write_leveling_static_config
+ (dev_num, if_id, freq,
+ wl_total_round_trip_delay_arr));
+ CHECK_STATUS(ddr3_tip_read_leveling_static_config
+ (dev_num, if_id, freq,
+ rl_total_round_trip_delay_arr));
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Init controller for static flow
+ */
+int ddr3_tip_static_init_controller(u32 dev_num)
+{
+ u32 index_cnt = 0;
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("ddr3_tip_static_init_controller\n"));
+ while (static_init_controller_config[dev_num][index_cnt].reg_addr !=
+ 0) {
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ static_init_controller_config[dev_num][index_cnt].
+ reg_addr,
+ static_init_controller_config[dev_num][index_cnt].
+ reg_data,
+ static_init_controller_config[dev_num][index_cnt].
+ reg_mask));
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Init_controller index_cnt %d\n",
+ index_cnt));
+ index_cnt++;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_tip_static_phy_init_controller(u32 dev_num)
+{
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Phy Init Controller 2\n"));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa4,
+ 0x3dfe));
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Phy Init Controller 3\n"));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa6,
+ 0xcb2));
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Phy Init Controller 4\n"));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa9,
+ 0));
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Static Receiver Calibration\n"));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xd0,
+ 0x1f));
+
+ DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+ ("Static V-REF Calibration\n"));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa8,
+ 0x434));
+
+ return MV_OK;
+}
+#endif
+
+/*
+ * Configure phy (called by static init controller) for static flow
+ */
+int ddr3_tip_configure_phy(u32 dev_num)
+{
+ u32 if_id, phy_id;
+ struct hws_topology_map *tm = ddr3_get_topology_map();
+
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+ PAD_ZRI_CALIB_PHY_REG,
+ ((0x7f & g_zpri_data) << 7 | (0x7f & g_znri_data))));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL,
+ PAD_ZRI_CALIB_PHY_REG,
+ ((0x7f & g_zpri_ctrl) << 7 | (0x7f & g_znri_ctrl))));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+ PAD_ODT_CALIB_PHY_REG,
+ ((0x3f & g_zpodt_data) << 6 | (0x3f & g_znodt_data))));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL,
+ PAD_ODT_CALIB_PHY_REG,
+ ((0x3f & g_zpodt_ctrl) << 6 | (0x3f & g_znodt_ctrl))));
+
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+ PAD_PRE_DISABLE_PHY_REG, 0));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+ CMOS_CONFIG_PHY_REG, 0));
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL,
+ CMOS_CONFIG_PHY_REG, 0));
+
+ for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+ /* check if the interface is enabled */
+ VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+ for (phy_id = 0;
+ phy_id < tm->num_of_bus_per_interface;
+ phy_id++) {
+ VALIDATE_ACTIVE(tm->bus_act_mask, phy_id);
+ /* Vref & clamp */
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, phy_id, DDR_PHY_DATA,
+ PAD_CONFIG_PHY_REG,
+ ((clamp_tbl[if_id] << 4) | vref),
+ ((0x7 << 4) | 0x7)));
+ /* clamp not relevant for control */
+ CHECK_STATUS(ddr3_tip_bus_read_modify_write
+ (dev_num, ACCESS_TYPE_UNICAST,
+ if_id, phy_id, DDR_PHY_CONTROL,
+ PAD_CONFIG_PHY_REG, 0x4, 0x7));
+ }
+ }
+
+ CHECK_STATUS(ddr3_tip_bus_write
+ (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+ ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0x90,
+ 0x6002));
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr_topology_def.h b/drivers/ddr/marvell/a38x/ddr_topology_def.h
new file mode 100644
index 0000000000..f8894e828a
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr_topology_def.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR_TOPOLOGY_DEF_H
+#define _DDR_TOPOLOGY_DEF_H
+
+#include "ddr3_training_ip_def.h"
+#include "ddr3_topology_def.h"
+
+#if defined(CONFIG_ARMADA_38X)
+#include "ddr3_a38x.h"
+#endif
+
+/* bus width in bits */
+enum hws_bus_width {
+ BUS_WIDTH_4,
+ BUS_WIDTH_8,
+ BUS_WIDTH_16,
+ BUS_WIDTH_32
+};
+
+enum hws_temperature {
+ HWS_TEMP_LOW,
+ HWS_TEMP_NORMAL,
+ HWS_TEMP_HIGH
+};
+
+enum hws_mem_size {
+ MEM_512M,
+ MEM_1G,
+ MEM_2G,
+ MEM_4G,
+ MEM_8G,
+ MEM_SIZE_LAST
+};
+
+struct bus_params {
+ /* Chip Select (CS) bitmask (bits 0-CS0, bit 1- CS1 ...) */
+ u8 cs_bitmask;
+
+ /*
+ * mirror enable/disable
+ * (bits 0-CS0 mirroring, bit 1- CS1 mirroring ...)
+ */
+ int mirror_enable_bitmask;
+
+ /* DQS Swap (polarity) - true if enable */
+ int is_dqs_swap;
+
+ /* CK swap (polarity) - true if enable */
+ int is_ck_swap;
+};
+
+struct if_params {
+ /* bus configuration */
+ struct bus_params as_bus_params[MAX_BUS_NUM];
+
+ /* Speed Bin Table */
+ enum hws_speed_bin speed_bin_index;
+
+ /* bus width of memory */
+ enum hws_bus_width bus_width;
+
+ /* Bus memory size (MBit) */
+ enum hws_mem_size memory_size;
+
+ /* The DDR frequency for each interfaces */
+ enum hws_ddr_freq memory_freq;
+
+ /*
+ * delay CAS Write Latency
+ * - 0 for using default value (jedec suggested)
+ */
+ u8 cas_wl;
+
+ /*
+ * delay CAS Latency
+ * - 0 for using default value (jedec suggested)
+ */
+ u8 cas_l;
+
+ /* operation temperature */
+ enum hws_temperature interface_temp;
+};
+
+struct hws_topology_map {
+ /* Number of interfaces (default is 12) */
+ u8 if_act_mask;
+
+ /* Controller configuration per interface */
+ struct if_params interface_params[MAX_INTERFACE_NUM];
+
+ /* BUS per interface (default is 4) */
+ u8 num_of_bus_per_interface;
+
+ /* Bit mask for active buses */
+ u8 bus_act_mask;
+};
+
+/* DDR3 training global configuration parameters */
+struct tune_train_params {
+ u32 ck_delay;
+ u32 ck_delay_16;
+ u32 p_finger;
+ u32 n_finger;
+ u32 phy_reg3_val;
+};
+
+#endif /* _DDR_TOPOLOGY_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h
new file mode 100644
index 0000000000..ff5f817383
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _DDR_TRAINING_IP_DB_H_
+#define _DDR_TRAINING_IP_DB_H_
+
+#include "ddr_topology_def.h"
+#include "ddr3_training_ip_db.h"
+
+u32 speed_bin_table(u8 index, enum speed_bin_table_elements element);
+u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index);
+
+#endif /* _DDR3_TRAINING_IP_DB_H_ */
diff --git a/drivers/ddr/marvell/a38x/silicon_if.h b/drivers/ddr/marvell/a38x/silicon_if.h
new file mode 100644
index 0000000000..7fce27da12
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/silicon_if.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __silicon_if_H
+#define __silicon_if_H
+
+/* max number of devices supported by driver */
+#ifdef CO_CPU_RUN
+#define HWS_MAX_DEVICE_NUM (1)
+#else
+#define HWS_MAX_DEVICE_NUM (16)
+#endif
+
+#endif /* __silicon_if_H */
diff --git a/drivers/ddr/marvell/a38x/xor.c b/drivers/ddr/marvell/a38x/xor.c
new file mode 100644
index 0000000000..9c73c54eec
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/xor.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+#include "xor_regs.h"
+
+/* defines */
+#ifdef MV_DEBUG
+#define DB(x) x
+#else
+#define DB(x)
+#endif
+
+static u32 ui_xor_regs_ctrl_backup;
+static u32 ui_xor_regs_base_backup[MAX_CS];
+static u32 ui_xor_regs_mask_backup[MAX_CS];
+
+void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, u32 cs_size, u32 base_delta)
+{
+ u32 reg, ui, base, cs_count;
+
+ ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
+ for (ui = 0; ui < MAX_CS; ui++)
+ ui_xor_regs_base_backup[ui] =
+ reg_read(XOR_BASE_ADDR_REG(0, ui));
+ for (ui = 0; ui < MAX_CS; ui++)
+ ui_xor_regs_mask_backup[ui] =
+ reg_read(XOR_SIZE_MASK_REG(0, ui));
+
+ reg = 0;
+ for (ui = 0; ui < (num_of_cs); ui++) {
+ /* Enable Window x for each CS */
+ reg |= (0x1 << (ui));
+ /* Enable Window x for each CS */
+ reg |= (0x3 << ((ui * 2) + 16));
+ }
+
+ reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
+
+ cs_count = 0;
+ for (ui = 0; ui < num_of_cs; ui++) {
+ if (cs_ena & (1 << ui)) {
+ /*
+ * window x - Base - 0x00000000,
+ * Attribute 0x0e - DRAM
+ */
+ base = cs_size * ui + base_delta;
+ switch (ui) {
+ case 0:
+ base |= 0xe00;
+ break;
+ case 1:
+ base |= 0xd00;
+ break;
+ case 2:
+ base |= 0xb00;
+ break;
+ case 3:
+ base |= 0x700;
+ break;
+ }
+
+ reg_write(XOR_BASE_ADDR_REG(0, cs_count), base);
+
+ /* window x - Size */
+ reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x7fff0000);
+ cs_count++;
+ }
+ }
+
+ mv_xor_hal_init(1);
+
+ return;
+}
+
+void mv_sys_xor_finish(void)
+{
+ u32 ui;
+
+ reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup);
+ for (ui = 0; ui < MAX_CS; ui++)
+ reg_write(XOR_BASE_ADDR_REG(0, ui),
+ ui_xor_regs_base_backup[ui]);
+ for (ui = 0; ui < MAX_CS; ui++)
+ reg_write(XOR_SIZE_MASK_REG(0, ui),
+ ui_xor_regs_mask_backup[ui]);
+
+ reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
+}
+
+/*
+ * mv_xor_hal_init - Initialize XOR engine
+ *
+ * DESCRIPTION:
+ * This function initialize XOR unit.
+ * INPUT:
+ * None.
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ */
+void mv_xor_hal_init(u32 xor_chan_num)
+{
+ u32 i;
+
+ /* Abort any XOR activity & set default configuration */
+ for (i = 0; i < xor_chan_num; i++) {
+ mv_xor_command_set(i, MV_STOP);
+ mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
+ (4 << XEXCR_DST_BURST_LIMIT_OFFS) |
+ (4 << XEXCR_SRC_BURST_LIMIT_OFFS));
+ }
+}
+
+/*
+ * mv_xor_ctrl_set - Set XOR channel control registers
+ *
+ * DESCRIPTION:
+ *
+ * INPUT:
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ * NOTE:
+ * This function does not modify the Operation_mode field of control register.
+ */
+int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
+{
+ u32 old_value;
+
+ /* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */
+ old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) &
+ XEXCR_OPERATION_MODE_MASK;
+ xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
+ xor_ctrl |= old_value;
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
+
+ return MV_OK;
+}
+
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size,
+ u32 init_val_high, u32 init_val_low)
+{
+ u32 temp;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN)
+ return MV_BAD_PARAM;
+
+ if (MV_ACTIVE == mv_xor_state_get(chan))
+ return MV_BUSY;
+
+ if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
+ (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
+ return MV_BAD_PARAM;
+
+ /* set the operation mode to Memory Init */
+ temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ temp &= ~XEXCR_OPERATION_MODE_MASK;
+ temp |= XEXCR_OPERATION_MODE_MEM_INIT;
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp);
+
+ /*
+ * update the start_ptr field in XOR Engine [0..1] Destination Pointer
+ * Register
+ */
+ reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
+
+ /*
+ * update the Block_size field in the XOR Engine[0..1] Block Size
+ * Registers
+ */
+ reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ block_size);
+
+ /*
+ * update the field Init_val_l in the XOR Engine Initial Value Register
+ * Low (XEIVRL)
+ */
+ reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
+
+ /*
+ * update the field Init_val_h in the XOR Engine Initial Value Register
+ * High (XEIVRH)
+ */
+ reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
+
+ /* start transfer */
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+
+ return MV_OK;
+}
+
+/*
+ * mv_xor_state_get - Get XOR channel state.
+ *
+ * DESCRIPTION:
+ * XOR channel activity state can be active, idle, paused.
+ * This function retrunes the channel activity state.
+ *
+ * INPUT:
+ * chan - the channel number
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * XOR_CHANNEL_IDLE - If the engine is idle.
+ * XOR_CHANNEL_ACTIVE - If the engine is busy.
+ * XOR_CHANNEL_PAUSED - If the engine is paused.
+ * MV_UNDEFINED_STATE - If the engine state is undefind or there is no
+ * such engine
+ */
+enum mv_state mv_xor_state_get(u32 chan)
+{
+ u32 state;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
+ return MV_UNDEFINED_STATE;
+ }
+
+ /* read the current state */
+ state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ state &= XEXACTR_XESTATUS_MASK;
+
+ /* return the state */
+ switch (state) {
+ case XEXACTR_XESTATUS_IDLE:
+ return MV_IDLE;
+ case XEXACTR_XESTATUS_ACTIVE:
+ return MV_ACTIVE;
+ case XEXACTR_XESTATUS_PAUSED:
+ return MV_PAUSED;
+ }
+
+ return MV_UNDEFINED_STATE;
+}
+
+/*
+ * mv_xor_command_set - Set command of XOR channel
+ *
+ * DESCRIPTION:
+ * XOR channel can be started, idle, paused and restarted.
+ * Paused can be set only if channel is active.
+ * Start can be set only if channel is idle or paused.
+ * Restart can be set only if channel is paused.
+ * Stop can be set only if channel is active.
+ *
+ * INPUT:
+ * chan - The channel number
+ * command - The command type (start, stop, restart, pause)
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
+ * undefind XOR engine mode
+ */
+int mv_xor_command_set(u32 chan, enum mv_command command)
+{
+ enum mv_state state;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
+ return MV_BAD_PARAM;
+ }
+
+ /* get the current state */
+ state = mv_xor_state_get(chan);
+
+ if ((command == MV_START) && (state == MV_IDLE)) {
+ /* command is start and current state is idle */
+ reg_bit_set(XOR_ACTIVATION_REG
+ (XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+ return MV_OK;
+ } else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
+ /* command is stop and current state is active */
+ reg_bit_set(XOR_ACTIVATION_REG
+ (XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTOP_MASK);
+ return MV_OK;
+ } else if (((enum mv_state)command == MV_PAUSED) &&
+ (state == MV_ACTIVE)) {
+ /* command is paused and current state is active */
+ reg_bit_set(XOR_ACTIVATION_REG
+ (XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XEPAUSE_MASK);
+ return MV_OK;
+ } else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
+ /* command is restart and current state is paused */
+ reg_bit_set(XOR_ACTIVATION_REG
+ (XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XERESTART_MASK);
+ return MV_OK;
+ } else if ((command == MV_STOP) && (state == MV_IDLE)) {
+ /* command is stop and current state is active */
+ return MV_OK;
+ }
+
+ /* illegal command */
+ DB(printf("%s: ERR. Illegal command\n", __func__));
+
+ return MV_BAD_PARAM;
+}
+
+void ddr3_new_tip_ecc_scrub(void)
+{
+ u32 cs_c, max_cs;
+ u32 cs_ena = 0;
+
+ printf("DDR3 Training Sequence - Start scrubbing\n");
+
+ max_cs = hws_ddr3_tip_max_cs_get();
+ for (cs_c = 0; cs_c < max_cs; cs_c++)
+ cs_ena |= 1 << cs_c;
+
+ mv_sys_xor_init(max_cs, cs_ena, 0x80000000, 0);
+
+ mv_xor_mem_init(0, 0x00000000, 0x80000000, 0xdeadbeef, 0xdeadbeef);
+ /* wait for previous transfer completion */
+ while (mv_xor_state_get(0) != MV_IDLE)
+ ;
+
+ mv_xor_mem_init(0, 0x80000000, 0x40000000, 0xdeadbeef, 0xdeadbeef);
+
+ /* wait for previous transfer completion */
+ while (mv_xor_state_get(0) != MV_IDLE)
+ ;
+
+ /* Return XOR State */
+ mv_sys_xor_finish();
+
+ printf("DDR3 Training Sequence - End scrubbing\n");
+}
diff --git a/drivers/ddr/marvell/a38x/xor.h b/drivers/ddr/marvell/a38x/xor.h
new file mode 100644
index 0000000000..7b1e316177
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/xor.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _XOR_H
+#define _XOR_H
+
+#define SRAM_BASE 0x40000000
+
+#include "ddr3_hws_hw_training_def.h"
+
+#define MV_XOR_MAX_UNIT 2 /* XOR unit == XOR engine */
+#define MV_XOR_MAX_CHAN 4 /* total channels for all units */
+#define MV_XOR_MAX_CHAN_PER_UNIT 2 /* channels for units */
+
+#define MV_IS_POWER_OF_2(num) (((num) != 0) && (((num) & ((num) - 1)) == 0))
+
+/*
+ * This structure describes address space window. Window base can be
+ * 64 bit, window size up to 4GB
+ */
+struct addr_win {
+ u32 base_low; /* 32bit base low */
+ u32 base_high; /* 32bit base high */
+ u32 size; /* 32bit size */
+};
+
+/* This structure describes SoC units address decode window */
+struct unit_win_info {
+ struct addr_win addr_win; /* An address window */
+ int enable; /* Address decode window is enabled/disabled */
+ u8 attrib; /* chip select attributes */
+ u8 target_id; /* Target Id of this MV_TARGET */
+};
+
+/*
+ * This enumerator describes the type of functionality the XOR channel
+ * can have while using the same data structures.
+ */
+enum xor_type {
+ MV_XOR, /* XOR channel functions as XOR accelerator */
+ MV_DMA, /* XOR channel functions as IDMA channel */
+ MV_CRC32 /* XOR channel functions as CRC 32 calculator */
+};
+
+enum mv_state {
+ MV_IDLE,
+ MV_ACTIVE,
+ MV_PAUSED,
+ MV_UNDEFINED_STATE
+};
+
+/*
+ * This enumerator describes the set of commands that can be applied on
+ * an engine (e.g. IDMA, XOR). Appling a comman depends on the current
+ * status (see MV_STATE enumerator)
+ *
+ * Start can be applied only when status is IDLE
+ * Stop can be applied only when status is IDLE, ACTIVE or PAUSED
+ * Pause can be applied only when status is ACTIVE
+ * Restart can be applied only when status is PAUSED
+ */
+enum mv_command {
+ MV_START, /* Start */
+ MV_STOP, /* Stop */
+ MV_PAUSE, /* Pause */
+ MV_RESTART /* Restart */
+};
+
+enum xor_override_target {
+ SRC_ADDR0, /* Source Address #0 Control */
+ SRC_ADDR1, /* Source Address #1 Control */
+ SRC_ADDR2, /* Source Address #2 Control */
+ SRC_ADDR3, /* Source Address #3 Control */
+ SRC_ADDR4, /* Source Address #4 Control */
+ SRC_ADDR5, /* Source Address #5 Control */
+ SRC_ADDR6, /* Source Address #6 Control */
+ SRC_ADDR7, /* Source Address #7 Control */
+ XOR_DST_ADDR, /* Destination Address Control */
+ XOR_NEXT_DESC /* Next Descriptor Address Control */
+};
+
+enum mv_state mv_xor_state_get(u32 chan);
+void mv_xor_hal_init(u32 xor_chan_num);
+int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl);
+int mv_xor_command_set(u32 chan, enum mv_command command);
+int mv_xor_override_set(u32 chan, enum xor_override_target target, u32 win_num,
+ int enable);
+
+#endif
diff --git a/drivers/ddr/marvell/a38x/xor_regs.h b/drivers/ddr/marvell/a38x/xor_regs.h
new file mode 100644
index 0000000000..cc1546ea54
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/xor_regs.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _XOR_REGS_h
+#define _XOR_REGS_h
+
+/*
+ * For controllers that have two XOR units, then chans 2 & 3 will be
+ * mapped to channels 0 & 1 of unit 1
+ */
+#define XOR_UNIT(chan) ((chan) >> 1)
+#define XOR_CHAN(chan) ((chan) & 1)
+
+#define MV_XOR_REGS_OFFSET(unit) (0x60900)
+#define MV_XOR_REGS_BASE(unit) (MV_XOR_REGS_OFFSET(unit))
+
+/* XOR Engine Control Register Map */
+#define XOR_CHANNEL_ARBITER_REG(unit) (MV_XOR_REGS_BASE(unit))
+#define XOR_CONFIG_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x10 + ((chan) * 4)))
+#define XOR_ACTIVATION_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x20 + ((chan) * 4)))
+
+/* XOR Engine Interrupt Register Map */
+#define XOR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x30))
+#define XOR_MASK_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x40))
+#define XOR_ERROR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x50))
+#define XOR_ERROR_ADDR_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x60))
+
+/* XOR Engine Descriptor Register Map */
+#define XOR_NEXT_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x200 + ((chan) * 4)))
+#define XOR_CURR_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x210 + ((chan) * 4)))
+#define XOR_BYTE_COUNT_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x220 + ((chan) * 4)))
+
+/* XOR Engine ECC/Mem_init Register Map */
+#define XOR_DST_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x2b0 + ((chan) * 4)))
+#define XOR_BLOCK_SIZE_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x2c0 + ((chan) * 4)))
+#define XOR_TIMER_MODE_CTRL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d0))
+#define XOR_TIMER_MODE_INIT_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d4))
+#define XOR_TIMER_MODE_CURR_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d8))
+#define XOR_INIT_VAL_LOW_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2e0))
+#define XOR_INIT_VAL_HIGH_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2e4))
+
+/* XOR Engine Debug Register Map */
+#define XOR_DEBUG_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x70))
+
+/* XOR register fileds */
+
+/* XOR Engine Channel Arbiter Register */
+#define XECAR_SLICE_OFFS(slice_num) (slice_num)
+#define XECAR_SLICE_MASK(slice_num) (1 << (XECAR_SLICE_OFFS(slice_num)))
+
+/* XOR Engine [0..1] Configuration Registers */
+#define XEXCR_OPERATION_MODE_OFFS (0)
+#define XEXCR_OPERATION_MODE_MASK (7 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_XOR (0 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_CRC (1 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_DMA (2 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_ECC (3 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_MEM_INIT (4 << XEXCR_OPERATION_MODE_OFFS)
+
+#define XEXCR_SRC_BURST_LIMIT_OFFS (4)
+#define XEXCR_SRC_BURST_LIMIT_MASK (7 << XEXCR_SRC_BURST_LIMIT_OFFS)
+#define XEXCR_DST_BURST_LIMIT_OFFS (8)
+#define XEXCR_DST_BURST_LIMIT_MASK (7 << XEXCR_DST_BURST_LIMIT_OFFS)
+#define XEXCR_DRD_RES_SWP_OFFS (12)
+#define XEXCR_DRD_RES_SWP_MASK (1 << XEXCR_DRD_RES_SWP_OFFS)
+#define XEXCR_DWR_REQ_SWP_OFFS (13)
+#define XEXCR_DWR_REQ_SWP_MASK (1 << XEXCR_DWR_REQ_SWP_OFFS)
+#define XEXCR_DES_SWP_OFFS (14)
+#define XEXCR_DES_SWP_MASK (1 << XEXCR_DES_SWP_OFFS)
+#define XEXCR_REG_ACC_PROTECT_OFFS (15)
+#define XEXCR_REG_ACC_PROTECT_MASK (1 << XEXCR_REG_ACC_PROTECT_OFFS)
+
+/* XOR Engine [0..1] Activation Registers */
+#define XEXACTR_XESTART_OFFS (0)
+#define XEXACTR_XESTART_MASK (1 << XEXACTR_XESTART_OFFS)
+#define XEXACTR_XESTOP_OFFS (1)
+#define XEXACTR_XESTOP_MASK (1 << XEXACTR_XESTOP_OFFS)
+#define XEXACTR_XEPAUSE_OFFS (2)
+#define XEXACTR_XEPAUSE_MASK (1 << XEXACTR_XEPAUSE_OFFS)
+#define XEXACTR_XERESTART_OFFS (3)
+#define XEXACTR_XERESTART_MASK (1 << XEXACTR_XERESTART_OFFS)
+#define XEXACTR_XESTATUS_OFFS (4)
+#define XEXACTR_XESTATUS_MASK (3 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_IDLE (0 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_ACTIVE (1 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_PAUSED (2 << XEXACTR_XESTATUS_OFFS)
+
+/* XOR Engine Interrupt Cause Register (XEICR) */
+#define XEICR_CHAN_OFFS 16
+#define XEICR_CAUSE_OFFS(chan) (chan * XEICR_CHAN_OFFS)
+#define XEICR_CAUSE_MASK(chan, cause) (1 << (cause + XEICR_CAUSE_OFFS(chan)))
+#define XEICR_COMP_MASK_ALL 0x000f000f
+#define XEICR_COMP_MASK(chan) (0x000f << XEICR_CAUSE_OFFS(chan))
+#define XEICR_ERR_MASK 0x03800380
+
+/* XOR Engine Error Cause Register (XEECR) */
+#define XEECR_ERR_TYPE_OFFS 0
+#define XEECR_ERR_TYPE_MASK (0x1f << XEECR_ERR_TYPE_OFFS)
+
+/* XOR Engine Error Address Register (XEEAR) */
+#define XEEAR_ERR_ADDR_OFFS (0)
+#define XEEAR_ERR_ADDR_MASK (0xffffffff << XEEAR_ERR_ADDR_OFFS)
+
+/* XOR Engine [0..1] Next Descriptor Pointer Register */
+#define XEXNDPR_NEXT_DESC_PTR_OFFS (0)
+#define XEXNDPR_NEXT_DESC_PTR_MASK (0xffffffff << \
+ XEXNDPR_NEXT_DESC_PTR_OFFS)
+
+/* XOR Engine [0..1] Current Descriptor Pointer Register */
+#define XEXCDPR_CURRENT_DESC_PTR_OFFS (0)
+#define XEXCDPR_CURRENT_DESC_PTR_MASK (0xffffffff << \
+ XEXCDPR_CURRENT_DESC_PTR_OFFS)
+
+/* XOR Engine [0..1] Byte Count Register */
+#define XEXBCR_BYTE_CNT_OFFS (0)
+#define XEXBCR_BYTE_CNT_MASK (0xffffffff << XEXBCR_BYTE_CNT_OFFS)
+
+/* XOR Engine [0..1] Destination Pointer Register */
+#define XEXDPR_DST_PTR_OFFS (0)
+#define XEXDPR_DST_PTR_MASK (0xffffffff << XEXDPR_DST_PTR_OFFS)
+#define XEXDPR_DST_PTR_XOR_MASK (0x3f)
+#define XEXDPR_DST_PTR_DMA_MASK (0x1f)
+#define XEXDPR_DST_PTR_CRC_MASK (0x1f)
+
+/* XOR Engine[0..1] Block Size Registers */
+#define XEXBSR_BLOCK_SIZE_OFFS (0)
+#define XEXBSR_BLOCK_SIZE_MASK (0xffffffff << XEXBSR_BLOCK_SIZE_OFFS)
+#define XEXBSR_BLOCK_SIZE_MIN_VALUE (128)
+#define XEXBSR_BLOCK_SIZE_MAX_VALUE (0xffffffff)
+
+/* XOR Engine Timer Mode Control Register (XETMCR) */
+#define XETMCR_TIMER_EN_OFFS (0)
+#define XETMCR_TIMER_EN_MASK (1 << XETMCR_TIMER_EN_OFFS)
+#define XETMCR_TIMER_EN_ENABLE (1 << XETMCR_TIMER_EN_OFFS)
+#define XETMCR_TIMER_EN_DISABLE (0 << XETMCR_TIMER_EN_OFFS)
+#define XETMCR_SECTION_SIZE_CTRL_OFFS (8)
+#define XETMCR_SECTION_SIZE_CTRL_MASK (0x1f << XETMCR_SECTION_SIZE_CTRL_OFFS)
+#define XETMCR_SECTION_SIZE_MIN_VALUE (7)
+#define XETMCR_SECTION_SIZE_MAX_VALUE (31)
+
+/* XOR Engine Timer Mode Initial Value Register (XETMIVR) */
+#define XETMIVR_TIMER_INIT_VAL_OFFS (0)
+#define XETMIVR_TIMER_INIT_VAL_MASK (0xffffffff << \
+ XETMIVR_TIMER_INIT_VAL_OFFS)
+
+/* XOR Engine Timer Mode Current Value Register (XETMCVR) */
+#define XETMCVR_TIMER_CRNT_VAL_OFFS (0)
+#define XETMCVR_TIMER_CRNT_VAL_MASK (0xffffffff << \
+ XETMCVR_TIMER_CRNT_VAL_OFFS)
+
+/* XOR Engine Initial Value Register Low (XEIVRL) */
+#define XEIVRL_INIT_VAL_L_OFFS (0)
+#define XEIVRL_INIT_VAL_L_MASK (0xffffffff << XEIVRL_INIT_VAL_L_OFFS)
+
+/* XOR Engine Initial Value Register High (XEIVRH) */
+#define XEIVRH_INIT_VAL_H_OFFS (0)
+#define XEIVRH_INIT_VAL_H_MASK (0xffffffff << XEIVRH_INIT_VAL_H_OFFS)
+
+/* XOR Engine Debug Register (XEDBR) */
+#define XEDBR_PARITY_ERR_INSR_OFFS (0)
+#define XEDBR_PARITY_ERR_INSR_MASK (1 << XEDBR_PARITY_ERR_INSR_OFFS)
+#define XEDBR_XBAR_ERR_INSR_OFFS (1)
+#define XEDBR_XBAR_ERR_INSR_MASK (1 << XEDBR_XBAR_ERR_INSR_OFFS)
+
+/* XOR Engine address decode registers. */
+/* Maximum address decode windows */
+#define XOR_MAX_ADDR_DEC_WIN 8
+/* Maximum address arbiter windows */
+#define XOR_MAX_REMAP_WIN 4
+
+/* XOR Engine Address Decoding Register Map */
+#define XOR_WINDOW_CTRL_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+ (0x240 + ((chan) * 4)))
+#define XOR_BASE_ADDR_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+ (0x250 + ((win_num) * 4)))
+#define XOR_SIZE_MASK_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+ (0x270 + ((win_num) * 4)))
+#define XOR_HIGH_ADDR_REMAP_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+ (0x290 + ((win_num) * 4)))
+#define XOR_ADDR_OVRD_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+ (0x2a0 + ((win_num) * 4)))
+
+/* XOR Engine [0..1] Window Control Registers */
+#define XEXWCR_WIN_EN_OFFS(win_num) (win_num)
+#define XEXWCR_WIN_EN_MASK(win_num) (1 << (XEXWCR_WIN_EN_OFFS(win_num)))
+#define XEXWCR_WIN_EN_ENABLE(win_num) (1 << (XEXWCR_WIN_EN_OFFS(win_num)))
+#define XEXWCR_WIN_EN_DISABLE(win_num) (0 << (XEXWCR_WIN_EN_OFFS(win_num)))
+
+#define XEXWCR_WIN_ACC_OFFS(win_num) ((2 * win_num) + 16)
+#define XEXWCR_WIN_ACC_MASK(win_num) (3 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+#define XEXWCR_WIN_ACC_NO_ACC(win_num) (0 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+#define XEXWCR_WIN_ACC_RO(win_num) (1 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+#define XEXWCR_WIN_ACC_RW(win_num) (3 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+
+/* XOR Engine Base Address Registers (XEBARx) */
+#define XEBARX_TARGET_OFFS (0)
+#define XEBARX_TARGET_MASK (0xf << XEBARX_TARGET_OFFS)
+#define XEBARX_ATTR_OFFS (8)
+#define XEBARX_ATTR_MASK (0xff << XEBARX_ATTR_OFFS)
+#define XEBARX_BASE_OFFS (16)
+#define XEBARX_BASE_MASK (0xffff << XEBARX_BASE_OFFS)
+
+/* XOR Engine Size Mask Registers (XESMRx) */
+#define XESMRX_SIZE_MASK_OFFS (16)
+#define XESMRX_SIZE_MASK_MASK (0xffff << XESMRX_SIZE_MASK_OFFS)
+#define XOR_WIN_SIZE_ALIGN _64K
+
+/* XOR Engine High Address Remap Register (XEHARRx1) */
+#define XEHARRX_REMAP_OFFS (0)
+#define XEHARRX_REMAP_MASK (0xffffffff << XEHARRX_REMAP_OFFS)
+
+#define XOR_OVERRIDE_CTRL_REG(chan) (MV_XOR_REGS_BASE(XOR_UNIT(chan)) + \
+ (0x2a0 + ((XOR_CHAN(chan)) * 4)))
+
+/* XOR Engine [0..1] Address Override Control Register */
+#define XEXAOCR_OVR_EN_OFFS(target) (3 * target)
+#define XEXAOCR_OVR_EN_MASK(target) (1 << (XEXAOCR_OVR_EN_OFFS(target)))
+#define XEXAOCR_OVR_PTR_OFFS(target) ((3 * target) + 1)
+#define XEXAOCR_OVR_PTR_MASK(target) (3 << (XEXAOCR_OVR_PTR_OFFS(target)))
+#define XEXAOCR_OVR_BAR(win_num, target) (win_num << \
+ (XEXAOCR_OVR_PTR_OFFS(target)))
+
+/* Maximum address override windows */
+#define XOR_MAX_OVERRIDE_WIN 4
+
+#endif /* _XOR_REGS_h */
diff --git a/drivers/ddr/marvell/axp/Makefile b/drivers/ddr/marvell/axp/Makefile
new file mode 100644
index 0000000000..50a69eaffa
--- /dev/null
+++ b/drivers/ddr/marvell/axp/Makefile
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD) += ddr3_dfs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_dqs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_hw_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_init.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_pbs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_read_leveling.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_sdram.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_spd.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_write_leveling.o
+obj-$(CONFIG_SPL_BUILD) += xor.o
diff --git a/drivers/ddr/marvell/axp/ddr3_axp.h b/drivers/ddr/marvell/axp/ddr3_axp.h
new file mode 100644
index 0000000000..d9e33f7c6e
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_axp.h
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_AXP_H
+#define __DDR3_AXP_H
+
+#define MV_78XX0_Z1_REV 0x0
+#define MV_78XX0_A0_REV 0x1
+#define MV_78XX0_B0_REV 0x2
+
+#define SAR_DDR3_FREQ_MASK 0xFE00000
+#define SAR_CPU_FAB_GET(cpu, fab) (((cpu & 0x7) << 21) | ((fab & 0xF) << 24))
+
+#define MAX_CS 4
+
+#define MIN_DIMM_ADDR 0x50
+#define FAR_END_DIMM_ADDR 0x50
+#define MAX_DIMM_ADDR 0x60
+
+#ifndef CONFIG_DDR_FIXED_SIZE
+#define SDRAM_CS_SIZE 0xFFFFFFF
+#else
+#define SDRAM_CS_SIZE (CONFIG_DDR_FIXED_SIZE - 1)
+#endif
+#define SDRAM_CS_BASE 0x0
+#define SDRAM_DIMM_SIZE 0x80000000
+
+#define CPU_CONFIGURATION_REG(id) (0x21800 + (id * 0x100))
+#define CPU_MRVL_ID_OFFSET 0x10
+#define SAR1_CPU_CORE_MASK 0x00000018
+#define SAR1_CPU_CORE_OFFSET 3
+
+#define ECC_SUPPORT
+#define NEW_FABRIC_TWSI_ADDR 0x4E
+#ifdef CONFIG_DB_784MP_GP
+#define BUS_WIDTH_ECC_TWSI_ADDR 0x4E
+#else
+#define BUS_WIDTH_ECC_TWSI_ADDR 0x4F
+#endif
+#define MV_MAX_DDR3_STATIC_SIZE 50
+#define MV_DDR3_MODES_NUMBER 30
+
+#define RESUME_RL_PATTERNS_ADDR (0xFE0000)
+#define RESUME_RL_PATTERNS_SIZE (0x100)
+#define RESUME_TRAINING_VALUES_ADDR (RESUME_RL_PATTERNS_ADDR + RESUME_RL_PATTERNS_SIZE)
+#define RESUME_TRAINING_VALUES_MAX (0xCD0)
+#define BOOT_INFO_ADDR (RESUME_RL_PATTERNS_ADDR + 0x1000)
+#define CHECKSUM_RESULT_ADDR (BOOT_INFO_ADDR + 0x1000)
+#define NUM_OF_REGISTER_ADDR (CHECKSUM_RESULT_ADDR + 4)
+#define SUSPEND_MAGIC_WORD (0xDEADB002)
+#define REGISTER_LIST_END (0xFFFFFFFF)
+
+/*
+ * Registers offset
+ */
+
+#define REG_SAMPLE_RESET_LOW_ADDR 0x18230
+#define REG_SAMPLE_RESET_HIGH_ADDR 0x18234
+#define REG_SAMPLE_RESET_CPU_FREQ_OFFS 21
+#define REG_SAMPLE_RESET_CPU_FREQ_MASK 0x00E00000
+#define REG_SAMPLE_RESET_FAB_OFFS 24
+#define REG_SAMPLE_RESET_FAB_MASK 0xF000000
+#define REG_SAMPLE_RESET_TCLK_OFFS 28
+#define REG_SAMPLE_RESET_CPU_ARCH_OFFS 31
+#define REG_SAMPLE_RESET_HIGH_CPU_FREQ_OFFS 20
+
+/* MISC */
+/*
+ * In mainline U-Boot we're re-configuring the mvebu base address
+ * register to 0xf1000000. So need to use this value for the DDR
+ * training code as well.
+ */
+#define INTER_REGS_BASE SOC_REGS_PHY_BASE
+
+/* DDR */
+#define REG_SDRAM_CONFIG_ADDR 0x1400
+#define REG_SDRAM_CONFIG_MASK 0x9FFFFFFF
+#define REG_SDRAM_CONFIG_RFRS_MASK 0x3FFF
+#define REG_SDRAM_CONFIG_WIDTH_OFFS 15
+#define REG_SDRAM_CONFIG_REGDIMM_OFFS 17
+#define REG_SDRAM_CONFIG_ECC_OFFS 18
+#define REG_SDRAM_CONFIG_IERR_OFFS 19
+#define REG_SDRAM_CONFIG_PUPRSTDIV_OFFS 28
+#define REG_SDRAM_CONFIG_RSTRD_OFFS 30
+
+#define REG_DUNIT_CTRL_LOW_ADDR 0x1404
+#define REG_DUNIT_CTRL_LOW_2T_OFFS 3
+#define REG_DUNIT_CTRL_LOW_2T_MASK 0x3
+#define REG_DUNIT_CTRL_LOW_DPDE_OFFS 14
+
+#define REG_SDRAM_TIMING_LOW_ADDR 0x1408
+
+#define REG_SDRAM_TIMING_HIGH_ADDR 0x140C
+#define REG_SDRAM_TIMING_H_R2R_OFFS 7
+#define REG_SDRAM_TIMING_H_R2R_MASK 0x3
+#define REG_SDRAM_TIMING_H_R2W_W2R_OFFS 9
+#define REG_SDRAM_TIMING_H_R2W_W2R_MASK 0x3
+#define REG_SDRAM_TIMING_H_W2W_OFFS 11
+#define REG_SDRAM_TIMING_H_W2W_MASK 0x1F
+#define REG_SDRAM_TIMING_H_R2R_H_OFFS 19
+#define REG_SDRAM_TIMING_H_R2R_H_MASK 0x7
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS 22
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_MASK 0x7
+
+#define REG_SDRAM_ADDRESS_CTRL_ADDR 0x1410
+#define REG_SDRAM_ADDRESS_SIZE_OFFS 2
+#define REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS 18
+#define REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS 4
+
+#define REG_SDRAM_OPEN_PAGES_ADDR 0x1414
+#define REG_SDRAM_OPERATION_CS_OFFS 8
+
+#define REG_SDRAM_OPERATION_ADDR 0x1418
+#define REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS 24
+#define REG_SDRAM_OPERATION_CWA_DATA_OFFS 20
+#define REG_SDRAM_OPERATION_CWA_DATA_MASK 0xF
+#define REG_SDRAM_OPERATION_CWA_RC_OFFS 16
+#define REG_SDRAM_OPERATION_CWA_RC_MASK 0xF
+#define REG_SDRAM_OPERATION_CMD_MR0 0xF03
+#define REG_SDRAM_OPERATION_CMD_MR1 0xF04
+#define REG_SDRAM_OPERATION_CMD_MR2 0xF08
+#define REG_SDRAM_OPERATION_CMD_MR3 0xF09
+#define REG_SDRAM_OPERATION_CMD_RFRS 0xF02
+#define REG_SDRAM_OPERATION_CMD_CWA 0xF0E
+#define REG_SDRAM_OPERATION_CMD_RFRS_DONE 0xF
+#define REG_SDRAM_OPERATION_CMD_MASK 0xF
+#define REG_SDRAM_OPERATION_CS_OFFS 8
+
+#define REG_OUDDR3_TIMING_ADDR 0x142C
+
+#define REG_SDRAM_MODE_ADDR 0x141C
+
+#define REG_SDRAM_EXT_MODE_ADDR 0x1420
+
+#define REG_DDR_CONT_HIGH_ADDR 0x1424
+
+#define REG_ODT_TIME_LOW_ADDR 0x1428
+#define REG_ODT_ON_CTL_RD_OFFS 12
+#define REG_ODT_OFF_CTL_RD_OFFS 16
+#define REG_SDRAM_ERROR_ADDR 0x1454
+#define REG_SDRAM_AUTO_PWR_SAVE_ADDR 0x1474
+#define REG_ODT_TIME_HIGH_ADDR 0x147C
+
+#define REG_SDRAM_INIT_CTRL_ADDR 0x1480
+#define REG_SDRAM_INIT_CTRL_OFFS 0
+#define REG_SDRAM_INIT_CKE_ASSERT_OFFS 2
+#define REG_SDRAM_INIT_RESET_DEASSERT_OFFS 3
+
+#define REG_SDRAM_ODT_CTRL_LOW_ADDR 0x1494
+
+#define REG_SDRAM_ODT_CTRL_HIGH_ADDR 0x1498
+/*#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK 0xFFFFFF55 */
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK 0x0
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA 0x3
+
+#define REG_DUNIT_ODT_CTRL_ADDR 0x149C
+#define REG_DUNIT_ODT_CTRL_OVRD_OFFS 8
+#define REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS 9
+
+#define REG_DRAM_FIFO_CTRL_ADDR 0x14A0
+
+#define REG_DRAM_AXI_CTRL_ADDR 0x14A8
+#define REG_DRAM_AXI_CTRL_AXIDATABUSWIDTH_OFFS 0
+
+#define REG_METAL_MASK_ADDR 0x14B0
+#define REG_METAL_MASK_MASK 0xDFFFFFFF
+#define REG_METAL_MASK_RETRY_OFFS 0
+
+#define REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR 0x14C0
+
+#define REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR 0x14C4
+#define REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR 0x14c8
+#define REG_DRAM_MAIN_PADS_CAL_ADDR 0x14CC
+
+#define REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR 0x17c8
+
+#define REG_CS_SIZE_SCRATCH_ADDR 0x1504
+#define REG_DYNAMIC_POWER_SAVE_ADDR 0x1520
+#define REG_DDR_IO_ADDR 0x1524
+#define REG_DDR_IO_CLK_RATIO_OFFS 15
+
+#define REG_DFS_ADDR 0x1528
+#define REG_DFS_DLLNEXTSTATE_OFFS 0
+#define REG_DFS_BLOCK_OFFS 1
+#define REG_DFS_SR_OFFS 2
+#define REG_DFS_ATSR_OFFS 3
+#define REG_DFS_RECONF_OFFS 4
+#define REG_DFS_CL_NEXT_STATE_OFFS 8
+#define REG_DFS_CL_NEXT_STATE_MASK 0xF
+#define REG_DFS_CWL_NEXT_STATE_OFFS 12
+#define REG_DFS_CWL_NEXT_STATE_MASK 0x7
+
+#define REG_READ_DATA_SAMPLE_DELAYS_ADDR 0x1538
+#define REG_READ_DATA_SAMPLE_DELAYS_MASK 0x1F
+#define REG_READ_DATA_SAMPLE_DELAYS_OFFS 8
+
+#define REG_READ_DATA_READY_DELAYS_ADDR 0x153C
+#define REG_READ_DATA_READY_DELAYS_MASK 0x1F
+#define REG_READ_DATA_READY_DELAYS_OFFS 8
+
+#define START_BURST_IN_ADDR 1
+
+#define REG_DRAM_TRAINING_SHADOW_ADDR 0x18488
+#define REG_DRAM_TRAINING_ADDR 0x15B0
+#define REG_DRAM_TRAINING_LOW_FREQ_OFFS 0
+#define REG_DRAM_TRAINING_PATTERNS_OFFS 4
+#define REG_DRAM_TRAINING_MED_FREQ_OFFS 2
+#define REG_DRAM_TRAINING_WL_OFFS 3
+#define REG_DRAM_TRAINING_RL_OFFS 6
+#define REG_DRAM_TRAINING_DQS_RX_OFFS 15
+#define REG_DRAM_TRAINING_DQS_TX_OFFS 16
+#define REG_DRAM_TRAINING_CS_OFFS 20
+#define REG_DRAM_TRAINING_RETEST_OFFS 24
+#define REG_DRAM_TRAINING_DFS_FREQ_OFFS 27
+#define REG_DRAM_TRAINING_DFS_REQ_OFFS 29
+#define REG_DRAM_TRAINING_ERROR_OFFS 30
+#define REG_DRAM_TRAINING_AUTO_OFFS 31
+#define REG_DRAM_TRAINING_RETEST_PAR 0x3
+#define REG_DRAM_TRAINING_RETEST_MASK 0xF8FFFFFF
+#define REG_DRAM_TRAINING_CS_MASK 0xFF0FFFFF
+#define REG_DRAM_TRAINING_PATTERNS_MASK 0xFF0F0000
+
+#define REG_DRAM_TRAINING_1_ADDR 0x15B4
+#define REG_DRAM_TRAINING_1_TRNBPOINT_OFFS 16
+
+#define REG_DRAM_TRAINING_2_ADDR 0x15B8
+#define REG_DRAM_TRAINING_2_OVERRUN_OFFS 17
+#define REG_DRAM_TRAINING_2_FIFO_RST_OFFS 4
+#define REG_DRAM_TRAINING_2_RL_MODE_OFFS 3
+#define REG_DRAM_TRAINING_2_WL_MODE_OFFS 2
+#define REG_DRAM_TRAINING_2_ECC_MUX_OFFS 1
+#define REG_DRAM_TRAINING_2_SW_OVRD_OFFS 0
+
+#define REG_DRAM_TRAINING_PATTERN_BASE_ADDR 0x15BC
+#define REG_DRAM_TRAINING_PATTERN_BASE_OFFS 3
+
+#define REG_TRAINING_DEBUG_2_ADDR 0x15C4
+#define REG_TRAINING_DEBUG_2_OFFS 16
+#define REG_TRAINING_DEBUG_2_MASK 0x3
+
+#define REG_TRAINING_DEBUG_3_ADDR 0x15C8
+#define REG_TRAINING_DEBUG_3_OFFS 3
+#define REG_TRAINING_DEBUG_3_MASK 0x7
+
+#define MR_CS_ADDR_OFFS 4
+
+#define REG_DDR3_MR0_ADDR 0x15D0
+#define REG_DDR3_MR0_CS_ADDR 0x1870
+#define REG_DDR3_MR0_CL_MASK 0x74
+#define REG_DDR3_MR0_CL_OFFS 2
+#define REG_DDR3_MR0_CL_HIGH_OFFS 3
+#define CL_MASK 0xF
+
+#define REG_DDR3_MR1_ADDR 0x15D4
+#define REG_DDR3_MR1_CS_ADDR 0x1874
+#define REG_DDR3_MR1_RTT_MASK 0xFFFFFDBB
+#define REG_DDR3_MR1_DLL_ENA_OFFS 0
+#define REG_DDR3_MR1_RTT_DISABLED 0x0
+#define REG_DDR3_MR1_RTT_RZQ2 0x40
+#define REG_DDR3_MR1_RTT_RZQ4 0x2
+#define REG_DDR3_MR1_RTT_RZQ6 0x42
+#define REG_DDR3_MR1_RTT_RZQ8 0x202
+#define REG_DDR3_MR1_RTT_RZQ12 0x4
+#define REG_DDR3_MR1_OUTBUF_WL_MASK 0xFFFFEF7F /* WL-disabled,OB-enabled */
+#define REG_DDR3_MR1_OUTBUF_DIS_OFFS 12 /* Output Buffer Disabled */
+#define REG_DDR3_MR1_WL_ENA_OFFS 7
+#define REG_DDR3_MR1_WL_ENA 0x80 /* WL Enabled */
+#define REG_DDR3_MR1_ODT_MASK 0xFFFFFDBB
+
+#define REG_DDR3_MR2_ADDR 0x15D8
+#define REG_DDR3_MR2_CS_ADDR 0x1878
+#define REG_DDR3_MR2_CWL_OFFS 3
+#define REG_DDR3_MR2_CWL_MASK 0x7
+#define REG_DDR3_MR2_ODT_MASK 0xFFFFF9FF
+#define REG_DDR3_MR3_ADDR 0x15DC
+#define REG_DDR3_MR3_CS_ADDR 0x187C
+
+#define REG_DDR3_RANK_CTRL_ADDR 0x15E0
+#define REG_DDR3_RANK_CTRL_CS_ENA_MASK 0xF
+#define REG_DDR3_RANK_CTRL_MIRROR_OFFS 4
+
+#define REG_ZQC_CONF_ADDR 0x15E4
+
+#define REG_DRAM_PHY_CONFIG_ADDR 0x15EC
+#define REG_DRAM_PHY_CONFIG_MASK 0x3FFFFFFF
+
+#define REG_ODPG_CNTRL_ADDR 0x1600
+#define REG_ODPG_CNTRL_OFFS 21
+
+#define REG_PHY_LOCK_MASK_ADDR 0x1670
+#define REG_PHY_LOCK_MASK_MASK 0xFFFFF000
+
+#define REG_PHY_LOCK_STATUS_ADDR 0x1674
+#define REG_PHY_LOCK_STATUS_LOCK_OFFS 9
+#define REG_PHY_LOCK_STATUS_LOCK_MASK 0xFFF
+#define REG_PHY_LOCK_APLL_ADLL_STATUS_MASK 0x7FF
+
+#define REG_PHY_REGISTRY_FILE_ACCESS_ADDR 0x16A0
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_WR 0xC0000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_RD 0x80000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE 0x80000000
+#define REG_PHY_BC_OFFS 27
+#define REG_PHY_CNTRL_OFFS 26
+#define REG_PHY_CS_OFFS 16
+#define REG_PHY_DQS_REF_DLY_OFFS 10
+#define REG_PHY_PHASE_OFFS 8
+#define REG_PHY_PUP_OFFS 22
+
+#define REG_TRAINING_WL_ADDR 0x16AC
+#define REG_TRAINING_WL_CS_MASK 0xFFFFFFFC
+#define REG_TRAINING_WL_UPD_OFFS 2
+#define REG_TRAINING_WL_CS_DONE_OFFS 3
+#define REG_TRAINING_WL_RATIO_MASK 0xFFFFFF0F
+#define REG_TRAINING_WL_1TO1 0x50
+#define REG_TRAINING_WL_2TO1 0x10
+#define REG_TRAINING_WL_DELAYEXP_MASK 0x20000000
+#define REG_TRAINING_WL_RESULTS_MASK 0x000001FF
+#define REG_TRAINING_WL_RESULTS_OFFS 20
+
+#define REG_REGISTERED_DRAM_CTRL_ADDR 0x16D0
+#define REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS 15
+#define REG_REGISTERED_DRAM_CTRL_PARITY_MASK 0x3F
+/* DLB*/
+#define REG_STATIC_DRAM_DLB_CONTROL 0x1700
+#define DLB_BUS_OPTIMIZATION_WEIGHTS_REG 0x1704
+#define DLB_AGING_REGISTER 0x1708
+#define DLB_EVICTION_CONTROL_REG 0x170c
+#define DLB_EVICTION_TIMERS_REGISTER_REG 0x1710
+
+#define DLB_ENABLE 0x1
+#define DLB_WRITE_COALESING (0x1 << 2)
+#define DLB_AXI_PREFETCH_EN (0x1 << 3)
+#define DLB_MBUS_PREFETCH_EN (0x1 << 4)
+#define PREFETCH_NLNSZTR (0x1 << 6)
+
+/* CPU */
+#define REG_BOOTROM_ROUTINE_ADDR 0x182D0
+#define REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS 12
+
+#define REG_DRAM_INIT_CTRL_STATUS_ADDR 0x18488
+#define REG_DRAM_INIT_CTRL_TRN_CLK_OFFS 16
+#define REG_CPU_DIV_CLK_CTRL_0_NEW_RATIO 0x000200FF
+#define REG_DRAM_INIT_CTRL_STATUS_2_ADDR 0x1488
+
+#define REG_CPU_DIV_CLK_CTRL_0_ADDR 0x18700
+
+#define REG_CPU_DIV_CLK_CTRL_1_ADDR 0x18704
+#define REG_CPU_DIV_CLK_CTRL_2_ADDR 0x18708
+
+#define REG_CPU_DIV_CLK_CTRL_3_ADDR 0x1870C
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK 0xFFFFC0FF
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS 8
+
+#define REG_CPU_DIV_CLK_CTRL_4_ADDR 0x18710
+
+#define REG_CPU_DIV_CLK_STATUS_0_ADDR 0x18718
+#define REG_CPU_DIV_CLK_ALL_STABLE_OFFS 8
+
+#define REG_CPU_PLL_CTRL_0_ADDR 0x1871C
+#define REG_CPU_PLL_STATUS_0_ADDR 0x18724
+#define REG_CORE_DIV_CLK_CTRL_ADDR 0x18740
+#define REG_CORE_DIV_CLK_STATUS_ADDR 0x18744
+#define REG_DDRPHY_APLL_CTRL_ADDR 0x18780
+
+#define REG_DDRPHY_APLL_CTRL_2_ADDR 0x18784
+
+#define REG_SFABRIC_CLK_CTRL_ADDR 0x20858
+#define REG_SFABRIC_CLK_CTRL_SMPL_OFFS 8
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_19_CTRL_ADDR 0x200e8
+#define REG_XBAR_WIN_4_CTRL_ADDR 0x20040
+#define REG_XBAR_WIN_4_BASE_ADDR 0x20044
+#define REG_XBAR_WIN_4_REMAP_ADDR 0x20048
+#define REG_FASTPATH_WIN_0_CTRL_ADDR 0x20184
+#define REG_XBAR_WIN_7_REMAP_ADDR 0x20078
+
+/* SRAM */
+#define REG_CDI_CONFIG_ADDR 0x20220
+#define REG_SRAM_WINDOW_0_ADDR 0x20240
+#define REG_SRAM_WINDOW_0_ENA_OFFS 0
+#define REG_SRAM_WINDOW_1_ADDR 0x20244
+#define REG_SRAM_L2_ENA_ADDR 0x8500
+#define REG_SRAM_CLEAN_BY_WAY_ADDR 0x87BC
+
+/* PMU */
+#define REG_PMU_I_F_CTRL_ADDR 0x1C090
+#define REG_PMU_DUNIT_BLK_OFFS 16
+#define REG_PMU_DUNIT_RFRS_OFFS 20
+#define REG_PMU_DUNIT_ACK_OFFS 24
+
+/* MBUS*/
+#define MBUS_UNITS_PRIORITY_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x420)
+#define FABRIC_UNITS_PRIORITY_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x424)
+#define MBUS_UNITS_PREFETCH_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x428)
+#define FABRIC_UNITS_PREFETCH_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x42c)
+
+#define REG_PM_STAT_MASK_ADDR 0x2210C
+#define REG_PM_STAT_MASK_CPU0_IDLE_MASK_OFFS 16
+
+#define REG_PM_EVENT_STAT_MASK_ADDR 0x22120
+#define REG_PM_EVENT_STAT_MASK_DFS_DONE_OFFS 17
+
+#define REG_PM_CTRL_CONFIG_ADDR 0x22104
+#define REG_PM_CTRL_CONFIG_DFS_REQ_OFFS 18
+
+#define REG_FABRIC_LOCAL_IRQ_MASK_ADDR 0x218C4
+#define REG_FABRIC_LOCAL_IRQ_PMU_MASK_OFFS 18
+
+/* Controller revision info */
+#define PCI_CLASS_CODE_AND_REVISION_ID 0x008
+#define PCCRIR_REVID_OFFS 0 /* Revision ID */
+#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS)
+
+/* Power Management Clock Gating Control Register */
+#define MV_PEX_IF_REGS_OFFSET(if) \
+ (if < 8 ? (0x40000 + ((if) / 4) * 0x40000 + ((if) % 4) * 0x4000) \
+ : (0x42000 + ((if) % 8) * 0x40000))
+#define MV_PEX_IF_REGS_BASE(unit) (MV_PEX_IF_REGS_OFFSET(unit))
+#define POWER_MNG_CTRL_REG 0x18220
+#define PEX_DEVICE_AND_VENDOR_ID 0x000
+#define PEX_CFG_DIRECT_ACCESS(if, reg) (MV_PEX_IF_REGS_BASE(if) + (reg))
+#define PMC_PEXSTOPCLOCK_OFFS(port) ((port) < 8 ? (5 + (port)) : (18 + (port)))
+#define PMC_PEXSTOPCLOCK_MASK(port) (1 << PMC_PEXSTOPCLOCK_OFFS(port))
+#define PMC_PEXSTOPCLOCK_EN(port) (1 << PMC_PEXSTOPCLOCK_OFFS(port))
+#define PMC_PEXSTOPCLOCK_STOP(port) (0 << PMC_PEXSTOPCLOCK_OFFS(port))
+
+/* TWSI */
+#define TWSI_DATA_ADDR_MASK 0x7
+#define TWSI_DATA_ADDR_OFFS 1
+
+/* General */
+#define MAX_CS 4
+
+/* Frequencies */
+#define FAB_OPT 21
+#define CLK_CPU 12
+#define CLK_VCO (2 * CLK_CPU)
+#define CLK_DDR 12
+
+/* Cpu Frequencies: */
+#define CLK_CPU_1000 0
+#define CLK_CPU_1066 1
+#define CLK_CPU_1200 2
+#define CLK_CPU_1333 3
+#define CLK_CPU_1500 4
+#define CLK_CPU_1666 5
+#define CLK_CPU_1800 6
+#define CLK_CPU_2000 7
+#define CLK_CPU_600 8
+#define CLK_CPU_667 9
+#define CLK_CPU_800 0xa
+
+/* Extra Cpu Frequencies: */
+#define CLK_CPU_1600 11
+#define CLK_CPU_2133 12
+#define CLK_CPU_2200 13
+#define CLK_CPU_2400 14
+
+/* DDR3 Frequencies: */
+#define DDR_100 0
+#define DDR_300 1
+#define DDR_333 1
+#define DDR_360 2
+#define DDR_400 3
+#define DDR_444 4
+#define DDR_500 5
+#define DDR_533 6
+#define DDR_600 7
+#define DDR_640 8
+#define DDR_666 8
+#define DDR_720 9
+#define DDR_750 9
+#define DDR_800 10
+#define DDR_833 11
+#define DDR_HCLK 20
+#define DDR_S 12
+#define DDR_S_1TO1 13
+#define MARGIN_FREQ DDR_400
+#define DFS_MARGIN DDR_100
+
+#define ODT_OPT 16
+#define ODT20 0x200
+#define ODT30 0x204
+#define ODT40 0x44
+#define ODT120 0x40
+#define ODT120D 0x400
+
+#define MRS_DELAY 100
+
+#define SDRAM_WL_SW_OFFS 0x100
+#define SDRAM_RL_OFFS 0x0
+#define SDRAM_PBS_I_OFFS 0x140
+#define SDRAM_PBS_II_OFFS 0x180
+#define SDRAM_PBS_NEXT_OFFS (SDRAM_PBS_II_OFFS - SDRAM_PBS_I_OFFS)
+#define SDRAM_PBS_TX_OFFS 0x180
+#define SDRAM_PBS_TX_DM_OFFS 576
+#define SDRAM_DQS_RX_OFFS 1024
+#define SDRAM_DQS_TX_OFFS 2048
+#define SDRAM_DQS_RX_SPECIAL_OFFS 5120
+
+#define LEN_STD_PATTERN 16
+#define LEN_KILLER_PATTERN 128
+#define LEN_SPECIAL_PATTERN 128
+#define LEN_PBS_PATTERN 16
+
+#endif /* __DDR3_AXP_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_axp_config.h b/drivers/ddr/marvell/axp/ddr3_axp_config.h
new file mode 100644
index 0000000000..800d2d1476
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_axp_config.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_AXP_CONFIG_H
+#define __DDR3_AXP_CONFIG_H
+
+/*
+ * DDR3_LOG_LEVEL Information
+ *
+ * Level 0: Provides an error code in a case of failure, RL, WL errors
+ * and other algorithm failure
+ * Level 1: Provides the D-Unit setup (SPD/Static configuration)
+ * Level 2: Provides the windows margin as a results of DQS centeralization
+ * Level 3: Provides the windows margin of each DQ as a results of DQS
+ * centeralization
+ */
+#ifdef CONFIG_DDR_LOG_LEVEL
+#define DDR3_LOG_LEVEL CONFIG_DDR_LOG_LEVEL
+#else
+#define DDR3_LOG_LEVEL 0
+#endif
+
+#define DDR3_PBS 1
+
+/* This flag allows the execution of SW WL/RL upon HW failure */
+#define DDR3_RUN_SW_WHEN_HW_FAIL 1
+
+/*
+ * General Configurations
+ *
+ * The following parameters are required for proper setup:
+ *
+ * DDR_TARGET_FABRIC - Set desired fabric configuration
+ * (for sample@Reset fabfreq parameter)
+ * DRAM_ECC - Set ECC support 1/0
+ * BUS_WIDTH - 64/32 bit
+ * CONFIG_SPD_EEPROM - Enables auto detection of DIMMs and their timing values
+ * DQS_CLK_ALIGNED - Set this if CLK and DQS signals are aligned on board
+ * MIXED_DIMM_STATIC - Mixed DIMM + On board devices support (ODT registers
+ * values are taken statically)
+ * DDR3_TRAINING_DEBUG - Debug prints of internal code
+ */
+#define DDR_TARGET_FABRIC 5
+#define DRAM_ECC 0
+
+#ifdef MV_DDR_32BIT
+#define BUS_WIDTH 32
+#else
+#define BUS_WIDTH 64
+#endif
+
+#undef DQS_CLK_ALIGNED
+#undef MIXED_DIMM_STATIC
+#define DDR3_TRAINING_DEBUG 0
+#define REG_DIMM_SKIP_WL 0
+
+/* Marvell boards specific configurations */
+#if defined(DB_78X60_PCAC)
+#undef CONFIG_SPD_EEPROM
+#define STATIC_TRAINING
+#endif
+
+#if defined(DB_78X60_AMC)
+#undef CONFIG_SPD_EEPROM
+#undef DRAM_ECC
+#define DRAM_ECC 1
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+/*
+ * DIMM support parameters:
+ * DRAM_2T - Set Desired 2T Mode - 0 - 1T, 0x1 - 2T, 0x2 - 3T
+ * DIMM_CS_BITMAP - bitmap representing the optional CS in DIMMs
+ * (0xF=CS0+CS1+CS2+CS3, 0xC=CS2+CS3...)
+ */
+#define DRAM_2T 0x0
+#define DIMM_CS_BITMAP 0xF
+#define DUNIT_SPD
+#endif
+
+#ifdef DRAM_ECC
+/*
+ * ECC support parameters:
+ *
+ * U_BOOT_START_ADDR, U_BOOT_SCRUB_SIZE - relevant when using ECC and need
+ * to configure the scrubbing area
+ */
+#define TRAINING_SIZE 0x20000
+#define U_BOOT_START_ADDR 0
+#define U_BOOT_SCRUB_SIZE 0x1000000 /* TRAINING_SIZE */
+#endif
+
+/*
+ * Registered DIMM Support - In case registered DIMM is attached,
+ * please supply the following values:
+ * (see JEDEC - JESD82-29A "Definition of the SSTE32882 Registering Clock
+ * Driver with Parity and Quad Chip
+ * Selects for DDR3/DDR3L/DDR3U RDIMM 1.5 V/1.35 V/1.25 V Applications")
+ * RC0: Global Features Control Word
+ * RC1: Clock Driver Enable Control Word
+ * RC2: Timing Control Word
+ * RC3-RC5 - taken from SPD
+ * RC8: Additional IBT Setting Control Word
+ * RC9: Power Saving Settings Control Word
+ * RC10: Encoding for RDIMM Operating Speed
+ * RC11: Operating Voltage VDD and VREFCA Control Word
+ */
+#define RDIMM_RC0 0
+#define RDIMM_RC1 0
+#define RDIMM_RC2 0
+#define RDIMM_RC8 0
+#define RDIMM_RC9 0
+#define RDIMM_RC10 0x2
+#define RDIMM_RC11 0x0
+
+#if defined(MIXED_DIMM_STATIC) || !defined(CONFIG_SPD_EEPROM)
+#define DUNIT_STATIC
+#endif
+
+#if defined(MIXED_DIMM_STATIC) || defined(CONFIG_SPD_EEPROM)
+/*
+ * This flag allows the user to change the dram refresh cycle in ps,
+ * only in case of SPD or MIX DIMM topology
+ */
+#define TREFI_USER_EN
+
+#ifdef TREFI_USER_EN
+#define TREFI_USER 3900000
+#endif
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+/*
+ * AUTO_DETECTION_SUPPORT - relevant ONLY for Marvell DB boards.
+ * Enables I2C auto detection different options
+ */
+#if defined(CONFIG_DB_88F78X60) || defined(CONFIG_DB_88F78X60_REV2) || \
+ defined(CONFIG_DB_784MP_GP)
+#define AUTO_DETECTION_SUPPORT
+#endif
+#endif
+
+#endif /* __DDR3_AXP_CONFIG_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_axp_mc_static.h b/drivers/ddr/marvell/axp/ddr3_axp_mc_static.h
new file mode 100644
index 0000000000..2c0e9075e9
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_axp_mc_static.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __AXP_MC_STATIC_H
+#define __AXP_MC_STATIC_H
+
+MV_DRAM_MC_INIT ddr3_A0_db_667[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x7301c924}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7301CA28}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630b800}, /*Dunit Control Low Register */
+ {0x00001408, 0x43149775}, /*DDR SDRAM Timing (Low) Register */
+ /* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+ {0x0000140C, 0x38d83fe0}, /*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+ {0x00001410, 0x040F0001}, /*DDR SDRAM Address Control Register */
+#else
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Open Pages Control Register */
+#endif
+
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0000D3FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000F8830}, /*Dunit Control High Register */
+ {0x0000142C, 0x214C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x0000c671},
+
+ {0x000014a0, 0x000002A9},
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192434e9}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0x092434e9}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ /* {0x00001524, 0x0000C800}, */
+ {0x00001538, 0x0000000b}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000d}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000640}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000010}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */
+ {0x000015EC, 0xd800aa25}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_A0_AMC_667[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x7301c924}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7301CA28}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630b800}, /*Dunit Control Low Register */
+ {0x00001408, 0x43149775}, /*DDR SDRAM Timing (Low) Register */
+ /* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+ {0x0000140C, 0x38d83fe0}, /*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+ {0x00001410, 0x040F0001}, /*DDR SDRAM Address Control Register */
+#else
+ {0x00001410, 0x040F000C}, /*DDR SDRAM Open Pages Control Register */
+#endif
+
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0000D3FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000F8830}, /*Dunit Control High Register */
+ {0x0000142C, 0x214C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x0000c671},
+
+ {0x000014a0, 0x000002A9},
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192434e9}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0x092434e9}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x3FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ /* {0x00001524, 0x0000C800}, */
+ {0x00001538, 0x0000000b}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000d}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000640}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000010}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */
+ {0x000015EC, 0xd800aa25}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_A0_db_400[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x73004C30}, /*DDR SDRAM Configuration Register */
+#else /* MV_DDR_64BIT */
+ {0x00001400, 0x7300CC30}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630B840}, /*Dunit Control Low Register */
+ {0x00001408, 0x33137663}, /*DDR SDRAM Timing (Low) Register */
+ {0x0000140C, 0x38000C55}, /*DDR SDRAM Timing (High) Register */
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Address Control Register */
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x0000141C, 0x00000672}, /*DDR SDRAM Mode Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0100D3FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000D6720}, /*Dunit Control High Register */
+ {0x0000142C, 0x014C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x00006571},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014a0, 0x000002A9},
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x000014C0, 0x192424C8}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0xEFB24C8}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000630}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000008}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQDS Configuration Register */
+ /* {0x000015EC, 0xDE000025}, *//*DDR PHY */
+ {0x000015EC, 0xF800AA25}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_Z1_db_600[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x73014A28}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7301CA28}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630B040}, /*Dunit Control Low Register */
+ {0x00001408, 0x44149887}, /*DDR SDRAM Timing (Low) Register */
+ /* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+ {0x0000140C, 0x38D83FE0}, /*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+ {0x00001410, 0x040F0001}, /*DDR SDRAM Address Control Register */
+#else
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Open Pages Control Register */
+#endif
+
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0100D1FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000F8830}, /*Dunit Control High Register */
+ {0x0000142C, 0x214C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x0000c671},
+
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192424C8}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0xEFB24C8}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ /* {0x00001524, 0x0000C800}, */
+ {0x00001538, 0x0000000b}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000d}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000650}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000010}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */
+ {0x000015EC, 0xDE000025}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_Z1_db_300[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x73004C30}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7300CC30}, /*DDR SDRAM Configuration Register */
+ /*{0x00001400, 0x7304CC30}, *//*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630B840}, /*Dunit Control Low Register */
+ {0x00001408, 0x33137663}, /*DDR SDRAM Timing (Low) Register */
+ {0x0000140C, 0x38000C55}, /*DDR SDRAM Timing (High) Register */
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Address Control Register */
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x0000141C, 0x00000672}, /*DDR SDRAM Mode Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0100F1FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000D6720}, /*Dunit Control High Register */
+ {0x0000142C, 0x014C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x00006571},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192424C8}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0xEFB24C8}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000630}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000008}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQDS Configuration Register */
+ {0x000015EC, 0xDE000025}, /*DDR PHY */
+
+ {0x0, 0x0}
+};
+
+#endif /* __AXP_MC_STATIC_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_axp_training_static.h b/drivers/ddr/marvell/axp/ddr3_axp_training_static.h
new file mode 100644
index 0000000000..4e615479ad
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_axp_training_static.h
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __AXP_TRAINING_STATIC_H
+#define __AXP_TRAINING_STATIC_H
+
+/*
+ * STATIC_TRAINING - Set only if static parameters for training are set and
+ * required
+ */
+
+MV_DRAM_TRAINING_INIT ddr3_db_rev2_667[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC002011A},
+ /*1 */
+ {0x000016A0, 0xC0420100},
+ /*2 */
+ {0x000016A0, 0xC082020A},
+ /*3 */
+ {0x000016A0, 0xC0C20017},
+ /*4 */
+ {0x000016A0, 0xC1020113},
+ /*5 */
+ {0x000016A0, 0xC1420107},
+ /*6 */
+ {0x000016A0, 0xC182011F},
+ /*7 */
+ {0x000016A0, 0xC1C2001C},
+ /*8 */
+ {0x000016A0, 0xC202010D},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0004A06},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0806A0D},
+ /*3 */
+ {0x000016A0, 0xC0C0A01B},
+ /*4 */
+ {0x000016A0, 0xC1003A01},
+ /*5 */
+ {0x000016A0, 0xC1408113},
+ /*6 */
+ {0x000016A0, 0xC1805609},
+ /*7 */
+ {0x000016A0, 0xC1C04504},
+ /*8 */
+ {0x000016A0, 0xC2009518},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_rev2_800[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020301},
+ /*1 */
+ {0x000016A0, 0xC0420202},
+ /*2 */
+ {0x000016A0, 0xC0820314},
+ /*3 */
+ {0x000016A0, 0xC0C20117},
+ /*4 */
+ {0x000016A0, 0xC1020219},
+ /*5 */
+ {0x000016A0, 0xC142020B},
+ /*6 */
+ {0x000016A0, 0xC182030A},
+ /*7 */
+ {0x000016A0, 0xC1C2011D},
+ /*8 */
+ {0x000016A0, 0xC2020212},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0007A12},
+ /*1 */
+ {0x000016A0, 0xC0408D16},
+ /*2 */
+ {0x000016A0, 0xC0809E1B},
+ /*3 */
+ {0x000016A0, 0xC0C0AC1F},
+ /*4 */
+ {0x000016A0, 0xC1005E0A},
+ /*5 */
+ {0x000016A0, 0xC140A91D},
+ /*6 */
+ {0x000016A0, 0xC1808E17},
+ /*7 */
+ {0x000016A0, 0xC1C05509},
+ /*8 */
+ {0x000016A0, 0xC2003A01},
+
+ /* PBS Leveling */
+ /*0 */
+ {0x000016A0, 0xC0007A12},
+ /*1 */
+ {0x000016A0, 0xC0408D16},
+ /*2 */
+ {0x000016A0, 0xC0809E1B},
+ /*3 */
+ {0x000016A0, 0xC0C0AC1F},
+ /*4 */
+ {0x000016A0, 0xC1005E0A},
+ /*5 */
+ {0x000016A0, 0xC140A91D},
+ /*6 */
+ {0x000016A0, 0xC1808E17},
+ /*7 */
+ {0x000016A0, 0xC1C05509},
+ /*8 */
+ {0x000016A0, 0xC2003A01},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000B},
+
+ {0x00001538, 0x0000000D}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x00000011}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_400[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 4 15 */
+ {0x000016A0, 0xC002010C},
+ /*1 2 4 2 */
+ {0x000016A0, 0xC042001C},
+ /*2 2 4 27 */
+ {0x000016A0, 0xC0820115},
+ /*3 2 4 0 */
+ {0x000016A0, 0xC0C20019},
+ /*4 2 4 13 */
+ {0x000016A0, 0xC1020108},
+ /*5 2 4 5 */
+ {0x000016A0, 0xC1420100},
+ /*6 2 4 19 */
+ {0x000016A0, 0xC1820111},
+ /*7 2 4 0 */
+ {0x000016A0, 0xC1C2001B},
+ /*8 2 4 10 */
+ /*{0x000016A0, 0xC2020117}, */
+ {0x000016A0, 0xC202010C},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0005508},
+ /*1 */
+ {0x000016A0, 0xC0409819},
+ /*2 */
+ {0x000016A0, 0xC080650C},
+ /*3 */
+ {0x000016A0, 0xC0C0700F},
+ /*4 */
+ {0x000016A0, 0xC1004103},
+ /*5 */
+ {0x000016A0, 0xC140A81D},
+ /*6 */
+ {0x000016A0, 0xC180650C},
+ /*7 */
+ {0x000016A0, 0xC1C08013},
+ /*8 */
+ {0x000016A0, 0xC2005508},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_533[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 4 15 */
+ {0x000016A0, 0xC002040C},
+ /*1 2 4 2 */
+ {0x000016A0, 0xC0420117},
+ /*2 2 4 27 */
+ {0x000016A0, 0xC082041B},
+ /*3 2 4 0 */
+ {0x000016A0, 0xC0C20117},
+ /*4 2 4 13 */
+ {0x000016A0, 0xC102040A},
+ /*5 2 4 5 */
+ {0x000016A0, 0xC1420117},
+ /*6 2 4 19 */
+ {0x000016A0, 0xC1820419},
+ /*7 2 4 0 */
+ {0x000016A0, 0xC1C20117},
+ /*8 2 4 10 */
+ {0x000016A0, 0xC2020117},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0008113},
+ /*1 */
+ {0x000016A0, 0xC0404504},
+ /*2 */
+ {0x000016A0, 0xC0808514},
+ /*3 */
+ {0x000016A0, 0xC0C09418},
+ /*4 */
+ {0x000016A0, 0xC1006D0E},
+ /*5 */
+ {0x000016A0, 0xC1405508},
+ /*6 */
+ {0x000016A0, 0xC1807D12},
+ /*7 */
+ {0x000016A0, 0xC1C0b01F},
+ /*8 */
+ {0x000016A0, 0xC2005D0A},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_600[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020104},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420010},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820112},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20009},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC102001F},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420014},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C2000C},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0009919},
+ /*1 */
+ {0x000016A0, 0xC0405508},
+ /*2 */
+ {0x000016A0, 0xC0809919},
+ /*3 */
+ {0x000016A0, 0xC0C09C1A},
+ /*4 */
+ {0x000016A0, 0xC1008113},
+ /*5 */
+ {0x000016A0, 0xC140650C},
+ /*6 */
+ {0x000016A0, 0xC1809518},
+ /*7 */
+ {0x000016A0, 0xC1C04103},
+ /*8 */
+ {0x000016A0, 0xC2006D0E},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_667[MV_MAX_DDR3_STATIC_SIZE] = {
+
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020103},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420012},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820113},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20012},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC1020100},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420016},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C20010},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC000b11F},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C0a81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC180ad1e},
+ /*7 */
+ {0x000016A0, 0xC1C04d06},
+ /*8 */
+ {0x000016A0, 0xC2008514},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_800[MV_MAX_DDR3_STATIC_SIZE] = {
+
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020213},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420108},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820210},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20108},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC102011A},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420300},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820204},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C20106},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC000620B},
+ /*1 */
+ {0x000016A0, 0xC0408D16},
+ /*2 */
+ {0x000016A0, 0xC0806A0D},
+ /*3 */
+ {0x000016A0, 0xC0C03D02},
+ /*4 */
+ {0x000016A0, 0xC1004a05},
+ /*5 */
+ {0x000016A0, 0xC140A11B},
+ /*6 */
+ {0x000016A0, 0xC1805E0A},
+ /*7 */
+ {0x000016A0, 0xC1C06D0E},
+ /*8 */
+ {0x000016A0, 0xC200AD1E},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000C}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000E}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_0[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC002010E},
+ /*1 */
+ {0x000016A0, 0xC042001E},
+ /*2 */
+ {0x000016A0, 0xC0820118},
+ /*3 */
+ {0x000016A0, 0xC0C2001E},
+ /*4 */
+ {0x000016A0, 0xC102010C},
+ /*5 */
+ {0x000016A0, 0xC1420102},
+ /*6 */
+ {0x000016A0, 0xC1820111},
+ /*7 */
+ {0x000016A0, 0xC1C2001C},
+ /*8 */
+ {0x000016A0, 0xC2020109},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0805207},
+ /*3 */
+ {0x000016A0, 0xC0C0A81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC1803E02},
+ /*7 */
+ {0x000016A0, 0xC1C05107},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_1[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020106},
+ /*1 */
+ {0x000016A0, 0xC0420016},
+ /*2 */
+ {0x000016A0, 0xC0820117},
+ /*3 */
+ {0x000016A0, 0xC0C2000F},
+ /*4 */
+ {0x000016A0, 0xC1020105},
+ /*5 */
+ {0x000016A0, 0xC142001B},
+ /*6 */
+ {0x000016A0, 0xC182010C},
+ /*7 */
+ {0x000016A0, 0xC1C20011},
+ /*8 */
+ {0x000016A0, 0xC2020101},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC0406D0E},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C04504},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC1803600},
+ /*7 */
+ {0x000016A0, 0xC1C0610B},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_2[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC002010C},
+ /*1 */
+ {0x000016A0, 0xC042001B},
+ /*2 */
+ {0x000016A0, 0xC082011D},
+ /*3 */
+ {0x000016A0, 0xC0C20015},
+ /*4 */
+ {0x000016A0, 0xC102010B},
+ /*5 */
+ {0x000016A0, 0xC1420101},
+ /*6 */
+ {0x000016A0, 0xC1820113},
+ /*7 */
+ {0x000016A0, 0xC1C20017},
+ /*8 */
+ {0x000016A0, 0xC2020107},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC0406D0E},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C04504},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC180B11F},
+ /*7 */
+ {0x000016A0, 0xC1C0610B},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_667_M[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /* CS 0 */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020103},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420012},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820113},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20012},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC1020100},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420016},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C20010},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC000b11F},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C0a81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC180ad1e},
+ /*7 */
+ {0x000016A0, 0xC1C04d06},
+ /*8 */
+ {0x000016A0, 0xC2008514},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ /* CS 1 */
+
+ {0x000016A0, 0xC0060103},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0460012},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0860113},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C60012},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC1060100},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1460016},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1860109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C60010},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2060112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC004b11F},
+ /*1 */
+ {0x000016A0, 0xC044690D},
+ /*2 */
+ {0x000016A0, 0xC0843600},
+ /*3 */
+ {0x000016A0, 0xC0C4a81D},
+ /*4 */
+ {0x000016A0, 0xC1049919},
+ /*5 */
+ {0x000016A0, 0xC1447911},
+ /*6 */
+ {0x000016A0, 0xC184ad1e},
+ /*7 */
+ {0x000016A0, 0xC1C44d06},
+ /*8 */
+ {0x000016A0, 0xC2048514},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC807000F},
+
+ /* Both CS */
+
+ {0x00001538, 0x00000B0B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x00000F0F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_3[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020118},
+ /*1 */
+ {0x000016A0, 0xC0420108},
+ /*2 */
+ {0x000016A0, 0xC0820202},
+ /*3 */
+ {0x000016A0, 0xC0C20108},
+ /*4 */
+ {0x000016A0, 0xC1020117},
+ /*5 */
+ {0x000016A0, 0xC142010C},
+ /*6 */
+ {0x000016A0, 0xC182011B},
+ /*7 */
+ {0x000016A0, 0xC1C20107},
+ /*8 */
+ {0x000016A0, 0xC2020113},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC0406D0E},
+ /*2 */
+ {0x000016A0, 0xC0805207},
+ /*3 */
+ {0x000016A0, 0xC0C0A81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC1803E02},
+ /*7 */
+ {0x000016A0, 0xC1C04D06},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_pcac_600[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020404},
+ /* 1 2 2 6 */
+ {0x000016A0, 0xC042031E},
+ /* 2 2 3 16 */
+ {0x000016A0, 0xC0820411},
+ /* 3 2 1 26 */
+ {0x000016A0, 0xC0C20400},
+ /* 4 2 2 29 */
+ {0x000016A0, 0xC1020404},
+ /* 5 2 2 13 */
+ {0x000016A0, 0xC142031D},
+ /* 6 2 3 6 */
+ {0x000016A0, 0xC182040C},
+ /* 7 2 1 31 */
+ {0x000016A0, 0xC1C2031B},
+ /* 8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /* 0 */
+ {0x000016A0, 0xC0004905},
+ /* 1 */
+ {0x000016A0, 0xC040A81D},
+ /* 2 */
+ {0x000016A0, 0xC0804504},
+ /* 3 */
+ {0x000016A0, 0xC0C08013},
+ /* 4 */
+ {0x000016A0, 0xC1004504},
+ /* 5 */
+ {0x000016A0, 0xC140A81D},
+ /* 6 */
+ {0x000016A0, 0xC1805909},
+ /* 7 */
+ {0x000016A0, 0xC1C09418},
+ /* 8 */
+ {0x000016A0, 0xC2006D0E},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+ {0x00001538, 0x00000009}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000D}, /*Read Data Ready Delay Register */
+ /* init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+#endif /* __AXP_TRAINING_STATIC_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_axp_vars.h b/drivers/ddr/marvell/axp/ddr3_axp_vars.h
new file mode 100644
index 0000000000..1b0ab5603e
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_axp_vars.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __AXP_VARS_H
+#define __AXP_VARS_H
+
+#include "ddr3_axp_config.h"
+#include "ddr3_axp_mc_static.h"
+#include "ddr3_axp_training_static.h"
+
+MV_DRAM_MODES ddr_modes[MV_DDR3_MODES_NUMBER] = {
+ /* Conf name CPUFreq FabFreq Chip ID Chip/Board MC regs Training Values */
+ /* db board values: */
+ {"db_800-400", 0xA, 0x5, 0x0, A0, ddr3_A0_db_400, NULL},
+ {"db_1200-300", 0x2, 0xC, 0x0, A0, ddr3_A0_db_400, NULL},
+ {"db_1200-600", 0x2, 0x5, 0x0, A0, NULL, NULL},
+ {"db_1333-667", 0x3, 0x5, 0x0, A0, ddr3_A0_db_667, ddr3_db_rev2_667},
+ {"db_1600-800", 0xB, 0x5, 0x0, A0, ddr3_A0_db_667, ddr3_db_rev2_800},
+ {"amc_1333-667", 0x3, 0x5, 0x0, A0_AMC, ddr3_A0_AMC_667, NULL},
+ {"db_667-667", 0x9, 0x13, 0x0, Z1, ddr3_Z1_db_600, ddr3_db_667},
+ {"db_800-400", 0xA, 0x1, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_400},
+ {"db_1066-533", 0x1, 0x1, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_533},
+ {"db_1200-300", 0x2, 0xC, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_667},
+ {"db_1200-600", 0x2, 0x5, 0x0, Z1, ddr3_Z1_db_600, NULL},
+ {"db_1333-333", 0x3, 0xC, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_400},
+ {"db_1333-667", 0x3, 0x5, 0x0, Z1, ddr3_Z1_db_600, ddr3_db_667},
+ /* pcac board values (Z1 device): */
+ {"pcac_1200-600", 0x2, 0x5, 0x0, Z1_PCAC, ddr3_Z1_db_600,
+ ddr3_pcac_600},
+ /* rd board values (Z1 device): */
+ {"rd_667_0", 0x3, 0x5, 0x0, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_0},
+ {"rd_667_1", 0x3, 0x5, 0x1, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_1},
+ {"rd_667_2", 0x3, 0x5, 0x2, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_2},
+ {"rd_667_3", 0x3, 0x5, 0x3, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_3}
+};
+
+/* ODT settings - if needed update the following tables: (ODT_OPT - represents the CS configuration bitmap) */
+
+u16 odt_static[ODT_OPT][MAX_CS] = { /* NearEnd/FarEnd */
+ {0, 0, 0, 0}, /* 0000 0/0 - Not supported */
+ {ODT40, 0, 0, 0}, /* 0001 0/1 */
+ {0, 0, 0, 0}, /* 0010 0/0 - Not supported */
+ {ODT40, ODT40, 0, 0}, /* 0011 0/2 */
+ {0, 0, ODT40, 0}, /* 0100 1/0 */
+ {ODT30, 0, ODT30, 0}, /* 0101 1/1 */
+ {0, 0, 0, 0}, /* 0110 0/0 - Not supported */
+ {ODT120, ODT20, ODT20, 0}, /* 0111 1/2 */
+ {0, 0, 0, 0}, /* 1000 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1001 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1010 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1011 0/0 - Not supported */
+ {0, 0, ODT40, 0}, /* 1100 2/0 */
+ {ODT20, 0, ODT120, ODT20}, /* 1101 2/1 */
+ {0, 0, 0, 0}, /* 1110 0/0 - Not supported */
+ {ODT120, ODT30, ODT120, ODT30} /* 1111 2/2 */
+};
+
+u16 odt_dynamic[ODT_OPT][MAX_CS] = { /* NearEnd/FarEnd */
+ {0, 0, 0, 0}, /* 0000 0/0 */
+ {0, 0, 0, 0}, /* 0001 0/1 */
+ {0, 0, 0, 0}, /* 0010 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 0011 0/2 */
+ {0, 0, 0, 0}, /* 0100 1/0 */
+ {ODT120D, 0, ODT120D, 0}, /* 0101 1/1 */
+ {0, 0, 0, 0}, /* 0110 0/0 - Not supported */
+ {0, 0, ODT120D, 0}, /* 0111 1/2 */
+ {0, 0, 0, 0}, /* 1000 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1001 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1010 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1011 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1100 2/0 */
+ {ODT120D, 0, 0, 0}, /* 1101 2/1 */
+ {0, 0, 0, 0}, /* 1110 0/0 - Not supported */
+ {0, 0, 0, 0} /* 1111 2/2 */
+};
+
+u32 odt_config[ODT_OPT] = {
+ 0, 0x00010000, 0, 0x00030000, 0x04000000, 0x05050104, 0, 0x07430340, 0,
+ 0, 0, 0,
+ 0x30000, 0x1C0D100C, 0, 0x3CC330C0
+};
+
+/*
+ * User can manually set SPD values (in case SPD is not available on
+ * DIMM/System).
+ * SPD Values can simplify calculating the DUNIT registers values
+ */
+u8 spd_data[SPD_SIZE] = {
+ /* AXP DB Board DIMM SPD Values - manually set */
+ 0x92, 0x10, 0x0B, 0x2, 0x3, 0x19, 0x0, 0x9, 0x09, 0x52, 0x1, 0x8, 0x0C,
+ 0x0, 0x7E, 0x0, 0x69, 0x78,
+ 0x69, 0x30, 0x69, 0x11, 0x20, 0x89, 0x0, 0x5, 0x3C, 0x3C, 0x0, 0xF0,
+ 0x82, 0x5, 0x80, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0F, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x80, 0x2C, 0x1, 0x10, 0x23, 0x35, 0x28, 0xEB, 0xCA, 0x19, 0x8F
+};
+
+/*
+ * Controller Specific configurations Starts Here - DO NOT MODIFY
+ */
+
+/* Frequency - values are 1/HCLK in ps */
+u32 cpu_fab_clk_to_hclk[FAB_OPT][CLK_CPU] =
+/* CPU Frequency:
+ 1000 1066 1200 1333 1500 1666 1800 2000 600 667 800 1600 Fabric */
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 2500, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 4500, 3750, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 2500, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {4000, 3750, 3333, 3000, 2666, 2400, 0, 0, 0, 0, 5000, 2500},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {2500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 5000, 0, 4000, 0, 0, 0, 0, 0, 0, 3750},
+ {5000, 0, 0, 3750, 3333, 0, 0, 0, 0, 0, 0, 3125},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 3330, 3000, 0, 0, 0, 0, 0, 0, 0, 2500},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3750},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 2500, 0},
+ {3000, 0, 2500, 0, 0, 0, 0, 0, 0, 0, 3750, 0}
+};
+
+u32 cpu_ddr_ratios[FAB_OPT][CLK_CPU] =
+/* CPU Frequency:
+ 1000 1066 1200 1333 1500 1666 1800 2000 600 667 800 1600 Fabric */
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_333, DDR_400, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_444, DDR_533, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, DDR_400, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {DDR_500, DDR_533, DDR_600, DDR_666, DDR_750, DDR_833, 0, 0, 0, 0,
+ DDR_400, DDR_800},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_333, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {DDR_400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, DDR_400, 0, DDR_500, 0, 0, 0, 0, 0, 0, DDR_533},
+ {DDR_400, 0, 0, DDR_533, DDR_600, 0, 0, 0, 0, 0, 0, DDR_640},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, DDR_300, DDR_333, 0, 0, 0, 0, 0, 0, 0, DDR_400},
+ {0, 0, 0, 0, 0, 0, DDR_600, DDR_666, 0, 0, 0, DDR_533},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_666, DDR_800, 0},
+ {DDR_666, 0, DDR_800, 0, 0, 0, 0, 0, 0, 0, DDR_533, 0}
+};
+
+u8 div_ratio1to1[CLK_VCO][CLK_DDR] =
+/* DDR Frequency:
+ 100 300 360 400 444 500 533 600 666 750 800 833 */
+{ {0xA, 3, 0, 3, 0, 2, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1000 */
+{0xB, 3, 0, 3, 0, 0, 2, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1066 */
+{0xC, 4, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1200 */
+{0xD, 4, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0}, /* 1:1 CLK_CPU_1333 */
+{0xF, 5, 0, 4, 0, 3, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1500 */
+{0x11, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1666 */
+{0x12, 6, 5, 4, 0, 0, 0, 3, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1800 */
+{0x14, 7, 0, 5, 0, 4, 0, 0, 3, 0, 0, 0}, /* 1:1 CLK_CPU_2000 */
+{0x6, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_600 */
+{0x6, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_667 */
+{0x8, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_800 */
+{0x10, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1600 */
+{0x14, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1000 VCO_2000 */
+{0x15, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1066 VCO_2133 */
+{0x18, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1200 VCO_2400 */
+{0x1A, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1333 VCO_2666 */
+{0x1E, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1500 VCO_3000 */
+{0x21, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1666 VCO_3333 */
+{0x24, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1800 VCO_3600 */
+{0x28, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_2000 VCO_4000 */
+{0xC, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_600 VCO_1200 */
+{0xD, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_667 VCO_1333 */
+{0x10, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_800 VCO_1600 */
+{0x20, 10, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0} /* 1:1 CLK_CPU_1600 VCO_3200 */
+};
+
+u8 div_ratio2to1[CLK_VCO][CLK_DDR] =
+/* DDR Frequency:
+ 100 300 360 400 444 500 533 600 666 750 800 833 */
+{ {0, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0}, /* 2:1 CLK_CPU_1000 */
+{0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1066 */
+{0, 0, 0, 3, 5, 0, 0, 2, 0, 0, 3, 3}, /* 2:1 CLK_CPU_1200 */
+{0, 0, 0, 0, 0, 0, 5, 0, 2, 0, 3, 0}, /* 2:1 CLK_CPU_1333 */
+{0, 0, 0, 0, 0, 3, 0, 5, 0, 2, 0, 0}, /* 2:1 CLK_CPU_1500 */
+{0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 2}, /* 2:1 CLK_CPU_1666 */
+{0, 0, 0, 0, 0, 0, 0, 3, 0, 5, 0, 0}, /* 2:1 CLK_CPU_1800 */
+{0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 5}, /* 2:1 CLK_CPU_2000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_600 */
+{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, /* 2:1 CLK_CPU_667 */
+{0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0}, /* 2:1 CLK_CPU_800 */
+{0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0}, /* 2:1 CLK_CPU_1600 */
+{0, 0, 0, 5, 0, 0, 0, 0, 3, 0, 0, 0}, /* 2:1 CLK_CPU_1000 VCO_2000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1066 VCO_2133 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0}, /* 2:1 CLK_CPU_1200 VCO_2400 */
+{0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1333 VCO_2666 */
+{0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1500 VCO_3000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1666 VCO_3333 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1800 VCO_3600 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_2000 VCO_4000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_600 VCO_1200 */
+{0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_667 VCO_1333 */
+{0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_800 VCO_1600 */
+{0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0} /* 2:1 CLK_CPU_1600 VCO_3200 */
+};
+
+#endif /* __AXP_VARS_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_dfs.c b/drivers/ddr/marvell/axp/ddr3_dfs.c
new file mode 100644
index 0000000000..934777368a
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_dfs.c
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DFS_C(s, d, l) \
+ DEBUG_DFS_S(s); DEBUG_DFS_D(d, l); DEBUG_DFS_S("\n")
+#define DEBUG_DFS_FULL_C(s, d, l) \
+ DEBUG_DFS_FULL_S(s); DEBUG_DFS_FULL_D(d, l); DEBUG_DFS_FULL_S("\n")
+
+#ifdef MV_DEBUG_DFS
+#define DEBUG_DFS_S(s) puts(s)
+#define DEBUG_DFS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DFS_S(s)
+#define DEBUG_DFS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DFS_FULL
+#define DEBUG_DFS_FULL_S(s) puts(s)
+#define DEBUG_DFS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DFS_FULL_S(s)
+#define DEBUG_DFS_FULL_D(d, l)
+#endif
+
+#if defined(MV88F672X)
+extern u8 div_ratio[CLK_VCO][CLK_DDR];
+extern void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+#else
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+extern u8 div_ratio1to1[CLK_CPU][CLK_DDR];
+extern u8 div_ratio2to1[CLK_CPU][CLK_DDR];
+#endif
+extern u16 odt_static[ODT_OPT][MAX_CS];
+
+extern u32 cpu_fab_clk_to_hclk[FAB_OPT][CLK_CPU];
+
+extern u32 ddr3_get_vco_freq(void);
+
+u32 ddr3_get_freq_parameter(u32 target_freq, int ratio_2to1);
+
+#ifdef MV_DEBUG_DFS
+static inline void dfs_reg_write(u32 addr, u32 val)
+{
+ printf("\n write reg 0x%08x = 0x%08x", addr, val);
+ writel(val, INTER_REGS_BASE + addr);
+}
+#else
+static inline void dfs_reg_write(u32 addr, u32 val)
+{
+ writel(val, INTER_REGS_BASE + addr);
+}
+#endif
+
+static void wait_refresh_op_complete(void)
+{
+ u32 reg;
+
+ /* Poll - Wait for Refresh operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ REG_SDRAM_OPERATION_CMD_RFRS_DONE;
+ } while (reg); /* Wait for '0' */
+}
+
+/*
+ * Name: ddr3_get_freq_parameter
+ * Desc: Finds CPU/DDR frequency ratio according to Sample@reset and table.
+ * Args: target_freq - target frequency
+ * Notes:
+ * Returns: freq_par - the ratio parameter
+ */
+u32 ddr3_get_freq_parameter(u32 target_freq, int ratio_2to1)
+{
+ u32 ui_vco_freq, freq_par;
+
+ ui_vco_freq = ddr3_get_vco_freq();
+
+#if defined(MV88F672X)
+ freq_par = div_ratio[ui_vco_freq][target_freq];
+#else
+ /* Find the ratio between PLL frequency and ddr-clk */
+ if (ratio_2to1)
+ freq_par = div_ratio2to1[ui_vco_freq][target_freq];
+ else
+ freq_par = div_ratio1to1[ui_vco_freq][target_freq];
+#endif
+
+ return freq_par;
+}
+
+/*
+ * Name: ddr3_dfs_high_2_low
+ * Desc:
+ * Args: freq - target frequency
+ * Notes:
+ * Returns: MV_OK - success, MV_FAIL - fail
+ */
+int ddr3_dfs_high_2_low(u32 freq, MV_DRAM_INFO *dram_info)
+{
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* This Flow is relevant for ArmadaXP A0 */
+ u32 reg, freq_par, tmp;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - 100MHz */
+ freq_par = ddr3_get_freq_parameter(freq, 0);
+
+#if defined(MV88F672X)
+ u32 hclk;
+ u32 cpu_freq = ddr3_get_cpu_freq();
+ get_target_freq(cpu_freq, &tmp, &hclk);
+#endif
+
+ /* Configure - DRAM DLL final state after DFS is complete - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ /* [0] - DfsDllNextState - Disable */
+ reg |= (1 << REG_DFS_DLLNEXTSTATE_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable internal
+ * access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Disable */
+ reg &= ~(1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* Configure - Block new external transactions - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Registered DIMM support */
+ if (dram_info->reg_dimm) {
+ /*
+ * Configure - Disable Register DIMM CKE Power
+ * Down mode - CWA_RC
+ */
+ reg = (0x9 & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+ REG_SDRAM_OPERATION_CWA_RC_OFFS;
+ /*
+ * Configure - Disable Register DIMM CKE Power
+ * Down mode - CWA_DATA
+ */
+ reg |= ((0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+
+ /*
+ * Configure - Disable Register DIMM CKE Power
+ * Down mode - Set Delay - tMRD
+ */
+ reg |= (0 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+
+ /* Configure - Issue CWA command with the above parameters */
+ reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for CWA operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ (REG_SDRAM_OPERATION_CMD_MASK);
+ } while (reg);
+
+ /* Configure - Disable outputs floating during Self Refresh */
+ reg = reg_read(REG_REGISTERED_DRAM_CTRL_ADDR);
+ /* [15] - SRFloatEn - Disable */
+ reg &= ~(1 << REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS);
+ /* 0x16D0 - DDR3 Registered DRAM Control */
+ dfs_reg_write(REG_REGISTERED_DRAM_CTRL_ADDR, reg);
+ }
+
+ /* Optional - Configure - DDR3_Rtt_nom_CS# */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS));
+ reg &= REG_DDR3_MR1_RTT_MASK;
+ dfs_reg_write(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* Configure - Move DRAM into Self Refresh */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_SR_OFFS); /* [2] - DfsSR - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Poll - Wait for Self Refresh indication */
+ do {
+ reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+ } while (reg == 0x0); /* 0x1528 [3] - DfsAtSR - Wait for '1' */
+
+ /* Start of clock change procedure (PLL) */
+#if defined(MV88F672X)
+ /* avantaLP */
+ /* Configure cpupll_clkdiv_reset_mask */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL0_MASK;
+ /* 0xE8264[7:0] 0xff CPU Clock Dividers Reset mask */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, (reg + 0xFF));
+
+ /* Configure cpu_clkdiv_reload_smooth */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELOAD_SMOOTH_MASK;
+ /* 0xE8260 [15:8] 0x2 CPU Clock Dividers Reload Smooth enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ (reg + (2 << CPU_PLL_CNTRL0_RELOAD_SMOOTH_OFFS)));
+
+ /* Configure cpupll_clkdiv_relax_en */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELAX_EN_MASK;
+ /* 0xE8260 [31:24] 0x2 Relax Enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ (reg + (2 << CPU_PLL_CNTRL0_RELAX_EN_OFFS)));
+
+ /* Configure cpupll_clkdiv_ddr_clk_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL1);
+ /*
+ * 0xE8268 [13:8] N Set Training clock:
+ * APLL Out Clock (VCO freq) / N = 100 MHz
+ */
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL1_MASK;
+ reg |= (freq_par << 8); /* full Integer ratio from PLL-out to ddr-clk */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL1, reg);
+
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x1 CPU Clock Dividers Reload Ratio trigger set */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0,
+ (reg + (1 << CPU_PLL_CLOCK_RELOAD_RATIO_OFFS)));
+
+ udelay(1);
+
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x0 CPU Clock Dividers Reload Ratio trigger clear */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, reg);
+
+ udelay(5);
+
+#else
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8] and
+ * force reserved bits[7:0].
+ */
+ reg = 0x0000FDFF;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel
+ * (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18704 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_2_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+
+ /* full Integer ratio from PLL-out to ddr-clk */
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_2_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+
+ /* Clock is not shut off gracefully - keep it running */
+ reg = 0x000FFF02;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==>
+ * only DDR Phy (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ reg = 0x0102FDFF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1); /* Wait 1usec */
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks
+ * are active - 0x18718 [8]
+ */
+ do {
+ reg = (reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR)) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests
+ * of ratio modifications.
+ */
+ reg = 0x000000FF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(5);
+#endif
+ /* End of clock change procedure (PLL) */
+
+ /* Configure - Select normal clock for the DDR PHY - Enable */
+ reg = reg_read(REG_DRAM_INIT_CTRL_STATUS_ADDR);
+ /* [16] - ddr_phy_trn_clk_sel - Enable */
+ reg |= (1 << REG_DRAM_INIT_CTRL_TRN_CLK_OFFS);
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+ /* Configure - Set Correct Ratio - 1:1 */
+ /* [15] - Phy2UnitClkRatio = 0 - Set 1:1 Ratio between Dunit and Phy */
+
+ reg = reg_read(REG_DDR_IO_ADDR) & ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Register */
+
+ /* Configure - 2T Mode - Restore original configuration */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ /* [3:4] 2T - 1T Mode - low freq */
+ reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+ /* 0x1404 - DDR Controller Control Low Register */
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* Configure - Restore CL and CWL - MRS Commands */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(REG_DFS_CL_NEXT_STATE_MASK << REG_DFS_CL_NEXT_STATE_OFFS);
+ reg &= ~(REG_DFS_CWL_NEXT_STATE_MASK << REG_DFS_CWL_NEXT_STATE_OFFS);
+ /* [8] - DfsCLNextState - MRS CL=6 after DFS (due to DLL-off mode) */
+ reg |= (0x4 << REG_DFS_CL_NEXT_STATE_OFFS);
+ /* [12] - DfsCWLNextState - MRS CWL=6 after DFS (due to DLL-off mode) */
+ reg |= (0x1 << REG_DFS_CWL_NEXT_STATE_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Poll - Wait for APLL + ADLLs lock on new frequency */
+ do {
+ reg = (reg_read(REG_PHY_LOCK_STATUS_ADDR)) &
+ REG_PHY_LOCK_APLL_ADLL_STATUS_MASK;
+ /* 0x1674 [10:0] - Phy lock status Register */
+ } while (reg != REG_PHY_LOCK_APLL_ADLL_STATUS_MASK);
+
+ /* Configure - Reset the PHY Read FIFO and Write channels - Set Reset */
+ reg = (reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK);
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /*
+ * Configure - DRAM Data PHY Read [30], Write [29] path
+ * reset - Release Reset
+ */
+ reg = (reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK);
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Registered DIMM support */
+ if (dram_info->reg_dimm) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (below 400MHz) - CWA_RC
+ */
+ reg = (0xA & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+ REG_SDRAM_OPERATION_CWA_RC_OFFS;
+
+ /*
+ * Configure - Change register DRAM operating speed
+ * (below 400MHz) - CWA_DATA
+ */
+ reg |= ((0x0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+
+ /* Configure - Set Delay - tSTAB */
+ reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+
+ /* Configure - Issue CWA command with the above parameters */
+ reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for CWA operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ (REG_SDRAM_OPERATION_CMD_MASK);
+ } while (reg);
+ }
+
+ /* Configure - Exit Self Refresh */
+ /* [2] - DfsSR */
+ reg = (reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS));
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll - DFS Register - 0x1528 [3] - DfsAtSR - All DRAM devices
+ * on all ranks are NOT in self refresh mode
+ */
+ do {
+ reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+ } while (reg); /* Wait for '0' */
+
+ /* Configure - Issue Refresh command */
+ /* [3-0] = 0x2 - Refresh Command, [11-8] - enabled Cs */
+ reg = REG_SDRAM_OPERATION_CMD_RFRS;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs))
+ reg &= ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ }
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Configure - Block new external transactions - Disable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Disable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable
+ * internal access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Enable */
+ reg |= (1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ /* Configure - Set CL */
+ reg = reg_read(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS)) &
+ ~REG_DDR3_MR0_CL_MASK;
+ tmp = 0x4; /* CL=6 - 0x4 */
+ reg |= ((tmp & 0x1) << REG_DDR3_MR0_CL_OFFS);
+ reg |= ((tmp & 0xE) << REG_DDR3_MR0_CL_HIGH_OFFS);
+ dfs_reg_write(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+
+ /* Configure - Set CWL */
+ reg = reg_read(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS))
+ & ~(REG_DDR3_MR2_CWL_MASK << REG_DDR3_MR2_CWL_OFFS);
+ /* CWL=6 - 0x1 */
+ reg |= ((0x1) << REG_DDR3_MR2_CWL_OFFS);
+ dfs_reg_write(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Ended successfuly - new Frequency - ",
+ freq, 1);
+
+ return MV_OK;
+#else
+ /* This Flow is relevant for Armada370 A0 and ArmadaXP Z1 */
+
+ u32 reg, freq_par;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - 100MHz */
+ freq_par = ddr3_get_freq_parameter(freq, 0);
+
+ reg = 0x0000FF00;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ /* 0x1600 - ODPG_CNTRL_Control */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ /* [21] = 1 - auto refresh disable */
+ reg |= (1 << REG_ODPG_CNTRL_OFFS);
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg &= REG_PHY_LOCK_MASK_MASK; /* [11:0] = 0 */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ reg = reg_read(REG_DFS_ADDR); /* 0x1528 - DFS register */
+
+ /* Disable reconfig */
+ reg &= ~0x10; /* [4] - Enable reconfig MR registers after DFS_ERG */
+ reg |= 0x1; /* [0] - DRAM DLL disabled after DFS */
+
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ reg = reg_read(REG_METAL_MASK_ADDR) & ~(1 << 0); /* [0] - disable */
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* [1] - DFS Block enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* [2] - DFS Self refresh enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - 0x1528 [3] - DfsAtSR -
+ * All DRAM devices on all ranks are in self refresh mode -
+ * DFS can be executed afterwards
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg == 0x0); /* Wait for '1' */
+
+ /* Disable ODT on DLL-off mode */
+ dfs_reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR,
+ REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK);
+
+ /* [11:0] = 0 */
+ reg = (reg_read(REG_PHY_LOCK_MASK_ADDR) & REG_PHY_LOCK_MASK_MASK);
+ /* 0x1670 - PHY lock mask register */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ /* Add delay between entering SR and start ratio modification */
+ udelay(1);
+
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8] and
+ * force reserved bits[7:0].
+ */
+ reg = 0x0000FDFF;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_3_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+ /* Full Integer ratio from PLL-out to ddr-clk */
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_3_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+
+ /* Clock is not shut off gracefully - keep it running */
+ reg = 0x000FFF02;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+ * (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ reg = 0x0102FDFF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1); /* Wait 1usec */
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks
+ * are active - 0x18718 [8]
+ */
+ do {
+ reg = (reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR)) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests of
+ * ratio modifications.
+ */
+ reg = 0x000000FF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(5);
+
+ /* Switch HCLK Mux to training clk (100Mhz), keep DFS request bit */
+ reg = 0x20050000;
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+ reg = reg_read(REG_DDR_IO_ADDR) & ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ /* [15] = 0 - Set 1:1 Ratio between Dunit and Phy */
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Regist */
+
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30]] - reset pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ reg = (reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK);
+ /* [31:30] - normal pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ udelay(1); /* Wait 1usec */
+
+ /* 0x1404 */
+ reg = (reg_read(REG_DUNIT_CTRL_LOW_ADDR) & 0xFFFFFFE7);
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* Poll Phy lock status register - APLL lock indication - 0x1674 */
+ do {
+ reg = (reg_read(REG_PHY_LOCK_STATUS_ADDR)) &
+ REG_PHY_LOCK_STATUS_LOCK_MASK;
+ } while (reg != REG_PHY_LOCK_STATUS_LOCK_MASK); /* Wait for '0xFFF' */
+
+ reg = (reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK);
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ udelay(1000); /* Wait 1msec */
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Config CL and CWL with MR0 and MR2 registers */
+ reg = reg_read(REG_DDR3_MR0_ADDR);
+ reg &= ~0x74; /* CL [3:0]; [6:4],[2] */
+ reg |= (1 << 5); /* CL = 4, CAS is 6 */
+ dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+ reg = REG_SDRAM_OPERATION_CMD_MR0 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ reg = reg_read(REG_DDR3_MR2_ADDR);
+ reg &= ~0x38; /* CWL [5:3] */
+ reg |= (1 << 3); /* CWL = 1, CWL is 6 */
+ dfs_reg_write(REG_DDR3_MR2_ADDR, reg);
+
+ reg = REG_SDRAM_OPERATION_CMD_MR2 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg |= (5 << (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+ /* Set current rd_ready_delay */
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((6) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ }
+ }
+
+ /* [2] - DFS Self refresh disable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* [1] - DFS Block enable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - 0x1528 [3] - DfsAtSR -
+ * All DRAM devices on all ranks are in self refresh mode - DFS can
+ * be executed afterwards
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg); /* Wait for '1' */
+
+ reg = (reg_read(REG_METAL_MASK_ADDR) | (1 << 0));
+ /* [0] - Enable Dunit to crossbar retry */
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* 0x1600 - PHY lock mask register */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ reg &= ~(1 << REG_ODPG_CNTRL_OFFS); /* [21] = 0 */
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg |= ~REG_PHY_LOCK_MASK_MASK; /* [11:0] = FFF */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Ended successfuly - new Frequency - ",
+ freq, 1);
+
+ return MV_OK;
+#endif
+}
+
+/*
+ * Name: ddr3_dfs_low_2_high
+ * Desc:
+ * Args: freq - target frequency
+ * Notes:
+ * Returns: MV_OK - success, MV_FAIL - fail
+ */
+int ddr3_dfs_low_2_high(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* This Flow is relevant for ArmadaXP A0 */
+ u32 reg, freq_par, tmp;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - freq */
+ freq_par = ddr3_get_freq_parameter(freq, ratio_2to1);
+
+#if defined(MV88F672X)
+ u32 hclk;
+ u32 cpu_freq = ddr3_get_cpu_freq();
+ get_target_freq(cpu_freq, &tmp, &hclk);
+#endif
+
+ /* Configure - DRAM DLL final state after DFS is complete - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ /* [0] - DfsDllNextState - Enable */
+ reg &= ~(1 << REG_DFS_DLLNEXTSTATE_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable
+ * internal access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Disable */
+ reg &= ~(1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* Configure - Block new external transactions - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Configure - Move DRAM into Self Refresh */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_SR_OFFS); /* [2] - DfsSR - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Poll - Wait for Self Refresh indication */
+ do {
+ reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+ } while (reg == 0x0); /* 0x1528 [3] - DfsAtSR - Wait for '1' */
+
+ /* Start of clock change procedure (PLL) */
+#if defined(MV88F672X)
+ /* avantaLP */
+ /* Configure cpupll_clkdiv_reset_mask */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL0_MASK;
+ /* 0xE8264[7:0] 0xff CPU Clock Dividers Reset mask */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, (reg + 0xFF));
+
+ /* Configure cpu_clkdiv_reload_smooth */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELOAD_SMOOTH_MASK;
+ /* 0xE8260 [15:8] 0x2 CPU Clock Dividers Reload Smooth enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ reg + (2 << CPU_PLL_CNTRL0_RELOAD_SMOOTH_OFFS));
+
+ /* Configure cpupll_clkdiv_relax_en */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELAX_EN_MASK;
+ /* 0xE8260 [31:24] 0x2 Relax Enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ reg + (2 << CPU_PLL_CNTRL0_RELAX_EN_OFFS));
+
+ /* Configure cpupll_clkdiv_ddr_clk_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL1);
+ /*
+ * 0xE8268 [13:8] N Set Training clock:
+ * APLL Out Clock (VCO freq) / N = 100 MHz
+ */
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL1_MASK;
+ reg |= (freq_par << 8); /* full Integer ratio from PLL-out to ddr-clk */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL1, reg);
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x1 CPU Clock Dividers Reload Ratio trigger set */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0,
+ reg + (1 << CPU_PLL_CLOCK_RELOAD_RATIO_OFFS));
+
+ udelay(1);
+
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x0 CPU Clock Dividers Reload Ratio trigger clear */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, reg);
+
+ udelay(5);
+
+#else
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8]
+ * and force reserved bits[7:0].
+ */
+ reg = 0x0000FFFF;
+
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18704 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_2_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* full Integer ratio from PLL-out to ddr-clk */
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_2_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+ reg = 0x000FFF02;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ reg = 0x0102FDFF;
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+ * (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1);
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks
+ * are active - 0x18718 [8]
+ */
+ do {
+ reg = reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ reg = 0x000000FF;
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests
+ * of ratio modifications.
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+#endif
+ /* End of clock change procedure (PLL) */
+
+ if (ratio_2to1) {
+ /* Configure - Select normal clock for the DDR PHY - Disable */
+ reg = reg_read(REG_DRAM_INIT_CTRL_STATUS_ADDR);
+ /* [16] - ddr_phy_trn_clk_sel - Disable */
+ reg &= ~(1 << REG_DRAM_INIT_CTRL_TRN_CLK_OFFS);
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+ }
+
+ /*
+ * Configure - Set Correct Ratio - according to target ratio
+ * parameter - 2:1/1:1
+ */
+ if (ratio_2to1) {
+ /*
+ * [15] - Phy2UnitClkRatio = 1 - Set 2:1 Ratio between
+ * Dunit and Phy
+ */
+ reg = reg_read(REG_DDR_IO_ADDR) |
+ (1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ } else {
+ /*
+ * [15] - Phy2UnitClkRatio = 0 - Set 1:1 Ratio between
+ * Dunit and Phy
+ */
+ reg = reg_read(REG_DDR_IO_ADDR) &
+ ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ }
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Register */
+
+ /* Configure - 2T Mode - Restore original configuration */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ /* [3:4] 2T - Restore value */
+ reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+ reg |= ((dram_info->mode_2t & REG_DUNIT_CTRL_LOW_2T_MASK) <<
+ REG_DUNIT_CTRL_LOW_2T_OFFS);
+ /* 0x1404 - DDR Controller Control Low Register */
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* Configure - Restore CL and CWL - MRS Commands */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(REG_DFS_CL_NEXT_STATE_MASK << REG_DFS_CL_NEXT_STATE_OFFS);
+ reg &= ~(REG_DFS_CWL_NEXT_STATE_MASK << REG_DFS_CWL_NEXT_STATE_OFFS);
+
+ if (freq == DDR_400) {
+ if (dram_info->target_frequency == 0x8)
+ tmp = ddr3_cl_to_valid_cl(5);
+ else
+ tmp = ddr3_cl_to_valid_cl(6);
+ } else {
+ tmp = ddr3_cl_to_valid_cl(dram_info->cl);
+ }
+
+ /* [8] - DfsCLNextState */
+ reg |= ((tmp & REG_DFS_CL_NEXT_STATE_MASK) << REG_DFS_CL_NEXT_STATE_OFFS);
+ if (freq == DDR_400) {
+ /* [12] - DfsCWLNextState */
+ reg |= (((0) & REG_DFS_CWL_NEXT_STATE_MASK) <<
+ REG_DFS_CWL_NEXT_STATE_OFFS);
+ } else {
+ /* [12] - DfsCWLNextState */
+ reg |= (((dram_info->cwl) & REG_DFS_CWL_NEXT_STATE_MASK) <<
+ REG_DFS_CWL_NEXT_STATE_OFFS);
+ }
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Optional - Configure - DDR3_Rtt_nom_CS# */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS));
+ reg &= REG_DDR3_MR1_RTT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ dfs_reg_write(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* Configure - Reset ADLLs - Set Reset */
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30]] - reset pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config Register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ /* Configure - Reset ADLLs - Release Reset */
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30] - normal pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ /* Poll - Wait for APLL + ADLLs lock on new frequency */
+ do {
+ reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+ REG_PHY_LOCK_APLL_ADLL_STATUS_MASK;
+ /* 0x1674 [10:0] - Phy lock status Register */
+ } while (reg != REG_PHY_LOCK_APLL_ADLL_STATUS_MASK);
+
+ /* Configure - Reset the PHY SDR clock divider */
+ if (ratio_2to1) {
+ /* Pup Reset Divider B - Set Reset */
+ /* [28] - DataPupRdRST = 0 */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) &
+ ~(1 << REG_SDRAM_CONFIG_PUPRSTDIV_OFFS);
+ /* [28] - DataPupRdRST = 1 */
+ tmp = reg_read(REG_SDRAM_CONFIG_ADDR) |
+ (1 << REG_SDRAM_CONFIG_PUPRSTDIV_OFFS);
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Pup Reset Divider B - Release Reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, tmp);
+ }
+
+ /* Configure - Reset the PHY Read FIFO and Write channels - Set Reset */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /*
+ * Configure - DRAM Data PHY Read [30], Write [29] path reset -
+ * Release Reset
+ */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Registered DIMM support */
+ if (dram_info->reg_dimm) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1333 / DDR3-1600) - CWA_RC
+ */
+ reg = (0xA & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+ REG_SDRAM_OPERATION_CWA_RC_OFFS;
+ if (freq <= DDR_400) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-800) - CWA_DATA
+ */
+ reg |= ((0x0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ } else if ((freq > DDR_400) && (freq <= DDR_533)) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1066) - CWA_DATA
+ */
+ reg |= ((0x1 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ } else if ((freq > DDR_533) && (freq <= DDR_666)) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1333) - CWA_DATA
+ */
+ reg |= ((0x2 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ } else {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1600) - CWA_DATA
+ */
+ reg |= ((0x3 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ }
+
+ /* Configure - Set Delay - tSTAB */
+ reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+ /* Configure - Issue CWA command with the above parameters */
+ reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for CWA operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ REG_SDRAM_OPERATION_CMD_MASK;
+ } while (reg);
+ }
+
+ /* Configure - Exit Self Refresh */
+ /* [2] - DfsSR */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll - DFS Register - 0x1528 [3] - DfsAtSR - All DRAM
+ * devices on all ranks are NOT in self refresh mode
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Configure - Issue Refresh command */
+ /* [3-0] = 0x2 - Refresh Command, [11-8] - enabled Cs */
+ reg = REG_SDRAM_OPERATION_CMD_RFRS;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs))
+ reg &= ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ }
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Configure - Block new external transactions - Disable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Disable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable
+ * internal access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Enable */
+ reg |= (1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ /* Configure - Set CL */
+ reg = reg_read(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS)) &
+ ~REG_DDR3_MR0_CL_MASK;
+ if (freq == DDR_400)
+ tmp = ddr3_cl_to_valid_cl(6);
+ else
+ tmp = ddr3_cl_to_valid_cl(dram_info->cl);
+ reg |= ((tmp & 0x1) << REG_DDR3_MR0_CL_OFFS);
+ reg |= ((tmp & 0xE) << REG_DDR3_MR0_CL_HIGH_OFFS);
+ dfs_reg_write(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+
+ /* Configure - Set CWL */
+ reg = reg_read(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS)) &
+ ~(REG_DDR3_MR2_CWL_MASK << REG_DDR3_MR2_CWL_OFFS);
+ if (freq == DDR_400)
+ reg |= ((0) << REG_DDR3_MR2_CWL_OFFS);
+ else
+ reg |= ((dram_info->cwl) << REG_DDR3_MR2_CWL_OFFS);
+ dfs_reg_write(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Ended successfuly - new Frequency - ",
+ freq, 1);
+
+ return MV_OK;
+
+#else
+
+ /* This Flow is relevant for Armada370 A0 and ArmadaXP Z1 */
+
+ u32 reg, freq_par, tmp;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - freq */
+ freq_par = ddr3_get_freq_parameter(freq, ratio_2to1);
+
+ reg = 0x0000FF00;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ /* 0x1600 - PHY lock mask register */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ reg |= (1 << REG_ODPG_CNTRL_OFFS); /* [21] = 1 */
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg &= REG_PHY_LOCK_MASK_MASK; /* [11:0] = 0 */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ /* Enable reconfig MR Registers after DFS */
+ reg = reg_read(REG_DFS_ADDR); /* 0x1528 - DFS register */
+ /* [4] - Disable - reconfig MR registers after DFS_ERG */
+ reg &= ~0x11;
+ /* [0] - Enable - DRAM DLL after DFS */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Disable DRAM Controller to crossbar retry */
+ /* [0] - disable */
+ reg = reg_read(REG_METAL_MASK_ADDR) & ~(1 << 0);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* Enable DRAM Blocking */
+ /* [1] - DFS Block enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Enable Self refresh */
+ /* [2] - DFS Self refresh enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - All DRAM devices on all ranks are in
+ * self refresh mode - DFS can be executed afterwards
+ */
+ /* 0x1528 [3] - DfsAtSR */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg == 0x0); /* Wait for '1' */
+
+ /*
+ * Set Correct Ratio - if freq>MARGIN_FREQ use 2:1 ratio
+ * else use 1:1 ratio
+ */
+ if (ratio_2to1) {
+ /* [15] = 1 - Set 2:1 Ratio between Dunit and Phy */
+ reg = reg_read(REG_DDR_IO_ADDR) |
+ (1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ } else {
+ /* [15] = 0 - Set 1:1 Ratio between Dunit and Phy */
+ reg = reg_read(REG_DDR_IO_ADDR) &
+ ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ }
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Register */
+
+ /* Switch HCLK Mux from (100Mhz) [16]=0, keep DFS request bit */
+ reg = 0x20040000;
+ /*
+ * [29] - training logic request DFS, [28:27] -
+ * preload patterns frequency [18]
+ */
+
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+ /* Add delay between entering SR and start ratio modification */
+ udelay(1);
+
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8] and
+ * force reserved bits[7:0].
+ */
+ reg = 0x0000FFFF;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18704 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_3_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* Full Integer ratio from PLL-out to ddr-clk */
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_3_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+
+ reg = 0x000FFF02;
+
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ reg = 0x0102FDFF;
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+ * (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1);
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks are
+ * active - 0x18718 [8]
+ */
+ do {
+ reg = reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ reg = 0x000000FF;
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests of
+ * ratio modifications.
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(5);
+
+ if (ratio_2to1) {
+ /* Pup Reset Divider B - Set Reset */
+ /* [28] = 0 - Pup Reset Divider B */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) & ~(1 << 28);
+ /* [28] = 1 - Pup Reset Divider B */
+ tmp = reg_read(REG_SDRAM_CONFIG_ADDR) | (1 << 28);
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Pup Reset Divider B - Release Reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, tmp);
+ }
+
+ /* DRAM Data PHYs ADLL Reset - Set Reset */
+ reg = (reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK);
+ /* [31:30]] - reset pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config Register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ udelay(25);
+
+ /* APLL lock indication - Poll Phy lock status Register - 0x1674 [9] */
+ do {
+ reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+ (1 << REG_PHY_LOCK_STATUS_LOCK_OFFS);
+ } while (reg == 0);
+
+ /* DRAM Data PHYs ADLL Reset - Release Reset */
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30] - normal pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ udelay(10000); /* Wait 10msec */
+
+ /*
+ * APLL lock indication - Poll Phy lock status Register - 0x1674 [11:0]
+ */
+ do {
+ reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+ REG_PHY_LOCK_STATUS_LOCK_MASK;
+ } while (reg != REG_PHY_LOCK_STATUS_LOCK_MASK);
+
+ /* DRAM Data PHY Read [30], Write [29] path reset - Set Reset */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* DRAM Data PHY Read [30], Write [29] path reset - Release Reset */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Disable DFS Reconfig */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << 4);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* [2] - DFS Self refresh disable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - 0x1528 [3] - DfsAtSR - All DRAM devices on
+ * all ranks are NOT in self refresh mode
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* 0x1404 */
+ reg = (reg_read(REG_DUNIT_CTRL_LOW_ADDR) & 0xFFFFFFE7) | 0x2;
+
+ /* Configure - 2T Mode - Restore original configuration */
+ /* [3:4] 2T - Restore value */
+ reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+ reg |= ((dram_info->mode_2t & REG_DUNIT_CTRL_LOW_2T_MASK) <<
+ REG_DUNIT_CTRL_LOW_2T_OFFS);
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ udelay(1); /* Wait 1us */
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = (reg_read(REG_DDR3_MR1_ADDR));
+ /* DLL Enable */
+ reg &= ~(1 << REG_DDR3_MR1_DLL_ENA_OFFS);
+ dfs_reg_write(REG_DDR3_MR1_ADDR, reg);
+
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* DLL Reset - MR0 */
+ reg = reg_read(REG_DDR3_MR0_ADDR);
+ dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR0 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ reg = reg_read(REG_DDR3_MR0_ADDR);
+ reg &= ~0x74; /* CL [3:0]; [6:4],[2] */
+
+ if (freq == DDR_400)
+ tmp = ddr3_cl_to_valid_cl(6) & 0xF;
+ else
+ tmp = ddr3_cl_to_valid_cl(dram_info->cl) & 0xF;
+
+ reg |= ((tmp & 0x1) << 2);
+ reg |= ((tmp >> 1) << 4); /* to bit 4 */
+ dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+
+ reg = REG_SDRAM_OPERATION_CMD_MR0 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ reg = reg_read(REG_DDR3_MR2_ADDR);
+ reg &= ~0x38; /* CWL [5:3] */
+ /* CWL = 0 ,for 400 MHg is 5 */
+ if (freq != DDR_400)
+ reg |= dram_info->cwl << REG_DDR3_MR2_CWL_OFFS;
+ dfs_reg_write(REG_DDR3_MR2_ADDR, reg);
+ reg = REG_SDRAM_OPERATION_CMD_MR2 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg |= (dram_info->cl <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+ /* Set current rd_ready_delay */
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((dram_info->cl + 1) <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ }
+ }
+
+ /* Enable ODT on DLL-on mode */
+ dfs_reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, 0);
+
+ /* [1] - DFS Block disable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Change DDR frequency to 100MHz procedure: */
+ /* 0x1600 - PHY lock mask register */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ reg &= ~(1 << REG_ODPG_CNTRL_OFFS); /* [21] = 0 */
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* Change DDR frequency to 100MHz procedure: */
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg |= ~REG_PHY_LOCK_MASK_MASK; /* [11:0] = FFF */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ reg = reg_read(REG_METAL_MASK_ADDR) | (1 << 0); /* [0] - disable */
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Ended successfuly - new Frequency - ",
+ freq, 1);
+ return MV_OK;
+#endif
+}
diff --git a/drivers/ddr/marvell/axp/ddr3_dqs.c b/drivers/ddr/marvell/axp/ddr3_dqs.c
new file mode 100644
index 0000000000..71a986d54f
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_dqs.c
@@ -0,0 +1,1374 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DQS_C(s, d, l) \
+ DEBUG_DQS_S(s); DEBUG_DQS_D(d, l); DEBUG_DQS_S("\n")
+#define DEBUG_DQS_FULL_C(s, d, l) \
+ DEBUG_DQS_FULL_S(s); DEBUG_DQS_FULL_D(d, l); DEBUG_DQS_FULL_S("\n")
+#define DEBUG_DQS_RESULTS_C(s, d, l) \
+ DEBUG_DQS_RESULTS_S(s); DEBUG_DQS_RESULTS_D(d, l); DEBUG_DQS_RESULTS_S("\n")
+#define DEBUG_PER_DQ_C(s, d, l) \
+ puts(s); printf("%x", d); puts("\n")
+
+#define DEBUG_DQS_RESULTS_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_DQS_RESULTS_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+
+#define DEBUG_PER_DQ_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%s", s)
+#define DEBUG_PER_DQ_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%x", d)
+#define DEBUG_PER_DQ_DD(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%d", d)
+
+#ifdef MV_DEBUG_DQS
+#define DEBUG_DQS_S(s) puts(s)
+#define DEBUG_DQS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DQS_S(s)
+#define DEBUG_DQS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DQS_FULL
+#define DEBUG_DQS_FULL_S(s) puts(s)
+#define DEBUG_DQS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DQS_FULL_S(s)
+#define DEBUG_DQS_FULL_D(d, l)
+#endif
+
+/* State machine for centralization - find low & high limit */
+enum {
+ PUP_ADLL_LIMITS_STATE_FAIL,
+ PUP_ADLL_LIMITS_STATE_PASS,
+ PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS,
+};
+
+/* Hold centralization low results */
+static int centralization_low_limit[MAX_PUP_NUM] = { 0 };
+/* Hold centralization high results */
+static int centralization_high_limit[MAX_PUP_NUM] = { 0 };
+
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx);
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+ int *size_valid);
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx);
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup);
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup);
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx);
+
+#ifdef MV88F78X60
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern u32 killer_pattern_64b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#else
+extern u32 killer_pattern[DQ_NUM][LEN_16BIT_KILLER_PATTERN];
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+#if defined(MV88F672X)
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+#endif
+extern u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN];
+
+static u32 *ddr3_dqs_choose_pattern(MV_DRAM_INFO *dram_info, u32 victim_dq)
+{
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&killer_pattern_64b[victim_dq];
+ break;
+#endif
+ default:
+#if defined(MV88F78X60)
+ pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+#else
+ pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+#endif
+ break;
+ }
+
+ return pattern_ptr;
+}
+
+/*
+ * Name: ddr3_dqs_centralization_rx
+ * Desc: Execute the DQS centralization RX phase.
+ * Args: dram_info
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, ecc, reg;
+ int status;
+
+ DEBUG_DQS_S("DDR3 - DQS Centralization RX - Starting procedure\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_DQS_S("DDR3 - DQS Centralization RX - SW Override Enabled\n");
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Centralization RX - CS - ",
+ (u32) cs, 1);
+
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Enabled\n");
+ else
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Disabled\n");
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Find all limits\n");
+
+ status = ddr3_find_adll_limits(dram_info, cs,
+ ecc, 0);
+ if (MV_OK != status)
+ return status;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Start calculating center\n");
+
+ status = ddr3_center_calc(dram_info, cs, ecc,
+ 0);
+ if (MV_OK != status)
+ return status;
+ }
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dqs_centralization_tx
+ * Desc: Execute the DQS centralization TX phase.
+ * Args: dram_info
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, ecc, reg;
+ int status;
+
+ DEBUG_DQS_S("DDR3 - DQS Centralization TX - Starting procedure\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_DQS_S("DDR3 - DQS Centralization TX - SW Override Enabled\n");
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Centralization TX - CS - ",
+ (u32) cs, 1);
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Enabled\n");
+ else
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Disabled\n");
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Find all limits\n");
+
+ status = ddr3_find_adll_limits(dram_info, cs,
+ ecc, 1);
+ if (MV_OK != status)
+ return status;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Start calculating center\n");
+
+ status = ddr3_center_calc(dram_info, cs, ecc,
+ 1);
+ if (MV_OK != status)
+ return status;
+ }
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_find_adll_limits
+ * Desc: Execute the Find ADLL limits phase.
+ * Args: dram_info
+ * cs
+ * ecc_ena
+ * is_tx Indicate whether Rx or Tx
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx)
+{
+ u32 victim_dq, pup, tmp;
+ u32 adll_addr;
+ u32 max_pup; /* maximal pup index */
+ u32 pup_mask = 0;
+ u32 unlock_pup; /* bit array of un locked pups */
+ u32 new_unlock_pup; /* bit array of compare failed pups */
+ u32 curr_adll;
+ u32 adll_start_val; /* adll start loop value - for rx or tx limit */
+ u32 high_limit; /* holds found High Limit */
+ u32 low_limit; /* holds found Low Limit */
+ int win_valid;
+ int update_win;
+ u32 sdram_offset;
+ u32 uj, cs_count, cs_tmp, ii;
+ u32 *pattern_ptr;
+ u32 dq;
+ u32 adll_end_val; /* adll end of loop val - for rx or tx limit */
+ u8 analog_pbs[DQ_NUM][MAX_PUP_NUM][DQ_NUM][2];
+ u8 analog_pbs_sum[MAX_PUP_NUM][DQ_NUM][2];
+ int pup_adll_limit_state[MAX_PUP_NUM]; /* hold state of each pup */
+
+ adll_addr = ((is_tx == 1) ? PUP_DQS_WR : PUP_DQS_RD);
+ adll_end_val = ((is_tx == 1) ? ADLL_MIN : ADLL_MAX);
+ adll_start_val = ((is_tx == 1) ? ADLL_MAX : ADLL_MIN);
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - Starting Find ADLL Limits\n");
+
+ /* init the array */
+ for (pup = 0; pup < max_pup; pup++) {
+ centralization_low_limit[pup] = ADLL_MIN;
+ centralization_high_limit[pup] = ADLL_MAX;
+ }
+
+ /* Killer Pattern */
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+ sdram_offset = cs_count * (SDRAM_CS_SIZE + 1);
+ sdram_offset += ((is_tx == 1) ?
+ SDRAM_DQS_TX_OFFS : SDRAM_DQS_RX_OFFS);
+
+ /* Prepare pup masks */
+ for (pup = 0; pup < max_pup; pup++)
+ pup_mask |= (1 << pup);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ analog_pbs_sum[pup][dq][0] = adll_start_val;
+ analog_pbs_sum[pup][dq][1] = adll_end_val;
+ }
+ }
+
+ /* Loop - use different pattern for each victim_dq */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Victim DQ - ",
+ (u32)victim_dq, 1);
+ /*
+ * The pups 3 bit arrays represent state machine. with
+ * 3 stages for each pup.
+ * 1. fail and didn't get pass in earlier compares.
+ * 2. pass compare
+ * 3. fail after pass - end state.
+ * The window limits are the adll values where the adll
+ * was in the pass stage.
+ */
+
+ /* Set all states to Fail (1st state) */
+ for (pup = 0; pup < max_pup; pup++)
+ pup_adll_limit_state[pup] = PUP_ADLL_LIMITS_STATE_FAIL;
+
+ /* Set current valid pups */
+ unlock_pup = pup_mask;
+
+ /* Set ADLL to start value */
+ curr_adll = adll_start_val;
+
+#if defined(MV88F78X60)
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ analog_pbs[victim_dq][pup][dq][0] =
+ adll_start_val;
+ analog_pbs[victim_dq][pup][dq][1] =
+ adll_end_val;
+ per_bit_data[pup][dq] = 0;
+ }
+ }
+#endif
+
+ for (uj = 0; uj < ADLL_MAX; uj++) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Setting ADLL to ",
+ curr_adll, 2);
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ tmp = ((is_tx == 1) ? curr_adll +
+ dram_info->wl_val[cs]
+ [pup * (1 - ecc) + ecc * ECC_PUP]
+ [D] : curr_adll);
+ ddr3_write_pup_reg(adll_addr, cs, pup +
+ (ecc * ECC_PUP), 0, tmp);
+ }
+ }
+
+ /* Choose pattern */
+ pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+ victim_dq);
+
+ /* '1' - means pup failed, '0' - means pup pass */
+ new_unlock_pup = 0;
+
+ /* Read and compare results for Victim_DQ# */
+ for (ii = 0; ii < 3; ii++) {
+ u32 tmp = 0;
+ if (MV_OK != ddr3_sdram_dqs_compare(dram_info,
+ unlock_pup, &tmp,
+ pattern_ptr,
+ LEN_KILLER_PATTERN,
+ sdram_offset +
+ LEN_KILLER_PATTERN *
+ 4 * victim_dq,
+ is_tx, 0, NULL,
+ 0))
+ return MV_DDR3_TRAINING_ERR_DRAM_COMPARE;
+
+ new_unlock_pup |= tmp;
+ }
+
+ pup = 0;
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - UnlockPup: ",
+ unlock_pup, 2);
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - NewUnlockPup: ",
+ new_unlock_pup, 2);
+
+ /* Update pup state */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 0) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Skipping pup ",
+ pup, 1);
+ continue;
+ }
+
+ /*
+ * Still didn't find the window limit of the pup
+ */
+ if (IS_PUP_ACTIVE(new_unlock_pup, pup) == 1) {
+ /* Current compare result == fail */
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_PASS) {
+ /*
+ * If now it failed but passed
+ * earlier
+ */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - PASS to FAIL: CS - ");
+ DEBUG_DQS_D(cs, 1);
+ DEBUG_DQS_S(", DQ - ");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", Pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(", ADLL - ");
+ DEBUG_DQS_D(curr_adll, 2);
+ DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if ((analog_pbs[victim_dq][pup][dq][0] != adll_start_val)
+ && (analog_pbs[victim_dq][pup]
+ [dq][1] == adll_end_val))
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [1] =
+ curr_adll;
+ }
+#endif
+ win_valid = 1;
+ update_win = 0;
+
+ /* Keep min / max limit value */
+ if (is_tx == 0) {
+ /* RX - found upper limit */
+ if (centralization_high_limit[pup] >
+ (curr_adll - 1)) {
+ high_limit =
+ curr_adll - 1;
+ low_limit =
+ centralization_low_limit[pup];
+ update_win = 1;
+ }
+ } else {
+ /* TX - found lower limit */
+ if (centralization_low_limit[pup] < (curr_adll + 1)) {
+ high_limit =
+ centralization_high_limit
+ [pup];
+ low_limit =
+ curr_adll + 1;
+ update_win =
+ 1;
+ }
+ }
+
+ if (update_win == 1) {
+ /*
+ * Before updating
+ * window limits we need
+ * to check that the
+ * limits are valid
+ */
+ if (MV_OK !=
+ ddr3_check_window_limits
+ (pup, high_limit,
+ low_limit, is_tx,
+ &win_valid))
+ return MV_DDR3_TRAINING_ERR_WIN_LIMITS;
+
+ if (win_valid == 1) {
+ /*
+ * Window limits
+ * should be
+ * updated
+ */
+ centralization_low_limit
+ [pup] =
+ low_limit;
+ centralization_high_limit
+ [pup] =
+ high_limit;
+ }
+ }
+
+ if (win_valid == 1) {
+ /* Found end of window - lock the pup */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS;
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Probably false pass - reset status */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_FAIL;
+
+#if defined(MV88F78X60)
+ /* Clear logging array of win size (per Dq) */
+ for (dq = 0;
+ dq < DQ_NUM;
+ dq++) {
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [0] =
+ adll_start_val;
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [1] =
+ adll_end_val;
+ per_bit_data
+ [pup][dq]
+ = 0;
+ }
+#endif
+ }
+ }
+ } else {
+ /* Current compare result == pass */
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_FAIL) {
+ /* If now it passed but failed earlier */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - FAIL to PASS: CS - ");
+ DEBUG_DQS_D(cs, 1);
+ DEBUG_DQS_S(", DQ - ");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", Pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(", ADLL - ");
+ DEBUG_DQS_D(curr_adll, 2);
+ DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+ for (dq = 0; dq < DQ_NUM;
+ dq++) {
+ if (analog_pbs[victim_dq][pup][dq][0] == adll_start_val)
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [0] =
+ curr_adll;
+ }
+#endif
+ /* Found start of window */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_PASS;
+
+ /* Keep min / max limit value */
+ if (is_tx == 0) {
+ /* RX - found low limit */
+ if (centralization_low_limit[pup] <= curr_adll)
+ centralization_low_limit
+ [pup] =
+ curr_adll;
+ } else {
+ /* TX - found high limit */
+ if (centralization_high_limit[pup] >= curr_adll)
+ centralization_high_limit
+ [pup] =
+ curr_adll;
+ }
+ }
+ }
+ }
+
+ if (unlock_pup == 0) {
+ /* Found limit to all pups */
+ DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - found PUP limit\n");
+ break;
+ }
+
+ /*
+ * Increment / decrement (Move to right / left
+ * one phase - ADLL) dqs RX / TX delay (for all un
+ * lock pups
+ */
+ if (is_tx == 0)
+ curr_adll++;
+ else
+ curr_adll--;
+ }
+
+ if (unlock_pup != 0) {
+ /*
+ * Found pups that didn't reach to the end of the
+ * state machine
+ */
+ DEBUG_DQS_C("DDR3 - DQS Find Limits - Pups that didn't reached end of the state machine: ",
+ unlock_pup, 1);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_FAIL) {
+ /* ERROR - found fail for all window size */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - Got FAIL for the complete range on pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_C(" victim DQ ",
+ victim_dq, 1);
+
+ /* For debug - set min limit to illegal limit */
+ centralization_low_limit[pup]
+ = ADLL_ERROR;
+ /*
+ * In case the pup is in mode
+ * PASS - the limit is the min
+ * / max adll, no need to
+ * update because of the results
+ * array default value
+ */
+ return MV_DDR3_TRAINING_ERR_PUP_RANGE;
+ }
+ }
+ }
+ }
+ }
+
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - DQ values per victim results:\n");
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ for (pup = 0; pup < max_pup; pup++) {
+ DEBUG_DQS_S("Victim DQ-");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", PUP-");
+ DEBUG_DQS_D(pup, 1);
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S(",S-");
+ DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+ [0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+ [1], 2);
+
+ if (is_tx == 0) {
+ if (analog_pbs[victim_dq][pup][dq][0]
+ > analog_pbs_sum[pup][dq][0])
+ analog_pbs_sum[pup][dq][0] =
+ analog_pbs[victim_dq][pup]
+ [dq][0];
+ if (analog_pbs[victim_dq][pup][dq][1]
+ < analog_pbs_sum[pup][dq][1])
+ analog_pbs_sum[pup][dq][1] =
+ analog_pbs[victim_dq][pup]
+ [dq][1];
+ } else {
+ if (analog_pbs[victim_dq][pup][dq][0]
+ < analog_pbs_sum[pup][dq][0])
+ analog_pbs_sum[pup][dq][0] =
+ analog_pbs[victim_dq][pup]
+ [dq][0];
+ if (analog_pbs[victim_dq][pup][dq][1]
+ > analog_pbs_sum[pup][dq][1])
+ analog_pbs_sum[pup][dq][1] =
+ analog_pbs[victim_dq][pup]
+ [dq][1];
+ }
+ }
+ DEBUG_DQS_S("\n");
+ }
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_3) {
+ u32 dq;
+
+ DEBUG_PER_DQ_S("\n########## LOG LEVEL 3(Windows margins per-DQ) ##########\n");
+ if (is_tx) {
+ DEBUG_PER_DQ_C("DDR3 - TX CS: ", cs, 1);
+ } else {
+ DEBUG_PER_DQ_C("DDR3 - RX CS: ", cs, 1);
+ }
+
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("\n DATA RESULTS:\n");
+ } else {
+ DEBUG_PER_DQ_S("\n ECC RESULTS:\n");
+ }
+
+ /* Since all dq has the same value we take 0 as representive */
+ dq = 0;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("\nBYTE:");
+ DEBUG_PER_DQ_D(pup, 1);
+ DEBUG_PER_DQ_S("\n");
+ } else {
+ DEBUG_PER_DQ_S("\nECC BYTE:\n");
+ }
+ DEBUG_PER_DQ_S(" DQ's LOW HIGH WIN-SIZE\n");
+ DEBUG_PER_DQ_S("============================================\n");
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("DQ[");
+ DEBUG_PER_DQ_DD((victim_dq +
+ DQ_NUM * pup), 2);
+ DEBUG_PER_DQ_S("]");
+ } else {
+ DEBUG_PER_DQ_S("CB[");
+ DEBUG_PER_DQ_DD(victim_dq, 2);
+ DEBUG_PER_DQ_S("]");
+ }
+ if (is_tx) {
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1], 2); /* low value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2); /* high value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0] - analog_pbs[victim_dq][pup][dq][1], 2); /* win-size */
+ } else {
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2); /* low value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D((analog_pbs[victim_dq][pup][dq][1] - 1), 2); /* high value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1] - analog_pbs[victim_dq][pup][dq][0], 2); /* win-size */
+ }
+ DEBUG_PER_DQ_S("\n");
+ }
+ }
+ DEBUG_PER_DQ_S("\n");
+ }
+
+ if (is_tx) {
+ DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ DEBUG_DQS_S("PUP-");
+ DEBUG_DQS_D(pup, 1);
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S(",S-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+ }
+ DEBUG_DQS_S("\n");
+ }
+
+ if (is_tx) {
+ DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (max_pup == 1) {
+ /* For ECC PUP */
+ DEBUG_DQS_S("DDR3 - DQS8");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS");
+ DEBUG_DQS_D(pup, 1);
+ }
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S("::S-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+ }
+ DEBUG_DQS_S("\n");
+ }
+
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - Ended\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_check_window_limits
+ * Desc: Check window High & Low limits.
+ * Args: pup pup index
+ * high_limit window high limit
+ * low_limit window low limit
+ * is_tx Indicate whether Rx or Tx
+ * size_valid Indicate whether window size is valid
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+ int *size_valid)
+{
+ DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Starting\n");
+
+ if (low_limit > high_limit) {
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(" Low Limit grater than High Limit\n");
+ *size_valid = 0;
+ return MV_OK;
+ }
+
+ /*
+ * Check that window size is valid, if not it was probably false pass
+ * before
+ */
+ if ((high_limit - low_limit) < MIN_WIN_SIZE) {
+ /*
+ * Since window size is too small probably there was false
+ * pass
+ */
+ *size_valid = 0;
+
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(" Window size is smaller than MIN_WIN_SIZE\n");
+
+ } else if ((high_limit - low_limit) > ADLL_MAX) {
+ *size_valid = 0;
+
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S
+ (" Window size is bigger than max ADLL taps (31) Exiting.\n");
+
+ return MV_FAIL;
+
+ } else {
+ *size_valid = 1;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_FULL_D(pup, 1);
+ DEBUG_DQS_FULL_C(" window size is ", (high_limit - low_limit),
+ 2);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_center_calc
+ * Desc: Execute the calculate the center of windows phase.
+ * Args: pDram Info
+ * is_tx Indicate whether Rx or Tx
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx)
+{
+ /* bit array of pups that need specail search */
+ u32 special_pattern_i_pup = 0;
+ u32 special_pattern_ii_pup = 0;
+ u32 pup;
+ u32 max_pup;
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (is_tx == 0) {
+ /* Check special pattern I */
+ /*
+ * Special pattern Low limit search - relevant only
+ * for Rx, win size < threshold and low limit = 0
+ */
+ if (((centralization_high_limit[pup] -
+ centralization_low_limit[pup]) < VALID_WIN_THRS)
+ && (centralization_low_limit[pup] == MIN_DELAY))
+ special_pattern_i_pup |= (1 << pup);
+
+ /* Check special pattern II */
+ /*
+ * Special pattern High limit search - relevant only
+ * for Rx, win size < threshold and high limit = 31
+ */
+ if (((centralization_high_limit[pup] -
+ centralization_low_limit[pup]) < VALID_WIN_THRS)
+ && (centralization_high_limit[pup] == MAX_DELAY))
+ special_pattern_ii_pup |= (1 << pup);
+ }
+ }
+
+ /* Run special pattern Low limit search - for relevant pup */
+ if (special_pattern_i_pup != 0) {
+ DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern I for Low limit search\n");
+ if (MV_OK !=
+ ddr3_special_pattern_i_search(dram_info, cs, ecc, is_tx,
+ special_pattern_i_pup))
+ return MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH;
+ }
+
+ /* Run special pattern High limit search - for relevant pup */
+ if (special_pattern_ii_pup != 0) {
+ DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern II for High limit search\n");
+ if (MV_OK !=
+ ddr3_special_pattern_ii_search(dram_info, cs, ecc, is_tx,
+ special_pattern_ii_pup))
+ return MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH;
+ }
+
+ /* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+ return ddr3_set_dqs_centralization_results(dram_info, cs, ecc, is_tx);
+}
+
+/*
+ * Name: ddr3_special_pattern_i_search
+ * Desc: Execute special pattern low limit search.
+ * Args:
+ * special_pattern_pup The pups that need the special search
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup)
+{
+ u32 victim_dq; /* loop index - victim DQ */
+ u32 adll_idx;
+ u32 pup;
+ u32 unlock_pup; /* bit array of the unlock pups */
+ u32 first_fail; /* bit array - of pups that get first fail */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 pass_pup; /* bit array of compare pass pup */
+ u32 sdram_offset;
+ u32 max_pup;
+ u32 comp_val;
+ u32 special_res[MAX_PUP_NUM]; /* hold tmp results */
+
+ DEBUG_DQS_S("DDR3 - DQS - Special Pattern I Search - Starting\n");
+
+ max_pup = ecc + (1 - ecc) * dram_info->num_of_std_pups;
+
+ /* Init the temporary results to max ADLL value */
+ for (pup = 0; pup < max_pup; pup++)
+ special_res[pup] = ADLL_MAX;
+
+ /* Run special pattern for all DQ - use the same pattern */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ unlock_pup = special_pattern_pup;
+ first_fail = 0;
+
+ sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS +
+ LEN_KILLER_PATTERN * 4 * victim_dq;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Set adll value per PUP. adll = high limit per pup */
+ if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+ /* only for pups that need special search */
+ ddr3_write_pup_reg(PUP_DQS_RD, cs,
+ pup + (ecc * ECC_PUP), 0,
+ centralization_high_limit
+ [pup]);
+ }
+ }
+
+ adll_idx = 0;
+ do {
+ /*
+ * Perform read and compare simultaneously for all
+ * un-locked MC use the special pattern mask
+ */
+ new_lockup_pup = 0;
+
+ if (MV_OK !=
+ ddr3_sdram_dqs_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ special_pattern
+ [victim_dq],
+ LEN_SPECIAL_PATTERN,
+ sdram_offset, 0,
+ 0, NULL, 1))
+ return MV_FAIL;
+
+ DEBUG_DQS_S("DDR3 - DQS - Special I - ADLL value is: ");
+ DEBUG_DQS_D(adll_idx, 2);
+ DEBUG_DQS_S(", UnlockPup: ");
+ DEBUG_DQS_D(unlock_pup, 2);
+ DEBUG_DQS_S(", NewLockPup: ");
+ DEBUG_DQS_D(new_lockup_pup, 2);
+ DEBUG_DQS_S("\n");
+
+ if (unlock_pup != new_lockup_pup)
+ DEBUG_DQS_S("DDR3 - DQS - Special I - Some Pup passed!\n");
+
+ /* Search for pups with passed compare & already fail */
+ pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+ first_fail |= new_lockup_pup;
+ unlock_pup &= ~pass_pup;
+
+ /* Get pass pups */
+ if (pass_pup != 0) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) ==
+ 1) {
+ /* If pup passed and has first fail = 1 */
+ /* keep min value of ADLL max value - current adll */
+ /* (centralization_high_limit[pup] + adll_idx) = current adll !!! */
+ comp_val =
+ (ADLL_MAX -
+ (centralization_high_limit
+ [pup] + adll_idx));
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special I - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" comp_val = ",
+ comp_val, 2);
+
+ if (comp_val <
+ special_res[pup]) {
+ special_res[pup] =
+ comp_val;
+ centralization_low_limit
+ [pup] =
+ (-1) *
+ comp_val;
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special I - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" Changed Low limit to ",
+ centralization_low_limit
+ [pup], 2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Did all PUP found missing window?
+ * Check for each pup if adll (different for each pup)
+ * reach maximum if reach max value - lock the pup
+ * if not - increment (Move to right one phase - ADLL)
+ * dqs RX delay
+ */
+ adll_idx++;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ /* Check only unlocked pups */
+ if ((centralization_high_limit[pup] +
+ adll_idx) >= ADLL_MAX) {
+ /* reach maximum - lock the pup */
+ DEBUG_DQS_C("DDR3 - DQS - Special I - reach maximum - lock pup ",
+ pup, 1);
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Didn't reach maximum - increment ADLL */
+ ddr3_write_pup_reg(PUP_DQS_RD,
+ cs,
+ pup +
+ (ecc *
+ ECC_PUP), 0,
+ (centralization_high_limit
+ [pup] +
+ adll_idx));
+ }
+ }
+ }
+ } while (unlock_pup != 0);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_special_pattern_ii_search
+ * Desc: Execute special pattern high limit search.
+ * Args:
+ * special_pattern_pup The pups that need the special search
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup)
+{
+ u32 victim_dq; /* loop index - victim DQ */
+ u32 adll_idx;
+ u32 pup;
+ u32 unlock_pup; /* bit array of the unlock pups */
+ u32 first_fail; /* bit array - of pups that get first fail */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 pass_pup; /* bit array of compare pass pup */
+ u32 sdram_offset;
+ u32 max_pup;
+ u32 comp_val;
+ u32 special_res[MAX_PUP_NUM]; /* hold tmp results */
+
+ DEBUG_DQS_S("DDR3 - DQS - Special Pattern II Search - Starting\n");
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ /* init the tmporary results to max ADLL value */
+ for (pup = 0; pup < max_pup; pup++)
+ special_res[pup] = ADLL_MAX;
+
+ sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS;
+
+ /* run special pattern for all DQ - use the same pattern */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ unlock_pup = special_pattern_pup;
+ first_fail = 0;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Set adll value per PUP. adll = 0 */
+ if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+ /* Only for pups that need special search */
+ ddr3_write_pup_reg(PUP_DQS_RD, cs,
+ pup + (ecc * ECC_PUP), 0,
+ ADLL_MIN);
+ }
+ }
+
+ adll_idx = 0;
+ do {
+ /*
+ * Perform read and compare simultaneously for all
+ * un-locked MC use the special pattern mask
+ */
+ new_lockup_pup = 0;
+
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, unlock_pup, &new_lockup_pup,
+ special_pattern[victim_dq],
+ LEN_SPECIAL_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_FAIL;
+
+ DEBUG_DQS_S("DDR3 - DQS - Special II - ADLL value is ");
+ DEBUG_DQS_D(adll_idx, 2);
+ DEBUG_DQS_S("unlock_pup ");
+ DEBUG_DQS_D(unlock_pup, 1);
+ DEBUG_DQS_S("new_lockup_pup ");
+ DEBUG_DQS_D(new_lockup_pup, 1);
+ DEBUG_DQS_S("\n");
+
+ if (unlock_pup != new_lockup_pup) {
+ DEBUG_DQS_S("DDR3 - DQS - Special II - Some Pup passed!\n");
+ }
+
+ /* Search for pups with passed compare & already fail */
+ pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+ first_fail |= new_lockup_pup;
+ unlock_pup &= ~pass_pup;
+
+ /* Get pass pups */
+ if (pass_pup != 0) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) ==
+ 1) {
+ /* If pup passed and has first fail = 1 */
+ /* keep min value of ADLL max value - current adll */
+ /* (adll_idx) = current adll !!! */
+ comp_val = adll_idx;
+
+ DEBUG_DQS_C("DDR3 - DQS - Special II - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C(" comp_val = ",
+ comp_val, 1);
+
+ if (comp_val <
+ special_res[pup]) {
+ special_res[pup] =
+ comp_val;
+ centralization_high_limit
+ [pup] =
+ ADLL_MAX +
+ comp_val;
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special II - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" Changed High limit to ",
+ centralization_high_limit
+ [pup], 2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Did all PUP found missing window?
+ * Check for each pup if adll (different for each pup)
+ * reach maximum if reach max value - lock the pup
+ * if not - increment (Move to right one phase - ADLL)
+ * dqs RX delay
+ */
+ adll_idx++;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ /* Check only unlocked pups */
+ if ((adll_idx) >= ADLL_MAX) {
+ /* Reach maximum - lock the pup */
+ DEBUG_DQS_C("DDR3 - DQS - Special II - reach maximum - lock pup ",
+ pup, 1);
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Didn't reach maximum - increment ADLL */
+ ddr3_write_pup_reg(PUP_DQS_RD,
+ cs,
+ pup +
+ (ecc *
+ ECC_PUP), 0,
+ (adll_idx));
+ }
+ }
+ }
+ } while (unlock_pup != 0);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_set_dqs_centralization_results
+ * Desc: Set to HW the DQS centralization phase results.
+ * Args:
+ * is_tx Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs,
+ u32 ecc, int is_tx)
+{
+ u32 pup, pup_num;
+ int addl_val;
+ u32 max_pup;
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ DEBUG_DQS_RESULTS_S("\n############ LOG LEVEL 2(Windows margins) ############\n");;
+
+ if (is_tx) {
+ DEBUG_DQS_RESULTS_C("DDR3 - DQS TX - Set Dqs Centralization Results - CS: ",
+ cs, 1);
+ } else {
+ DEBUG_DQS_RESULTS_C("DDR3 - DQS RX - Set Dqs Centralization Results - CS: ",
+ cs, 1);
+ }
+
+ /* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+ DEBUG_DQS_RESULTS_S("\nDQS LOW HIGH WIN-SIZE Set\n");
+ DEBUG_DQS_RESULTS_S("==============================================\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ addl_val = (centralization_high_limit[pup] +
+ centralization_low_limit[pup]) / 2;
+
+ pup_num = pup * (1 - ecc) + ecc * ECC_PUP;
+
+ DEBUG_DQS_RESULTS_D(pup_num, 1);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_low_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_high_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_high_limit[pup] -
+ centralization_low_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(addl_val, 2);
+ DEBUG_DQS_RESULTS_S("\n");
+
+ if (addl_val < ADLL_MIN) {
+ addl_val = ADLL_MIN;
+ DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MIN (since it was lower than 0)\n");
+ }
+
+ if (addl_val > ADLL_MAX) {
+ addl_val = ADLL_MAX;
+ DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MAX (since it was higher than 31)\n");
+ }
+
+ if (is_tx) {
+ ddr3_write_pup_reg(PUP_DQS_WR, cs, pup_num, 0,
+ addl_val +
+ dram_info->wl_val[cs][pup_num][D]);
+ } else {
+ ddr3_write_pup_reg(PUP_DQS_RD, cs, pup_num, 0,
+ addl_val);
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cs_count, cs_tmp, victim_dq;
+ u32 sdram_addr;
+ u32 *pattern_ptr;
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+
+ /* Init killer pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_DQS_RX_OFFS);
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+ victim_dq);
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, (u32)NULL, NULL,
+ pattern_ptr, LEN_KILLER_PATTERN,
+ sdram_addr + LEN_KILLER_PATTERN *
+ 4 * victim_dq, 1, 0, NULL,
+ 0))
+ return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+ }
+
+ /* Init special-killer pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_DQS_RX_SPECIAL_OFFS);
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, (u32)NULL, NULL,
+ special_pattern[victim_dq],
+ LEN_KILLER_PATTERN, sdram_addr +
+ LEN_KILLER_PATTERN * 4 * victim_dq,
+ 1, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+ }
+ }
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/axp/ddr3_hw_training.c b/drivers/ddr/marvell/axp/ddr3_hw_training.c
new file mode 100644
index 0000000000..a8c5e6a534
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_hw_training.c
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+#include "ddr3_hw_training.h"
+#include "xor.h"
+
+#ifdef MV88F78X60
+#include "ddr3_patterns_64bit.h"
+#else
+#include "ddr3_patterns_16bit.h"
+#if defined(MV88F672X)
+#include "ddr3_patterns_16bit.h"
+#endif
+#endif
+
+/*
+ * Debug
+ */
+
+#define DEBUG_MAIN_C(s, d, l) \
+ DEBUG_MAIN_S(s); DEBUG_MAIN_D(d, l); DEBUG_MAIN_S("\n")
+#define DEBUG_MAIN_FULL_C(s, d, l) \
+ DEBUG_MAIN_FULL_S(s); DEBUG_MAIN_FULL_D(d, l); DEBUG_MAIN_FULL_S("\n")
+
+#ifdef MV_DEBUG_MAIN
+#define DEBUG_MAIN_S(s) puts(s)
+#define DEBUG_MAIN_D(d, l) printf("%x", d)
+#else
+#define DEBUG_MAIN_S(s)
+#define DEBUG_MAIN_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_MAIN_FULL
+#define DEBUG_MAIN_FULL_S(s) puts(s)
+#define DEBUG_MAIN_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_MAIN_FULL_S(s)
+#define DEBUG_MAIN_FULL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_SUSPEND_RESUME
+#define DEBUG_SUSPEND_RESUME_S(s) puts(s)
+#define DEBUG_SUSPEND_RESUME_D(d, l) printf("%x", d)
+#else
+#define DEBUG_SUSPEND_RESUME_S(s)
+#define DEBUG_SUSPEND_RESUME_D(d, l)
+#endif
+
+static u32 ddr3_sw_wl_rl_debug;
+static u32 ddr3_run_pbs = 1;
+
+void ddr3_print_version(void)
+{
+ puts("DDR3 Training Sequence - Ver 5.7.");
+}
+
+void ddr3_set_sw_wl_rl_debug(u32 val)
+{
+ ddr3_sw_wl_rl_debug = val;
+}
+
+void ddr3_set_pbs(u32 val)
+{
+ ddr3_run_pbs = val;
+}
+
+int ddr3_hw_training(u32 target_freq, u32 ddr_width, int xor_bypass,
+ u32 scrub_offs, u32 scrub_size, int dqs_clk_aligned,
+ int debug_mode, int reg_dimm_skip_wl)
+{
+ /* A370 has no PBS mechanism */
+ __maybe_unused u32 first_loop_flag = 0;
+ u32 freq, reg;
+ MV_DRAM_INFO dram_info;
+ int ratio_2to1 = 0;
+ int tmp_ratio = 1;
+ int status;
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 1\n");
+
+ memset(&dram_info, 0, sizeof(dram_info));
+ dram_info.num_cs = ddr3_get_cs_num_from_reg();
+ dram_info.cs_ena = ddr3_get_cs_ena_from_reg();
+ dram_info.target_frequency = target_freq;
+ dram_info.ddr_width = ddr_width;
+ dram_info.num_of_std_pups = ddr_width / PUP_SIZE;
+ dram_info.rl400_bug = 0;
+ dram_info.multi_cs_mr_support = 0;
+#ifdef MV88F67XX
+ dram_info.rl400_bug = 1;
+#endif
+
+ /* Ignore ECC errors - if ECC is enabled */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if (reg & (1 << REG_SDRAM_CONFIG_ECC_OFFS)) {
+ dram_info.ecc_ena = 1;
+ reg |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+ } else {
+ dram_info.ecc_ena = 0;
+ }
+
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if (reg & (1 << REG_SDRAM_CONFIG_REGDIMM_OFFS))
+ dram_info.reg_dimm = 1;
+ else
+ dram_info.reg_dimm = 0;
+
+ dram_info.num_of_total_pups = ddr_width / PUP_SIZE + dram_info.ecc_ena;
+
+ /* Get target 2T value */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ dram_info.mode_2t = (reg >> REG_DUNIT_CTRL_LOW_2T_OFFS) &
+ REG_DUNIT_CTRL_LOW_2T_MASK;
+
+ /* Get target CL value */
+#ifdef MV88F67XX
+ reg = reg_read(REG_DDR3_MR0_ADDR) >> 2;
+#else
+ reg = reg_read(REG_DDR3_MR0_CS_ADDR) >> 2;
+#endif
+
+ reg = (((reg >> 1) & 0xE) | (reg & 0x1)) & 0xF;
+ dram_info.cl = ddr3_valid_cl_to_cl(reg);
+
+ /* Get target CWL value */
+#ifdef MV88F67XX
+ reg = reg_read(REG_DDR3_MR2_ADDR) >> REG_DDR3_MR2_CWL_OFFS;
+#else
+ reg = reg_read(REG_DDR3_MR2_CS_ADDR) >> REG_DDR3_MR2_CWL_OFFS;
+#endif
+
+ reg &= REG_DDR3_MR2_CWL_MASK;
+ dram_info.cwl = reg;
+#if !defined(MV88F67XX)
+ /* A370 has no PBS mechanism */
+#if defined(MV88F78X60)
+ if ((dram_info.target_frequency > DDR_400) && (ddr3_run_pbs))
+ first_loop_flag = 1;
+#else
+ /* first_loop_flag = 1; skip mid freq at ALP/A375 */
+ if ((dram_info.target_frequency > DDR_400) && (ddr3_run_pbs) &&
+ (mv_ctrl_revision_get() >= UMC_A0))
+ first_loop_flag = 1;
+ else
+ first_loop_flag = 0;
+#endif
+#endif
+
+ freq = dram_info.target_frequency;
+
+ /* Set ODT to always on */
+ ddr3_odt_activate(1);
+
+ /* Init XOR */
+ mv_sys_xor_init(&dram_info);
+
+ /* Get DRAM/HCLK ratio */
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ ratio_2to1 = 1;
+
+ /*
+ * Xor Bypass - ECC support in AXP is currently available for 1:1
+ * modes frequency modes.
+ * Not all frequency modes support the ddr3 training sequence
+ * (Only 1200/300).
+ * Xor Bypass allows using the Xor initializations and scrubbing
+ * inside the ddr3 training sequence without running the training
+ * itself.
+ */
+ if (xor_bypass == 0) {
+ if (ddr3_run_pbs) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - Run with PBS.\n");
+ } else {
+ DEBUG_MAIN_S("DDR3 Training Sequence - Run without PBS.\n");
+ }
+
+ if (dram_info.target_frequency > DFS_MARGIN) {
+ tmp_ratio = 0;
+ freq = DDR_100;
+
+ if (dram_info.reg_dimm == 1)
+ freq = DDR_300;
+
+ if (MV_OK != ddr3_dfs_high_2_low(freq, &dram_info)) {
+ /* Set low - 100Mhz DDR Frequency by HW */
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs High2Low)\n");
+ return MV_DDR3_TRAINING_ERR_DFS_H2L;
+ }
+
+ if ((dram_info.reg_dimm == 1) &&
+ (reg_dimm_skip_wl == 0)) {
+ if (MV_OK !=
+ ddr3_write_leveling_hw_reg_dimm(freq,
+ &dram_info))
+ DEBUG_MAIN_S("DDR3 Training Sequence - Registered DIMM Low WL - SKIP\n");
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_1)
+ ddr3_print_freq(freq);
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 2\n");
+ } else {
+ if (!dqs_clk_aligned) {
+#ifdef MV88F67XX
+ /*
+ * If running training sequence without DFS,
+ * we must run Write leveling before writing
+ * the patterns
+ */
+
+ /*
+ * ODT - Multi CS system use SW WL,
+ * Single CS System use HW WL
+ */
+ if (dram_info.cs_ena > 1) {
+ if (MV_OK !=
+ ddr3_write_leveling_sw(
+ freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ if (MV_OK !=
+ ddr3_write_leveling_hw(freq,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+#else
+ if (MV_OK != ddr3_write_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ if (ddr3_sw_wl_rl_debug) {
+ if (MV_OK !=
+ ddr3_write_leveling_sw(
+ freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+#endif
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 3\n");
+ }
+
+ if (MV_OK != ddr3_load_patterns(&dram_info, 0)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Loading Patterns)\n");
+ return MV_DDR3_TRAINING_ERR_LOAD_PATTERNS;
+ }
+
+ /*
+ * TODO:
+ * The mainline U-Boot port of the bin_hdr DDR training code
+ * needs a delay of minimum 20ms here (10ms is a bit too short
+ * and the CPU hangs). The bin_hdr code doesn't have this delay.
+ * To be save here, lets add a delay of 50ms here.
+ *
+ * Tested on the Marvell DB-MV784MP-GP board
+ */
+ mdelay(50);
+
+ do {
+ freq = dram_info.target_frequency;
+ tmp_ratio = ratio_2to1;
+ DEBUG_MAIN_FULL_S("DDR3 Training Sequence - DEBUG - 4\n");
+
+#if defined(MV88F78X60)
+ /*
+ * There is a difference on the DFS frequency at the
+ * first iteration of this loop
+ */
+ if (first_loop_flag) {
+ freq = DDR_400;
+ tmp_ratio = 0;
+ }
+#endif
+
+ if (MV_OK != ddr3_dfs_low_2_high(freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs Low2High)\n");
+ return MV_DDR3_TRAINING_ERR_DFS_H2L;
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_1) {
+ ddr3_print_freq(freq);
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 5\n");
+
+ /* Write leveling */
+ if (!dqs_clk_aligned) {
+#ifdef MV88F67XX
+ /*
+ * ODT - Multi CS system that not support Multi
+ * CS MRS commands must use SW WL
+ */
+ if (dram_info.cs_ena > 1) {
+ if (MV_OK != ddr3_write_leveling_sw(
+ freq, tmp_ratio, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ if (MV_OK != ddr3_write_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+#else
+ if ((dram_info.reg_dimm == 1) &&
+ (freq == DDR_400)) {
+ if (reg_dimm_skip_wl == 0) {
+ if (MV_OK != ddr3_write_leveling_hw_reg_dimm(
+ freq, &dram_info))
+ DEBUG_MAIN_S("DDR3 Training Sequence - Registered DIMM WL - SKIP\n");
+ }
+ } else {
+ if (MV_OK != ddr3_write_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ if (ddr3_sw_wl_rl_debug) {
+ if (MV_OK != ddr3_write_leveling_sw(
+ freq, tmp_ratio, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+ }
+#endif
+ if (debug_mode)
+ DEBUG_MAIN_S
+ ("DDR3 Training Sequence - DEBUG - 6\n");
+ }
+
+ /* Read Leveling */
+ /*
+ * Armada 370 - Support for HCLK @ 400MHZ - must use
+ * SW read leveling
+ */
+ if (freq == DDR_400 && dram_info.rl400_bug) {
+ status = ddr3_read_leveling_sw(freq, tmp_ratio,
+ &dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S
+ ("DDR3 Training Sequence - FAILED (Read Leveling Sw)\n");
+ return status;
+ }
+ } else {
+ if (MV_OK != ddr3_read_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Hw)\n");
+ if (ddr3_sw_wl_rl_debug) {
+ if (MV_OK != ddr3_read_leveling_sw(
+ freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 7\n");
+
+ if (MV_OK != ddr3_wl_supplement(&dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hi-Freq Sup)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HI_FREQ;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 8\n");
+#if !defined(MV88F67XX)
+ /* A370 has no PBS mechanism */
+#if defined(MV88F78X60) || defined(MV88F672X)
+ if (first_loop_flag == 1) {
+ first_loop_flag = 0;
+
+ status = MV_OK;
+ status = ddr3_pbs_rx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (PBS RX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 9\n");
+
+ status = ddr3_pbs_tx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (PBS TX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 10\n");
+ }
+#endif
+#endif
+ } while (freq != dram_info.target_frequency);
+
+ status = ddr3_dqs_centralization_rx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (DQS Centralization RX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 11\n");
+
+ status = ddr3_dqs_centralization_tx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (DQS Centralization TX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 12\n");
+ }
+
+ ddr3_set_performance_params(&dram_info);
+
+ if (dram_info.ecc_ena) {
+ /* Need to SCRUB the DRAM memory area to load U-boot */
+ mv_sys_xor_finish();
+ dram_info.num_cs = 1;
+ dram_info.cs_ena = 1;
+ mv_sys_xor_init(&dram_info);
+ mv_xor_mem_init(0, scrub_offs, scrub_size, 0xdeadbeef,
+ 0xdeadbeef);
+
+ /* Wait for previous transfer completion */
+ while (mv_xor_state_get(0) != MV_IDLE)
+ ;
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 13\n");
+ }
+
+ /* Return XOR State */
+ mv_sys_xor_finish();
+
+#if defined(MV88F78X60)
+ /* Save training results in memeory for resume state */
+ ddr3_save_training(&dram_info);
+#endif
+ /* Clear ODT always on */
+ ddr3_odt_activate(0);
+
+ /* Configure Dynamic read ODT */
+ ddr3_odt_read_dynamic_config(&dram_info);
+
+ return MV_OK;
+}
+
+void ddr3_set_performance_params(MV_DRAM_INFO *dram_info)
+{
+ u32 twr2wr, trd2rd, trd2wr_wr2rd;
+ u32 tmp1, tmp2, reg;
+
+ DEBUG_MAIN_FULL_C("Max WL Phase: ", dram_info->wl_max_phase, 2);
+ DEBUG_MAIN_FULL_C("Min WL Phase: ", dram_info->wl_min_phase, 2);
+ DEBUG_MAIN_FULL_C("Max RL Phase: ", dram_info->rl_max_phase, 2);
+ DEBUG_MAIN_FULL_C("Min RL Phase: ", dram_info->rl_min_phase, 2);
+
+ if (dram_info->wl_max_phase < 2)
+ twr2wr = 0x2;
+ else
+ twr2wr = 0x3;
+
+ trd2rd = 0x1 + (dram_info->rl_max_phase + 1) / 2 +
+ (dram_info->rl_max_phase + 1) % 2;
+
+ tmp1 = (dram_info->rl_max_phase - dram_info->wl_min_phase) / 2 +
+ (((dram_info->rl_max_phase - dram_info->wl_min_phase) % 2) >
+ 0 ? 1 : 0);
+ tmp2 = (dram_info->wl_max_phase - dram_info->rl_min_phase) / 2 +
+ ((dram_info->wl_max_phase - dram_info->rl_min_phase) % 2 >
+ 0 ? 1 : 0);
+ trd2wr_wr2rd = (tmp1 >= tmp2) ? tmp1 : tmp2;
+
+ trd2wr_wr2rd += 2;
+ trd2rd += 2;
+ twr2wr += 2;
+
+ DEBUG_MAIN_FULL_C("WR 2 WR: ", twr2wr, 2);
+ DEBUG_MAIN_FULL_C("RD 2 RD: ", trd2rd, 2);
+ DEBUG_MAIN_FULL_C("RD 2 WR / WR 2 RD: ", trd2wr_wr2rd, 2);
+
+ reg = reg_read(REG_SDRAM_TIMING_HIGH_ADDR);
+
+ reg &= ~(REG_SDRAM_TIMING_H_W2W_MASK << REG_SDRAM_TIMING_H_W2W_OFFS);
+ reg |= ((twr2wr & REG_SDRAM_TIMING_H_W2W_MASK) <<
+ REG_SDRAM_TIMING_H_W2W_OFFS);
+
+ reg &= ~(REG_SDRAM_TIMING_H_R2R_MASK << REG_SDRAM_TIMING_H_R2R_OFFS);
+ reg &= ~(REG_SDRAM_TIMING_H_R2R_H_MASK <<
+ REG_SDRAM_TIMING_H_R2R_H_OFFS);
+ reg |= ((trd2rd & REG_SDRAM_TIMING_H_R2R_MASK) <<
+ REG_SDRAM_TIMING_H_R2R_OFFS);
+ reg |= (((trd2rd >> 2) & REG_SDRAM_TIMING_H_R2R_H_MASK) <<
+ REG_SDRAM_TIMING_H_R2R_H_OFFS);
+
+ reg &= ~(REG_SDRAM_TIMING_H_R2W_W2R_MASK <<
+ REG_SDRAM_TIMING_H_R2W_W2R_OFFS);
+ reg &= ~(REG_SDRAM_TIMING_H_R2W_W2R_H_MASK <<
+ REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS);
+ reg |= ((trd2wr_wr2rd & REG_SDRAM_TIMING_H_R2W_W2R_MASK) <<
+ REG_SDRAM_TIMING_H_R2W_W2R_OFFS);
+ reg |= (((trd2wr_wr2rd >> 2) & REG_SDRAM_TIMING_H_R2W_W2R_H_MASK) <<
+ REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS);
+
+ reg_write(REG_SDRAM_TIMING_HIGH_ADDR, reg);
+}
+
+/*
+ * Perform DDR3 PUP Indirect Write
+ */
+void ddr3_write_pup_reg(u32 mode, u32 cs, u32 pup, u32 phase, u32 delay)
+{
+ u32 reg = 0;
+
+ if (pup == PUP_BC)
+ reg |= (1 << REG_PHY_BC_OFFS);
+ else
+ reg |= (pup << REG_PHY_PUP_OFFS);
+
+ reg |= ((0x4 * cs + mode) << REG_PHY_CS_OFFS);
+ reg |= (phase << REG_PHY_PHASE_OFFS) | delay;
+
+ if (mode == PUP_WL_MODE)
+ reg |= ((INIT_WL_DELAY + delay) << REG_PHY_DQS_REF_DLY_OFFS);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+
+ /* If read Leveling mode - need to write to register 3 separetly */
+ if (mode == PUP_RL_MODE) {
+ reg = 0;
+
+ if (pup == PUP_BC)
+ reg |= (1 << REG_PHY_BC_OFFS);
+ else
+ reg |= (pup << REG_PHY_PUP_OFFS);
+
+ reg |= ((0x4 * cs + mode + 1) << REG_PHY_CS_OFFS);
+ reg |= (INIT_RL_DELAY);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg);
+ }
+}
+
+/*
+ * Perform DDR3 PUP Indirect Read
+ */
+u32 ddr3_read_pup_reg(u32 mode, u32 cs, u32 pup)
+{
+ u32 reg;
+
+ reg = (pup << REG_PHY_PUP_OFFS) |
+ ((0x4 * cs + mode) << REG_PHY_CS_OFFS);
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_RD;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+
+ return reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR); /* 0x16A0 */
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_patterns(MV_DRAM_INFO *dram_info, int resume)
+{
+ u32 reg;
+
+ /* Enable SW override - Required for the ECC Pup */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ if (resume == 0) {
+#if defined(MV88F78X60) || defined(MV88F672X)
+ ddr3_load_pbs_patterns(dram_info);
+#endif
+ ddr3_load_dqs_patterns(dram_info);
+ }
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ /* Set Base Addr */
+#if defined(MV88F67XX)
+ reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR, 0);
+#else
+ if (resume == 0)
+ reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR, 0);
+ else
+ reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR,
+ RESUME_RL_PATTERNS_ADDR);
+#endif
+
+ /* Set Patterns */
+ if (resume == 0) {
+ reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
+ (1 << REG_DRAM_TRAINING_PATTERNS_OFFS);
+ } else {
+ reg = (0x1 << REG_DRAM_TRAINING_CS_OFFS) |
+ (1 << REG_DRAM_TRAINING_PATTERNS_OFFS);
+ }
+
+ reg |= (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ udelay(100);
+
+ /* Check if Successful */
+ if (reg_read(REG_DRAM_TRAINING_ADDR) &
+ (1 << REG_DRAM_TRAINING_ERROR_OFFS))
+ return MV_OK;
+ else
+ return MV_FAIL;
+}
+
+#if !defined(MV88F67XX)
+/*
+ * Name: ddr3_save_training(MV_DRAM_INFO *dram_info)
+ * Desc: saves the training results to memeory (RL,WL,PBS,Rx/Tx
+ * Centeralization)
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_save_training(MV_DRAM_INFO *dram_info)
+{
+ u32 val, pup, tmp_cs, cs, i, dq;
+ u32 crc = 0;
+ u32 regs = 0;
+ u32 *sdram_offset = (u32 *)RESUME_TRAINING_VALUES_ADDR;
+ u32 mode_config[MAX_TRAINING_MODE];
+
+ mode_config[DQS_WR_MODE] = PUP_DQS_WR;
+ mode_config[WL_MODE_] = PUP_WL_MODE;
+ mode_config[RL_MODE_] = PUP_RL_MODE;
+ mode_config[DQS_RD_MODE] = PUP_DQS_RD;
+ mode_config[PBS_TX_DM_MODE] = PUP_PBS_TX_DM;
+ mode_config[PBS_TX_MODE] = PUP_PBS_TX;
+ mode_config[PBS_RX_MODE] = PUP_PBS_RX;
+
+ /* num of training modes */
+ for (i = 0; i < MAX_TRAINING_MODE; i++) {
+ tmp_cs = dram_info->cs_ena;
+ /* num of CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (tmp_cs & (1 << cs)) {
+ /* num of PUPs */
+ for (pup = 0; pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups &&
+ dram_info->ecc_ena)
+ pup = ECC_PUP;
+ if (i == PBS_TX_DM_MODE) {
+ /*
+ * Change CS bitmask because
+ * PBS works only with CS0
+ */
+ tmp_cs = 0x1;
+ val = ddr3_read_pup_reg(
+ mode_config[i], CS0, pup);
+ } else if (i == PBS_TX_MODE ||
+ i == PBS_RX_MODE) {
+ /*
+ * Change CS bitmask because
+ * PBS works only with CS0
+ */
+ tmp_cs = 0x1;
+ for (dq = 0; dq <= DQ_NUM;
+ dq++) {
+ val = ddr3_read_pup_reg(
+ mode_config[i] + dq,
+ CS0,
+ pup);
+ (*sdram_offset) = val;
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ }
+ continue;
+ } else {
+ val = ddr3_read_pup_reg(
+ mode_config[i], cs, pup);
+ }
+
+ *sdram_offset = val;
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ }
+ }
+ }
+ }
+
+ *sdram_offset = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ *sdram_offset = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ sdram_offset = (u32 *)NUM_OF_REGISTER_ADDR;
+ *sdram_offset = regs;
+ DEBUG_SUSPEND_RESUME_S("Training Results CheckSum write= ");
+ DEBUG_SUSPEND_RESUME_D(crc, 8);
+ DEBUG_SUSPEND_RESUME_S("\n");
+ sdram_offset = (u32 *)CHECKSUM_RESULT_ADDR;
+ *sdram_offset = crc;
+}
+
+/*
+ * Name: ddr3_read_training_results()
+ * Desc: Reads the training results from memeory (RL,WL,PBS,Rx/Tx
+ * Centeralization)
+ * and writes them to the relevant registers
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: None.
+ */
+int ddr3_read_training_results(void)
+{
+ u32 val, reg, idx, dqs_wr_idx = 0, crc = 0;
+ u32 *sdram_offset = (u32 *)RESUME_TRAINING_VALUES_ADDR;
+ u32 training_val[RESUME_TRAINING_VALUES_MAX] = { 0 };
+ u32 regs = *((u32 *)NUM_OF_REGISTER_ADDR);
+
+ /*
+ * Read Training results & Dunit registers from memory and write
+ * it to an array
+ */
+ for (idx = 0; idx < regs; idx++) {
+ training_val[idx] = *sdram_offset;
+ crc += *sdram_offset;
+ sdram_offset++;
+ }
+
+ sdram_offset = (u32 *)CHECKSUM_RESULT_ADDR;
+
+ if ((*sdram_offset) == crc) {
+ DEBUG_SUSPEND_RESUME_S("Training Results CheckSum read PASS= ");
+ DEBUG_SUSPEND_RESUME_D(crc, 8);
+ DEBUG_SUSPEND_RESUME_S("\n");
+ } else {
+ DEBUG_MAIN_S("Wrong Training Results CheckSum\n");
+ return MV_FAIL;
+ }
+
+ /*
+ * We iterate through all the registers except for the last 2 since
+ * they are Dunit registers (and not PHY registers)
+ */
+ for (idx = 0; idx < (regs - 2); idx++) {
+ val = training_val[idx];
+ reg = (val >> REG_PHY_CS_OFFS) & 0x3F; /*read the phy address */
+
+ /* Check if the values belongs to the DQS WR */
+ if (reg == PUP_WL_MODE) {
+ /* bit[5:0] in DQS_WR are delay */
+ val = (training_val[dqs_wr_idx++] & 0x3F);
+ /*
+ * bit[15:10] are DQS_WR delay & bit[9:0] are
+ * WL phase & delay
+ */
+ val = (val << REG_PHY_DQS_REF_DLY_OFFS) |
+ (training_val[idx] & 0x3C003FF);
+ /* Add Request pending and write operation bits */
+ val |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ } else if (reg == PUP_DQS_WR) {
+ /*
+ * Do nothing since DQS_WR will be done in PUP_WL_MODE
+ */
+ continue;
+ }
+
+ val |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, val);
+ do {
+ val = (reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (val); /* Wait for '0' to mark the end of the transaction */
+ }
+
+ /* write last 2 Dunit configurations */
+ val = training_val[idx];
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, val); /* reg 0x1538 */
+ val = training_val[idx + 1];
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, val); /* reg 0x153c */
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_check_if_resume_mode()
+ * Desc: Reads the address (0x3000) of the Resume Magic word (0xDEADB002)
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: return (magic_word == SUSPEND_MAGIC_WORD)
+ */
+int ddr3_check_if_resume_mode(MV_DRAM_INFO *dram_info, u32 freq)
+{
+ u32 magic_word;
+ u32 *sdram_offset = (u32 *)BOOT_INFO_ADDR;
+
+ if (dram_info->reg_dimm != 1) {
+ /*
+ * Perform write levleling in order initiate the phy with
+ * low frequency
+ */
+ if (MV_OK != ddr3_write_leveling_hw(freq, dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+
+ if (MV_OK != ddr3_load_patterns(dram_info, 1)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Loading Patterns)\n");
+ return MV_DDR3_TRAINING_ERR_LOAD_PATTERNS;
+ }
+
+ /* Enable CS0 only for RL */
+ dram_info->cs_ena = 0x1;
+
+ /* Perform Read levleling in order to get stable memory */
+ if (MV_OK != ddr3_read_leveling_hw(freq, dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+
+ /* Back to relevant CS */
+ dram_info->cs_ena = ddr3_get_cs_ena_from_reg();
+
+ magic_word = *sdram_offset;
+ return magic_word == SUSPEND_MAGIC_WORD;
+}
+
+/*
+ * Name: ddr3_training_suspend_resume()
+ * Desc: Execute the Resume state
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: return (magic_word == SUSPEND_MAGIC_WORD)
+ */
+int ddr3_training_suspend_resume(MV_DRAM_INFO *dram_info)
+{
+ u32 freq, reg;
+ int tmp_ratio;
+
+ /* Configure DDR */
+ if (MV_OK != ddr3_read_training_results())
+ return MV_FAIL;
+
+ /* Reset read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+
+ /* Start Auto Read Leveling procedure */
+ reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+
+ /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ udelay(2);
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Clear Auto Read Leveling procedure */
+ reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Return to target frequency */
+ freq = dram_info->target_frequency;
+ tmp_ratio = 1;
+ if (MV_OK != ddr3_dfs_low_2_high(freq, tmp_ratio, dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs Low2High)\n");
+ return MV_DDR3_TRAINING_ERR_DFS_H2L;
+ }
+
+ if (dram_info->ecc_ena) {
+ /* Scabbling the RL area pattern and the training area */
+ mv_sys_xor_finish();
+ dram_info->num_cs = 1;
+ dram_info->cs_ena = 1;
+ mv_sys_xor_init(dram_info);
+ mv_xor_mem_init(0, RESUME_RL_PATTERNS_ADDR,
+ RESUME_RL_PATTERNS_SIZE, 0xFFFFFFFF, 0xFFFFFFFF);
+
+ /* Wait for previous transfer completion */
+
+ while (mv_xor_state_get(0) != MV_IDLE)
+ ;
+
+ /* Return XOR State */
+ mv_sys_xor_finish();
+ }
+
+ return MV_OK;
+}
+#endif
+
+void ddr3_print_freq(u32 freq)
+{
+ u32 tmp_freq;
+
+ switch (freq) {
+ case 0:
+ tmp_freq = 100;
+ break;
+ case 1:
+ tmp_freq = 300;
+ break;
+ case 2:
+ tmp_freq = 360;
+ break;
+ case 3:
+ tmp_freq = 400;
+ break;
+ case 4:
+ tmp_freq = 444;
+ break;
+ case 5:
+ tmp_freq = 500;
+ break;
+ case 6:
+ tmp_freq = 533;
+ break;
+ case 7:
+ tmp_freq = 600;
+ break;
+ case 8:
+ tmp_freq = 666;
+ break;
+ case 9:
+ tmp_freq = 720;
+ break;
+ case 10:
+ tmp_freq = 800;
+ break;
+ default:
+ tmp_freq = 100;
+ }
+
+ printf("Current frequency is: %dMHz\n", tmp_freq);
+}
+
+int ddr3_get_min_max_read_sample_delay(u32 cs_enable, u32 reg, u32 *min,
+ u32 *max, u32 *cs_max)
+{
+ u32 cs, delay;
+
+ *min = 0xFFFFFFFF;
+ *max = 0x0;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if ((cs_enable & (1 << cs)) == 0)
+ continue;
+
+ delay = ((reg >> (cs * 8)) & 0x1F);
+
+ if (delay < *min)
+ *min = delay;
+
+ if (delay > *max) {
+ *max = delay;
+ *cs_max = cs;
+ }
+ }
+
+ return MV_OK;
+}
+
+int ddr3_get_min_max_rl_phase(MV_DRAM_INFO *dram_info, u32 *min, u32 *max,
+ u32 cs)
+{
+ u32 pup, reg, phase;
+
+ *min = 0xFFFFFFFF;
+ *max = 0x0;
+
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ reg = ddr3_read_pup_reg(PUP_RL_MODE, cs, pup);
+ phase = ((reg >> 8) & 0x7);
+
+ if (phase < *min)
+ *min = phase;
+
+ if (phase > *max)
+ *max = phase;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_odt_activate(int activate)
+{
+ u32 reg, mask;
+
+ mask = (1 << REG_DUNIT_ODT_CTRL_OVRD_OFFS) |
+ (1 << REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS);
+ /* {0x0000149C} - DDR Dunit ODT Control Register */
+ reg = reg_read(REG_DUNIT_ODT_CTRL_ADDR);
+ if (activate)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ reg_write(REG_DUNIT_ODT_CTRL_ADDR, reg);
+
+ return MV_OK;
+}
+
+int ddr3_odt_read_dynamic_config(MV_DRAM_INFO *dram_info)
+{
+ u32 min_read_sample_delay, max_read_sample_delay, max_rl_phase;
+ u32 min, max, cs_max;
+ u32 cs_ena, reg;
+
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ cs_ena = ddr3_get_cs_ena_from_reg();
+
+ /* Get minimum and maximum of read sample delay of all CS */
+ ddr3_get_min_max_read_sample_delay(cs_ena, reg, &min_read_sample_delay,
+ &max_read_sample_delay, &cs_max);
+
+ /*
+ * Get minimum and maximum read leveling phase which belongs to the
+ * maximal read sample delay
+ */
+ ddr3_get_min_max_rl_phase(dram_info, &min, &max, cs_max);
+ max_rl_phase = max;
+
+ /* DDR ODT Timing (Low) Register calculation */
+ reg = reg_read(REG_ODT_TIME_LOW_ADDR);
+ reg &= ~(0x1FF << REG_ODT_ON_CTL_RD_OFFS);
+ reg |= (((min_read_sample_delay - 1) & 0xF) << REG_ODT_ON_CTL_RD_OFFS);
+ reg |= (((max_read_sample_delay + 4 + (((max_rl_phase + 1) / 2) + 1)) &
+ 0x1F) << REG_ODT_OFF_CTL_RD_OFFS);
+ reg_write(REG_ODT_TIME_LOW_ADDR, reg);
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/marvell/axp/ddr3_hw_training.h b/drivers/ddr/marvell/axp/ddr3_hw_training.h
new file mode 100644
index 0000000000..cffa7c4ff9
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_hw_training.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_TRAINING_H
+#define __DDR3_TRAINING_H
+
+#include "ddr3_init.h"
+
+#ifdef MV88F78X60
+#include "ddr3_axp.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375.h"
+#endif
+
+/* The following is a list of Marvell status */
+#define MV_ERROR (-1)
+#define MV_OK (0x00) /* Operation succeeded */
+#define MV_FAIL (0x01) /* Operation failed */
+#define MV_BAD_VALUE (0x02) /* Illegal value (general) */
+#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */
+#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */
+#define MV_BAD_PTR (0x05) /* Illegal pointer value */
+#define MV_BAD_SIZE (0x06) /* Illegal size */
+#define MV_BAD_STATE (0x07) /* Illegal state of state machine */
+#define MV_SET_ERROR (0x08) /* Set operation failed */
+#define MV_GET_ERROR (0x09) /* Get operation failed */
+#define MV_CREATE_ERROR (0x0A) /* Fail while creating an item */
+#define MV_NOT_FOUND (0x0B) /* Item not found */
+#define MV_NO_MORE (0x0C) /* No more items found */
+#define MV_NO_SUCH (0x0D) /* No such item */
+#define MV_TIMEOUT (0x0E) /* Time Out */
+#define MV_NO_CHANGE (0x0F) /* Parameter(s) is already in this value */
+#define MV_NOT_SUPPORTED (0x10) /* This request is not support */
+#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented*/
+#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */
+#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */
+#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */
+#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */
+#define MV_INIT_ERROR (0x16) /* Error occured while INIT process */
+#define MV_HW_ERROR (0x17) /* Hardware error */
+#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */
+#define MV_RX_ERROR (0x19) /* Recieve operation not succeeded */
+#define MV_NOT_READY (0x1A) /* The other side is not ready yet */
+#define MV_ALREADY_EXIST (0x1B) /* Tried to create existing item */
+#define MV_OUT_OF_CPU_MEM (0x1C) /* Cpu memory allocation failed. */
+#define MV_NOT_STARTED (0x1D) /* Not started yet */
+#define MV_BUSY (0x1E) /* Item is busy. */
+#define MV_TERMINATE (0x1F) /* Item terminates it's work. */
+#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */
+#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */
+#define MV_WRITE_PROTECT (0x22) /* Write protected */
+
+#define MV_INVALID (int)(-1)
+
+/*
+ * Debug (Enable/Disable modules) and Error report
+ */
+
+#ifdef BASIC_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS_RESULTS
+#endif
+
+#ifdef FULL_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS
+
+#define MV_DEBUG_PBS
+#define MV_DEBUG_DFS
+#define MV_DEBUG_MAIN_FULL
+#define MV_DEBUG_DFS_FULL
+#define MV_DEBUG_DQS_FULL
+#define MV_DEBUG_RL_FULL
+#define MV_DEBUG_WL_FULL
+#endif
+
+/*
+ * General Consts
+ */
+
+#define SDRAM_READ_WRITE_LEN_IN_WORDS 16
+#define SDRAM_READ_WRITE_LEN_IN_DOUBLE_WORDS 8
+#define CACHE_LINE_SIZE 0x20
+
+#define SDRAM_CS_BASE 0x0
+
+#define SRAM_BASE 0x40000000
+#define SRAM_SIZE 0xFFF
+
+#define LEN_64BIT_STD_PATTERN 16
+#define LEN_64BIT_KILLER_PATTERN 128
+#define LEN_64BIT_SPECIAL_PATTERN 128
+#define LEN_64BIT_PBS_PATTERN 16
+#define LEN_WL_SUP_PATTERN 32
+
+#define LEN_16BIT_STD_PATTERN 4
+#define LEN_16BIT_KILLER_PATTERN 128
+#define LEN_16BIT_SPECIAL_PATTERN 128
+#define LEN_16BIT_PBS_PATTERN 4
+
+#define CMP_BYTE_SHIFT 8
+#define CMP_BYTE_MASK 0xFF
+#define PUP_SIZE 8
+
+#define S 0
+#define C 1
+#define P 2
+#define D 3
+#define DQS 6
+#define PS 2
+#define DS 3
+#define PE 4
+#define DE 5
+
+#define CS0 0
+#define MAX_DIMM_NUM 2
+#define MAX_DELAY 0x1F
+
+/*
+ * Invertion limit and phase1 limit are WA for the RL @ 1:1 design bug -
+ * Armada 370 & AXP Z1
+ */
+#define MAX_DELAY_INV_LIMIT 0x5
+#define MIN_DELAY_PHASE_1_LIMIT 0x10
+
+#define MAX_DELAY_INV (0x3F - MAX_DELAY_INV_LIMIT)
+#define MIN_DELAY 0
+#define MAX_PUP_NUM 9
+#define ECC_PUP 8
+#define DQ_NUM 8
+#define DQS_DQ_NUM 8
+#define INIT_WL_DELAY 13
+#define INIT_RL_DELAY 15
+#define TWLMRD_DELAY 20
+#define TCLK_3_DELAY 3
+#define ECC_BIT 8
+#define DMA_SIZE 64
+#define MV_DMA_0 0
+#define MAX_TRAINING_RETRY 10
+
+#define PUP_RL_MODE 0x2
+#define PUP_WL_MODE 0
+#define PUP_PBS_TX 0x10
+#define PUP_PBS_TX_DM 0x1A
+#define PUP_PBS_RX 0x30
+#define PUP_DQS_WR 0x1
+#define PUP_DQS_RD 0x3
+#define PUP_BC 10
+#define PUP_DELAY_MASK 0x1F
+#define PUP_PHASE_MASK 0x7
+#define PUP_NUM_64BIT 8
+#define PUP_NUM_32BIT 4
+#define PUP_NUM_16BIT 2
+
+/* control PHY registers */
+#define CNTRL_PUP_DESKEW 0x10
+
+/* WL */
+#define COUNT_WL_HI_FREQ 2
+#define COUNT_WL 2
+#define COUNT_WL_RFRS 9
+#define WL_HI_FREQ_SHIFT 2
+#define WL_HI_FREQ_STATE 1
+#define COUNT_HW_WL 2
+
+/* RL */
+/*
+ * RL_MODE - this define uses the RL mode SW RL instead of the functional
+ * window SW RL
+ */
+#define RL_MODE
+#define RL_WINDOW_WA
+#define MAX_PHASE_1TO1 2
+#define MAX_PHASE_2TO1 4
+
+#define MAX_PHASE_RL_UL_1TO1 0
+#define MAX_PHASE_RL_L_1TO1 4
+#define MAX_PHASE_RL_UL_2TO1 3
+#define MAX_PHASE_RL_L_2TO1 7
+
+#define RL_UNLOCK_STATE 0
+#define RL_WINDOW_STATE 1
+#define RL_FINAL_STATE 2
+#define RL_RETRY_COUNT 2
+#define COUNT_HW_RL 2
+
+/* PBS */
+#define MAX_PBS 31
+#define MIN_PBS 0
+#define COUNT_PBS_PATTERN 2
+#define COUNT_PBS_STARTOVER 2
+#define COUNT_PBS_REPEAT 3
+#define COUNT_PBS_COMP_RETRY_NUM 2
+#define PBS_DIFF_LIMIT 31
+#define PATTERN_PBS_TX_A 0x55555555
+#define PATTERN_PBS_TX_B 0xAAAAAAAA
+
+/* DQS */
+#define ADLL_ERROR 0x55
+#define ADLL_MAX 31
+#define ADLL_MIN 0
+#define MIN_WIN_SIZE 4
+#define VALID_WIN_THRS MIN_WIN_SIZE
+
+#define MODE_2TO1 1
+#define MODE_1TO1 0
+
+/*
+ * Macros
+ */
+#define IS_PUP_ACTIVE(_data_, _pup_) (((_data_) >> (_pup_)) & 0x1)
+
+/*
+ * Internal ERROR codes
+ */
+#define MV_DDR3_TRAINING_ERR_WR_LVL_HW 0xDD302001
+#define MV_DDR3_TRAINING_ERR_LOAD_PATTERNS 0xDD302002
+#define MV_DDR3_TRAINING_ERR_WR_LVL_HI_FREQ 0xDD302003
+#define MV_DDR3_TRAINING_ERR_DFS_H2L 0xDD302004
+#define MV_DDR3_TRAINING_ERR_DRAM_COMPARE 0xDD302005
+#define MV_DDR3_TRAINING_ERR_WIN_LIMITS 0xDD302006
+#define MV_DDR3_TRAINING_ERR_PUP_RANGE 0xDD302025
+#define MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH 0xDD302007
+#define MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH 0xDD302008
+#define MV_DDR3_TRAINING_ERR_DQS_PATTERN 0xDD302009
+#define MV_DDR3_TRAINING_ERR_PBS_ADLL_SHR_1PHASE 0xDD302010
+#define MV_DDR3_TRAINING_ERR_PBS_TX_MAX_VAL 0xDD302011
+#define MV_DDR3_TRAINING_ERR_PBS_RX_PER_BIT 0xDD302012
+#define MV_DDR3_TRAINING_ERR_PBS_TX_PER_BIT 0xDD302013
+#define MV_DDR3_TRAINING_ERR_PBS_RX_MAX_VAL 0xDD302014
+#define MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP 0xDD302015
+#define MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_MAX_VAL 0xDD302016
+#define MV_DDR3_TRAINING_ERR_RD_LVL_RL_PATTERN 0xDD302017
+#define MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK 0xDD302018
+#define MV_DDR3_TRAINING_ERR_RD_LVL_PUP_UNLOCK 0xDD302019
+#define MV_DDR3_TRAINING_ERR_WR_LVL_SW 0xDD302020
+#define MV_DDR3_TRAINING_ERR_PRBS_RX 0xDD302021
+#define MV_DDR3_TRAINING_ERR_DQS_RX 0xDD302022
+#define MV_DDR3_TRAINING_ERR_PRBS_TX 0xDD302023
+#define MV_DDR3_TRAINING_ERR_DQS_TX 0xDD302024
+
+/*
+ * DRAM information structure
+ */
+typedef struct dram_info {
+ u32 num_cs;
+ u32 cs_ena;
+ u32 num_of_std_pups; /* Q value = ddrWidth/8 - Without ECC!! */
+ u32 num_of_total_pups; /* numOfStdPups + eccEna */
+ u32 target_frequency; /* DDR Frequency */
+ u32 ddr_width; /* 32/64 Bit or 16/32 Bit */
+ u32 ecc_ena; /* 0/1 */
+ u32 wl_val[MAX_CS][MAX_PUP_NUM][7];
+ u32 rl_val[MAX_CS][MAX_PUP_NUM][7];
+ u32 rl_max_phase;
+ u32 rl_min_phase;
+ u32 wl_max_phase;
+ u32 wl_min_phase;
+ u32 rd_smpl_dly;
+ u32 rd_rdy_dly;
+ u32 cl;
+ u32 cwl;
+ u32 mode_2t;
+ int rl400_bug;
+ int multi_cs_mr_support;
+ int reg_dimm;
+} MV_DRAM_INFO;
+
+enum training_modes {
+ DQS_WR_MODE,
+ WL_MODE_,
+ RL_MODE_,
+ DQS_RD_MODE,
+ PBS_TX_DM_MODE,
+ PBS_TX_MODE,
+ PBS_RX_MODE,
+ MAX_TRAINING_MODE,
+};
+
+typedef struct dram_training_init {
+ u32 reg_addr;
+ u32 reg_value;
+} MV_DRAM_TRAINING_INIT;
+
+typedef struct dram_mv_init {
+ u32 reg_addr;
+ u32 reg_value;
+} MV_DRAM_MC_INIT;
+
+/* Board/Soc revisions define */
+enum board_rev {
+ Z1,
+ Z1_PCAC,
+ Z1_RD_SLED,
+ A0,
+ A0_AMC
+};
+
+typedef struct dram_modes {
+ char *mode_name;
+ u8 cpu_freq;
+ u8 fab_freq;
+ u8 chip_id;
+ int chip_board_rev;
+ MV_DRAM_MC_INIT *regs;
+ MV_DRAM_TRAINING_INIT *vals;
+} MV_DRAM_MODES;
+
+/*
+ * Function Declarations
+ */
+
+u32 cache_inv(u32 addr);
+void flush_l1_v7(u32 line);
+void flush_l1_v6(u32 line);
+
+u32 ddr3_cl_to_valid_cl(u32 cl);
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl);
+
+void ddr3_write_pup_reg(u32 mode, u32 cs, u32 pup, u32 phase, u32 delay);
+u32 ddr3_read_pup_reg(u32 mode, u32 cs, u32 pup);
+
+int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked, int is_tx,
+ u32 pbs_pattern_idx, u32 pbs_curr_val,
+ u32 pbs_lock_val, u32 *skew_array,
+ u8 *unlock_pup_dq_array, u32 ecc);
+
+int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern, int b_special_compare);
+
+int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern, u32 pattern_len,
+ u32 sdram_offset, int write, int mask,
+ u32 *mask_pattern, int b_special_compare);
+
+int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern);
+
+int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 sdram_offset);
+int ddr3_dram_sram_read(u32 src, u32 dst, u32 len);
+int ddr3_load_patterns(MV_DRAM_INFO *dram_info, int resume);
+
+int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+
+int ddr3_write_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_write_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+int ddr3_write_leveling_hw_reg_dimm(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_wl_supplement(MV_DRAM_INFO *dram_info);
+
+int ddr3_dfs_high_2_low(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_dfs_low_2_high(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+
+int ddr3_pbs_tx(MV_DRAM_INFO *dram_info);
+int ddr3_pbs_rx(MV_DRAM_INFO *dram_info);
+int ddr3_load_pbs_patterns(MV_DRAM_INFO *dram_info);
+
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info);
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info);
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info);
+
+void ddr3_static_training_init(void);
+
+u8 ddr3_get_eprom_fabric(void);
+void ddr3_set_performance_params(MV_DRAM_INFO *dram_info);
+int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len);
+void ddr3_save_training(MV_DRAM_INFO *dram_info);
+int ddr3_read_training_results(void);
+int ddr3_training_suspend_resume(MV_DRAM_INFO *dram_info);
+int ddr3_get_min_max_read_sample_delay(u32 cs_enable, u32 reg, u32 *min,
+ u32 *max, u32 *cs_max);
+int ddr3_get_min_max_rl_phase(MV_DRAM_INFO *dram_info, u32 *min, u32 *max,
+ u32 cs);
+int ddr3_odt_activate(int activate);
+int ddr3_odt_read_dynamic_config(MV_DRAM_INFO *dram_info);
+void ddr3_print_freq(u32 freq);
+void ddr3_reset_phy_read_fifo(void);
+
+#endif /* __DDR3_TRAINING_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_init.c b/drivers/ddr/marvell/axp/ddr3_init.c
new file mode 100644
index 0000000000..11b85916b7
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_init.c
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#if defined(MV88F78X60)
+#include "ddr3_axp_vars.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370_vars.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375_vars.h"
+#endif
+
+#ifdef STATIC_TRAINING
+static void ddr3_static_training_init(void);
+#endif
+#ifdef DUNIT_STATIC
+static void ddr3_static_mc_init(void);
+#endif
+#if defined(DUNIT_STATIC) || defined(STATIC_TRAINING)
+MV_DRAM_MODES *ddr3_get_static_ddr_mode(void);
+#endif
+#if defined(MV88F672X)
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+#endif
+u32 mv_board_id_get(void);
+extern void ddr3_set_sw_wl_rl_debug(u32);
+extern void ddr3_set_pbs(u32);
+extern void ddr3_set_log_level(u32 val);
+
+static u32 log_level = DDR3_LOG_LEVEL;
+
+static u32 ddr3_init_main(void);
+
+/*
+ * Name: ddr3_set_log_level
+ * Desc: This routine initialize the log_level acording to nLogLevel
+ * which getting from user
+ * Args: nLogLevel
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_set_log_level(u32 val)
+{
+ log_level = val;
+}
+
+/*
+ * Name: ddr3_get_log_level
+ * Desc: This routine returns the log level
+ * Args: none
+ * Notes:
+ * Returns: log level.
+ */
+u32 ddr3_get_log_level(void)
+{
+ return log_level;
+}
+
+static void debug_print_reg(u32 reg)
+{
+ printf("0x%08x = 0x%08x\n", reg, reg_read(reg));
+}
+
+static void print_dunit_setup(void)
+{
+ puts("\n########### LOG LEVEL 1 (D-UNIT SETUP)###########\n");
+
+#ifdef DUNIT_STATIC
+ puts("\nStatic D-UNIT Setup:\n");
+#endif
+#ifdef DUNIT_SPD
+ puts("\nDynamic(using SPD) D-UNIT Setup:\n");
+#endif
+ debug_print_reg(REG_SDRAM_CONFIG_ADDR);
+ debug_print_reg(REG_DUNIT_CTRL_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_TIMING_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_TIMING_HIGH_ADDR);
+ debug_print_reg(REG_SDRAM_ADDRESS_CTRL_ADDR);
+ debug_print_reg(REG_SDRAM_OPEN_PAGES_ADDR);
+ debug_print_reg(REG_SDRAM_OPERATION_ADDR);
+ debug_print_reg(REG_SDRAM_MODE_ADDR);
+ debug_print_reg(REG_SDRAM_EXT_MODE_ADDR);
+ debug_print_reg(REG_DDR_CONT_HIGH_ADDR);
+ debug_print_reg(REG_ODT_TIME_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_ERROR_ADDR);
+ debug_print_reg(REG_SDRAM_AUTO_PWR_SAVE_ADDR);
+ debug_print_reg(REG_OUDDR3_TIMING_ADDR);
+ debug_print_reg(REG_ODT_TIME_HIGH_ADDR);
+ debug_print_reg(REG_SDRAM_ODT_CTRL_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_ODT_CTRL_HIGH_ADDR);
+ debug_print_reg(REG_DUNIT_ODT_CTRL_ADDR);
+#ifndef MV88F67XX
+ debug_print_reg(REG_DRAM_FIFO_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_AXI_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR);
+ debug_print_reg(REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR);
+ debug_print_reg(REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_MAIN_PADS_CAL_ADDR);
+ debug_print_reg(REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR);
+ debug_print_reg(REG_CS_SIZE_SCRATCH_ADDR);
+ debug_print_reg(REG_DYNAMIC_POWER_SAVE_ADDR);
+ debug_print_reg(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ debug_print_reg(REG_READ_DATA_READY_DELAYS_ADDR);
+ debug_print_reg(REG_DDR3_MR0_ADDR);
+ debug_print_reg(REG_DDR3_MR1_ADDR);
+ debug_print_reg(REG_DDR3_MR2_ADDR);
+ debug_print_reg(REG_DDR3_MR3_ADDR);
+ debug_print_reg(REG_DDR3_RANK_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_PHY_CONFIG_ADDR);
+ debug_print_reg(REG_STATIC_DRAM_DLB_CONTROL);
+ debug_print_reg(DLB_BUS_OPTIMIZATION_WEIGHTS_REG);
+ debug_print_reg(DLB_AGING_REGISTER);
+ debug_print_reg(DLB_EVICTION_CONTROL_REG);
+ debug_print_reg(DLB_EVICTION_TIMERS_REGISTER_REG);
+#if defined(MV88F672X)
+ debug_print_reg(REG_FASTPATH_WIN_CTRL_ADDR(0));
+ debug_print_reg(REG_FASTPATH_WIN_BASE_ADDR(0));
+ debug_print_reg(REG_FASTPATH_WIN_CTRL_ADDR(1));
+ debug_print_reg(REG_FASTPATH_WIN_BASE_ADDR(1));
+#else
+ debug_print_reg(REG_FASTPATH_WIN_0_CTRL_ADDR);
+#endif
+ debug_print_reg(REG_CDI_CONFIG_ADDR);
+#endif
+}
+
+#if !defined(STATIC_TRAINING)
+static void ddr3_restore_and_set_final_windows(u32 *win_backup)
+{
+ u32 ui, reg, cs;
+ u32 win_ctrl_reg, num_of_win_regs;
+ u32 cs_ena = ddr3_get_cs_ena_from_reg();
+
+#if defined(MV88F672X)
+ if (DDR3_FAST_PATH_EN == 0)
+ return;
+#endif
+
+#if defined(MV88F672X)
+ win_ctrl_reg = REG_XBAR_WIN_16_CTRL_ADDR;
+ num_of_win_regs = 8;
+#else
+ win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+ num_of_win_regs = 16;
+#endif
+
+ /* Return XBAR windows 4-7 or 16-19 init configuration */
+ for (ui = 0; ui < num_of_win_regs; ui++)
+ reg_write((win_ctrl_reg + 0x4 * ui), win_backup[ui]);
+
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - Switching XBAR Window to FastPath Window\n");
+
+#if defined(MV88F672X)
+ /* Set L2 filtering to 1G */
+ reg_write(0x8c04, 0x40000000);
+
+ /* Open fast path windows */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ /* set fast path window control for the cs */
+ reg = 0x1FFFFFE1;
+ reg |= (cs << 2);
+ reg |= (SDRAM_CS_SIZE & 0xFFFF0000);
+ /* Open fast path Window */
+ reg_write(REG_FASTPATH_WIN_CTRL_ADDR(cs), reg);
+ /* set fast path window base address for the cs */
+ reg = (((SDRAM_CS_SIZE + 1) * cs) & 0xFFFF0000);
+ /* Set base address */
+ reg_write(REG_FASTPATH_WIN_BASE_ADDR(cs), reg);
+ }
+ }
+#else
+ reg = 0x1FFFFFE1;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= (cs << 2);
+ break;
+ }
+ }
+
+ /* Open fast path Window to - 0.5G */
+ reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, reg);
+#endif
+}
+
+static void ddr3_save_and_set_training_windows(u32 *win_backup)
+{
+ u32 cs_ena = ddr3_get_cs_ena_from_reg();
+ u32 reg, tmp_count, cs, ui;
+ u32 win_ctrl_reg, win_base_reg, win_remap_reg;
+ u32 num_of_win_regs, win_jump_index;
+
+#if defined(MV88F672X)
+ /* Disable L2 filtering */
+ reg_write(0x8c04, 0);
+
+ win_ctrl_reg = REG_XBAR_WIN_16_CTRL_ADDR;
+ win_base_reg = REG_XBAR_WIN_16_BASE_ADDR;
+ win_remap_reg = REG_XBAR_WIN_16_REMAP_ADDR;
+ win_jump_index = 0x8;
+ num_of_win_regs = 8;
+#else
+ win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+ win_base_reg = REG_XBAR_WIN_4_BASE_ADDR;
+ win_remap_reg = REG_XBAR_WIN_4_REMAP_ADDR;
+ win_jump_index = 0x10;
+ num_of_win_regs = 16;
+#endif
+
+ /* Close XBAR Window 19 - Not needed */
+ /* {0x000200e8} - Open Mbus Window - 2G */
+ reg_write(REG_XBAR_WIN_19_CTRL_ADDR, 0);
+
+ /* Save XBAR Windows 4-19 init configurations */
+ for (ui = 0; ui < num_of_win_regs; ui++)
+ win_backup[ui] = reg_read(win_ctrl_reg + 0x4 * ui);
+
+ /* Open XBAR Windows 4-7 or 16-19 for other CS */
+ reg = 0;
+ tmp_count = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ switch (cs) {
+ case 0:
+ reg = 0x0E00;
+ break;
+ case 1:
+ reg = 0x0D00;
+ break;
+ case 2:
+ reg = 0x0B00;
+ break;
+ case 3:
+ reg = 0x0700;
+ break;
+ }
+ reg |= (1 << 0);
+ reg |= (SDRAM_CS_SIZE & 0xFFFF0000);
+
+ reg_write(win_ctrl_reg + win_jump_index * tmp_count,
+ reg);
+ reg = ((SDRAM_CS_SIZE + 1) * (tmp_count)) & 0xFFFF0000;
+ reg_write(win_base_reg + win_jump_index * tmp_count,
+ reg);
+
+ if (win_remap_reg <= REG_XBAR_WIN_7_REMAP_ADDR) {
+ reg_write(win_remap_reg +
+ win_jump_index * tmp_count, 0);
+ }
+
+ tmp_count++;
+ }
+ }
+}
+#endif /* !defined(STATIC_TRAINING) */
+
+/*
+ * Name: ddr3_init - Main DDR3 Init function
+ * Desc: This routine initialize the DDR3 MC and runs HW training.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+int ddr3_init(void)
+{
+ unsigned int status;
+
+ ddr3_set_pbs(DDR3_PBS);
+ ddr3_set_sw_wl_rl_debug(DDR3_RUN_SW_WHEN_HW_FAIL);
+
+ status = ddr3_init_main();
+ if (status == MV_DDR3_TRAINING_ERR_BAD_SAR)
+ DEBUG_INIT_S("DDR3 Training Error: Bad sample at reset");
+ if (status == MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP)
+ DEBUG_INIT_S("DDR3 Training Error: Bad DIMM setup");
+ if (status == MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT)
+ DEBUG_INIT_S("DDR3 Training Error: Max CS limit");
+ if (status == MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT)
+ DEBUG_INIT_S("DDR3 Training Error: Max enable CS limit");
+ if (status == MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP)
+ DEBUG_INIT_S("DDR3 Training Error: Bad R-DIMM setup");
+ if (status == MV_DDR3_TRAINING_ERR_TWSI_FAIL)
+ DEBUG_INIT_S("DDR3 Training Error: TWSI failure");
+ if (status == MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH)
+ DEBUG_INIT_S("DDR3 Training Error: DIMM type no match");
+ if (status == MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE)
+ DEBUG_INIT_S("DDR3 Training Error: TWSI bad type");
+ if (status == MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH)
+ DEBUG_INIT_S("DDR3 Training Error: bus width no match");
+ if (status > MV_DDR3_TRAINING_ERR_HW_FAIL_BASE)
+ DEBUG_INIT_C("DDR3 Training Error: HW Failure 0x", status, 8);
+
+ return status;
+}
+
+static void print_ddr_target_freq(u32 cpu_freq, u32 fab_opt)
+{
+ puts("\nDDR3 Training Sequence - Run DDR3 at ");
+
+ switch (cpu_freq) {
+#if defined(MV88F672X)
+ case 21:
+ puts("533 Mhz\n");
+ break;
+#else
+ case 1:
+ puts("533 Mhz\n");
+ break;
+ case 2:
+ if (fab_opt == 5)
+ puts("600 Mhz\n");
+ if (fab_opt == 9)
+ puts("400 Mhz\n");
+ break;
+ case 3:
+ puts("667 Mhz\n");
+ break;
+ case 4:
+ if (fab_opt == 5)
+ puts("750 Mhz\n");
+ if (fab_opt == 9)
+ puts("500 Mhz\n");
+ break;
+ case 0xa:
+ puts("400 Mhz\n");
+ break;
+ case 0xb:
+ if (fab_opt == 5)
+ puts("800 Mhz\n");
+ if (fab_opt == 9)
+ puts("553 Mhz\n");
+ if (fab_opt == 0xA)
+ puts("640 Mhz\n");
+ break;
+#endif
+ default:
+ puts("NOT DEFINED FREQ\n");
+ }
+}
+
+static u32 ddr3_init_main(void)
+{
+ u32 target_freq;
+ u32 reg = 0;
+ u32 cpu_freq, fab_opt, hclk_time_ps, soc_num;
+ __maybe_unused u32 ecc = DRAM_ECC;
+ __maybe_unused int dqs_clk_aligned = 0;
+ __maybe_unused u32 scrub_offs, scrub_size;
+ __maybe_unused u32 ddr_width = BUS_WIDTH;
+ __maybe_unused int status;
+ __maybe_unused u32 win_backup[16];
+
+ /* SoC/Board special Initializtions */
+ fab_opt = ddr3_get_fab_opt();
+
+#ifdef CONFIG_SPD_EEPROM
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
+ ddr3_print_version();
+ DEBUG_INIT_S("4\n");
+ /* Lib version 5.5.4 */
+
+ fab_opt = ddr3_get_fab_opt();
+
+ /* Switching CPU to MRVL ID */
+ soc_num = (reg_read(REG_SAMPLE_RESET_HIGH_ADDR) & SAR1_CPU_CORE_MASK) >>
+ SAR1_CPU_CORE_OFFSET;
+ switch (soc_num) {
+ case 0x3:
+ reg_bit_set(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET);
+ reg_bit_set(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET);
+ case 0x1:
+ reg_bit_set(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET);
+ case 0x0:
+ reg_bit_set(CPU_CONFIGURATION_REG(0), CPU_MRVL_ID_OFFSET);
+ default:
+ break;
+ }
+
+ /* Power down deskew PLL */
+#if !defined(MV88F672X)
+ /* 0x18780 [25] */
+ reg = (reg_read(REG_DDRPHY_APLL_CTRL_ADDR) & ~(1 << 25));
+ reg_write(REG_DDRPHY_APLL_CTRL_ADDR, reg);
+#endif
+
+ /*
+ * Stage 0 - Set board configuration
+ */
+ cpu_freq = ddr3_get_cpu_freq();
+ if (fab_opt > FAB_OPT)
+ fab_opt = FAB_OPT - 1;
+
+ if (ddr3_get_log_level() > 0)
+ print_ddr_target_freq(cpu_freq, fab_opt);
+
+#if defined(MV88F672X)
+ get_target_freq(cpu_freq, &target_freq, &hclk_time_ps);
+#else
+ target_freq = cpu_ddr_ratios[fab_opt][cpu_freq];
+ hclk_time_ps = cpu_fab_clk_to_hclk[fab_opt][cpu_freq];
+#endif
+ if ((target_freq == 0) || (hclk_time_ps == 0)) {
+ DEBUG_INIT_S("DDR3 Training Sequence - FAILED - Wrong Sample at Reset Configurations\n");
+ if (target_freq == 0) {
+ DEBUG_INIT_C("target_freq", target_freq, 2);
+ DEBUG_INIT_C("fab_opt", fab_opt, 2);
+ DEBUG_INIT_C("cpu_freq", cpu_freq, 2);
+ } else if (hclk_time_ps == 0) {
+ DEBUG_INIT_C("hclk_time_ps", hclk_time_ps, 2);
+ DEBUG_INIT_C("fab_opt", fab_opt, 2);
+ DEBUG_INIT_C("cpu_freq", cpu_freq, 2);
+ }
+
+ return MV_DDR3_TRAINING_ERR_BAD_SAR;
+ }
+
+#if defined(ECC_SUPPORT)
+ scrub_offs = U_BOOT_START_ADDR;
+ scrub_size = U_BOOT_SCRUB_SIZE;
+#else
+ scrub_offs = 0;
+ scrub_size = 0;
+#endif
+
+#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
+ ecc = DRAM_ECC;
+#endif
+
+#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
+ ecc = 0;
+ if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_ECC))
+ ecc = 1;
+#endif
+
+#ifdef DQS_CLK_ALIGNED
+ dqs_clk_aligned = 1;
+#endif
+
+ /* Check if DRAM is already initialized */
+ if (reg_read(REG_BOOTROM_ROUTINE_ADDR) &
+ (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
+ DEBUG_INIT_S("DDR3 Training Sequence - 2nd boot - Skip\n");
+ return MV_OK;
+ }
+
+ /*
+ * Stage 1 - Dunit Setup
+ */
+
+#ifdef DUNIT_STATIC
+ /*
+ * For Static D-Unit Setup use must set the correct static values
+ * at the ddr3_*soc*_vars.h file
+ */
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - Static MC Init\n");
+ ddr3_static_mc_init();
+
+#ifdef ECC_SUPPORT
+ ecc = DRAM_ECC;
+ if (ecc) {
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ reg |= (1 << REG_SDRAM_CONFIG_ECC_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+ }
+#endif
+#endif
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+#if defined(AUTO_DETECTION_SUPPORT)
+ /*
+ * Configurations for both static and dynamic MC setups
+ *
+ * Dynamically Set 32Bit and ECC for AXP (Relevant only for
+ * Marvell DB boards)
+ */
+ if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_BUS_WIDTH)) {
+ ddr_width = 32;
+ DEBUG_INIT_S("DDR3 Training Sequence - DRAM bus width 32Bit\n");
+ }
+#endif
+
+#if defined(MV88F672X)
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if ((reg >> 15) & 1)
+ ddr_width = 32;
+ else
+ ddr_width = 16;
+#endif
+#endif
+
+#ifdef DUNIT_SPD
+ status = ddr3_dunit_setup(ecc, hclk_time_ps, &ddr_width);
+ if (MV_OK != status) {
+ DEBUG_INIT_S("DDR3 Training Sequence - FAILED (ddr3 Dunit Setup)\n");
+ return status;
+ }
+#endif
+
+ /* Fix read ready phases for all SOC in reg 0x15C8 */
+ reg = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK);
+ reg |= 0x4; /* Phase 0 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << REG_TRAINING_DEBUG_3_OFFS);
+ reg |= (0x4 << (1 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 1 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (3 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (3 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 3 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (4 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (4 * REG_TRAINING_DEBUG_3_OFFS));
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (5 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (5 * REG_TRAINING_DEBUG_3_OFFS));
+ reg_write(REG_TRAINING_DEBUG_3_ADDR, reg);
+
+#if defined(MV88F672X)
+ /*
+ * AxiBrespMode[8] = Compliant,
+ * AxiAddrDecodeCntrl[11] = Internal,
+ * AxiDataBusWidth[0] = 128bit
+ */
+ /* 0x14A8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0);
+#else
+ /* 0x14A8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0x00000100);
+ reg_write(REG_CDI_CONFIG_ADDR, 0x00000006);
+
+ if ((ddr_width == 64) && (reg_read(REG_DDR_IO_ADDR) &
+ (1 << REG_DDR_IO_CLK_RATIO_OFFS))) {
+ /* 0x14A8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0x00000101);
+ reg_write(REG_CDI_CONFIG_ADDR, 0x00000007);
+ }
+#endif
+
+#if !defined(MV88F67XX)
+ /*
+ * ARMADA-370 activate DLB later at the u-boot,
+ * Armada38x - No DLB activation at this time
+ */
+ reg_write(DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x18C01E);
+
+#if defined(MV88F78X60)
+ /* WA according to eratta GL-8672902*/
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV)
+ reg_write(DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0xc19e);
+#endif
+
+ reg_write(DLB_AGING_REGISTER, 0x0f7f007f);
+ reg_write(DLB_EVICTION_CONTROL_REG, 0x0);
+ reg_write(DLB_EVICTION_TIMERS_REGISTER_REG, 0x00FF3C1F);
+
+ reg_write(MBUS_UNITS_PRIORITY_CONTROL_REG, 0x55555555);
+ reg_write(FABRIC_UNITS_PRIORITY_CONTROL_REG, 0xAA);
+ reg_write(MBUS_UNITS_PREFETCH_CONTROL_REG, 0xffff);
+ reg_write(FABRIC_UNITS_PREFETCH_CONTROL_REG, 0xf0f);
+
+#if defined(MV88F78X60)
+ /* WA according to eratta GL-8672902 */
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV) {
+ reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+ reg |= DLB_ENABLE;
+ reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+ }
+#endif /* end defined(MV88F78X60) */
+#endif /* end !defined(MV88F67XX) */
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_1)
+ print_dunit_setup();
+
+ /*
+ * Stage 2 - Training Values Setup
+ */
+#ifdef STATIC_TRAINING
+ /*
+ * DRAM Init - After all the D-unit values are set, its time to init
+ * the D-unit
+ */
+ /* Wait for '0' */
+ reg_write(REG_SDRAM_INIT_CTRL_ADDR, 0x1);
+ do {
+ reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+ (1 << REG_SDRAM_INIT_CTRL_OFFS);
+ } while (reg);
+
+ /* ddr3 init using static parameters - HW training is disabled */
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - Static Training Parameters\n");
+ ddr3_static_training_init();
+
+#if defined(MV88F78X60)
+ /*
+ * If ECC is enabled, need to scrub the U-Boot area memory region -
+ * Run training function with Xor bypass just to scrub the memory
+ */
+ status = ddr3_hw_training(target_freq, ddr_width,
+ 1, scrub_offs, scrub_size,
+ dqs_clk_aligned, DDR3_TRAINING_DEBUG,
+ REG_DIMM_SKIP_WL);
+ if (MV_OK != status) {
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - FAILED\n");
+ return status;
+ }
+#endif
+#else
+ /* Set X-BAR windows for the training sequence */
+ ddr3_save_and_set_training_windows(win_backup);
+
+ /* Run DDR3 Training Sequence */
+ /* DRAM Init */
+ reg_write(REG_SDRAM_INIT_CTRL_ADDR, 0x1);
+ do {
+ reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+ (1 << REG_SDRAM_INIT_CTRL_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* ddr3 init using DDR3 HW training procedure */
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - HW Training Procedure\n");
+ status = ddr3_hw_training(target_freq, ddr_width,
+ 0, scrub_offs, scrub_size,
+ dqs_clk_aligned, DDR3_TRAINING_DEBUG,
+ REG_DIMM_SKIP_WL);
+ if (MV_OK != status) {
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - FAILED\n");
+ return status;
+ }
+#endif
+
+ /*
+ * Stage 3 - Finish
+ */
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* Disable ECC Ignore bit */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) &
+ ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+#endif
+
+#if !defined(STATIC_TRAINING)
+ /* Restore and set windows */
+ ddr3_restore_and_set_final_windows(win_backup);
+#endif
+
+ /* Update DRAM init indication in bootROM register */
+ reg = reg_read(REG_BOOTROM_ROUTINE_ADDR);
+ reg_write(REG_BOOTROM_ROUTINE_ADDR,
+ reg | (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS));
+
+#if !defined(MV88F67XX)
+#if defined(MV88F78X60)
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV) {
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if (ecc == 0)
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg | (1 << 19));
+ }
+#endif /* end defined(MV88F78X60) */
+
+ reg_write(DLB_EVICTION_CONTROL_REG, 0x9);
+
+ reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+ reg |= (DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN |
+ DLB_MBUS_PREFETCH_EN | PREFETCH_NLNSZTR);
+ reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+#endif /* end !defined(MV88F67XX) */
+
+#ifdef STATIC_TRAINING
+ DEBUG_INIT_S("DDR3 Training Sequence - Ended Successfully (S)\n");
+#else
+ DEBUG_INIT_S("DDR3 Training Sequence - Ended Successfully\n");
+#endif
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_get_cpu_freq
+ * Desc: read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+
+u32 ddr3_get_cpu_freq(void)
+{
+ u32 reg, cpu_freq;
+
+#if defined(MV88F672X)
+ /* Read sample at reset setting */
+ reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR); /* 0xE8200 */
+ cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+ REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+#else
+ /* Read sample at reset setting */
+ reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR); /* 0x18230 [23:21] */
+#if defined(MV88F78X60)
+ cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+ REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+ reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR); /* 0x18234 [20] */
+ cpu_freq |= (((reg >> REG_SAMPLE_RESET_HIGH_CPU_FREQ_OFFS) & 0x1) << 3);
+#elif defined(MV88F67XX)
+ cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+ REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+#endif
+#endif
+
+ return cpu_freq;
+}
+
+/*
+ * Name: ddr3_get_fab_opt
+ * Desc: read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_get_fab_opt(void)
+{
+ __maybe_unused u32 reg, fab_opt;
+
+#if defined(MV88F672X)
+ return 0; /* No fabric */
+#else
+ /* Read sample at reset setting */
+ reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR);
+ fab_opt = (reg & REG_SAMPLE_RESET_FAB_MASK) >>
+ REG_SAMPLE_RESET_FAB_OFFS;
+
+#if defined(MV88F78X60)
+ reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR);
+ fab_opt |= (((reg >> 19) & 0x1) << 4);
+#endif
+
+ return fab_opt;
+#endif
+}
+
+/*
+ * Name: ddr3_get_vco_freq
+ * Desc: read S@R and return VCO frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_get_vco_freq(void)
+{
+ u32 fab, cpu_freq, ui_vco_freq;
+
+ fab = ddr3_get_fab_opt();
+ cpu_freq = ddr3_get_cpu_freq();
+
+ if (fab == 2 || fab == 3 || fab == 7 || fab == 8 || fab == 10 ||
+ fab == 15 || fab == 17 || fab == 20)
+ ui_vco_freq = cpu_freq + CLK_CPU;
+ else
+ ui_vco_freq = cpu_freq;
+
+ return ui_vco_freq;
+}
+
+#ifdef STATIC_TRAINING
+/*
+ * Name: ddr3_static_training_init - Init DDR3 Training with
+ * static parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_static_training_init(void)
+{
+ MV_DRAM_MODES *ddr_mode;
+ u32 reg;
+ int j;
+
+ ddr_mode = ddr3_get_static_ddr_mode();
+
+ j = 0;
+ while (ddr_mode->vals[j].reg_addr != 0) {
+ udelay(10); /* haim want to delay each write */
+ reg_write(ddr_mode->vals[j].reg_addr,
+ ddr_mode->vals[j].reg_value);
+
+ if (ddr_mode->vals[j].reg_addr ==
+ REG_PHY_REGISTRY_FILE_ACCESS_ADDR)
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg);
+ j++;
+ }
+}
+#endif
+
+/*
+ * Name: ddr3_get_static_mc_value - Init Memory controller with static
+ * parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, u32 offset2,
+ u32 mask2)
+{
+ u32 reg, tmp;
+
+ reg = reg_read(reg_addr);
+
+ tmp = (reg >> offset1) & mask1;
+ if (mask2)
+ tmp |= (reg >> offset2) & mask2;
+
+ return tmp;
+}
+
+/*
+ * Name: ddr3_get_static_ddr_mode - Init Memory controller with static
+ * parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+__weak MV_DRAM_MODES *ddr3_get_static_ddr_mode(void)
+{
+ u32 chip_board_rev, i;
+ u32 size;
+
+ /* Do not modify this code. relevant only for marvell Boards */
+#if defined(DB_78X60_PCAC)
+ chip_board_rev = Z1_PCAC;
+#elif defined(DB_78X60_AMC)
+ chip_board_rev = A0_AMC;
+#elif defined(DB_88F6710_PCAC)
+ chip_board_rev = A0_PCAC;
+#elif defined(RD_88F6710)
+ chip_board_rev = A0_RD;
+#elif defined(MV88F672X)
+ chip_board_rev = mv_board_id_get();
+#else
+ chip_board_rev = A0;
+#endif
+
+ size = sizeof(ddr_modes) / sizeof(MV_DRAM_MODES);
+ for (i = 0; i < size; i++) {
+ if ((ddr3_get_cpu_freq() == ddr_modes[i].cpu_freq) &&
+ (ddr3_get_fab_opt() == ddr_modes[i].fab_freq) &&
+ (chip_board_rev == ddr_modes[i].chip_board_rev))
+ return &ddr_modes[i];
+ }
+
+ return &ddr_modes[0];
+}
+
+#ifdef DUNIT_STATIC
+/*
+ * Name: ddr3_static_mc_init - Init Memory controller with static parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_static_mc_init(void)
+{
+ MV_DRAM_MODES *ddr_mode;
+ u32 reg;
+ int j;
+
+ ddr_mode = ddr3_get_static_ddr_mode();
+ j = 0;
+ while (ddr_mode->regs[j].reg_addr != 0) {
+ reg_write(ddr_mode->regs[j].reg_addr,
+ ddr_mode->regs[j].reg_value);
+ if (ddr_mode->regs[j].reg_addr ==
+ REG_PHY_REGISTRY_FILE_ACCESS_ADDR)
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg);
+ j++;
+ }
+}
+#endif
+
+/*
+ * Name: ddr3_check_config - Check user configurations: ECC/MultiCS
+ * Desc:
+ * Args: twsi Address
+ * Notes: Only Available for ArmadaXP/Armada 370 DB boards
+ * Returns: None.
+ */
+int ddr3_check_config(u32 twsi_addr, MV_CONFIG_TYPE config_type)
+{
+#ifdef AUTO_DETECTION_SUPPORT
+ u8 data = 0;
+ int ret;
+ int offset;
+
+ if ((config_type == CONFIG_ECC) || (config_type == CONFIG_BUS_WIDTH))
+ offset = 1;
+ else
+ offset = 0;
+
+ ret = i2c_read(twsi_addr, offset, 1, (u8 *)&data, 1);
+ if (!ret) {
+ switch (config_type) {
+ case CONFIG_ECC:
+ if (data & 0x2)
+ return 1;
+ break;
+ case CONFIG_BUS_WIDTH:
+ if (data & 0x1)
+ return 1;
+ break;
+#ifdef DB_88F6710
+ case CONFIG_MULTI_CS:
+ if (CFG_MULTI_CS_MODE(data))
+ return 1;
+ break;
+#else
+ case CONFIG_MULTI_CS:
+ break;
+#endif
+ }
+ }
+#endif
+
+ return 0;
+}
+
+#if defined(DB_88F78X60_REV2)
+/*
+ * Name: ddr3_get_eprom_fabric - Get Fabric configuration from EPROM
+ * Desc:
+ * Args: twsi Address
+ * Notes: Only Available for ArmadaXP DB Rev2 boards
+ * Returns: None.
+ */
+u8 ddr3_get_eprom_fabric(void)
+{
+#ifdef AUTO_DETECTION_SUPPORT
+ u8 data = 0;
+ int ret;
+
+ ret = i2c_read(NEW_FABRIC_TWSI_ADDR, 1, 1, (u8 *)&data, 1);
+ if (!ret)
+ return data & 0x1F;
+#endif
+
+ return 0;
+}
+
+#endif
+
+/*
+ * Name: ddr3_cl_to_valid_cl - this return register matching CL value
+ * Desc:
+ * Args: clValue - the value
+
+ * Notes:
+ * Returns: required CL value
+ */
+u32 ddr3_cl_to_valid_cl(u32 cl)
+{
+ switch (cl) {
+ case 5:
+ return 2;
+ break;
+ case 6:
+ return 4;
+ break;
+ case 7:
+ return 6;
+ break;
+ case 8:
+ return 8;
+ break;
+ case 9:
+ return 10;
+ break;
+ case 10:
+ return 12;
+ break;
+ case 11:
+ return 14;
+ break;
+ case 12:
+ return 1;
+ break;
+ case 13:
+ return 3;
+ break;
+ case 14:
+ return 5;
+ break;
+ default:
+ return 2;
+ }
+}
+
+/*
+ * Name: ddr3_cl_to_valid_cl - this return register matching CL value
+ * Desc:
+ * Args: clValue - the value
+ * Notes:
+ * Returns: required CL value
+ */
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl)
+{
+ switch (ui_valid_cl) {
+ case 1:
+ return 12;
+ break;
+ case 2:
+ return 5;
+ break;
+ case 3:
+ return 13;
+ break;
+ case 4:
+ return 6;
+ break;
+ case 5:
+ return 14;
+ break;
+ case 6:
+ return 7;
+ break;
+ case 8:
+ return 8;
+ break;
+ case 10:
+ return 9;
+ break;
+ case 12:
+ return 10;
+ break;
+ case 14:
+ return 11;
+ break;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Name: ddr3_get_cs_num_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_num_from_reg(void)
+{
+ u32 cs_ena = ddr3_get_cs_ena_from_reg();
+ u32 cs_count = 0;
+ u32 cs;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ cs_count++;
+ }
+
+ return cs_count;
+}
+
+/*
+ * Name: ddr3_get_cs_ena_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_ena_from_reg(void)
+{
+ return reg_read(REG_DDR3_RANK_CTRL_ADDR) &
+ REG_DDR3_RANK_CTRL_CS_ENA_MASK;
+}
+
+/*
+ * mv_ctrl_rev_get - Get Marvell controller device revision number
+ *
+ * DESCRIPTION:
+ * This function returns 8bit describing the device revision as defined
+ * in PCI Express Class Code and Revision ID Register.
+ *
+ * INPUT:
+ * None.
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * 8bit desscribing Marvell controller revision number
+ *
+ */
+#if !defined(MV88F672X)
+u8 mv_ctrl_rev_get(void)
+{
+ u8 rev_num;
+
+#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
+ /* Check pex power state */
+ u32 pex_power;
+ pex_power = mv_ctrl_pwr_clck_get(PEX_UNIT_ID, 0);
+ if (pex_power == 0)
+ mv_ctrl_pwr_clck_set(PEX_UNIT_ID, 0, 1);
+#endif
+ rev_num = (u8)reg_read(PEX_CFG_DIRECT_ACCESS(0,
+ PCI_CLASS_CODE_AND_REVISION_ID));
+
+#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
+ /* Return to power off state */
+ if (pex_power == 0)
+ mv_ctrl_pwr_clck_set(PEX_UNIT_ID, 0, 0);
+#endif
+
+ return (rev_num & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS;
+}
+
+#endif
+
+#if defined(MV88F672X)
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps)
+{
+ u32 tmp, hclk;
+
+ switch (freq_mode) {
+ case CPU_333MHz_DDR_167MHz_L2_167MHz:
+ hclk = 84;
+ tmp = DDR_100;
+ break;
+ case CPU_266MHz_DDR_266MHz_L2_133MHz:
+ case CPU_333MHz_DDR_222MHz_L2_167MHz:
+ case CPU_400MHz_DDR_200MHz_L2_200MHz:
+ case CPU_400MHz_DDR_267MHz_L2_200MHz:
+ case CPU_533MHz_DDR_267MHz_L2_267MHz:
+ case CPU_500MHz_DDR_250MHz_L2_250MHz:
+ case CPU_600MHz_DDR_300MHz_L2_300MHz:
+ case CPU_800MHz_DDR_267MHz_L2_400MHz:
+ case CPU_900MHz_DDR_300MHz_L2_450MHz:
+ tmp = DDR_300;
+ hclk = 150;
+ break;
+ case CPU_333MHz_DDR_333MHz_L2_167MHz:
+ case CPU_500MHz_DDR_334MHz_L2_250MHz:
+ case CPU_666MHz_DDR_333MHz_L2_333MHz:
+ tmp = DDR_333;
+ hclk = 165;
+ break;
+ case CPU_533MHz_DDR_356MHz_L2_267MHz:
+ tmp = DDR_360;
+ hclk = 180;
+ break;
+ case CPU_400MHz_DDR_400MHz_L2_200MHz:
+ case CPU_600MHz_DDR_400MHz_L2_300MHz:
+ case CPU_800MHz_DDR_400MHz_L2_400MHz:
+ case CPU_400MHz_DDR_400MHz_L2_400MHz:
+ tmp = DDR_400;
+ hclk = 200;
+ break;
+ case CPU_666MHz_DDR_444MHz_L2_333MHz:
+ case CPU_900MHz_DDR_450MHz_L2_450MHz:
+ tmp = DDR_444;
+ hclk = 222;
+ break;
+ case CPU_500MHz_DDR_500MHz_L2_250MHz:
+ case CPU_1000MHz_DDR_500MHz_L2_500MHz:
+ case CPU_1000MHz_DDR_500MHz_L2_333MHz:
+ tmp = DDR_500;
+ hclk = 250;
+ break;
+ case CPU_533MHz_DDR_533MHz_L2_267MHz:
+ case CPU_800MHz_DDR_534MHz_L2_400MHz:
+ case CPU_1100MHz_DDR_550MHz_L2_550MHz:
+ tmp = DDR_533;
+ hclk = 267;
+ break;
+ case CPU_600MHz_DDR_600MHz_L2_300MHz:
+ case CPU_900MHz_DDR_600MHz_L2_450MHz:
+ case CPU_1200MHz_DDR_600MHz_L2_600MHz:
+ tmp = DDR_600;
+ hclk = 300;
+ break;
+ case CPU_666MHz_DDR_666MHz_L2_333MHz:
+ case CPU_1000MHz_DDR_667MHz_L2_500MHz:
+ tmp = DDR_666;
+ hclk = 333;
+ break;
+ default:
+ *ddr_freq = 0;
+ *hclk_ps = 0;
+ break;
+ }
+
+ *ddr_freq = tmp; /* DDR freq define */
+ *hclk_ps = 1000000 / hclk; /* values are 1/HCLK in ps */
+
+ return;
+}
+#endif
diff --git a/drivers/ddr/marvell/axp/ddr3_init.h b/drivers/ddr/marvell/axp/ddr3_init.h
new file mode 100644
index 0000000000..b259e098e5
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_init.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_INIT_H
+#define __DDR3_INIT_H
+
+/*
+ * Debug
+ */
+
+/*
+ * MV_DEBUG_INIT need to be defines, otherwise the output of the
+ * DDR2 training code is not complete and misleading
+ */
+#define MV_DEBUG_INIT
+
+#ifdef MV_DEBUG_INIT
+#define DEBUG_INIT_S(s) puts(s)
+#define DEBUG_INIT_D(d, l) printf("%x", d)
+#define DEBUG_INIT_D_10(d, l) printf("%d", d)
+#else
+#define DEBUG_INIT_S(s)
+#define DEBUG_INIT_D(d, l)
+#define DEBUG_INIT_D_10(d, l)
+#endif
+
+#ifdef MV_DEBUG_INIT_FULL
+#define DEBUG_INIT_FULL_S(s) puts(s)
+#define DEBUG_INIT_FULL_D(d, l) printf("%x", d)
+#define DEBUG_INIT_FULL_D_10(d, l) printf("%d", d)
+#define DEBUG_WR_REG(reg, val) \
+ { DEBUG_INIT_S("Write Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+ DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#define DEBUG_RD_REG(reg, val) \
+ { DEBUG_INIT_S("Read Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+ DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#else
+#define DEBUG_INIT_FULL_S(s)
+#define DEBUG_INIT_FULL_D(d, l)
+#define DEBUG_INIT_FULL_D_10(d, l)
+#define DEBUG_WR_REG(reg, val)
+#define DEBUG_RD_REG(reg, val)
+#endif
+
+#define DEBUG_INIT_FULL_C(s, d, l) \
+ { DEBUG_INIT_FULL_S(s); DEBUG_INIT_FULL_D(d, l); DEBUG_INIT_FULL_S("\n"); }
+#define DEBUG_INIT_C(s, d, l) \
+ { DEBUG_INIT_S(s); DEBUG_INIT_D(d, l); DEBUG_INIT_S("\n"); }
+
+#define MV_MBUS_REGS_OFFSET (0x20000)
+
+#include "ddr3_hw_training.h"
+
+#define MAX_DIMM_NUM 2
+#define SPD_SIZE 128
+
+#ifdef MV88F78X60
+#include "ddr3_axp.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375.h"
+#endif
+
+/* DRR training Error codes */
+/* Stage 0 errors */
+#define MV_DDR3_TRAINING_ERR_BAD_SAR 0xDD300001
+/* Stage 1 errors */
+#define MV_DDR3_TRAINING_ERR_TWSI_FAIL 0xDD301001
+#define MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH 0xDD301001
+#define MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE 0xDD301003
+#define MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH 0xDD301004
+#define MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP 0xDD301005
+#define MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT 0xDD301006
+#define MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT 0xDD301007
+#define MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP 0xDD301008
+/* Stage 2 errors */
+#define MV_DDR3_TRAINING_ERR_HW_FAIL_BASE 0xDD302000
+
+typedef enum config_type {
+ CONFIG_ECC,
+ CONFIG_MULTI_CS,
+ CONFIG_BUS_WIDTH
+} MV_CONFIG_TYPE;
+
+enum log_level {
+ MV_LOG_LEVEL_0,
+ MV_LOG_LEVEL_1,
+ MV_LOG_LEVEL_2,
+ MV_LOG_LEVEL_3
+};
+
+int ddr3_hw_training(u32 target_freq, u32 ddr_width,
+ int xor_bypass, u32 scrub_offs, u32 scrub_size,
+ int dqs_clk_aligned, int debug_mode, int reg_dimm_skip_wl);
+
+void ddr3_print_version(void);
+void fix_pll_val(u8 target_fab);
+u8 ddr3_get_eprom_fabric(void);
+u32 ddr3_get_fab_opt(void);
+u32 ddr3_get_cpu_freq(void);
+u32 ddr3_get_vco_freq(void);
+int ddr3_check_config(u32 addr, MV_CONFIG_TYPE config_type);
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, u32 offset2,
+ u32 mask2);
+u32 ddr3_cl_to_valid_cl(u32 cl);
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl);
+u32 ddr3_get_cs_num_from_reg(void);
+u32 ddr3_get_cs_ena_from_reg(void);
+u8 mv_ctrl_rev_get(void);
+
+u32 ddr3_get_log_level(void);
+
+/* SPD */
+int ddr3_dunit_setup(u32 ecc_ena, u32 hclk_time, u32 *ddr_width);
+
+/*
+ * Accessor functions for the registers
+ */
+static inline void reg_write(u32 addr, u32 val)
+{
+ writel(val, INTER_REGS_BASE + addr);
+}
+
+static inline u32 reg_read(u32 addr)
+{
+ return readl(INTER_REGS_BASE + addr);
+}
+
+static inline void reg_bit_set(u32 addr, u32 mask)
+{
+ setbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+static inline void reg_bit_clr(u32 addr, u32 mask)
+{
+ clrbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+#endif /* __DDR3_INIT_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_patterns_64bit.h b/drivers/ddr/marvell/axp/ddr3_patterns_64bit.h
new file mode 100644
index 0000000000..1b57328f7f
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_patterns_64bit.h
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_PATTERNS_64_H
+#define __DDR3_PATTERNS_64_H
+
+/*
+ * Patterns Declerations
+ */
+
+u32 wl_sup_pattern[LEN_WL_SUP_PATTERN] __aligned(32) = {
+ 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d,
+ 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d,
+ 0x24232221, 0x28272625, 0x2c2b2a29, 0x302f2e2d,
+ 0x34333231, 0x38373635, 0x3c3b3a39, 0x403f3e3d,
+ 0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d,
+ 0x54535251, 0x58575655, 0x5c5b5a59, 0x605f5e5d,
+ 0x64636261, 0x68676665, 0x6c6b6a69, 0x706f6e6d,
+ 0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d
+};
+
+u32 pbs_pattern_32b[2][LEN_PBS_PATTERN] __aligned(32) = {
+ {
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555,
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555,
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555,
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555
+ },
+ {
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA,
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA,
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA,
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA
+ }
+};
+
+u32 pbs_pattern_64b[2][LEN_PBS_PATTERN] __aligned(32) = {
+ {
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555
+ },
+ {
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA
+ }
+};
+
+u32 rl_pattern[LEN_STD_PATTERN] __aligned(32) = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0x01010101, 0x01010101
+};
+
+u32 killer_pattern_32b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+ {
+ 0x01010101, 0x00000000, 0x01010101, 0xFFFFFFFF,
+ 0x01010101, 0x00000000, 0x01010101, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE,
+ 0x01010101, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0x01010101, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, 0x00000000,
+ 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x01010101,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x01010101,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0x00000000, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFEFEFEFE, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0x00000000, 0xFEFEFEFE, 0x00000000,
+ 0xFEFEFEFE, 0x00000000, 0xFEFEFEFE, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x00000000,
+ 0x01010101, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE
+ },
+ {
+ 0x02020202, 0x00000000, 0x02020202, 0xFFFFFFFF,
+ 0x02020202, 0x00000000, 0x02020202, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD,
+ 0x02020202, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0x02020202, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, 0x00000000,
+ 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x02020202,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x02020202,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0x00000000, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFDFDFDFD, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0x00000000, 0xFDFDFDFD, 0x00000000,
+ 0xFDFDFDFD, 0x00000000, 0xFDFDFDFD, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x00000000,
+ 0x02020202, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD
+ },
+ {
+ 0x04040404, 0x00000000, 0x04040404, 0xFFFFFFFF,
+ 0x04040404, 0x00000000, 0x04040404, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB,
+ 0x04040404, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0x04040404, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, 0x00000000,
+ 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x04040404,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x04040404,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0x00000000, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFBFBFBFB, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0x00000000, 0xFBFBFBFB, 0x00000000,
+ 0xFBFBFBFB, 0x00000000, 0xFBFBFBFB, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x00000000,
+ 0x04040404, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB
+ },
+ {
+ 0x08080808, 0x00000000, 0x08080808, 0xFFFFFFFF,
+ 0x08080808, 0x00000000, 0x08080808, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7,
+ 0x08080808, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0x08080808, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, 0x00000000,
+ 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x08080808,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x08080808,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0x00000000, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xF7F7F7F7, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0x00000000, 0xF7F7F7F7, 0x00000000,
+ 0xF7F7F7F7, 0x00000000, 0xF7F7F7F7, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x00000000,
+ 0x08080808, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7
+ },
+ {
+ 0x10101010, 0x00000000, 0x10101010, 0xFFFFFFFF,
+ 0x10101010, 0x00000000, 0x10101010, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF,
+ 0x10101010, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0x10101010, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, 0x00000000,
+ 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x10101010,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x10101010,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0x00000000, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xEFEFEFEF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0x00000000, 0xEFEFEFEF, 0x00000000,
+ 0xEFEFEFEF, 0x00000000, 0xEFEFEFEF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x00000000,
+ 0x10101010, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF
+ },
+ {
+ 0x20202020, 0x00000000, 0x20202020, 0xFFFFFFFF,
+ 0x20202020, 0x00000000, 0x20202020, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF,
+ 0x20202020, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0x20202020, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, 0x00000000,
+ 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x20202020,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x20202020,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0x00000000, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xDFDFDFDF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0x00000000, 0xDFDFDFDF, 0x00000000,
+ 0xDFDFDFDF, 0x00000000, 0xDFDFDFDF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x00000000,
+ 0x20202020, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF
+ },
+ {
+ 0x40404040, 0x00000000, 0x40404040, 0xFFFFFFFF,
+ 0x40404040, 0x00000000, 0x40404040, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF,
+ 0x40404040, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0x40404040, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, 0x00000000,
+ 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x40404040,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x40404040,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0x00000000, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xBFBFBFBF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0x00000000, 0xBFBFBFBF, 0x00000000,
+ 0xBFBFBFBF, 0x00000000, 0xBFBFBFBF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x00000000,
+ 0x40404040, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF
+ },
+ {
+ 0x80808080, 0x00000000, 0x80808080, 0xFFFFFFFF,
+ 0x80808080, 0x00000000, 0x80808080, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F,
+ 0x80808080, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x80808080, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, 0x00000000,
+ 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x80808080,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x80808080,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0x00000000, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x7F7F7F7F, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x00000000, 0x7F7F7F7F, 0x00000000,
+ 0x7F7F7F7F, 0x00000000, 0x7F7F7F7F, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x00000000,
+ 0x80808080, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F
+ }
+};
+
+u32 killer_pattern_64b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+ {
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE
+ },
+ {
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD
+ },
+ {
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB
+ },
+ {
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7
+ },
+ {
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF
+ },
+ {
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF
+ },
+ {
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF
+ },
+ {
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F
+ }
+};
+
+u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN] __aligned(32) = {
+ {
+ 0x00000000, 0x00000000, 0x01010101, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101,
+ 0x00000000, 0x00000000, 0x01010101, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202,
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x04040404, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404,
+ 0x00000000, 0x00000000, 0x04040404, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x08080808, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808,
+ 0x00000000, 0x00000000, 0x08080808, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010,
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x20202020, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020,
+ 0x00000000, 0x00000000, 0x20202020, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x40404040, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040,
+ 0x00000000, 0x00000000, 0x40404040, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x80808080, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080,
+ 0x00000000, 0x00000000, 0x80808080, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000
+ }
+};
+
+/* Fabric ratios table */
+u32 fabric_ratio[FAB_OPT] = {
+ 0x04010204,
+ 0x04020202,
+ 0x08020306,
+ 0x08020303,
+ 0x04020303,
+ 0x04020204,
+ 0x04010202,
+ 0x08030606,
+ 0x08030505,
+ 0x04020306,
+ 0x0804050A,
+ 0x04030606,
+ 0x04020404,
+ 0x04030306,
+ 0x04020505,
+ 0x08020505,
+ 0x04010303,
+ 0x08050A0A,
+ 0x04030408,
+ 0x04010102,
+ 0x08030306
+};
+
+u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM] = {
+ {3, 2, 5, 7, 1, 0, 6, 4},
+ {2, 3, 6, 7, 1, 0, 4, 5},
+ {1, 3, 5, 6, 0, 2, 4, 7},
+ {0, 2, 4, 7, 1, 3, 5, 6},
+ {3, 0, 4, 6, 1, 2, 5, 7},
+ {0, 3, 5, 7, 1, 2, 4, 6},
+ {2, 3, 5, 7, 1, 0, 4, 6},
+ {0, 2, 5, 4, 1, 3, 6, 7},
+ {2, 3, 4, 7, 0, 1, 5, 6}
+};
+
+#endif /* __DDR3_PATTERNS_64_H */
diff --git a/drivers/ddr/marvell/axp/ddr3_pbs.c b/drivers/ddr/marvell/axp/ddr3_pbs.c
new file mode 100644
index 0000000000..00ea3fdb91
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_pbs.c
@@ -0,0 +1,1592 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_PBS_FULL_C(s, d, l) \
+ DEBUG_PBS_FULL_S(s); DEBUG_PBS_FULL_D(d, l); DEBUG_PBS_FULL_S("\n")
+#define DEBUG_PBS_C(s, d, l) \
+ DEBUG_PBS_S(s); DEBUG_PBS_D(d, l); DEBUG_PBS_S("\n")
+
+#ifdef MV_DEBUG_PBS
+#define DEBUG_PBS_S(s) puts(s)
+#define DEBUG_PBS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_PBS_S(s)
+#define DEBUG_PBS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_FULL_PBS
+#define DEBUG_PBS_FULL_S(s) puts(s)
+#define DEBUG_PBS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_PBS_FULL_S(s)
+#define DEBUG_PBS_FULL_D(d, l)
+#endif
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+
+/* Temp array for skew data storage */
+static u32 skew_array[(MAX_PUP_NUM) * DQ_NUM] = { 0 };
+
+/* PBS locked dq (per pup) */
+extern u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM];
+extern u32 pbs_locked_dm[MAX_PUP_NUM];
+extern u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM];
+
+#if defined(MV88F672X)
+extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+#else
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
+#endif
+
+extern u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM];
+
+static int ddr3_tx_shift_dqs_adll_step_before_fail(MV_DRAM_INFO *dram_info,
+ u32 cur_pup, u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_rx_shift_dqs_to_first_fail(MV_DRAM_INFO *dram_info, u32 cur_pup,
+ u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_pbs_per_bit(MV_DRAM_INFO *dram_info, int *start_over, int is_tx,
+ u32 *pcur_pup, u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_set_pbs_results(MV_DRAM_INFO *dram_info, int is_tx);
+static void ddr3_pbs_write_pup_dqs_reg(u32 cs, u32 pup, u32 dqs_delay);
+
+/*
+ * Name: ddr3_pbs_tx
+ * Desc: Execute the PBS TX phase.
+ * Args: dram_info ddr3 training information struct
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_pbs_tx(MV_DRAM_INFO *dram_info)
+{
+ /* Array of Deskew results */
+
+ /*
+ * Array to hold the total sum of skew from all iterations
+ * (for average purpose)
+ */
+ u32 skew_sum_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ /*
+ * Array to hold the total average skew from both patterns
+ * (for average purpose)
+ */
+ u32 pattern_skew_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ u32 pbs_rep_time = 0; /* counts number of loop in case of fail */
+ /* bit array for unlock pups - used to repeat on the RX operation */
+ u32 cur_pup;
+ u32 max_pup;
+ u32 pbs_retry;
+ u32 pup, dq, pups, cur_max_pup, valid_pup, reg;
+ u32 pattern_idx;
+ u32 ecc;
+ /* indicates whether we need to start the loop again */
+ int start_over;
+
+ DEBUG_PBS_S("DDR3 - PBS TX - Starting PBS TX procedure\n");
+
+ pups = dram_info->num_of_total_pups;
+ max_pup = dram_info->num_of_total_pups;
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_PBS_S("DDR3 - PBS RX - SW Override Enabled\n");
+
+ reg = 1 << REG_DRAM_TRAINING_AUTO_OFFS;
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Running twice for 2 different patterns. each patterns - 3 times */
+ for (pattern_idx = 0; pattern_idx < COUNT_PBS_PATTERN; pattern_idx++) {
+ DEBUG_PBS_C("DDR3 - PBS TX - Working with pattern - ",
+ pattern_idx, 1);
+
+ /* Reset sum array */
+ for (pup = 0; pup < pups; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_sum_array[pup][dq] = 0;
+ }
+
+ /*
+ * Perform PBS several of times (3 for each pattern).
+ * At the end, we'll use the average
+ */
+ /* If there is ECC, do each PBS again with mux change */
+ for (pbs_retry = 0; pbs_retry < COUNT_PBS_REPEAT; pbs_retry++) {
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+ /*
+ * This parameter stores the current PUP
+ * num - ecc mode dependent - 4-8 / 1 pups
+ */
+ cur_max_pup = (1 - ecc) *
+ dram_info->num_of_std_pups + ecc;
+
+ if (ecc) {
+ /* Only 1 pup in this case */
+ valid_pup = 0x1;
+ } else if (cur_max_pup > 4) {
+ /* 64 bit - 8 pups */
+ valid_pup = 0xFF;
+ } else if (cur_max_pup == 4) {
+ /* 32 bit - 4 pups */
+ valid_pup = 0xF;
+ } else {
+ /* 16 bit - 2 pups */
+ valid_pup = 0x3;
+ }
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena * ecc <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_PBS_S("DDR3 - PBS Tx - ECC Mux Enabled\n");
+ else
+ DEBUG_PBS_S("DDR3 - PBS Tx - ECC Mux Disabled\n");
+
+ /* Init iteration values */
+ /* Clear the locked DQs */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pbs_locked_dq[
+ pup + ecc *
+ (max_pup - 1)][dq] =
+ 0;
+ }
+ }
+
+ pbs_rep_time = 0;
+ cur_pup = valid_pup;
+ start_over = 0;
+
+ /*
+ * Run loop On current Pattern and current
+ * pattern iteration (just to cover the false
+ * fail problem)
+ */
+ do {
+ DEBUG_PBS_S("DDR3 - PBS Tx - Pbs Rep Loop is ");
+ DEBUG_PBS_D(pbs_rep_time, 1);
+ DEBUG_PBS_S(", for Retry No.");
+ DEBUG_PBS_D(pbs_retry, 1);
+ DEBUG_PBS_S("\n");
+
+ /* Set all PBS values to MIN (0) */
+ DEBUG_PBS_S("DDR3 - PBS Tx - Set all PBS values to MIN\n");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ ddr3_write_pup_reg(
+ PUP_PBS_TX +
+ pbs_dq_mapping[pup *
+ (1 - ecc) +
+ ecc * ECC_PUP]
+ [dq], CS0, (1 - ecc) *
+ PUP_BC + ecc * ECC_PUP, 0,
+ 0);
+ }
+
+ /*
+ * Shift DQ ADLL right, One step before
+ * fail
+ */
+ DEBUG_PBS_S("DDR3 - PBS Tx - ADLL shift right one phase before fail\n");
+
+ if (MV_OK != ddr3_tx_shift_dqs_adll_step_before_fail
+ (dram_info, cur_pup, pattern_idx,
+ ecc))
+ return MV_DDR3_TRAINING_ERR_PBS_ADLL_SHR_1PHASE;
+
+ /* PBS For each bit */
+ DEBUG_PBS_S("DDR3 - PBS Tx - perform PBS for each bit\n");
+
+ /*
+ * In this stage - start_over = 0
+ */
+ if (MV_OK != ddr3_pbs_per_bit(
+ dram_info, &start_over, 1,
+ &cur_pup, pattern_idx, ecc))
+ return MV_DDR3_TRAINING_ERR_PBS_TX_PER_BIT;
+
+ } while ((start_over == 1) &&
+ (++pbs_rep_time < COUNT_PBS_STARTOVER));
+
+ if (pbs_rep_time == COUNT_PBS_STARTOVER &&
+ start_over == 1) {
+ DEBUG_PBS_S("DDR3 - PBS Tx - FAIL - Adll reach max value\n");
+ return MV_DDR3_TRAINING_ERR_PBS_TX_MAX_VAL;
+ }
+
+ DEBUG_PBS_FULL_C("DDR3 - PBS TX - values for iteration - ",
+ pbs_retry, 1);
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc
+ * from pbs value the min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D((pup + (ecc * ECC_PUP)), 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew -
+ * last / first failing bit
+ * Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_array
+ [((pup) * DQ_NUM) +
+ dq], 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /*
+ * Collect the results we got on this trial
+ * of PBS
+ */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ skew_sum_array[pup + (ecc * (max_pup - 1))]
+ [dq] += skew_array
+ [((pup) * DQ_NUM) + dq];
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ }
+ }
+
+ DEBUG_PBS_C("DDR3 - PBS TX - values for current pattern - ",
+ pattern_idx, 1);
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the
+ * min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* set skew value for all dq */
+ /* Bit# Deskew <- Bit# Deskew - last / first failing bit Deskew For all bits (per PUP) (minimize delay elements) */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT, 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /*
+ * Calculate the average skew for current pattern for each
+ * pup and each bit
+ */
+ DEBUG_PBS_C("DDR3 - PBS TX - Average for pattern - ",
+ pattern_idx, 1);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * FOR ECC only :: found min and max value for current
+ * pattern skew array
+ */
+ /* Loop for all dqs */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pattern_skew_array[pup][dq] +=
+ (skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT);
+ }
+ }
+ }
+
+ /* Calculate the average skew */
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_array[((pup) * DQ_NUM) + dq] =
+ pattern_skew_array[pup][dq] / COUNT_PBS_PATTERN;
+ }
+
+ DEBUG_PBS_S("DDR3 - PBS TX - Average for all patterns:\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the min
+ * pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_array[(pup * DQ_NUM) + dq], 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /* Return ADLL to default value */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (pup == (max_pup - 1) && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ ddr3_pbs_write_pup_dqs_reg(CS0, pup, INIT_WL_DELAY);
+ }
+
+ /* Set averaged PBS results */
+ ddr3_set_pbs_results(dram_info, 1);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ DEBUG_PBS_S("DDR3 - PBS Tx - PBS TX ended successfuly\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tx_shift_dqs_adll_step_before_fail
+ * Desc: Execute the Tx shift DQ phase.
+ * Args: dram_info ddr3 training information struct
+ * cur_pup bit array of the function active pups.
+ * pbs_pattern_idx Index of PBS pattern
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_tx_shift_dqs_adll_step_before_fail(MV_DRAM_INFO *dram_info,
+ u32 cur_pup,
+ u32 pbs_pattern_idx, u32 ecc)
+{
+ u32 unlock_pup; /* bit array of unlock pups */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 adll_val = 4; /* INIT_WL_DELAY */
+ u32 cur_max_pup, pup;
+ u32 dqs_dly_set[MAX_PUP_NUM] = { 0 };
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ /* Set current pup number */
+ if (cur_pup == 0x1) /* Ecc mode */
+ cur_max_pup = 1;
+ else
+ cur_max_pup = dram_info->num_of_std_pups;
+
+ unlock_pup = cur_pup; /* '1' for each unlocked pup */
+
+ /* Loop on all ADLL Vaules */
+ do {
+ /* Loop until found first fail */
+ adll_val++;
+
+ /*
+ * Increment (Move to right - ADLL) DQ TX delay
+ * (broadcast to all Data PUPs)
+ */
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_pbs_write_pup_dqs_reg(CS0,
+ pup * (1 - ecc) +
+ ECC_PUP * ecc, adll_val);
+
+ /*
+ * Write and Read, compare results (read was already verified)
+ */
+ /* 0 - all locked */
+ new_lockup_pup = 0;
+
+ if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ pattern_ptr, LEN_PBS_PATTERN,
+ SDRAM_PBS_TX_OFFS, 1, 0,
+ NULL,
+ 0))
+ return MV_FAIL;
+
+ unlock_pup &= ~new_lockup_pup;
+
+ DEBUG_PBS_FULL_S("Shift DQS by 2 steps for PUPs: ");
+ DEBUG_PBS_FULL_D(unlock_pup, 2);
+ DEBUG_PBS_FULL_C(", Set ADLL value = ", adll_val, 2);
+
+ /* If any PUP failed there is '1' to mark the PUP */
+ if (new_lockup_pup != 0) {
+ /*
+ * Decrement (Move Back to Left two steps - ADLL)
+ * DQ TX delay for current failed pups and save
+ */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (((new_lockup_pup >> pup) & 0x1) &&
+ dqs_dly_set[pup] == 0)
+ dqs_dly_set[pup] = adll_val - 1;
+ }
+ }
+ } while ((unlock_pup != 0) && (adll_val != ADLL_MAX));
+
+ if (unlock_pup != 0) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Tx - Shift DQ - Adll value reached maximum\n");
+
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (((unlock_pup >> pup) & 0x1) &&
+ dqs_dly_set[pup] == 0)
+ dqs_dly_set[pup] = adll_val - 1;
+ }
+ }
+
+ DEBUG_PBS_FULL_C("PBS TX one step before fail last pups locked Adll ",
+ adll_val - 2, 2);
+
+ /* Set the PUP DQS DLY Values */
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_pbs_write_pup_dqs_reg(CS0, pup * (1 - ecc) + ECC_PUP * ecc,
+ dqs_dly_set[pup]);
+
+ /* Found one phase before fail */
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_pbs_rx
+ * Desc: Execute the PBS RX phase.
+ * Args: dram_info ddr3 training information struct
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_pbs_rx(MV_DRAM_INFO *dram_info)
+{
+ /*
+ * Array to hold the total sum of skew from all iterations
+ * (for average purpose)
+ */
+ u32 skew_sum_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ /*
+ * Array to hold the total average skew from both patterns
+ * (for average purpose)
+ */
+ u32 pattern_skew_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ u32 pbs_rep_time = 0; /* counts number of loop in case of fail */
+ /* bit array for unlock pups - used to repeat on the RX operation */
+ u32 cur_pup;
+ u32 max_pup;
+ u32 pbs_retry;
+ u32 pup, dq, pups, cur_max_pup, valid_pup, reg;
+ u32 pattern_idx;
+ u32 ecc;
+ /* indicates whether we need to start the loop again */
+ int start_over;
+ int status;
+
+ DEBUG_PBS_S("DDR3 - PBS RX - Starting PBS RX procedure\n");
+
+ pups = dram_info->num_of_total_pups;
+ max_pup = dram_info->num_of_total_pups;
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - SW Override Enabled\n");
+
+ reg = 1 << REG_DRAM_TRAINING_AUTO_OFFS;
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Running twice for 2 different patterns. each patterns - 3 times */
+ for (pattern_idx = 0; pattern_idx < COUNT_PBS_PATTERN; pattern_idx++) {
+ DEBUG_PBS_FULL_C("DDR3 - PBS RX - Working with pattern - ",
+ pattern_idx, 1);
+
+ /* Reset sum array */
+ for (pup = 0; pup < pups; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_sum_array[pup][dq] = 0;
+ }
+
+ /*
+ * Perform PBS several of times (3 for each pattern).
+ * At the end, we'll use the average
+ */
+ /* If there is ECC, do each PBS again with mux change */
+ for (pbs_retry = 0; pbs_retry < COUNT_PBS_REPEAT; pbs_retry++) {
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+ /*
+ * This parameter stores the current PUP
+ * num - ecc mode dependent - 4-8 / 1 pups
+ */
+ cur_max_pup = (1 - ecc) *
+ dram_info->num_of_std_pups + ecc;
+
+ if (ecc) {
+ /* Only 1 pup in this case */
+ valid_pup = 0x1;
+ } else if (cur_max_pup > 4) {
+ /* 64 bit - 8 pups */
+ valid_pup = 0xFF;
+ } else if (cur_max_pup == 4) {
+ /* 32 bit - 4 pups */
+ valid_pup = 0xF;
+ } else {
+ /* 16 bit - 2 pups */
+ valid_pup = 0x3;
+ }
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena * ecc <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - ECC Mux Enabled\n");
+ else
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - ECC Mux Disabled\n");
+
+ /* Init iteration values */
+ /* Clear the locked DQs */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pbs_locked_dq[
+ pup + ecc * (max_pup - 1)][dq] =
+ 0;
+ }
+ }
+
+ pbs_rep_time = 0;
+ cur_pup = valid_pup;
+ start_over = 0;
+
+ /*
+ * Run loop On current Pattern and current
+ * pattern iteration (just to cover the false
+ * fail problem
+ */
+ do {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Pbs Rep Loop is ");
+ DEBUG_PBS_FULL_D(pbs_rep_time, 1);
+ DEBUG_PBS_FULL_S(", for Retry No.");
+ DEBUG_PBS_FULL_D(pbs_retry, 1);
+ DEBUG_PBS_FULL_S("\n");
+
+ /* Set all PBS values to MAX (31) */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ ddr3_write_pup_reg(
+ PUP_PBS_RX +
+ pbs_dq_mapping[
+ pup * (1 - ecc)
+ + ecc * ECC_PUP]
+ [dq], CS0,
+ pup + ecc * ECC_PUP,
+ 0, MAX_PBS);
+ }
+
+ /* Set all DQS PBS values to MIN (0) */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ ddr3_write_pup_reg(PUP_PBS_RX +
+ DQ_NUM, CS0,
+ pup +
+ ecc *
+ ECC_PUP, 0,
+ 0);
+ }
+
+ /* Shift DQS, To first Fail */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Shift RX DQS to first fail\n");
+
+ status = ddr3_rx_shift_dqs_to_first_fail
+ (dram_info, cur_pup,
+ pattern_idx, ecc);
+ if (MV_OK != status) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - ddr3_rx_shift_dqs_to_first_fail failed.\n");
+ DEBUG_PBS_D(status, 8);
+ DEBUG_PBS_S("\nDDR3 - PBS Rx - SKIP.\n");
+
+ /* Reset read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Start Auto Read Leveling procedure */
+ reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS)
+ + (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+ /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR))
+ & (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Clear Auto Read Leveling procedure */
+ reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ /* Set ADLL to 15 */
+ for (pup = 0; pup < max_pup;
+ pup++) {
+ ddr3_write_pup_reg
+ (PUP_DQS_RD, CS0,
+ pup +
+ (ecc * ECC_PUP), 0,
+ 15);
+ }
+
+ /* Set all PBS values to MIN (0) */
+ for (pup = 0; pup < cur_max_pup;
+ pup++) {
+ for (dq = 0;
+ dq < DQ_NUM; dq++)
+ ddr3_write_pup_reg
+ (PUP_PBS_RX +
+ pbs_dq_mapping
+ [pup * (1 - ecc) +
+ ecc * ECC_PUP]
+ [dq], CS0,
+ pup + ecc * ECC_PUP,
+ 0, MIN_PBS);
+ }
+
+ return MV_OK;
+ }
+
+ /* PBS For each bit */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - perform PBS for each bit\n");
+ /* in this stage - start_over = 0; */
+ if (MV_OK != ddr3_pbs_per_bit(
+ dram_info, &start_over,
+ 0, &cur_pup,
+ pattern_idx, ecc)) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - ddr3_pbs_per_bit failed.");
+ return MV_DDR3_TRAINING_ERR_PBS_RX_PER_BIT;
+ }
+
+ } while ((start_over == 1) &&
+ (++pbs_rep_time < COUNT_PBS_STARTOVER));
+
+ if (pbs_rep_time == COUNT_PBS_STARTOVER &&
+ start_over == 1) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - FAIL - Algorithm failed doing RX PBS\n");
+ return MV_DDR3_TRAINING_ERR_PBS_RX_MAX_VAL;
+ }
+
+ /* Return DQS ADLL to default value - 15 */
+ /* Set all DQS PBS values to MIN (0) */
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+ pup + ecc * ECC_PUP,
+ 0, INIT_RL_DELAY);
+
+ DEBUG_PBS_FULL_C("DDR3 - PBS RX - values for iteration - ",
+ pbs_retry, 1);
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from
+ * pbs value the min pbs val
+ */
+ DEBUG_PBS_FULL_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_FULL_D((pup +
+ (ecc * ECC_PUP)), 1);
+ DEBUG_PBS_FULL_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew -
+ * last / first failing bit
+ * Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_FULL_S("DQ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S("-");
+ DEBUG_PBS_FULL_D(skew_array
+ [((pup) *
+ DQ_NUM) +
+ dq], 2);
+ DEBUG_PBS_FULL_S(", ");
+ }
+ DEBUG_PBS_FULL_S("\n");
+ }
+
+ /*
+ * Collect the results we got on this trial
+ * of PBS
+ */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ skew_sum_array
+ [pup + (ecc * (max_pup - 1))]
+ [dq] +=
+ skew_array[((pup) * DQ_NUM) + dq];
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ }
+ }
+
+ /*
+ * Calculate the average skew for current pattern for each
+ * pup and each bit
+ */
+ DEBUG_PBS_FULL_C("DDR3 - PBS RX - Average for pattern - ",
+ pattern_idx, 1);
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * FOR ECC only :: found min and max value for
+ * current pattern skew array
+ */
+ /* Loop for all dqs */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pattern_skew_array[pup][dq] +=
+ (skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT);
+ }
+ }
+
+ DEBUG_PBS_C("DDR3 - PBS RX - values for current pattern - ",
+ pattern_idx, 1);
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the
+ * min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS RX - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT, 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+ }
+
+ /* Calculate the average skew */
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_array[((pup) * DQ_NUM) + dq] =
+ pattern_skew_array[pup][dq] / COUNT_PBS_PATTERN;
+ }
+
+ DEBUG_PBS_S("DDR3 - PBS RX - Average for all patterns:\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the
+ * min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_array[(pup * DQ_NUM) + dq], 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /* Return ADLL to default value */
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0, PUP_BC, 0, INIT_RL_DELAY);
+
+ /* Set averaged PBS results */
+ ddr3_set_pbs_results(dram_info, 0);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - ended successfuly\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_rx_shift_dqs_to_first_fail
+ * Desc: Execute the Rx shift DQ phase.
+ * Args: dram_info ddr3 training information struct
+ * cur_pup bit array of the function active pups.
+ * pbs_pattern_idx Index of PBS pattern
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_rx_shift_dqs_to_first_fail(MV_DRAM_INFO *dram_info, u32 cur_pup,
+ u32 pbs_pattern_idx, u32 ecc)
+{
+ u32 unlock_pup; /* bit array of unlock pups */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 adll_val = MAX_DELAY;
+ u32 dqs_deskew_val = 0; /* current value of DQS PBS deskew */
+ u32 cur_max_pup, pup, pass_pup;
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ /* Set current pup number */
+ if (cur_pup == 0x1) /* Ecc mode */
+ cur_max_pup = 1;
+ else
+ cur_max_pup = dram_info->num_of_std_pups;
+
+ unlock_pup = cur_pup; /* '1' for each unlocked pup */
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Starting...\n");
+
+ /* Set DQS ADLL to MAX */
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Set DQS ADLL to Max for all PUPs\n");
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0, pup + ecc * ECC_PUP, 0,
+ MAX_DELAY);
+
+ /* Loop on all ADLL Vaules */
+ do {
+ /* Loop until found fail for all pups */
+ new_lockup_pup = 0;
+ if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ pattern_ptr, LEN_PBS_PATTERN,
+ SDRAM_PBS_I_OFFS +
+ pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS,
+ 0, 0, NULL, 0)) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP(ddr3_sdram_compare)\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+ }
+
+ if ((new_lockup_pup != 0) && (dqs_deskew_val <= 1)) {
+ /* Fail on start with first deskew value */
+ /* Decrement DQS ADLL */
+ --adll_val;
+ if (adll_val == ADLL_MIN) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - fail on start with first deskew value\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+ }
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0, pup + ecc * ECC_PUP,
+ 0, adll_val);
+ continue;
+ }
+
+ /* Update all new locked pups */
+ unlock_pup &= ~new_lockup_pup;
+
+ if ((unlock_pup == 0) || (dqs_deskew_val == MAX_PBS)) {
+ if (dqs_deskew_val == MAX_PBS) {
+ /*
+ * Reach max value of dqs deskew or get fail
+ * for all pups
+ */
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - DQS deskew reached maximum value\n");
+ }
+ break;
+ }
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Inc DQS deskew for PUPs: ");
+ DEBUG_PBS_FULL_D(unlock_pup, 2);
+ DEBUG_PBS_FULL_C(", deskew = ", dqs_deskew_val, 2);
+
+ /* Increment DQS deskew elements - Only for unlocked pups */
+ dqs_deskew_val++;
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ ddr3_write_pup_reg(PUP_PBS_RX + DQS_DQ_NUM, CS0,
+ pup + ecc * ECC_PUP, 0,
+ dqs_deskew_val);
+ }
+ }
+ } while (1);
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - ADLL shift one step before fail\n");
+ /* Continue to ADLL shift one step before fail */
+ unlock_pup = cur_pup;
+ do {
+ /* Loop until pass compare for all pups */
+ new_lockup_pup = 0;
+ /* Read and compare results */
+ if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup, &new_lockup_pup,
+ pattern_ptr, LEN_PBS_PATTERN,
+ SDRAM_PBS_I_OFFS +
+ pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS,
+ 1, 0, NULL, 0)) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP(ddr3_sdram_compare)\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+ }
+
+ /*
+ * Get mask for pup which passed so their adll will be
+ * changed to 2 steps before fails
+ */
+ pass_pup = unlock_pup & ~new_lockup_pup;
+
+ DEBUG_PBS_FULL_S("Shift DQS by 2 steps for PUPs: ");
+ DEBUG_PBS_FULL_D(pass_pup, 2);
+ DEBUG_PBS_FULL_C(", Set ADLL value = ", (adll_val - 2), 2);
+
+ /* Only for pass pups */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) == 1) {
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+ pup + ecc * ECC_PUP, 0,
+ (adll_val - 2));
+ }
+ }
+
+ /* Locked pups that compare success */
+ unlock_pup &= new_lockup_pup;
+
+ if (unlock_pup == 0) {
+ /* All pups locked */
+ break;
+ }
+
+ /* Found error */
+ if (adll_val == 0) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Shift DQS - Adll reach min value\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_MAX_VAL;
+ }
+
+ /*
+ * Decrement (Move Back to Left one phase - ADLL) dqs RX delay
+ */
+ adll_val--;
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+ pup + ecc * ECC_PUP, 0,
+ adll_val);
+ }
+ }
+ } while (1);
+
+ return MV_OK;
+}
+
+/*
+ * lock_pups() extracted from ddr3_pbs_per_bit(). This just got too
+ * much indented making it hard to read / edit.
+ */
+static void lock_pups(u32 pup, u32 *pup_locked, u8 *unlock_pup_dq_array,
+ u32 pbs_curr_val, u32 start_pbs, u32 ecc, int is_tx)
+{
+ u32 dq;
+ int idx;
+
+ /* Lock PBS value for all remaining PUPs bits */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Lock PBS value for all remaining PUPs bits, pup ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_C(" pbs value ", pbs_curr_val, 2);
+
+ idx = pup * (1 - ecc) + ecc * ECC_PUP;
+ *pup_locked &= ~(1 << pup);
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if (IS_PUP_ACTIVE(unlock_pup_dq_array[dq], pup) == 1) {
+ int offs;
+
+ /* Lock current dq */
+ unlock_pup_dq_array[dq] &= ~(1 << pup);
+ skew_array[(pup * DQ_NUM) + dq] = pbs_curr_val;
+
+ if (is_tx == 1)
+ offs = PUP_PBS_TX;
+ else
+ offs = PUP_PBS_RX;
+
+ ddr3_write_pup_reg(offs +
+ pbs_dq_mapping[idx][dq], CS0,
+ idx, 0, start_pbs);
+ }
+ }
+}
+
+/*
+ * Name: ddr3_pbs_per_bit
+ * Desc: Execute the Per Bit Skew phase.
+ * Args: start_over Return whether need to start over the algorithm
+ * is_tx Indicate whether Rx or Tx
+ * pcur_pup bit array of the function active pups. return the
+ * pups that need to repeat on the PBS
+ * pbs_pattern_idx Index of PBS pattern
+ *
+ * Notes: Current implementation supports double activation of this function.
+ * i.e. in order to activate this function (using start_over) more than
+ * twice, the implementation should change.
+ * imlementation limitation are marked using
+ * ' CHIP-ONLY! - Implementation Limitation '
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_pbs_per_bit(MV_DRAM_INFO *dram_info, int *start_over, int is_tx,
+ u32 *pcur_pup, u32 pbs_pattern_idx, u32 ecc)
+{
+ /*
+ * Bit array to indicate if we already get fail on bit per pup & dq bit
+ */
+ u8 unlock_pup_dq_array[DQ_NUM] = {
+ *pcur_pup, *pcur_pup, *pcur_pup, *pcur_pup, *pcur_pup,
+ *pcur_pup, *pcur_pup, *pcur_pup
+ };
+
+ u8 cmp_unlock_pup_dq_array[COUNT_PBS_COMP_RETRY_NUM][DQ_NUM];
+ u32 pup, dq;
+ /* value of pbs is according to RX or TX */
+ u32 start_pbs, last_pbs;
+ u32 pbs_curr_val;
+ /* bit array that indicates all dq of the pup locked */
+ u32 pup_locked;
+ u32 first_fail[MAX_PUP_NUM] = { 0 }; /* count first fail per pup */
+ /* indicates whether we get first fail per pup */
+ int first_failed[MAX_PUP_NUM] = { 0 };
+ /* bit array that indicates pup already get fail */
+ u32 sum_pup_fail;
+ /* use to calculate diff between curr pbs to first fail pbs */
+ u32 calc_pbs_diff;
+ u32 pbs_cmp_retry;
+ u32 max_pup;
+
+ /* Set init values for retry array - 8 retry */
+ for (pbs_cmp_retry = 0; pbs_cmp_retry < COUNT_PBS_COMP_RETRY_NUM;
+ pbs_cmp_retry++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ cmp_unlock_pup_dq_array[pbs_cmp_retry][dq] = *pcur_pup;
+ }
+
+ memset(&skew_array, 0, MAX_PUP_NUM * DQ_NUM * sizeof(u32));
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Started\n");
+
+ /* The pbs value depends if rx or tx */
+ if (is_tx == 1) {
+ start_pbs = MIN_PBS;
+ last_pbs = MAX_PBS;
+ } else {
+ start_pbs = MAX_PBS;
+ last_pbs = MIN_PBS;
+ }
+
+ pbs_curr_val = start_pbs;
+ pup_locked = *pcur_pup;
+
+ /* Set current pup number */
+ if (pup_locked == 0x1) /* Ecc mode */
+ max_pup = 1;
+ else
+ max_pup = dram_info->num_of_std_pups;
+
+ do {
+ /* Increment/ decrement PBS for un-lock bits only */
+ if (is_tx == 1)
+ pbs_curr_val++;
+ else
+ pbs_curr_val--;
+
+ /* Set Current PBS delay */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Check DQ bits to see if locked in all pups */
+ if (unlock_pup_dq_array[dq] == 0) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - All pups are locked for DQ ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S("\n");
+ continue;
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ int idx;
+
+ idx = pup * (1 - ecc) + ecc * ECC_PUP;
+
+ if (IS_PUP_ACTIVE(unlock_pup_dq_array[dq], pup)
+ == 0)
+ continue;
+
+ if (is_tx == 1)
+ ddr3_write_pup_reg(
+ PUP_PBS_TX + pbs_dq_mapping[idx][dq],
+ CS0, idx, 0, pbs_curr_val);
+ else
+ ddr3_write_pup_reg(
+ PUP_PBS_RX + pbs_dq_mapping[idx][dq],
+ CS0, idx, 0, pbs_curr_val);
+ }
+ }
+
+ /*
+ * Write Read and compare results - run the test
+ * DDR_PBS_COMP_RETRY_NUM times
+ */
+ /* Run number of read and write to verify */
+ for (pbs_cmp_retry = 0;
+ pbs_cmp_retry < COUNT_PBS_COMP_RETRY_NUM;
+ pbs_cmp_retry++) {
+
+ if (MV_OK !=
+ ddr3_sdram_pbs_compare(dram_info, pup_locked, is_tx,
+ pbs_pattern_idx,
+ pbs_curr_val, start_pbs,
+ skew_array,
+ cmp_unlock_pup_dq_array
+ [pbs_cmp_retry], ecc))
+ return MV_FAIL;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if ((IS_PUP_ACTIVE(unlock_pup_dq_array[dq],
+ pup) == 1)
+ && (IS_PUP_ACTIVE(cmp_unlock_pup_dq_array
+ [pbs_cmp_retry][dq],
+ pup) == 0)) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - PbsCurrVal: ");
+ DEBUG_PBS_FULL_D(pbs_curr_val, 2);
+ DEBUG_PBS_FULL_S(" PUP: ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_S(" DQ: ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S(" - failed\n");
+ }
+ }
+ }
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ unlock_pup_dq_array[dq] &=
+ cmp_unlock_pup_dq_array[pbs_cmp_retry][dq];
+ }
+ }
+
+ pup_locked = 0;
+ sum_pup_fail = *pcur_pup;
+
+ /* Check which DQ is failed */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Summarize the locked pup */
+ pup_locked |= unlock_pup_dq_array[dq];
+
+ /* Check if get fail */
+ sum_pup_fail &= unlock_pup_dq_array[dq];
+ }
+
+ /* If all PUPS are locked in all DQ - Break */
+ if (pup_locked == 0) {
+ /* All pups are locked */
+ *start_over = 0;
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - All bit in all pups are successfully locked\n");
+ break;
+ }
+
+ /* PBS deskew elements reach max ? */
+ if (pbs_curr_val == last_pbs) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - PBS deskew elements reach max\n");
+ /* CHIP-ONLY! - Implementation Limitation */
+ *start_over = (sum_pup_fail != 0) && (!(*start_over));
+ *pcur_pup = pup_locked;
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - StartOver: ");
+ DEBUG_PBS_FULL_D(*start_over, 1);
+ DEBUG_PBS_FULL_S(" pup_locked: ");
+ DEBUG_PBS_FULL_D(pup_locked, 2);
+ DEBUG_PBS_FULL_S(" sum_pup_fail: ");
+ DEBUG_PBS_FULL_D(sum_pup_fail, 2);
+ DEBUG_PBS_FULL_S("\n");
+
+ /* Lock PBS value for all remaining bits */
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Check if current pup already received error */
+ if (IS_PUP_ACTIVE(pup_locked, pup) == 1) {
+ /* Valid pup for current function */
+ if (IS_PUP_ACTIVE(sum_pup_fail, pup) ==
+ 1 && (*start_over == 1)) {
+ DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - skipping lock of pup (first loop of pbs)",
+ pup, 1);
+ continue;
+ } else
+ if (IS_PUP_ACTIVE(sum_pup_fail, pup)
+ == 1) {
+ DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - Locking pup %d (even though it wasn't supposed to be locked)",
+ pup, 1);
+ }
+
+ /* Already got fail on the PUP */
+ /* Lock PBS value for all remaining bits */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Locking remaning DQs for pup - ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if (IS_PUP_ACTIVE
+ (unlock_pup_dq_array[dq],
+ pup) == 1) {
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S(",");
+ /* set current PBS */
+ skew_array[((pup) *
+ DQ_NUM) +
+ dq] =
+ pbs_curr_val;
+ }
+ }
+
+ if (*start_over == 1) {
+ /*
+ * Reset this pup bit - when
+ * restart the PBS, ignore this
+ * pup
+ */
+ *pcur_pup &= ~(1 << pup);
+ }
+ DEBUG_PBS_FULL_S("\n");
+ } else {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Pup ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_C(" is not set in puplocked - ",
+ pup_locked, 1);
+ }
+ }
+
+ /* Need to start the PBS again */
+ if (*start_over == 1) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - false fail - returning to start\n");
+ return MV_OK;
+ }
+ break;
+ }
+
+ /* Diff Check */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pup_locked, pup) == 1) {
+ /* pup is not locked */
+ if (first_failed[pup] == 0) {
+ /* No first fail until now */
+ if (IS_PUP_ACTIVE(sum_pup_fail, pup) ==
+ 0) {
+ /* Get first fail */
+ DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - First fail in pup ",
+ pup, 1);
+ first_failed[pup] = 1;
+ first_fail[pup] = pbs_curr_val;
+ }
+ } else {
+ /* Already got first fail */
+ if (is_tx == 1) {
+ /* TX - inc pbs */
+ calc_pbs_diff = pbs_curr_val -
+ first_fail[pup];
+ } else {
+ /* RX - dec pbs */
+ calc_pbs_diff = first_fail[pup] -
+ pbs_curr_val;
+ }
+
+ if (calc_pbs_diff >= PBS_DIFF_LIMIT) {
+ lock_pups(pup, &pup_locked,
+ unlock_pup_dq_array,
+ pbs_curr_val,
+ start_pbs, ecc, is_tx);
+ }
+ }
+ }
+ }
+ } while (1);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_set_pbs_results
+ * Desc: Set to HW the PBS phase results.
+ * Args: is_tx Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_set_pbs_results(MV_DRAM_INFO *dram_info, int is_tx)
+{
+ u32 pup, phys_pup, dq;
+ u32 max_pup; /* number of valid pups */
+ u32 pbs_min; /* minimal pbs val per pup */
+ u32 pbs_max; /* maximum pbs val per pup */
+ u32 val[9];
+
+ max_pup = dram_info->num_of_total_pups;
+ DEBUG_PBS_FULL_S("DDR3 - PBS - ddr3_set_pbs_results:\n");
+
+ /* Loop for all dqs & pups */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (pup == (max_pup - 1) && dram_info->ecc_ena)
+ phys_pup = ECC_PUP;
+ else
+ phys_pup = pup;
+
+ /*
+ * To minimize delay elements, inc from pbs value the min
+ * pbs val
+ */
+ pbs_min = MAX_PBS;
+ pbs_max = 0;
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if (pbs_min > skew_array[(pup * DQ_NUM) + dq])
+ pbs_min = skew_array[(pup * DQ_NUM) + dq];
+
+ if (pbs_max < skew_array[(pup * DQ_NUM) + dq])
+ pbs_max = skew_array[(pup * DQ_NUM) + dq];
+ }
+
+ pbs_max -= pbs_min;
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_FULL_D(phys_pup, 1);
+ DEBUG_PBS_FULL_S(": Min Val = ");
+ DEBUG_PBS_FULL_D(pbs_min, 2);
+ DEBUG_PBS_FULL_C(", Max Val = ", pbs_max, 2);
+
+ val[pup] = 0;
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ int idx;
+ int offs;
+
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+
+ DEBUG_PBS_FULL_S("DQ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S("-");
+ DEBUG_PBS_FULL_D((skew_array[(pup * DQ_NUM) + dq] -
+ pbs_min), 2);
+ DEBUG_PBS_FULL_S(", ");
+
+ idx = (pup * DQ_NUM) + dq;
+
+ if (is_tx == 1)
+ offs = PUP_PBS_TX;
+ else
+ offs = PUP_PBS_RX;
+
+ ddr3_write_pup_reg(offs + pbs_dq_mapping[phys_pup][dq],
+ CS0, phys_pup, 0,
+ skew_array[idx] - pbs_min);
+
+ if (is_tx == 1)
+ val[pup] += skew_array[idx] - pbs_min;
+ }
+
+ DEBUG_PBS_FULL_S("\n");
+
+ /* Set the DQS the half of the Max PBS of the DQs */
+ if (is_tx == 1) {
+ ddr3_write_pup_reg(PUP_PBS_TX + 8, CS0, phys_pup, 0,
+ pbs_max / 2);
+ ddr3_write_pup_reg(PUP_PBS_TX + 0xa, CS0, phys_pup, 0,
+ val[pup] / 8);
+ } else
+ ddr3_write_pup_reg(PUP_PBS_RX + 8, CS0, phys_pup, 0,
+ pbs_max / 2);
+ }
+
+ return MV_OK;
+}
+
+static void ddr3_pbs_write_pup_dqs_reg(u32 cs, u32 pup, u32 dqs_delay)
+{
+ u32 reg, delay;
+
+ reg = (ddr3_read_pup_reg(PUP_WL_MODE, cs, pup) & 0x3FF);
+ delay = reg & PUP_DELAY_MASK;
+ reg |= ((dqs_delay + delay) << REG_PHY_DQS_REF_DLY_OFFS);
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg |= (pup << REG_PHY_PUP_OFFS);
+ reg |= ((0x4 * cs + PUP_WL_MODE) << REG_PHY_CS_OFFS);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+
+ udelay(10);
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_pbs_patterns(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cs_count, cs_tmp;
+ u32 sdram_addr;
+ u32 *pattern_ptr0, *pattern_ptr1;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr0 = (u32 *)&pbs_pattern[0];
+ pattern_ptr1 = (u32 *)&pbs_pattern[1];
+ break;
+#endif
+ case 32:
+ pattern_ptr0 = (u32 *)&pbs_pattern_32b[0];
+ pattern_ptr1 = (u32 *)&pbs_pattern_32b[1];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr0 = (u32 *)&pbs_pattern_64b[0];
+ pattern_ptr1 = (u32 *)&pbs_pattern_64b[1];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+
+ /* Init PBS I pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_PBS_I_OFFS);
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, (u32) NULL, NULL,
+ pattern_ptr0, LEN_STD_PATTERN,
+ sdram_addr, 1, 0, NULL,
+ 0))
+ return MV_FAIL;
+
+ /* Init PBS II pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_PBS_II_OFFS);
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, (u32) NULL, NULL,
+ pattern_ptr1, LEN_STD_PATTERN,
+ sdram_addr, 1, 0, NULL,
+ 0))
+ return MV_FAIL;
+ }
+ }
+
+ return MV_OK;
+}
+#endif
diff --git a/drivers/ddr/marvell/axp/ddr3_read_leveling.c b/drivers/ddr/marvell/axp/ddr3_read_leveling.c
new file mode 100644
index 0000000000..4662bde994
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_read_leveling.c
@@ -0,0 +1,1214 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_RL_C(s, d, l) \
+ DEBUG_RL_S(s); DEBUG_RL_D(d, l); DEBUG_RL_S("\n")
+#define DEBUG_RL_FULL_C(s, d, l) \
+ DEBUG_RL_FULL_S(s); DEBUG_RL_FULL_D(d, l); DEBUG_RL_FULL_S("\n")
+
+#ifdef MV_DEBUG_RL
+#define DEBUG_RL_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_RL_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+#else
+#define DEBUG_RL_S(s)
+#define DEBUG_RL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_RL_FULL
+#define DEBUG_RL_FULL_S(s) puts(s)
+#define DEBUG_RL_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_RL_FULL_S(s)
+#define DEBUG_RL_FULL_D(d, l)
+#endif
+
+extern u32 rl_pattern[LEN_STD_PATTERN];
+
+#ifdef RL_MODE
+static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info);
+#else
+static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info);
+#endif
+
+/*
+ * Name: ddr3_read_leveling_hw
+ * Desc: Execute the Read leveling phase by HW
+ * Args: dram_info - main struct
+ * freq - current sequence frequency
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
+{
+ u32 reg;
+
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_RL_S("DDR3 - Read Leveling - Starting HW RL procedure\n");
+
+ /* Start Auto Read Leveling procedure */
+ reg = 1 << REG_DRAM_TRAINING_RL_OFFS;
+ /* Config the retest number */
+ reg |= (COUNT_HW_RL << REG_DRAM_TRAINING_RETEST_OFFS);
+
+ /* Enable CS in the automatic process */
+ reg |= (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS);
+
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+ /* Wait */
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Check if Successful */
+ if (reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+ u32 delay, phase, pup, cs;
+
+ dram_info->rl_max_phase = 0;
+ dram_info->rl_min_phase = 10;
+
+ /* Read results to arrays */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ reg =
+ ddr3_read_pup_reg(PUP_RL_MODE, cs,
+ pup);
+ phase = (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ delay = reg & PUP_DELAY_MASK;
+ dram_info->rl_val[cs][pup][P] = phase;
+ if (phase > dram_info->rl_max_phase)
+ dram_info->rl_max_phase = phase;
+ if (phase < dram_info->rl_min_phase)
+ dram_info->rl_min_phase = phase;
+ dram_info->rl_val[cs][pup][D] = delay;
+ dram_info->rl_val[cs][pup][S] =
+ RL_FINAL_STATE;
+ reg =
+ ddr3_read_pup_reg(PUP_RL_MODE + 0x1,
+ cs, pup);
+ dram_info->rl_val[cs][pup][DQS] =
+ (reg & 0x3F);
+ }
+#ifdef MV_DEBUG_RL
+ /* Print results */
+ DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ",
+ (u32) cs, 1);
+
+ for (pup = 0;
+ pup < (dram_info->num_of_total_pups);
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
+ DEBUG_RL_D((u32) pup, 1);
+ DEBUG_RL_S(", Phase: ");
+ DEBUG_RL_D((u32) dram_info->
+ rl_val[cs][pup][P], 1);
+ DEBUG_RL_S(", Delay: ");
+ DEBUG_RL_D((u32) dram_info->
+ rl_val[cs][pup][D], 2);
+ DEBUG_RL_S("\n");
+ }
+#endif
+ }
+ }
+
+ dram_info->rd_rdy_dly =
+ reg_read(REG_READ_DATA_READY_DELAYS_ADDR) &
+ REG_READ_DATA_SAMPLE_DELAYS_MASK;
+ dram_info->rd_smpl_dly =
+ reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR) &
+ REG_READ_DATA_READY_DELAYS_MASK;
+#ifdef MV_DEBUG_RL
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
+ dram_info->rd_smpl_dly, 2);
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
+ dram_info->rd_rdy_dly, 2);
+ DEBUG_RL_S("DDR3 - Read Leveling - HW RL Ended Successfully\n");
+#endif
+ return MV_OK;
+
+ } else {
+ DEBUG_RL_S("DDR3 - Read Leveling - HW RL Error\n");
+ return MV_FAIL;
+ }
+}
+
+/*
+ * Name: ddr3_read_leveling_sw
+ * Desc: Execute the Read leveling phase by SW
+ * Args: dram_info - main struct
+ * freq - current sequence frequency
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, cs, ecc, pup_num, phase, delay, pup;
+ int status;
+
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_RL_S("DDR3 - Read Leveling - Starting SW RL procedure\n");
+
+ /* Enable SW Read Leveling */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS);
+ /* [0]=1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+#ifdef RL_MODE
+ reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+#endif
+
+ /* Loop for each CS */
+ for (cs = 0; cs < dram_info->num_cs; cs++) {
+ DEBUG_RL_C("DDR3 - Read Leveling - CS - ", (u32) cs, 1);
+
+ for (ecc = 0; ecc <= (dram_info->ecc_ena); ecc++) {
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_RL_S("DDR3 - Read Leveling - ECC Mux Enabled\n");
+ else
+ DEBUG_RL_S("DDR3 - Read Leveling - ECC Mux Disabled\n");
+
+ /* Set current sample delays */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg |= (dram_info->cl <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+ /* Set current Ready delay */
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ reg |= ((dram_info->cl + 1) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ } else {
+ /* 2:1 mode */
+ reg |= ((dram_info->cl + 2) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ }
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+
+ /* Read leveling Single CS[cs] */
+#ifdef RL_MODE
+ status =
+ ddr3_read_leveling_single_cs_rl_mode(cs, freq,
+ ratio_2to1,
+ ecc,
+ dram_info);
+ if (MV_OK != status)
+ return status;
+#else
+ status =
+ ddr3_read_leveling_single_cs_window_mode(cs, freq,
+ ratio_2to1,
+ ecc,
+ dram_info)
+ if (MV_OK != status)
+ return status;
+#endif
+ }
+
+ /* Print results */
+ DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ", (u32) cs,
+ 1);
+
+ for (pup = 0;
+ pup < (dram_info->num_of_std_pups + dram_info->ecc_ena);
+ pup++) {
+ DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
+ DEBUG_RL_D((u32) pup, 1);
+ DEBUG_RL_S(", Phase: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][P], 1);
+ DEBUG_RL_S(", Delay: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][D], 2);
+ DEBUG_RL_S("\n");
+ }
+
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
+ dram_info->rd_smpl_dly, 2);
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
+ dram_info->rd_rdy_dly, 2);
+
+ /* Configure PHY with average of 3 locked leveling settings */
+ for (pup = 0;
+ pup < (dram_info->num_of_std_pups + dram_info->ecc_ena);
+ pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ? ECC_BIT : pup;
+
+ /* For now, set last cnt result */
+ phase = dram_info->rl_val[cs][pup][P];
+ delay = dram_info->rl_val[cs][pup][D];
+ ddr3_write_pup_reg(PUP_RL_MODE, cs, pup_num, phase,
+ delay);
+ }
+ }
+
+ /* Reset PHY read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* ECC Support - Switch ECC Mux off ecc=0 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+#ifdef RL_MODE
+ reg_write(REG_DRAM_TRAINING_ADDR, 0); /* 0x15B0 - Training Register */
+#endif
+
+ /* Disable SW Read Leveling */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 0 - Disable SW override */
+ reg = (reg | (0x1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS));
+ /* [3] = 1 - Disable RL MODE */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ DEBUG_RL_S("DDR3 - Read Leveling - Finished RL procedure for all CS\n");
+ return MV_OK;
+}
+
+#ifdef RL_MODE
+/*
+ * overrun() extracted from ddr3_read_leveling_single_cs_rl_mode().
+ * This just got too much indented making it hard to read / edit.
+ */
+static void overrun(u32 cs, MV_DRAM_INFO *info, u32 pup, u32 locked_pups,
+ u32 *locked_sum, u32 ecc, int *first_octet_locked,
+ int *counter_in_progress, int final_delay, u32 delay,
+ u32 phase)
+{
+ /* If no OverRun */
+ if (((~locked_pups >> pup) & 0x1) && (final_delay == 0)) {
+ int idx;
+
+ idx = pup + ecc * ECC_BIT;
+
+ /* PUP passed, start examining */
+ if (info->rl_val[cs][idx][S] == RL_UNLOCK_STATE) {
+ /* Must be RL_UNLOCK_STATE */
+ /* Match expected value ? - Update State Machine */
+ if (info->rl_val[cs][idx][C] < RL_RETRY_COUNT) {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
+ (u32)pup, 1);
+ info->rl_val[cs][idx][C]++;
+
+ /* If pup got to last state - lock the delays */
+ if (info->rl_val[cs][idx][C] == RL_RETRY_COUNT) {
+ info->rl_val[cs][idx][C] = 0;
+ info->rl_val[cs][idx][DS] = delay;
+ info->rl_val[cs][idx][PS] = phase;
+
+ /* Go to Final State */
+ info->rl_val[cs][idx][S] = RL_FINAL_STATE;
+ *locked_sum = *locked_sum + 1;
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have locked pup: ",
+ (u32)pup, 1);
+
+ /*
+ * If first lock - need to lock delays
+ */
+ if (*first_octet_locked == 0) {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
+ (u32)pup, 1);
+ *first_octet_locked = 1;
+ }
+
+ /*
+ * If pup is in not in final state but
+ * there was match - dont increment
+ * counter
+ */
+ } else {
+ *counter_in_progress = 1;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Name: ddr3_read_leveling_single_cs_rl_mode
+ * Desc: Execute Read leveling for single Chip select
+ * Args: cs - current chip select
+ * freq - current sequence frequency
+ * ecc - ecc iteration indication
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info)
+{
+ u32 reg, delay, phase, pup, rd_sample_delay, add, locked_pups,
+ repeat_max_cnt, sdram_offset, locked_sum;
+ u32 phase_min, ui_max_delay;
+ int all_locked, first_octet_locked, counter_in_progress;
+ int final_delay = 0;
+
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);
+
+ /* Init values */
+ phase = 0;
+ delay = 0;
+ rd_sample_delay = dram_info->cl;
+ all_locked = 0;
+ first_octet_locked = 0;
+ repeat_max_cnt = 0;
+ locked_sum = 0;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++)
+ dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;
+
+ /* Main loop */
+ while (!all_locked) {
+ counter_in_progress = 0;
+
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
+ DEBUG_RL_FULL_D(rd_sample_delay, 2);
+ DEBUG_RL_FULL_S(", RdRdyDly = ");
+ DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
+ DEBUG_RL_FULL_S(", Phase = ");
+ DEBUG_RL_FULL_D(phase, 1);
+ DEBUG_RL_FULL_S(", Delay = ");
+ DEBUG_RL_FULL_D(delay, 2);
+ DEBUG_RL_FULL_S("\n");
+
+ /*
+ * Broadcast to all PUPs current RL delays: DQS phase,
+ * leveling delay
+ */
+ ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);
+
+ /* Reset PHY read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Read pattern from SDRAM */
+ sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
+ locked_pups = 0;
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
+ rl_pattern, LEN_STD_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PATTERN;
+
+ /* Octet evaluation */
+ /* pup_num = Q or 1 for ECC */
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+ /* Check Overrun */
+ if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
+ (REG_DRAM_TRAINING_2_OVERRUN_OFFS + pup)) & 0x1)) {
+ overrun(cs, dram_info, pup, locked_pups,
+ &locked_sum, ecc, &first_octet_locked,
+ &counter_in_progress, final_delay,
+ delay, phase);
+ } else {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
+ (u32)pup, 1);
+ }
+ }
+
+ if (locked_sum == (dram_info->num_of_std_pups *
+ (1 - ecc) + ecc)) {
+ all_locked = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
+ }
+
+ /*
+ * This is a fix for unstable condition where pups are
+ * toggling between match and no match
+ */
+ /*
+ * If some of the pups is >1 <3, check if we did it too
+ * many times
+ */
+ if (counter_in_progress == 1) {
+ /* Notify at least one Counter is >=1 and < 3 */
+ if (repeat_max_cnt < RL_RETRY_COUNT) {
+ repeat_max_cnt++;
+ counter_in_progress = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
+ counter_in_progress = 0;
+ }
+ }
+
+ /*
+ * Check some of the pups are in the middle of state machine
+ * and don't increment the delays
+ */
+ if (!counter_in_progress && !all_locked) {
+ int idx;
+
+ idx = pup + ecc * ECC_BIT;
+
+ repeat_max_cnt = 0;
+ /* if 1:1 mode */
+ if ((!ratio_2to1) && ((phase == 0) || (phase == 4)))
+ ui_max_delay = MAX_DELAY_INV;
+ else
+ ui_max_delay = MAX_DELAY;
+
+ /* Increment Delay */
+ if (delay < ui_max_delay) {
+ delay++;
+ /*
+ * Mark the last delay/pahse place for
+ * window final place
+ */
+ if (delay == ui_max_delay) {
+ if ((!ratio_2to1 && phase ==
+ MAX_PHASE_RL_L_1TO1)
+ || (ratio_2to1 && phase ==
+ MAX_PHASE_RL_L_2TO1))
+ final_delay = 1;
+ }
+ } else {
+ /* Phase+CL Incrementation */
+ delay = 0;
+
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ if (first_octet_locked) {
+ /* some Pup was Locked */
+ if (phase < MAX_PHASE_RL_L_1TO1) {
+ if (phase == 1) {
+ phase = 4;
+ } else {
+ phase++;
+ delay = MIN_DELAY_PHASE_1_LIMIT;
+ }
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ DEBUG_RL_S("1)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked n");
+ return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK;
+ }
+ } else {
+ /* NO Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_1TO1) {
+ phase++;
+ delay =
+ MIN_DELAY_PHASE_1_LIMIT;
+ } else {
+ phase = 0;
+ }
+ }
+ } else {
+ /* 2:1 mode */
+ if (first_octet_locked) {
+ /* some Pup was Locked */
+ if (phase < MAX_PHASE_RL_L_2TO1) {
+ phase++;
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ DEBUG_RL_S("2)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+ /* pup_num = Q or 1 for ECC */
+ if (dram_info->rl_val[cs][idx][S]
+ == 0) {
+ DEBUG_RL_C("Failed byte is = ",
+ pup, 1);
+ }
+ }
+ return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK;
+ }
+ } else {
+ /* No Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_2TO1)
+ phase++;
+ else
+ phase = 0;
+ }
+ }
+
+ /*
+ * If we finished a full Phases cycle (so now
+ * phase = 0, need to increment rd_sample_dly
+ */
+ if (phase == 0 && first_octet_locked == 0) {
+ rd_sample_delay++;
+ if (rd_sample_delay == 0x10) {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ DEBUG_RL_S("3)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+ /* pup_num = Q or 1 for ECC */
+ if (dram_info->
+ rl_val[cs][idx][S] == 0) {
+ DEBUG_RL_C("Failed byte is = ",
+ pup, 1);
+ }
+ }
+ return MV_DDR3_TRAINING_ERR_RD_LVL_PUP_UNLOCK;
+ }
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK
+ << (REG_READ_DATA_SAMPLE_DELAYS_OFFS
+ * cs));
+ reg |= (rd_sample_delay <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS *
+ cs));
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
+ reg);
+ }
+
+ /*
+ * Set current rdReadyDelay according to the
+ * hash table (Need to do this in every phase
+ * change)
+ */
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase) {
+ case 0:
+ add = (add >>
+ REG_TRAINING_DEBUG_2_OFFS);
+ break;
+ case 1:
+ add = (add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 3));
+ break;
+ case 4:
+ add = (add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 6));
+ break;
+ case 5:
+ add = (add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 9));
+ break;
+ }
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ } else {
+ /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >>
+ (phase *
+ REG_TRAINING_DEBUG_3_OFFS));
+ add &= REG_TRAINING_DEBUG_3_MASK;
+ }
+
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((rd_sample_delay + add) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_smpl_dly = rd_sample_delay;
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+ }
+
+ /* Reset counters for pups with states<RD_STATE_COUNT */
+ for (pup = 0; pup <
+ (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++) {
+ if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
+ dram_info->rl_val[cs][idx][C] = 0;
+ }
+ }
+ }
+
+ phase_min = 10;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
+ if (dram_info->rl_val[cs][pup][PS] < phase_min)
+ phase_min = dram_info->rl_val[cs][pup][PS];
+ }
+
+ /*
+ * Set current rdReadyDelay according to the hash table (Need to
+ * do this in every phase change)
+ */
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase_min) {
+ case 0:
+ add = (add >> REG_TRAINING_DEBUG_2_OFFS);
+ break;
+ case 1:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
+ break;
+ case 4:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
+ break;
+ case 5:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
+ break;
+ }
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ } else {
+ /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >> (phase_min * REG_TRAINING_DEBUG_3_OFFS));
+ add &= REG_TRAINING_DEBUG_3_MASK;
+ }
+
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+
+ for (cs = 0; cs < dram_info->num_cs; cs++) {
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
+ dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
+ }
+ }
+
+ return MV_OK;
+}
+
+#else
+
+/*
+ * Name: ddr3_read_leveling_single_cs_window_mode
+ * Desc: Execute Read leveling for single Chip select
+ * Args: cs - current chip select
+ * freq - current sequence frequency
+ * ecc - ecc iteration indication
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info)
+{
+ u32 reg, delay, phase, sum, pup, rd_sample_delay, add, locked_pups,
+ repeat_max_cnt, sdram_offset, final_sum, locked_sum;
+ u32 delay_s, delay_e, tmp, phase_min, ui_max_delay;
+ int all_locked, first_octet_locked, counter_in_progress;
+ int final_delay = 0;
+
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);
+
+ /* Init values */
+ phase = 0;
+ delay = 0;
+ rd_sample_delay = dram_info->cl;
+ all_locked = 0;
+ first_octet_locked = 0;
+ repeat_max_cnt = 0;
+ sum = 0;
+ final_sum = 0;
+ locked_sum = 0;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++)
+ dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;
+
+ /* Main loop */
+ while (!all_locked) {
+ counter_in_progress = 0;
+
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
+ DEBUG_RL_FULL_D(rd_sample_delay, 2);
+ DEBUG_RL_FULL_S(", RdRdyDly = ");
+ DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
+ DEBUG_RL_FULL_S(", Phase = ");
+ DEBUG_RL_FULL_D(phase, 1);
+ DEBUG_RL_FULL_S(", Delay = ");
+ DEBUG_RL_FULL_D(delay, 2);
+ DEBUG_RL_FULL_S("\n");
+
+ /*
+ * Broadcast to all PUPs current RL delays: DQS phase,leveling
+ * delay
+ */
+ ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);
+
+ /* Reset PHY read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Read pattern from SDRAM */
+ sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
+ locked_pups = 0;
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
+ rl_pattern, LEN_STD_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PATTERN;
+
+ /* Octet evaluation */
+ for (pup = 0; pup < (dram_info->num_of_std_pups *
+ (1 - ecc) + ecc); pup++) {
+ /* pup_num = Q or 1 for ECC */
+ int idx;
+
+ idx = pup + ecc * ECC_BIT;
+
+ /* Check Overrun */
+ if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
+ (REG_DRAM_TRAINING_2_OVERRUN_OFFS +
+ pup)) & 0x1)) {
+ /* If no OverRun */
+
+ /* Inside the window */
+ if (dram_info->rl_val[cs][idx][S] == RL_WINDOW_STATE) {
+ /*
+ * Match expected value ? - Update
+ * State Machine
+ */
+ if (((~locked_pups >> pup) & 0x1)
+ && (final_delay == 0)) {
+ /* Match - Still inside the Window */
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got another match inside the window for pup: ",
+ (u32)pup, 1);
+
+ } else {
+ /* We got fail -> this is the end of the window */
+ dram_info->rl_val[cs][idx][DE] = delay;
+ dram_info->rl_val[cs][idx][PE] = phase;
+ /* Go to Final State */
+ dram_info->rl_val[cs][idx][S]++;
+ final_sum++;
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We finished the window for pup: ",
+ (u32)pup, 1);
+ }
+
+ /* Before the start of the window */
+ } else if (dram_info->rl_val[cs][idx][S] ==
+ RL_UNLOCK_STATE) {
+ /* Must be RL_UNLOCK_STATE */
+ /*
+ * Match expected value ? - Update
+ * State Machine
+ */
+ if (dram_info->rl_val[cs][idx][C] <
+ RL_RETRY_COUNT) {
+ if (((~locked_pups >> pup) & 0x1)) {
+ /* Match */
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
+ (u32)pup, 1);
+ dram_info->rl_val[cs][idx][C]++;
+
+ /* If pup got to last state - lock the delays */
+ if (dram_info->rl_val[cs][idx][C] ==
+ RL_RETRY_COUNT) {
+ dram_info->rl_val[cs][idx][C] = 0;
+ dram_info->rl_val[cs][idx][DS] =
+ delay;
+ dram_info->rl_val[cs][idx][PS] =
+ phase;
+ dram_info->rl_val[cs][idx][S]++; /* Go to Window State */
+ locked_sum++;
+ /* Will count the pups that got locked */
+
+ /* IF First lock - need to lock delays */
+ if (first_octet_locked == 0) {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
+ (u32)pup, 1);
+ first_octet_locked
+ =
+ 1;
+ }
+ }
+
+ /* if pup is in not in final state but there was match - dont increment counter */
+ else {
+ counter_in_progress
+ = 1;
+ }
+ }
+ }
+ }
+ } else {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
+ (u32)pup, 1);
+ counter_in_progress = 1;
+ }
+ }
+
+ if (final_sum == (dram_info->num_of_std_pups * (1 - ecc) + ecc)) {
+ all_locked = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
+ }
+
+ /*
+ * This is a fix for unstable condition where pups are
+ * toggling between match and no match
+ */
+ /*
+ * If some of the pups is >1 <3, check if we did it too many
+ * times
+ */
+ if (counter_in_progress == 1) {
+ if (repeat_max_cnt < RL_RETRY_COUNT) {
+ /* Notify at least one Counter is >=1 and < 3 */
+ repeat_max_cnt++;
+ counter_in_progress = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
+ counter_in_progress = 0;
+ }
+ }
+
+ /*
+ * Check some of the pups are in the middle of state machine
+ * and don't increment the delays
+ */
+ if (!counter_in_progress && !all_locked) {
+ repeat_max_cnt = 0;
+ if (!ratio_2to1)
+ ui_max_delay = MAX_DELAY_INV;
+ else
+ ui_max_delay = MAX_DELAY;
+
+ /* Increment Delay */
+ if (delay < ui_max_delay) {
+ /* Delay Incrementation */
+ delay++;
+ if (delay == ui_max_delay) {
+ /*
+ * Mark the last delay/pahse place
+ * for window final place
+ */
+ if ((!ratio_2to1
+ && phase == MAX_PHASE_RL_L_1TO1)
+ || (ratio_2to1
+ && phase ==
+ MAX_PHASE_RL_L_2TO1))
+ final_delay = 1;
+ }
+ } else {
+ /* Phase+CL Incrementation */
+ delay = 0;
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ if (first_octet_locked) {
+ /* some pupet was Locked */
+ if (phase < MAX_PHASE_RL_L_1TO1) {
+#ifdef RL_WINDOW_WA
+ if (phase == 0)
+#else
+ if (phase == 1)
+#endif
+ phase = 4;
+ else
+ phase++;
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
+ }
+ } else {
+ /* No Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_1TO1) {
+#ifdef RL_WINDOW_WA
+ if (phase == 0)
+ phase = 4;
+#else
+ phase++;
+#endif
+ } else
+ phase = 0;
+ }
+ } else {
+ /* 2:1 mode */
+ if (first_octet_locked) {
+ /* Some Pup was Locked */
+ if (phase < MAX_PHASE_RL_L_2TO1) {
+ phase++;
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
+ }
+ } else {
+ /* No Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_2TO1)
+ phase++;
+ else
+ phase = 0;
+ }
+ }
+
+ /*
+ * If we finished a full Phases cycle (so
+ * now phase = 0, need to increment
+ * rd_sample_dly
+ */
+ if (phase == 0 && first_octet_locked == 0) {
+ rd_sample_delay++;
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS
+ * cs));
+ reg |= (rd_sample_delay <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS *
+ cs));
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
+ reg);
+ }
+
+ /*
+ * Set current rdReadyDelay according to the
+ * hash table (Need to do this in every phase
+ * change)
+ */
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase) {
+ case 0:
+ add = add >>
+ REG_TRAINING_DEBUG_2_OFFS;
+ break;
+ case 1:
+ add = add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 3);
+ break;
+ case 4:
+ add = add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 6);
+ break;
+ case 5:
+ add = add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 9);
+ break;
+ }
+ } else {
+ /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >> phase *
+ REG_TRAINING_DEBUG_3_OFFS);
+ }
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((rd_sample_delay + add) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_smpl_dly = rd_sample_delay;
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+ }
+
+ /* Reset counters for pups with states<RD_STATE_COUNT */
+ for (pup = 0;
+ pup <
+ (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++) {
+ if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
+ dram_info->rl_val[cs][idx][C] = 0;
+ }
+ }
+ }
+
+ phase_min = 10;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
+ DEBUG_RL_S("DDR3 - Read Leveling - Window info - PUP: ");
+ DEBUG_RL_D((u32) pup, 1);
+ DEBUG_RL_S(", PS: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PS], 1);
+ DEBUG_RL_S(", DS: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DS], 2);
+ DEBUG_RL_S(", PE: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PE], 1);
+ DEBUG_RL_S(", DE: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DE], 2);
+ DEBUG_RL_S("\n");
+ }
+
+ /* Find center of the window procedure */
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++) {
+#ifdef RL_WINDOW_WA
+ if (!ratio_2to1) { /* 1:1 mode */
+ if (dram_info->rl_val[cs][idx][PS] == 4)
+ dram_info->rl_val[cs][idx][PS] = 1;
+ if (dram_info->rl_val[cs][idx][PE] == 4)
+ dram_info->rl_val[cs][idx][PE] = 1;
+
+ delay_s = dram_info->rl_val[cs][idx][PS] *
+ MAX_DELAY_INV + dram_info->rl_val[cs][idx][DS];
+ delay_e = dram_info->rl_val[cs][idx][PE] *
+ MAX_DELAY_INV + dram_info->rl_val[cs][idx][DE];
+
+ tmp = (delay_e - delay_s) / 2 + delay_s;
+ phase = tmp / MAX_DELAY_INV;
+ if (phase == 1) /* 1:1 mode */
+ phase = 4;
+
+ if (phase < phase_min) /* for the read ready delay */
+ phase_min = phase;
+
+ dram_info->rl_val[cs][idx][P] = phase;
+ dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY_INV;
+
+ } else {
+ delay_s = dram_info->rl_val[cs][idx][PS] *
+ MAX_DELAY + dram_info->rl_val[cs][idx][DS];
+ delay_e = dram_info->rl_val[cs][idx][PE] *
+ MAX_DELAY + dram_info->rl_val[cs][idx][DE];
+
+ tmp = (delay_e - delay_s) / 2 + delay_s;
+ phase = tmp / MAX_DELAY;
+
+ if (phase < phase_min) /* for the read ready delay */
+ phase_min = phase;
+
+ dram_info->rl_val[cs][idx][P] = phase;
+ dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
+ }
+#else
+ if (!ratio_2to1) { /* 1:1 mode */
+ if (dram_info->rl_val[cs][idx][PS] > 1)
+ dram_info->rl_val[cs][idx][PS] -= 2;
+ if (dram_info->rl_val[cs][idx][PE] > 1)
+ dram_info->rl_val[cs][idx][PE] -= 2;
+ }
+
+ delay_s = dram_info->rl_val[cs][idx][PS] * MAX_DELAY +
+ dram_info->rl_val[cs][idx][DS];
+ delay_e = dram_info->rl_val[cs][idx][PE] * MAX_DELAY +
+ dram_info->rl_val[cs][idx][DE];
+
+ tmp = (delay_e - delay_s) / 2 + delay_s;
+ phase = tmp / MAX_DELAY;
+ if (!ratio_2to1 && phase > 1) /* 1:1 mode */
+ phase += 2;
+
+ if (phase < phase_min) /* for the read ready delay */
+ phase_min = phase;
+
+ dram_info->rl_val[cs][idx][P] = phase;
+ dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
+#endif
+ }
+
+ /* Set current rdReadyDelay according to the hash table (Need to do this in every phase change) */
+ if (!ratio_2to1) { /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase_min) {
+ case 0:
+ add = (add >> REG_TRAINING_DEBUG_2_OFFS);
+ break;
+ case 1:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
+ break;
+ case 4:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
+ break;
+ case 5:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
+ break;
+ }
+ } else { /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >> phase_min * REG_TRAINING_DEBUG_3_OFFS);
+ }
+
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &=
+ ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |=
+ ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+
+ for (cs = 0; cs < dram_info->num_cs; cs++) {
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
+ dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
+ }
+ }
+
+ return MV_OK;
+}
+#endif
diff --git a/drivers/ddr/marvell/axp/ddr3_sdram.c b/drivers/ddr/marvell/axp/ddr3_sdram.c
new file mode 100644
index 0000000000..50c1bf8361
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_sdram.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+#include "xor.h"
+#include "xor_regs.h"
+
+static void ddr3_flush_l1_line(u32 line);
+
+extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+#if defined(MV88F78X60)
+extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
+#endif
+extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+/* PBS locked dq (per pup) */
+u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
+u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
+u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
+
+int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+
+static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
+
+static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
+
+#define XOR_TIMEOUT 0x8000000
+
+struct xor_channel_t {
+ struct crc_dma_desc *desc;
+ unsigned long desc_phys_addr;
+};
+
+#define XOR_CAUSE_DONE_MASK(chan) ((0x1 | 0x2) << (chan * 16))
+
+void xor_waiton_eng(int chan)
+{
+ int timeout;
+
+ timeout = 0;
+ while (!(reg_read(XOR_CAUSE_REG(XOR_UNIT(chan))) &
+ XOR_CAUSE_DONE_MASK(XOR_CHAN(chan)))) {
+ if (timeout > XOR_TIMEOUT)
+ goto timeout;
+
+ timeout++;
+ }
+
+ timeout = 0;
+ while (mv_xor_state_get(chan) != MV_IDLE) {
+ if (timeout > XOR_TIMEOUT)
+ goto timeout;
+
+ timeout++;
+ }
+
+ /* Clear int */
+ reg_write(XOR_CAUSE_REG(XOR_UNIT(chan)),
+ ~(XOR_CAUSE_DONE_MASK(XOR_CHAN(chan))));
+
+timeout:
+ return;
+}
+
+static int special_compare_pattern(u32 uj)
+{
+ if ((uj == 30) || (uj == 31) || (uj == 61) || (uj == 62) ||
+ (uj == 93) || (uj == 94) || (uj == 126) || (uj == 127))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Compare code extracted as its used by multiple functions. This
+ * reduces code-size and makes it easier to maintain it. Additionally
+ * the code is not indented that much and therefore easier to read.
+ */
+static void compare_pattern_v1(u32 uj, u32 *pup, u32 *pattern,
+ u32 pup_groups, int debug_dqs)
+{
+ u32 val;
+ u32 uk;
+ u32 var1;
+ u32 var2;
+ __maybe_unused u32 dq;
+
+ if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0xFF)) {
+ for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+ val = CMP_BYTE_SHIFT * uk;
+ var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
+ var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
+
+ if (var1 != var2) {
+ *pup |= (1 << (uk + (PUP_NUM_32BIT *
+ (uj % pup_groups))));
+
+#ifdef MV_DEBUG_DQS
+ if (!debug_dqs)
+ continue;
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ val = uk + (PUP_NUM_32BIT *
+ (uj % pup_groups));
+ if (((var1 >> dq) & 0x1) !=
+ ((var2 >> dq) & 0x1))
+ per_bit_data[val][dq] = 1;
+ else
+ per_bit_data[val][dq] = 0;
+ }
+#endif
+ }
+ }
+ }
+}
+
+static void compare_pattern_v2(u32 uj, u32 *pup, u32 *pattern)
+{
+ u32 val;
+ u32 uk;
+ u32 var1;
+ u32 var2;
+
+ if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0x3)) {
+ /* Found error */
+ for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+ val = CMP_BYTE_SHIFT * uk;
+ var1 = (sdram_data[uj] >> val) & CMP_BYTE_MASK;
+ var2 = (pattern[uj] >> val) & CMP_BYTE_MASK;
+ if (var1 != var2)
+ *pup |= (1 << (uk % PUP_NUM_16BIT));
+ }
+ }
+}
+
+/*
+ * Name: ddr3_sdram_compare
+ * Desc: Execute compare per PUP
+ * Args: unlock_pup Bit array of the unlock pups
+ * new_locked_pup Output bit array of the pups with failed compare
+ * pattern Pattern to compare
+ * pattern_len Length of pattern (in bytes)
+ * sdram_offset offset address to the SDRAM
+ * write write to the SDRAM before read
+ * mask compare pattern with mask;
+ * mask_pattern Mask to compare pattern
+ *
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern,
+ int special_compare)
+{
+ u32 uj;
+ __maybe_unused u32 pup_groups;
+ __maybe_unused u32 dq;
+
+#if !defined(MV88F67XX)
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+#endif
+
+ ddr3_reset_phy_read_fifo();
+
+ /* Check if need to write to sdram before read */
+ if (write == 1)
+ ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
+
+ ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
+
+ /* Compare read result to write */
+ for (uj = 0; uj < pattern_len; uj++) {
+ if (special_compare && special_compare_pattern(uj))
+ continue;
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+ compare_pattern_v1(uj, new_locked_pup, pattern, pup_groups, 1);
+#elif defined(MV88F67XX)
+ compare_pattern_v2(uj, new_locked_pup, pattern);
+#endif
+ }
+
+ return MV_OK;
+}
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+/*
+ * Name: ddr3_sdram_dm_compare
+ * Desc: Execute compare per PUP
+ * Args: unlock_pup Bit array of the unlock pups
+ * new_locked_pup Output bit array of the pups with failed compare
+ * pattern Pattern to compare
+ * pattern_len Length of pattern (in bytes)
+ * sdram_offset offset address to the SDRAM
+ * write write to the SDRAM before read
+ * mask compare pattern with mask;
+ * mask_pattern Mask to compare pattern
+ *
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 sdram_offset)
+{
+ u32 uj, uk, var1, var2, pup_groups;
+ u32 val;
+ u32 pup = 0;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ ddr3_dram_sram_burst((u32)pattern, SDRAM_PBS_TX_OFFS,
+ LEN_PBS_PATTERN);
+ ddr3_dram_sram_burst(SDRAM_PBS_TX_OFFS, (u32)sdram_data,
+ LEN_PBS_PATTERN);
+
+ /* Validate the correctness of the results */
+ for (uj = 0; uj < LEN_PBS_PATTERN; uj++)
+ compare_pattern_v1(uj, &pup, pattern, pup_groups, 0);
+
+ /* Test the DM Signals */
+ *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10) = 0x12345678;
+ *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14) = 0x12345678;
+
+ sdram_data[0] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10);
+ sdram_data[1] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14);
+
+ for (uj = 0; uj < 2; uj++) {
+ if (((sdram_data[uj]) != (pattern[uj])) &&
+ (*new_locked_pup != 0xFF)) {
+ for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+ val = CMP_BYTE_SHIFT * uk;
+ var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
+ var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
+ if (var1 != var2) {
+ *new_locked_pup |= (1 << (uk +
+ (PUP_NUM_32BIT * (uj % pup_groups))));
+ *new_locked_pup |= pup;
+ }
+ }
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_sdram_pbs_compare
+ * Desc: Execute SRAM compare per PUP and DQ.
+ * Args: pup_locked bit array of locked pups
+ * is_tx Indicate whether Rx or Tx
+ * pbs_pattern_idx Index of PBS pattern
+ * pbs_curr_val The PBS value
+ * pbs_lock_val The value to set to locked PBS
+ * skew_array Global array to update with the compare results
+ * ai_unlock_pup_dq_array bit array of the locked / unlocked pups per dq.
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked,
+ int is_tx, u32 pbs_pattern_idx,
+ u32 pbs_curr_val, u32 pbs_lock_val,
+ u32 *skew_array, u8 *unlock_pup_dq_array,
+ u32 ecc)
+{
+ /* bit array failed dq per pup for current compare */
+ u32 pbs_write_pup[DQ_NUM] = { 0 };
+ u32 update_pup; /* pup as HW convention */
+ u32 max_pup; /* maximal pup index */
+ u32 pup_addr;
+ u32 ui, dq, pup;
+ int var1, var2;
+ u32 sdram_offset, pup_groups, tmp_pup;
+ u32 *pattern_ptr;
+ u32 val;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ max_pup = dram_info->num_of_std_pups;
+
+ sdram_offset = SDRAM_PBS_I_OFFS + pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ ddr3_reset_phy_read_fifo();
+
+ /* Check if need to write to sdram before read */
+ if (is_tx == 1) {
+ ddr3_dram_sram_burst((u32)pattern_ptr, sdram_offset,
+ LEN_PBS_PATTERN);
+ }
+
+ ddr3_dram_sram_read(sdram_offset, (u32)sdram_data, LEN_PBS_PATTERN);
+
+ /* Compare read result to write */
+ for (ui = 0; ui < LEN_PBS_PATTERN; ui++) {
+ if ((sdram_data[ui]) != (pattern_ptr[ui])) {
+ /* found error */
+ /* error in low pup group */
+ for (pup = 0; pup < PUP_NUM_32BIT; pup++) {
+ val = CMP_BYTE_SHIFT * pup;
+ var1 = ((sdram_data[ui] >> val) &
+ CMP_BYTE_MASK);
+ var2 = ((pattern_ptr[ui] >> val) &
+ CMP_BYTE_MASK);
+
+ if (var1 != var2) {
+ if (dram_info->ddr_width > 16) {
+ tmp_pup = (pup + PUP_NUM_32BIT *
+ (ui % pup_groups));
+ } else {
+ tmp_pup = (pup % PUP_NUM_16BIT);
+ }
+
+ update_pup = (1 << tmp_pup);
+ if (ecc && (update_pup != 0x1))
+ continue;
+
+ /*
+ * Pup is failed - Go over all DQs and
+ * look for failures
+ */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ val = tmp_pup * (1 - ecc) +
+ ecc * ECC_PUP;
+ if (((var1 >> dq) & 0x1) !=
+ ((var2 >> dq) & 0x1)) {
+ if (pbs_locked_dq[val][dq] == 1 &&
+ pbs_locked_value[val][dq] != pbs_curr_val)
+ continue;
+
+ /*
+ * Activate write to
+ * update PBS to
+ * pbs_lock_val
+ */
+ pbs_write_pup[dq] |=
+ update_pup;
+
+ /*
+ * Update the
+ * unlock_pup_dq_array
+ */
+ unlock_pup_dq_array[dq] &=
+ ~update_pup;
+
+ /*
+ * Lock PBS value for
+ * failed bits in
+ * compare operation
+ */
+ skew_array[tmp_pup * DQ_NUM + dq] =
+ pbs_curr_val;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pup_addr = (is_tx == 1) ? PUP_PBS_TX : PUP_PBS_RX;
+
+ /* Set last failed bits PBS to min / max pbs value */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (pbs_write_pup[dq] & (1 << pup)) {
+ val = pup * (1 - ecc) + ecc * ECC_PUP;
+ if (pbs_locked_dq[val][dq] == 1 &&
+ pbs_locked_value[val][dq] != pbs_curr_val)
+ continue;
+
+ /* Mark the dq as locked */
+ pbs_locked_dq[val][dq] = 1;
+ pbs_locked_value[val][dq] = pbs_curr_val;
+ ddr3_write_pup_reg(pup_addr +
+ pbs_dq_mapping[val][dq],
+ CS0, val, 0, pbs_lock_val);
+ }
+ }
+ }
+
+ return MV_OK;
+}
+#endif
+
+/*
+ * Name: ddr3_sdram_direct_compare
+ * Desc: Execute compare per PUP without DMA (no burst mode)
+ * Args: unlock_pup Bit array of the unlock pups
+ * new_locked_pup Output bit array of the pups with failed compare
+ * pattern Pattern to compare
+ * pattern_len Length of pattern (in bytes)
+ * sdram_offset offset address to the SDRAM
+ * write write to the SDRAM before read
+ * mask compare pattern with mask;
+ * auiMaskPatter Mask to compare pattern
+ *
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset,
+ int write, int mask, u32 *mask_pattern)
+{
+ u32 uj, uk, pup_groups;
+ u32 *sdram_addr; /* used to read from SDRAM */
+
+ sdram_addr = (u32 *)sdram_offset;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ /* Check if need to write before read */
+ if (write == 1) {
+ for (uk = 0; uk < pattern_len; uk++) {
+ *sdram_addr = pattern[uk];
+ sdram_addr++;
+ }
+ }
+
+ sdram_addr = (u32 *)sdram_offset;
+
+ for (uk = 0; uk < pattern_len; uk++) {
+ sdram_data[uk] = *sdram_addr;
+ sdram_addr++;
+ }
+
+ /* Compare read result to write */
+ for (uj = 0; uj < pattern_len; uj++) {
+ if (dram_info->ddr_width > 16) {
+ compare_pattern_v1(uj, new_locked_pup, pattern,
+ pup_groups, 0);
+ } else {
+ compare_pattern_v2(uj, new_locked_pup, pattern);
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dram_sram_burst
+ * Desc: Read from the SDRAM in burst of 64 bytes
+ * Args: src
+ * dst
+ * Notes: Using the XOR mechanism
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len)
+{
+ u32 chan, byte_count, cs_num, byte;
+ struct xor_channel_t channel;
+
+ chan = 0;
+ byte_count = len * 4;
+
+ /* Wait for previous transfer completion */
+ while (mv_xor_state_get(chan) != MV_IDLE)
+ ;
+
+ /* Build the channel descriptor */
+ channel.desc = &dma_desc;
+
+ /* Enable Address Override and set correct src and dst */
+ if (src < SRAM_BASE) {
+ /* src is DRAM CS, dst is SRAM */
+ cs_num = (src / (1 + SDRAM_CS_SIZE));
+ reg_write(XOR_ADDR_OVRD_REG(0, 0),
+ ((cs_num << 1) | (1 << 0)));
+ channel.desc->src_addr0 = (src % (1 + SDRAM_CS_SIZE));
+ channel.desc->dst_addr = dst;
+ } else {
+ /* src is SRAM, dst is DRAM CS */
+ cs_num = (dst / (1 + SDRAM_CS_SIZE));
+ reg_write(XOR_ADDR_OVRD_REG(0, 0),
+ ((cs_num << 25) | (1 << 24)));
+ channel.desc->src_addr0 = (src);
+ channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
+ channel.desc->src_addr0 = src;
+ channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
+ }
+
+ channel.desc->src_addr1 = 0;
+ channel.desc->byte_cnt = byte_count;
+ channel.desc->next_desc_ptr = 0;
+ channel.desc->status = 1 << 31;
+ channel.desc->desc_cmd = 0x0;
+ channel.desc_phys_addr = (unsigned long)&dma_desc;
+
+ ddr3_flush_l1_line((u32)&dma_desc);
+
+ /* Issue the transfer */
+ if (mv_xor_transfer(chan, MV_DMA, channel.desc_phys_addr) != MV_OK)
+ return MV_FAIL;
+
+ /* Wait for completion */
+ xor_waiton_eng(chan);
+
+ if (dst > SRAM_BASE) {
+ for (byte = 0; byte < byte_count; byte += 0x20)
+ cache_inv(dst + byte);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_flush_l1_line
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static void ddr3_flush_l1_line(u32 line)
+{
+ u32 reg;
+
+#if defined(MV88F672X)
+ reg = 1;
+#else
+ reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR) &
+ (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
+#ifdef MV88F67XX
+ reg = ~reg & (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
+#endif
+#endif
+
+ if (reg) {
+ /* V7 Arch mode */
+ flush_l1_v7(line);
+ flush_l1_v7(line + CACHE_LINE_SIZE);
+ } else {
+ /* V6 Arch mode */
+ flush_l1_v6(line);
+ flush_l1_v6(line + CACHE_LINE_SIZE);
+ }
+}
+
+int ddr3_dram_sram_read(u32 src, u32 dst, u32 len)
+{
+ u32 ui;
+ u32 *dst_ptr, *src_ptr;
+
+ dst_ptr = (u32 *)dst;
+ src_ptr = (u32 *)src;
+
+ for (ui = 0; ui < len; ui++) {
+ *dst_ptr = *src_ptr;
+ dst_ptr++;
+ src_ptr++;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern,
+ int special_compare)
+{
+ u32 uj, pup_groups;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ ddr3_reset_phy_read_fifo();
+
+ /* Check if need to write to sdram before read */
+ if (write == 1)
+ ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
+
+ ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
+
+ /* Compare read result to write */
+ for (uj = 0; uj < pattern_len; uj++) {
+ if (special_compare && special_compare_pattern(uj))
+ continue;
+
+ if (dram_info->ddr_width > 16) {
+ compare_pattern_v1(uj, new_locked_pup, pattern,
+ pup_groups, 1);
+ } else {
+ compare_pattern_v2(uj, new_locked_pup, pattern);
+ }
+ }
+
+ return MV_OK;
+}
+
+void ddr3_reset_phy_read_fifo(void)
+{
+ u32 reg;
+
+ /* reset read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Start Auto Read Leveling procedure */
+ reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+
+ /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+
+ /* Clear Auto Read Leveling procedure */
+ reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+}
diff --git a/drivers/ddr/marvell/axp/ddr3_spd.c b/drivers/ddr/marvell/axp/ddr3_spd.c
new file mode 100644
index 0000000000..f4f94c5c7e
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_spd.c
@@ -0,0 +1,1300 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#if defined(MV88F78X60)
+#include "ddr3_axp_config.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370_config.h"
+#endif
+
+#if defined(MV88F672X)
+#include "ddr3_a375_config.h"
+#endif
+
+#ifdef DUNIT_SPD
+
+/* DIMM SPD offsets */
+#define SPD_DEV_TYPE_BYTE 2
+
+#define SPD_MODULE_TYPE_BYTE 3
+#define SPD_MODULE_MASK 0xf
+#define SPD_MODULE_TYPE_RDIMM 1
+#define SPD_MODULE_TYPE_UDIMM 2
+
+#define SPD_DEV_DENSITY_BYTE 4
+#define SPD_DEV_DENSITY_MASK 0xf
+
+#define SPD_ROW_NUM_BYTE 5
+#define SPD_ROW_NUM_MIN 12
+#define SPD_ROW_NUM_OFF 3
+#define SPD_ROW_NUM_MASK (7 << SPD_ROW_NUM_OFF)
+
+#define SPD_COL_NUM_BYTE 5
+#define SPD_COL_NUM_MIN 9
+#define SPD_COL_NUM_OFF 0
+#define SPD_COL_NUM_MASK (7 << SPD_COL_NUM_OFF)
+
+#define SPD_MODULE_ORG_BYTE 7
+#define SPD_MODULE_SDRAM_DEV_WIDTH_OFF 0
+#define SPD_MODULE_SDRAM_DEV_WIDTH_MASK (7 << SPD_MODULE_SDRAM_DEV_WIDTH_OFF)
+#define SPD_MODULE_BANK_NUM_MIN 1
+#define SPD_MODULE_BANK_NUM_OFF 3
+#define SPD_MODULE_BANK_NUM_MASK (7 << SPD_MODULE_BANK_NUM_OFF)
+
+#define SPD_BUS_WIDTH_BYTE 8
+#define SPD_BUS_WIDTH_OFF 0
+#define SPD_BUS_WIDTH_MASK (7 << SPD_BUS_WIDTH_OFF)
+#define SPD_BUS_ECC_OFF 3
+#define SPD_BUS_ECC_MASK (3 << SPD_BUS_ECC_OFF)
+
+#define SPD_MTB_DIVIDEND_BYTE 10
+#define SPD_MTB_DIVISOR_BYTE 11
+#define SPD_TCK_BYTE 12
+#define SPD_SUP_CAS_LAT_LSB_BYTE 14
+#define SPD_SUP_CAS_LAT_MSB_BYTE 15
+#define SPD_TAA_BYTE 16
+#define SPD_TWR_BYTE 17
+#define SPD_TRCD_BYTE 18
+#define SPD_TRRD_BYTE 19
+#define SPD_TRP_BYTE 20
+
+#define SPD_TRAS_MSB_BYTE 21
+#define SPD_TRAS_MSB_MASK 0xf
+
+#define SPD_TRC_MSB_BYTE 21
+#define SPD_TRC_MSB_MASK 0xf0
+
+#define SPD_TRAS_LSB_BYTE 22
+#define SPD_TRC_LSB_BYTE 23
+#define SPD_TRFC_LSB_BYTE 24
+#define SPD_TRFC_MSB_BYTE 25
+#define SPD_TWTR_BYTE 26
+#define SPD_TRTP_BYTE 27
+
+#define SPD_TFAW_MSB_BYTE 28
+#define SPD_TFAW_MSB_MASK 0xf
+
+#define SPD_TFAW_LSB_BYTE 29
+#define SPD_OPT_FEATURES_BYTE 30
+#define SPD_THERMAL_REFRESH_OPT_BYTE 31
+
+#define SPD_ADDR_MAP_BYTE 63
+#define SPD_ADDR_MAP_MIRROR_OFFS 0
+
+#define SPD_RDIMM_RC_BYTE 69
+#define SPD_RDIMM_RC_NIBBLE_MASK 0xF
+#define SPD_RDIMM_RC_NUM 16
+
+/* Dimm Memory Type values */
+#define SPD_MEM_TYPE_SDRAM 0x4
+#define SPD_MEM_TYPE_DDR1 0x7
+#define SPD_MEM_TYPE_DDR2 0x8
+#define SPD_MEM_TYPE_DDR3 0xB
+
+#define DIMM_MODULE_MANU_OFFS 64
+#define DIMM_MODULE_MANU_SIZE 8
+#define DIMM_MODULE_VEN_OFFS 73
+#define DIMM_MODULE_VEN_SIZE 25
+#define DIMM_MODULE_ID_OFFS 99
+#define DIMM_MODULE_ID_SIZE 18
+
+/* enumeration for voltage levels. */
+enum dimm_volt_if {
+ TTL_5V_TOLERANT,
+ LVTTL,
+ HSTL_1_5V,
+ SSTL_3_3V,
+ SSTL_2_5V,
+ VOLTAGE_UNKNOWN,
+};
+
+/* enumaration for SDRAM CAS Latencies. */
+enum dimm_sdram_cas {
+ SD_CL_1 = 1,
+ SD_CL_2,
+ SD_CL_3,
+ SD_CL_4,
+ SD_CL_5,
+ SD_CL_6,
+ SD_CL_7,
+ SD_FAULT
+};
+
+/* enumeration for memory types */
+enum memory_type {
+ MEM_TYPE_SDRAM,
+ MEM_TYPE_DDR1,
+ MEM_TYPE_DDR2,
+ MEM_TYPE_DDR3
+};
+
+/* DIMM information structure */
+typedef struct dimm_info {
+ /* DIMM dimensions */
+ u32 num_of_module_ranks;
+ u32 data_width;
+ u32 rank_capacity;
+ u32 num_of_devices;
+
+ u32 sdram_width;
+ u32 num_of_banks_on_each_device;
+ u32 sdram_capacity;
+
+ u32 num_of_row_addr;
+ u32 num_of_col_addr;
+
+ u32 addr_mirroring;
+
+ u32 err_check_type; /* ECC , PARITY.. */
+ u32 type_info; /* DDR2 only */
+
+ /* DIMM timing parameters */
+ u32 supported_cas_latencies;
+ u32 refresh_interval;
+ u32 min_cycle_time;
+ u32 min_row_precharge_time;
+ u32 min_row_active_to_row_active;
+ u32 min_ras_to_cas_delay;
+ u32 min_write_recovery_time; /* DDR3/2 only */
+ u32 min_write_to_read_cmd_delay; /* DDR3/2 only */
+ u32 min_read_to_prech_cmd_delay; /* DDR3/2 only */
+ u32 min_active_to_precharge;
+ u32 min_refresh_recovery; /* DDR3/2 only */
+ u32 min_cas_lat_time;
+ u32 min_four_active_win_delay;
+ u8 dimm_rc[SPD_RDIMM_RC_NUM];
+
+ /* DIMM vendor ID */
+ u32 vendor;
+} MV_DIMM_INFO;
+
+static int ddr3_spd_sum_init(MV_DIMM_INFO *info, MV_DIMM_INFO *sum_info,
+ u32 dimm);
+static u32 ddr3_get_max_val(u32 spd_val, u32 dimm_num, u32 static_val);
+static u32 ddr3_get_min_val(u32 spd_val, u32 dimm_num, u32 static_val);
+static int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width);
+static u32 ddr3_div(u32 val, u32 divider, u32 sub);
+
+extern u8 spd_data[SPD_SIZE];
+extern u32 odt_config[ODT_OPT];
+extern u16 odt_static[ODT_OPT][MAX_CS];
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+
+#if !(defined(DB_88F6710) || defined(DB_88F6710_PCAC) || defined(RD_88F6710))
+/*
+ * Name: ddr3_get_dimm_num - Find number of dimms and their addresses
+ * Desc:
+ * Args: dimm_addr - array of dimm addresses
+ * Notes:
+ * Returns: None.
+ */
+static u32 ddr3_get_dimm_num(u32 *dimm_addr)
+{
+ u32 dimm_cur_addr;
+ u8 data[3];
+ u32 dimm_num = 0;
+ int ret;
+
+ /* Read the dimm eeprom */
+ for (dimm_cur_addr = MAX_DIMM_ADDR; dimm_cur_addr > MIN_DIMM_ADDR;
+ dimm_cur_addr--) {
+ data[SPD_DEV_TYPE_BYTE] = 0;
+
+ /* Far-End DIMM must be connected */
+ if ((dimm_num == 0) && (dimm_cur_addr < FAR_END_DIMM_ADDR))
+ return 0;
+
+ ret = i2c_read(dimm_cur_addr, 0, 1, (uchar *)data, 3);
+ if (!ret) {
+ if (data[SPD_DEV_TYPE_BYTE] == SPD_MEM_TYPE_DDR3) {
+ dimm_addr[dimm_num] = dimm_cur_addr;
+ dimm_num++;
+ }
+ }
+ }
+
+ return dimm_num;
+}
+#endif
+
+/*
+ * Name: dimmSpdInit - Get the SPD parameters.
+ * Desc: Read the DIMM SPD parameters into given struct parameter.
+ * Args: dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
+ * info - DIMM information structure.
+ * Notes:
+ * Returns: MV_OK if function could read DIMM parameters, 0 otherwise.
+ */
+int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width)
+{
+ u32 tmp;
+ u32 time_base;
+ int ret;
+ __maybe_unused u32 rc;
+ __maybe_unused u8 vendor_high, vendor_low;
+
+ if (dimm_addr != 0) {
+ memset(spd_data, 0, SPD_SIZE * sizeof(u8));
+
+ ret = i2c_read(dimm_addr, 0, 1, (uchar *)spd_data, SPD_SIZE);
+ if (ret)
+ return MV_DDR3_TRAINING_ERR_TWSI_FAIL;
+ }
+
+ /* Check if DDR3 */
+ if (spd_data[SPD_DEV_TYPE_BYTE] != SPD_MEM_TYPE_DDR3)
+ return MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE;
+
+ /* Error Check Type */
+ /* No byte for error check in DDR3 SPD, use DDR2 convention */
+ info->err_check_type = 0;
+
+ /* Check if ECC */
+ if ((spd_data[SPD_BUS_WIDTH_BYTE] & 0x18) >> 3)
+ info->err_check_type = 1;
+
+ DEBUG_INIT_FULL_C("DRAM err_check_type ", info->err_check_type, 1);
+ switch (spd_data[SPD_MODULE_TYPE_BYTE]) {
+ case 1:
+ /* support RDIMM */
+ info->type_info = SPD_MODULE_TYPE_RDIMM;
+ break;
+ case 2:
+ /* support UDIMM */
+ info->type_info = SPD_MODULE_TYPE_UDIMM;
+ break;
+ case 11: /* LRDIMM current not supported */
+ default:
+ info->type_info = (spd_data[SPD_MODULE_TYPE_BYTE]);
+ break;
+ }
+
+ /* Size Calculations: */
+
+ /* Number Of Row Addresses - 12/13/14/15/16 */
+ info->num_of_row_addr =
+ (spd_data[SPD_ROW_NUM_BYTE] & SPD_ROW_NUM_MASK) >>
+ SPD_ROW_NUM_OFF;
+ info->num_of_row_addr += SPD_ROW_NUM_MIN;
+ DEBUG_INIT_FULL_C("DRAM num_of_row_addr ", info->num_of_row_addr, 2);
+
+ /* Number Of Column Addresses - 9/10/11/12 */
+ info->num_of_col_addr =
+ (spd_data[SPD_COL_NUM_BYTE] & SPD_COL_NUM_MASK) >>
+ SPD_COL_NUM_OFF;
+ info->num_of_col_addr += SPD_COL_NUM_MIN;
+ DEBUG_INIT_FULL_C("DRAM num_of_col_addr ", info->num_of_col_addr, 1);
+
+ /* Number Of Ranks = number of CS on Dimm - 1/2/3/4 Ranks */
+ info->num_of_module_ranks =
+ (spd_data[SPD_MODULE_ORG_BYTE] & SPD_MODULE_BANK_NUM_MASK) >>
+ SPD_MODULE_BANK_NUM_OFF;
+ info->num_of_module_ranks += SPD_MODULE_BANK_NUM_MIN;
+ DEBUG_INIT_FULL_C("DRAM numOfModuleBanks ", info->num_of_module_ranks,
+ 1);
+
+ /* Data Width - 8/16/32/64 bits */
+ info->data_width =
+ 1 << (3 + (spd_data[SPD_BUS_WIDTH_BYTE] & SPD_BUS_WIDTH_MASK));
+ DEBUG_INIT_FULL_C("DRAM data_width ", info->data_width, 1);
+
+ /* Number Of Banks On Each Device - 8/16/32/64 banks */
+ info->num_of_banks_on_each_device =
+ 1 << (3 + ((spd_data[SPD_DEV_DENSITY_BYTE] >> 4) & 0x7));
+ DEBUG_INIT_FULL_C("DRAM num_of_banks_on_each_device ",
+ info->num_of_banks_on_each_device, 1);
+
+ /* Total SDRAM capacity - 256Mb/512Mb/1Gb/2Gb/4Gb/8Gb/16Gb - MegaBits */
+ info->sdram_capacity =
+ spd_data[SPD_DEV_DENSITY_BYTE] & SPD_DEV_DENSITY_MASK;
+
+ /* Sdram Width - 4/8/16/32 bits */
+ info->sdram_width = 1 << (2 + (spd_data[SPD_MODULE_ORG_BYTE] &
+ SPD_MODULE_SDRAM_DEV_WIDTH_MASK));
+ DEBUG_INIT_FULL_C("DRAM sdram_width ", info->sdram_width, 1);
+
+ /* CS (Rank) Capacity - MB */
+ /*
+ * DDR3 device uiDensity val are: (device capacity/8) *
+ * (Module_width/Device_width)
+ */
+ /* Jedec SPD DDR3 - page 7, Save spd_data in Mb - 2048=2GB */
+ if (dimm_width == 32) {
+ info->rank_capacity =
+ ((1 << info->sdram_capacity) * 256 *
+ (info->data_width / info->sdram_width)) << 16;
+ /* CS size = CS size / 2 */
+ } else {
+ info->rank_capacity =
+ ((1 << info->sdram_capacity) * 256 *
+ (info->data_width / info->sdram_width) * 0x2) << 16;
+ /* 0x2 => 0x100000-1Mbit / 8-bit->byte / 0x10000 */
+ }
+ DEBUG_INIT_FULL_C("DRAM rank_capacity[31] ", info->rank_capacity, 1);
+
+ /* Number of devices includeing Error correction */
+ info->num_of_devices =
+ ((info->data_width / info->sdram_width) *
+ info->num_of_module_ranks) + info->err_check_type;
+ DEBUG_INIT_FULL_C("DRAM num_of_devices ", info->num_of_devices, 1);
+
+ /* Address Mapping from Edge connector to DRAM - mirroring option */
+ info->addr_mirroring =
+ spd_data[SPD_ADDR_MAP_BYTE] & (1 << SPD_ADDR_MAP_MIRROR_OFFS);
+
+ /* Timings - All in ps */
+
+ time_base = (1000 * spd_data[SPD_MTB_DIVIDEND_BYTE]) /
+ spd_data[SPD_MTB_DIVISOR_BYTE];
+
+ /* Minimum Cycle Time At Max CasLatancy */
+ info->min_cycle_time = spd_data[SPD_TCK_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM tCKmin ", info->min_cycle_time, 1);
+
+ /* Refresh Interval */
+ /* No byte for refresh interval in DDR3 SPD, use DDR2 convention */
+ /*
+ * JEDEC param are 0 <= Tcase <= 85: 7.8uSec, 85 <= Tcase
+ * <= 95: 3.9uSec
+ */
+ info->refresh_interval = 7800000; /* Set to 7.8uSec */
+ DEBUG_INIT_FULL_C("DRAM refresh_interval ", info->refresh_interval, 1);
+
+ /* Suported Cas Latencies - DDR 3: */
+
+ /*
+ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
+ *******-******-******-******-******-******-******-*******-*******
+ CAS = 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 *
+ *********************************************************-*******
+ *******-******-******-******-******-******-******-*******-*******
+ * bit15 |bit14 |bit13 |bit12 |bit11 |bit10 | bit9 | bit8 *
+ *******-******-******-******-******-******-******-*******-*******
+ CAS = TBD | 18 | 17 | 16 | 15 | 14 | 13 | 12 *
+ */
+
+ /* DDR3 include 2 byte of CAS support */
+ info->supported_cas_latencies =
+ (spd_data[SPD_SUP_CAS_LAT_MSB_BYTE] << 8) |
+ spd_data[SPD_SUP_CAS_LAT_LSB_BYTE];
+ DEBUG_INIT_FULL_C("DRAM supported_cas_latencies ",
+ info->supported_cas_latencies, 1);
+
+ /* Minimum Cycle Time At Max CasLatancy */
+ info->min_cas_lat_time = (spd_data[SPD_TAA_BYTE] * time_base);
+ /*
+ * This field divided by the cycleTime will give us the CAS latency
+ * to config
+ */
+
+ /*
+ * For DDR3 and DDR2 includes Write Recovery Time field.
+ * Other SDRAM ignore
+ */
+ info->min_write_recovery_time = spd_data[SPD_TWR_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_write_recovery_time ",
+ info->min_write_recovery_time, 1);
+
+ /* Mininmum Ras to Cas Delay */
+ info->min_ras_to_cas_delay = spd_data[SPD_TRCD_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_ras_to_cas_delay ",
+ info->min_ras_to_cas_delay, 1);
+
+ /* Minimum Row Active to Row Active Time */
+ info->min_row_active_to_row_active =
+ spd_data[SPD_TRRD_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_row_active_to_row_active ",
+ info->min_row_active_to_row_active, 1);
+
+ /* Minimum Row Precharge Delay Time */
+ info->min_row_precharge_time = spd_data[SPD_TRP_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_row_precharge_time ",
+ info->min_row_precharge_time, 1);
+
+ /* Minimum Active to Precharge Delay Time - tRAS ps */
+ info->min_active_to_precharge =
+ (spd_data[SPD_TRAS_MSB_BYTE] & SPD_TRAS_MSB_MASK) << 8;
+ info->min_active_to_precharge |= spd_data[SPD_TRAS_LSB_BYTE];
+ info->min_active_to_precharge *= time_base;
+ DEBUG_INIT_FULL_C("DRAM min_active_to_precharge ",
+ info->min_active_to_precharge, 1);
+
+ /* Minimum Refresh Recovery Delay Time - tRFC ps */
+ info->min_refresh_recovery = spd_data[SPD_TRFC_MSB_BYTE] << 8;
+ info->min_refresh_recovery |= spd_data[SPD_TRFC_LSB_BYTE];
+ info->min_refresh_recovery *= time_base;
+ DEBUG_INIT_FULL_C("DRAM min_refresh_recovery ",
+ info->min_refresh_recovery, 1);
+
+ /*
+ * For DDR3 and DDR2 includes Internal Write To Read Command Delay
+ * field.
+ */
+ info->min_write_to_read_cmd_delay = spd_data[SPD_TWTR_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_write_to_read_cmd_delay ",
+ info->min_write_to_read_cmd_delay, 1);
+
+ /*
+ * For DDR3 and DDR2 includes Internal Read To Precharge Command Delay
+ * field.
+ */
+ info->min_read_to_prech_cmd_delay = spd_data[SPD_TRTP_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_read_to_prech_cmd_delay ",
+ info->min_read_to_prech_cmd_delay, 1);
+
+ /*
+ * For DDR3 includes Minimum Activate to Activate/Refresh Command
+ * field
+ */
+ tmp = ((spd_data[SPD_TFAW_MSB_BYTE] & SPD_TFAW_MSB_MASK) << 8) |
+ spd_data[SPD_TFAW_LSB_BYTE];
+ info->min_four_active_win_delay = tmp * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_four_active_win_delay ",
+ info->min_four_active_win_delay, 1);
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* Registered DIMM support */
+ if (info->type_info == SPD_MODULE_TYPE_RDIMM) {
+ for (rc = 2; rc < 6; rc += 2) {
+ tmp = spd_data[SPD_RDIMM_RC_BYTE + rc / 2];
+ info->dimm_rc[rc] =
+ spd_data[SPD_RDIMM_RC_BYTE + rc / 2] &
+ SPD_RDIMM_RC_NIBBLE_MASK;
+ info->dimm_rc[rc + 1] =
+ (spd_data[SPD_RDIMM_RC_BYTE + rc / 2] >> 4) &
+ SPD_RDIMM_RC_NIBBLE_MASK;
+ }
+
+ vendor_low = spd_data[66];
+ vendor_high = spd_data[65];
+ info->vendor = (vendor_high << 8) + vendor_low;
+ DEBUG_INIT_C("DDR3 Training Sequence - Registered DIMM vendor ID 0x",
+ info->vendor, 4);
+
+ info->dimm_rc[0] = RDIMM_RC0;
+ info->dimm_rc[1] = RDIMM_RC1;
+ info->dimm_rc[2] = RDIMM_RC2;
+ info->dimm_rc[8] = RDIMM_RC8;
+ info->dimm_rc[9] = RDIMM_RC9;
+ info->dimm_rc[10] = RDIMM_RC10;
+ info->dimm_rc[11] = RDIMM_RC11;
+ }
+#endif
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_spd_sum_init - Get the SPD parameters.
+ * Desc: Read the DIMM SPD parameters into given struct parameter.
+ * Args: dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
+ * info - DIMM information structure.
+ * Notes:
+ * Returns: MV_OK if function could read DIMM parameters, 0 otherwise.
+ */
+int ddr3_spd_sum_init(MV_DIMM_INFO *info, MV_DIMM_INFO *sum_info, u32 dimm)
+{
+ if (dimm == 0) {
+ memcpy(sum_info, info, sizeof(MV_DIMM_INFO));
+ return MV_OK;
+ }
+ if (sum_info->type_info != info->type_info) {
+ DEBUG_INIT_S("DDR3 Dimm Compare - DIMM type does not match - FAIL\n");
+ return MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH;
+ }
+ if (sum_info->err_check_type > info->err_check_type) {
+ sum_info->err_check_type = info->err_check_type;
+ DEBUG_INIT_S("DDR3 Dimm Compare - ECC does not match. ECC is disabled\n");
+ }
+ if (sum_info->data_width != info->data_width) {
+ DEBUG_INIT_S("DDR3 Dimm Compare - DRAM bus width does not match - FAIL\n");
+ return MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH;
+ }
+ if (sum_info->min_cycle_time < info->min_cycle_time)
+ sum_info->min_cycle_time = info->min_cycle_time;
+ if (sum_info->refresh_interval < info->refresh_interval)
+ sum_info->refresh_interval = info->refresh_interval;
+ sum_info->supported_cas_latencies &= info->supported_cas_latencies;
+ if (sum_info->min_cas_lat_time < info->min_cas_lat_time)
+ sum_info->min_cas_lat_time = info->min_cas_lat_time;
+ if (sum_info->min_write_recovery_time < info->min_write_recovery_time)
+ sum_info->min_write_recovery_time =
+ info->min_write_recovery_time;
+ if (sum_info->min_ras_to_cas_delay < info->min_ras_to_cas_delay)
+ sum_info->min_ras_to_cas_delay = info->min_ras_to_cas_delay;
+ if (sum_info->min_row_active_to_row_active <
+ info->min_row_active_to_row_active)
+ sum_info->min_row_active_to_row_active =
+ info->min_row_active_to_row_active;
+ if (sum_info->min_row_precharge_time < info->min_row_precharge_time)
+ sum_info->min_row_precharge_time = info->min_row_precharge_time;
+ if (sum_info->min_active_to_precharge < info->min_active_to_precharge)
+ sum_info->min_active_to_precharge =
+ info->min_active_to_precharge;
+ if (sum_info->min_refresh_recovery < info->min_refresh_recovery)
+ sum_info->min_refresh_recovery = info->min_refresh_recovery;
+ if (sum_info->min_write_to_read_cmd_delay <
+ info->min_write_to_read_cmd_delay)
+ sum_info->min_write_to_read_cmd_delay =
+ info->min_write_to_read_cmd_delay;
+ if (sum_info->min_read_to_prech_cmd_delay <
+ info->min_read_to_prech_cmd_delay)
+ sum_info->min_read_to_prech_cmd_delay =
+ info->min_read_to_prech_cmd_delay;
+ if (sum_info->min_four_active_win_delay <
+ info->min_four_active_win_delay)
+ sum_info->min_four_active_win_delay =
+ info->min_four_active_win_delay;
+ if (sum_info->min_write_to_read_cmd_delay <
+ info->min_write_to_read_cmd_delay)
+ sum_info->min_write_to_read_cmd_delay =
+ info->min_write_to_read_cmd_delay;
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dunit_setup
+ * Desc: Set the controller with the timing values.
+ * Args: ecc_ena - User ECC setup
+ * Notes:
+ * Returns:
+ */
+int ddr3_dunit_setup(u32 ecc_ena, u32 hclk_time, u32 *ddr_width)
+{
+ u32 reg, tmp, cwl;
+ u32 ddr_clk_time;
+ MV_DIMM_INFO dimm_info[2];
+ MV_DIMM_INFO sum_info;
+ u32 stat_val, spd_val;
+ u32 cs, cl, cs_num, cs_ena;
+ u32 dimm_num = 0;
+ int status;
+ u32 rc;
+ __maybe_unused u32 dimm_cnt, cs_count, dimm;
+ __maybe_unused u32 dimm_addr[2] = { 0, 0 };
+
+#if defined(DB_88F6710) || defined(DB_88F6710_PCAC) || defined(RD_88F6710)
+ /* Armada 370 - SPD is not available on DIMM */
+ /*
+ * Set MC registers according to Static SPD values Values -
+ * must be set manually
+ */
+ /*
+ * We only have one optional DIMM for the DB and we already got the
+ * SPD matching values
+ */
+ status = ddr3_spd_init(&dimm_info[0], 0, *ddr_width);
+ if (MV_OK != status)
+ return status;
+
+ dimm_num = 1;
+ /* Use JP8 to enable multiCS support for Armada 370 DB */
+ if (!ddr3_check_config(EEPROM_MODULE_ADDR, CONFIG_MULTI_CS))
+ dimm_info[0].num_of_module_ranks = 1;
+ status = ddr3_spd_sum_init(&dimm_info[0], &sum_info, 0);
+ if (MV_OK != status)
+ return status;
+#else
+ /* Dynamic D-Unit Setup - Read SPD values */
+#ifdef DUNIT_SPD
+ dimm_num = ddr3_get_dimm_num(dimm_addr);
+ if (dimm_num == 0) {
+#ifdef MIXED_DIMM_STATIC
+ DEBUG_INIT_S("DDR3 Training Sequence - No DIMMs detected\n");
+#else
+ DEBUG_INIT_S("DDR3 Training Sequence - FAILED (Wrong DIMMs Setup)\n");
+ return MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP;
+#endif
+ } else {
+ DEBUG_INIT_C("DDR3 Training Sequence - Number of DIMMs detected: ",
+ dimm_num, 1);
+ }
+
+ for (dimm = 0; dimm < dimm_num; dimm++) {
+ status = ddr3_spd_init(&dimm_info[dimm], dimm_addr[dimm],
+ *ddr_width);
+ if (MV_OK != status)
+ return status;
+ status = ddr3_spd_sum_init(&dimm_info[dimm], &sum_info, dimm);
+ if (MV_OK != status)
+ return status;
+ }
+#endif
+#endif
+
+ /* Set number of enabled CS */
+ cs_num = 0;
+#ifdef DUNIT_STATIC
+ cs_num = ddr3_get_cs_num_from_reg();
+#endif
+#ifdef DUNIT_SPD
+ for (dimm = 0; dimm < dimm_num; dimm++)
+ cs_num += dimm_info[dimm].num_of_module_ranks;
+#endif
+ if (cs_num > MAX_CS) {
+ DEBUG_INIT_C("DDR3 Training Sequence - Number of CS exceed limit - ",
+ MAX_CS, 1);
+ return MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT;
+ }
+
+ /* Set bitmap of enabled CS */
+ cs_ena = 0;
+#ifdef DUNIT_STATIC
+ cs_ena = ddr3_get_cs_ena_from_reg();
+#endif
+#ifdef DUNIT_SPD
+ dimm = 0;
+
+ if (dimm_num) {
+ for (cs = 0; cs < MAX_CS; cs += 2) {
+ if (((1 << cs) & DIMM_CS_BITMAP) &&
+ !(cs_ena & (1 << cs))) {
+ if (dimm_info[dimm].num_of_module_ranks == 1)
+ cs_ena |= (0x1 << cs);
+ else if (dimm_info[dimm].num_of_module_ranks == 2)
+ cs_ena |= (0x3 << cs);
+ else if (dimm_info[dimm].num_of_module_ranks == 3)
+ cs_ena |= (0x7 << cs);
+ else if (dimm_info[dimm].num_of_module_ranks == 4)
+ cs_ena |= (0xF << cs);
+
+ dimm++;
+ if (dimm == dimm_num)
+ break;
+ }
+ }
+ }
+#endif
+
+ if (cs_ena > 0xF) {
+ DEBUG_INIT_C("DDR3 Training Sequence - Number of enabled CS exceed limit - ",
+ MAX_CS, 1);
+ return MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT;
+ }
+
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - Number of CS = ", cs_num, 1);
+
+ /* Check Ratio - '1' - 2:1, '0' - 1:1 */
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ ddr_clk_time = hclk_time / 2;
+ else
+ ddr_clk_time = hclk_time;
+
+#ifdef DUNIT_STATIC
+ /* Get target CL value from set register */
+ reg = (reg_read(REG_DDR3_MR0_ADDR) >> 2);
+ reg = ((((reg >> 1) & 0xE)) | (reg & 0x1)) & 0xF;
+
+ cl = ddr3_get_max_val(ddr3_div(sum_info.min_cas_lat_time,
+ ddr_clk_time, 0),
+ dimm_num, ddr3_valid_cl_to_cl(reg));
+#else
+ cl = ddr3_div(sum_info.min_cas_lat_time, ddr_clk_time, 0);
+#endif
+ if (cl < 5)
+ cl = 5;
+
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - Cas Latency = ", cl, 1);
+
+ /* {0x00001400} - DDR SDRAM Configuration Register */
+ reg = 0x73004000;
+ stat_val = ddr3_get_static_mc_value(
+ REG_SDRAM_CONFIG_ADDR, REG_SDRAM_CONFIG_ECC_OFFS, 0x1, 0, 0);
+ if (ecc_ena && ddr3_get_min_val(sum_info.err_check_type, dimm_num,
+ stat_val)) {
+ reg |= (1 << REG_SDRAM_CONFIG_ECC_OFFS);
+ reg |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - ECC Enabled\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - ECC Disabled\n");
+ }
+
+ if (sum_info.type_info == SPD_MODULE_TYPE_RDIMM) {
+#ifdef DUNIT_STATIC
+ DEBUG_INIT_S("DDR3 Training Sequence - FAIL - Illegal R-DIMM setup\n");
+ return MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP;
+#endif
+ reg |= (1 << REG_SDRAM_CONFIG_REGDIMM_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - R-DIMM\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - U-DIMM\n");
+ }
+
+#ifndef MV88F67XX
+#ifdef DUNIT_STATIC
+ if (ddr3_get_min_val(sum_info.data_width, dimm_num, BUS_WIDTH) == 64) {
+#else
+ if (*ddr_width == 64) {
+#endif
+ reg |= (1 << REG_SDRAM_CONFIG_WIDTH_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 64Bits\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 32Bits\n");
+ }
+#else
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 16Bits\n");
+#endif
+
+#if defined(MV88F672X)
+ if (*ddr_width == 32) {
+ reg |= (1 << REG_SDRAM_CONFIG_WIDTH_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 32Bits\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 16Bits\n");
+ }
+#endif
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_CONFIG_ADDR, 0,
+ REG_SDRAM_CONFIG_RFRS_MASK, 0, 0);
+ tmp = ddr3_get_min_val(sum_info.refresh_interval / hclk_time,
+ dimm_num, stat_val);
+
+#ifdef TREFI_USER_EN
+ tmp = min(TREFI_USER / hclk_time, tmp);
+#endif
+
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - RefreshInterval/Hclk = ", tmp, 4);
+ reg |= tmp;
+
+ if (cl != 3)
+ reg |= (1 << 16); /* If 2:1 need to set P2DWr */
+
+#if defined(MV88F672X)
+ reg |= (1 << 27); /* PhyRfRST = Disable */
+#endif
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /*{0x00001404} - DDR SDRAM Configuration Register */
+ reg = 0x3630B800;
+#ifdef DUNIT_SPD
+ reg |= (DRAM_2T << REG_DUNIT_CTRL_LOW_2T_OFFS);
+#endif
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* {0x00001408} - DDR SDRAM Timing (Low) Register */
+ reg = 0x0;
+
+ /* tRAS - (0:3,20) */
+ spd_val = ddr3_div(sum_info.min_active_to_precharge,
+ ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 0, 0xF, 16, 0x10);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRAS-1 = ", tmp, 1);
+ reg |= (tmp & 0xF);
+ reg |= ((tmp & 0x10) << 16); /* to bit 20 */
+
+ /* tRCD - (4:7) */
+ spd_val = ddr3_div(sum_info.min_ras_to_cas_delay, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 4, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRCD-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 4);
+
+ /* tRP - (8:11) */
+ spd_val = ddr3_div(sum_info.min_row_precharge_time, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 8, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRP-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 8);
+
+ /* tWR - (12:15) */
+ spd_val = ddr3_div(sum_info.min_write_recovery_time, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 12, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tWR-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 12);
+
+ /* tWTR - (16:19) */
+ spd_val = ddr3_div(sum_info.min_write_to_read_cmd_delay, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 16, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tWTR-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 16);
+
+ /* tRRD - (24:27) */
+ spd_val = ddr3_div(sum_info.min_row_active_to_row_active, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 24, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRRD-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 24);
+
+ /* tRTP - (28:31) */
+ spd_val = ddr3_div(sum_info.min_read_to_prech_cmd_delay, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 28, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRTP-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 28);
+
+ if (cl < 7)
+ reg = 0x33137663;
+
+ reg_write(REG_SDRAM_TIMING_LOW_ADDR, reg);
+
+ /*{0x0000140C} - DDR SDRAM Timing (High) Register */
+ /* Add cycles to R2R W2W */
+ reg = 0x39F8FF80;
+
+ /* tRFC - (0:6,16:18) */
+ spd_val = ddr3_div(sum_info.min_refresh_recovery, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_HIGH_ADDR,
+ 0, 0x7F, 9, 0x380);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRFC-1 = ", tmp, 1);
+ reg |= (tmp & 0x7F);
+ reg |= ((tmp & 0x380) << 9); /* to bit 16 */
+ reg_write(REG_SDRAM_TIMING_HIGH_ADDR, reg);
+
+ /*{0x00001410} - DDR SDRAM Address Control Register */
+ reg = 0x000F0000;
+
+ /* tFAW - (24:28) */
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ tmp = sum_info.min_four_active_win_delay;
+ spd_val = ddr3_div(tmp, ddr_clk_time, 0);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_ADDRESS_CTRL_ADDR,
+ 24, 0x3F, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tFAW = ", tmp, 1);
+ reg |= ((tmp & 0x3F) << 24);
+#else
+ tmp = sum_info.min_four_active_win_delay -
+ 4 * (sum_info.min_row_active_to_row_active);
+ spd_val = ddr3_div(tmp, ddr_clk_time, 0);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_ADDRESS_CTRL_ADDR,
+ 24, 0x1F, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tFAW-4*tRRD = ", tmp, 1);
+ reg |= ((tmp & 0x1F) << 24);
+#endif
+
+ /* SDRAM device capacity */
+#ifdef DUNIT_STATIC
+ reg |= (reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR) & 0xF0FFFF);
+#endif
+
+#ifdef DUNIT_SPD
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+ if (dimm_info[dimm_cnt].sdram_capacity < 0x3) {
+ reg |= ((dimm_info[dimm_cnt].sdram_capacity + 1) <<
+ (REG_SDRAM_ADDRESS_SIZE_OFFS +
+ (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs)));
+ } else if (dimm_info[dimm_cnt].sdram_capacity > 0x3) {
+ reg |= ((dimm_info[dimm_cnt].sdram_capacity & 0x3) <<
+ (REG_SDRAM_ADDRESS_SIZE_OFFS +
+ (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs)));
+ reg |= ((dimm_info[dimm_cnt].sdram_capacity & 0x4) <<
+ (REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + cs));
+ }
+ }
+ }
+
+ /* SDRAM device structure */
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+ if (dimm_info[dimm_cnt].sdram_width == 16)
+ reg |= (1 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs));
+ }
+ }
+#endif
+ reg_write(REG_SDRAM_ADDRESS_CTRL_ADDR, reg);
+
+ /*{0x00001418} - DDR SDRAM Operation Register */
+ reg = 0xF00;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ reg &= ~(1 << (cs + REG_SDRAM_OPERATION_CS_OFFS));
+ }
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /*{0x00001420} - DDR SDRAM Extended Mode Register */
+ reg = 0x00000004;
+ reg_write(REG_SDRAM_EXT_MODE_ADDR, reg);
+
+ /*{0x00001424} - DDR Controller Control (High) Register */
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ reg = 0x0000D3FF;
+#else
+ reg = 0x0100D1FF;
+#endif
+ reg_write(REG_DDR_CONT_HIGH_ADDR, reg);
+
+ /*{0x0000142C} - DDR3 Timing Register */
+ reg = 0x014C2F38;
+#if defined(MV88F78X60) || defined(MV88F672X)
+ reg = 0x1FEC2F38;
+#endif
+ reg_write(0x142C, reg);
+
+ /*{0x00001484} - MBus CPU Block Register */
+#ifdef MV88F67XX
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ reg_write(REG_MBUS_CPU_BLOCK_ADDR, 0x0000E907);
+#endif
+
+ /*
+ * In case of mixed dimm and on-board devices setup paramters will
+ * be taken statically
+ */
+ /*{0x00001494} - DDR SDRAM ODT Control (Low) Register */
+ reg = odt_config[cs_ena];
+ reg_write(REG_SDRAM_ODT_CTRL_LOW_ADDR, reg);
+
+ /*{0x00001498} - DDR SDRAM ODT Control (High) Register */
+ reg = 0x00000000;
+ reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+ /*{0x0000149C} - DDR Dunit ODT Control Register */
+ reg = cs_ena;
+ reg_write(REG_DUNIT_ODT_CTRL_ADDR, reg);
+
+ /*{0x000014A0} - DDR Dunit ODT Control Register */
+#if defined(MV88F672X)
+ reg = 0x000006A9;
+ reg_write(REG_DRAM_FIFO_CTRL_ADDR, reg);
+#endif
+
+ /*{0x000014C0} - DRAM address and Control Driving Strenght */
+ reg_write(REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR, 0x192435e9);
+
+ /*{0x000014C4} - DRAM Data and DQS Driving Strenght */
+ reg_write(REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR, 0xB2C35E9);
+
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ /*{0x000014CC} - DRAM Main Pads Calibration Machine Control Register */
+ reg = reg_read(REG_DRAM_MAIN_PADS_CAL_ADDR);
+ reg_write(REG_DRAM_MAIN_PADS_CAL_ADDR, reg | (1 << 0));
+#endif
+
+#if defined(MV88F672X)
+ /* DRAM Main Pads Calibration Machine Control Register */
+ /* 0x14CC[4:3] - CalUpdateControl = IntOnly */
+ reg = reg_read(REG_DRAM_MAIN_PADS_CAL_ADDR);
+ reg &= 0xFFFFFFE7;
+ reg |= (1 << 3);
+ reg_write(REG_DRAM_MAIN_PADS_CAL_ADDR, reg);
+#endif
+
+#ifdef DUNIT_SPD
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if ((1 << cs) & DIMM_CS_BITMAP) {
+ if ((1 << cs) & cs_ena) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks ==
+ cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+ reg_write(REG_CS_SIZE_SCRATCH_ADDR + (cs * 0x8),
+ dimm_info[dimm_cnt].rank_capacity - 1);
+ } else {
+ reg_write(REG_CS_SIZE_SCRATCH_ADDR + (cs * 0x8), 0);
+ }
+ }
+ }
+#endif
+
+ /*{0x00020184} - Close FastPath - 2G */
+ reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, 0);
+
+ /*{0x00001538} - Read Data Sample Delays Register */
+ reg = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ reg |= (cl << (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ }
+
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+ DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Read Data Sample Delays = ", reg,
+ 1);
+
+ /*{0x0000153C} - Read Data Ready Delay Register */
+ reg = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= ((cl + 2) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ }
+ }
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Read Data Ready Delays = ", reg, 1);
+
+ /* Set MR registers */
+ /* MR0 */
+ reg = 0x00000600;
+ tmp = ddr3_cl_to_valid_cl(cl);
+ reg |= ((tmp & 0x1) << 2);
+ reg |= ((tmp & 0xE) << 3); /* to bit 4 */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg_write(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* MR1 */
+ reg = 0x00000044 & REG_DDR3_MR1_ODT_MASK;
+ if (cs_num > 1)
+ reg = 0x00000046 & REG_DDR3_MR1_ODT_MASK;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= odt_static[cs_ena][cs];
+ reg_write(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* MR2 */
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ tmp = hclk_time / 2;
+ else
+ tmp = hclk_time;
+
+ if (tmp >= 2500)
+ cwl = 5; /* CWL = 5 */
+ else if (tmp >= 1875 && tmp < 2500)
+ cwl = 6; /* CWL = 6 */
+ else if (tmp >= 1500 && tmp < 1875)
+ cwl = 7; /* CWL = 7 */
+ else if (tmp >= 1250 && tmp < 1500)
+ cwl = 8; /* CWL = 8 */
+ else if (tmp >= 1070 && tmp < 1250)
+ cwl = 9; /* CWL = 9 */
+ else if (tmp >= 935 && tmp < 1070)
+ cwl = 10; /* CWL = 10 */
+ else if (tmp >= 833 && tmp < 935)
+ cwl = 11; /* CWL = 11 */
+ else if (tmp >= 750 && tmp < 833)
+ cwl = 12; /* CWL = 12 */
+ else {
+ cwl = 12; /* CWL = 12 */
+ printf("Unsupported hclk %d MHz\n", tmp);
+ }
+
+ reg = ((cwl - 5) << REG_DDR3_MR2_CWL_OFFS);
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg &= REG_DDR3_MR2_ODT_MASK;
+ reg |= odt_dynamic[cs_ena][cs];
+ reg_write(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* MR3 */
+ reg = 0x00000000;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg_write(REG_DDR3_MR3_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* {0x00001428} - DDR ODT Timing (Low) Register */
+ reg = 0;
+ reg |= (((cl - cwl + 1) & 0xF) << 4);
+ reg |= (((cl - cwl + 6) & 0xF) << 8);
+ reg |= ((((cl - cwl + 6) >> 4) & 0x1) << 21);
+ reg |= (((cl - 1) & 0xF) << 12);
+ reg |= (((cl + 6) & 0x1F) << 16);
+ reg_write(REG_ODT_TIME_LOW_ADDR, reg);
+
+ /* {0x0000147C} - DDR ODT Timing (High) Register */
+ reg = 0x00000071;
+ reg |= ((cwl - 1) << 8);
+ reg |= ((cwl + 5) << 12);
+ reg_write(REG_ODT_TIME_HIGH_ADDR, reg);
+
+#ifdef DUNIT_SPD
+ /*{0x000015E0} - DDR3 Rank Control Register */
+ reg = cs_ena;
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+
+ if (dimm_info[dimm_cnt].addr_mirroring &&
+ (cs == 1 || cs == 3) &&
+ (sum_info.type_info != SPD_MODULE_TYPE_RDIMM)) {
+ reg |= (1 << (REG_DDR3_RANK_CTRL_MIRROR_OFFS + cs));
+ DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Setting Address Mirroring for CS = ",
+ cs, 1);
+ }
+ }
+ }
+ reg_write(REG_DDR3_RANK_CTRL_ADDR, reg);
+#endif
+
+ /*{0xD00015E4} - ZQDS Configuration Register */
+ reg = 0x00203c18;
+ reg_write(REG_ZQC_CONF_ADDR, reg);
+
+ /* {0x00015EC} - DDR PHY */
+#if defined(MV88F78X60)
+ reg = 0xF800AAA5;
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV)
+ reg = 0xF800A225;
+#else
+ reg = 0xDE000025;
+#if defined(MV88F672X)
+ reg = 0xF800A225;
+#endif
+#endif
+ reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ /* Registered DIMM support - supported only in AXP A0 devices */
+ /* Currently supported for SPD detection only */
+ /*
+ * Flow is according to the Registered DIMM chapter in the
+ * Functional Spec
+ */
+ if (sum_info.type_info == SPD_MODULE_TYPE_RDIMM) {
+ DEBUG_INIT_S("DDR3 Training Sequence - Registered DIMM detected\n");
+
+ /* Set commands parity completion */
+ reg = reg_read(REG_REGISTERED_DRAM_CTRL_ADDR);
+ reg &= ~REG_REGISTERED_DRAM_CTRL_PARITY_MASK;
+ reg |= 0x8;
+ reg_write(REG_REGISTERED_DRAM_CTRL_ADDR, reg);
+
+ /* De-assert M_RESETn and assert M_CKE */
+ reg_write(REG_SDRAM_INIT_CTRL_ADDR,
+ 1 << REG_SDRAM_INIT_CKE_ASSERT_OFFS);
+ do {
+ reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+ (1 << REG_SDRAM_INIT_CKE_ASSERT_OFFS);
+ } while (reg);
+
+ for (rc = 0; rc < SPD_RDIMM_RC_NUM; rc++) {
+ if (rc != 6 && rc != 7) {
+ /* Set CWA Command */
+ reg = (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+ reg |= ((dimm_info[0].dimm_rc[rc] &
+ REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ reg |= rc << REG_SDRAM_OPERATION_CWA_RC_OFFS;
+ /* Configure - Set Delay - tSTAB/tMRD */
+ if (rc == 2 || rc == 10)
+ reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /*
+ * Poll the "cmd" field in the SDRAM OP
+ * register for 0x0
+ */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ (REG_SDRAM_OPERATION_CMD_MASK);
+ } while (reg);
+ }
+ }
+ }
+#endif
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_div - this function divides integers
+ * Desc:
+ * Args: val - the value
+ * divider - the divider
+ * sub - substruction value
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_div(u32 val, u32 divider, u32 sub)
+{
+ return val / divider + (val % divider > 0 ? 1 : 0) - sub;
+}
+
+/*
+ * Name: ddr3_get_max_val
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_max_val(u32 spd_val, u32 dimm_num, u32 static_val)
+{
+#ifdef DUNIT_STATIC
+ if (dimm_num > 0) {
+ if (spd_val >= static_val)
+ return spd_val;
+ else
+ return static_val;
+ } else {
+ return static_val;
+ }
+#else
+ return spd_val;
+#endif
+}
+
+/*
+ * Name: ddr3_get_min_val
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_min_val(u32 spd_val, u32 dimm_num, u32 static_val)
+{
+#ifdef DUNIT_STATIC
+ if (dimm_num > 0) {
+ if (spd_val <= static_val)
+ return spd_val;
+ else
+ return static_val;
+ } else
+ return static_val;
+#else
+ return spd_val;
+#endif
+}
+#endif
diff --git a/drivers/ddr/marvell/axp/ddr3_write_leveling.c b/drivers/ddr/marvell/axp/ddr3_write_leveling.c
new file mode 100644
index 0000000000..df3a3df4a6
--- /dev/null
+++ b/drivers/ddr/marvell/axp/ddr3_write_leveling.c
@@ -0,0 +1,1366 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_WL_C(s, d, l) \
+ DEBUG_WL_S(s); DEBUG_WL_D(d, l); DEBUG_WL_S("\n")
+#define DEBUG_WL_FULL_C(s, d, l) \
+ DEBUG_WL_FULL_S(s); DEBUG_WL_FULL_D(d, l); DEBUG_WL_FULL_S("\n")
+
+#ifdef MV_DEBUG_WL
+#define DEBUG_RL_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_RL_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+#else
+#define DEBUG_WL_S(s)
+#define DEBUG_WL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_WL_FULL
+#define DEBUG_WL_FULL_S(s) puts(s)
+#define DEBUG_WL_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_WL_FULL_S(s)
+#define DEBUG_WL_FULL_D(d, l)
+#endif
+
+#define WL_SUP_EXPECTED_DATA 0x21
+#define WL_SUP_READ_DRAM_ENTRY 0x8
+
+static int ddr3_write_leveling_single_cs(u32 cs, u32 freq, int ratio_2to1,
+ u32 *result,
+ MV_DRAM_INFO *dram_info);
+static void ddr3_write_ctrl_pup_reg(int bc_acc, u32 pup, u32 reg_addr,
+ u32 data);
+
+extern u16 odt_static[ODT_OPT][MAX_CS];
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+extern u32 wl_sup_pattern[LEN_WL_SUP_PATTERN];
+
+/*
+ * Name: ddr3_write_leveling_hw
+ * Desc: Execute Write leveling phase by HW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, phase, delay, cs, pup;
+#ifdef MV88F67XX
+ int dpde_flag = 0;
+#endif
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting HW WL procedure\n");
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ reg = 1 << REG_DRAM_TRAINING_WL_OFFS;
+ /* Config the retest number */
+ reg |= (COUNT_HW_WL << REG_DRAM_TRAINING_RETEST_OFFS);
+ reg |= (dram_info->cs_ena << (REG_DRAM_TRAINING_CS_OFFS));
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+ /* Wait */
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Check if Successful */
+ if (reg & (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+ /*
+ * Read results to arrays - Results are required for WL
+ * High freq Supplement and DQS Centralization
+ */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE, cs,
+ pup);
+ phase =
+ (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ delay = reg & PUP_DELAY_MASK;
+ dram_info->wl_val[cs][pup][P] = phase;
+ dram_info->wl_val[cs][pup][D] = delay;
+ dram_info->wl_val[cs][pup][S] =
+ WL_HI_FREQ_STATE - 1;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE + 0x1,
+ cs, pup);
+ dram_info->wl_val[cs][pup][DQS] =
+ (reg & 0x3F);
+ }
+
+#ifdef MV_DEBUG_WL
+ /* Debug message - Print res for cs[i]: cs,PUP,Phase,Delay */
+ DEBUG_WL_S("DDR3 - Write Leveling - Write Leveling Cs - ");
+ DEBUG_WL_D((u32) cs, 1);
+ DEBUG_WL_S(" Results:\n");
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ DEBUG_WL_S("DDR3 - Write Leveling - PUP: ");
+ DEBUG_WL_D((u32) pup, 1);
+ DEBUG_WL_S(", Phase: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [P], 1);
+ DEBUG_WL_S(", Delay: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [D], 2);
+ DEBUG_WL_S("\n");
+ }
+#endif
+ }
+ }
+
+ /* Dynamic pad issue (BTS669) during WL */
+#ifdef MV88F67XX
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+
+ return MV_OK;
+ } else {
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Error\n");
+ return MV_FAIL;
+ }
+}
+
+/*
+ * Name: ddr3_wl_supplement
+ * Desc: Write Leveling Supplement
+ * Args: dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_wl_supplement(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cnt, pup_num, sum, phase, delay, max_pup_num, pup, sdram_offset;
+ u32 tmp_count, ecc, reg;
+ u32 ddr_width, tmp_pup, idx;
+ u32 sdram_pup_val, uj;
+ u32 one_clk_err = 0, align_err = 0, no_err = 0, err = 0, err_n = 0;
+ u32 sdram_data[LEN_WL_SUP_PATTERN] __aligned(32) = { 0 };
+
+ ddr_width = dram_info->ddr_width;
+ no_err = 0;
+
+ DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - Starting\n");
+
+ switch (ddr_width) {
+ /* Data error from pos-adge to pos-adge */
+ case 16:
+ one_clk_err = 4;
+ align_err = 4;
+ break;
+ case 32:
+ one_clk_err = 8;
+ align_err = 8;
+ break;
+ case 64:
+ one_clk_err = 0x10;
+ align_err = 0x10;
+ break;
+ default:
+ DEBUG_WL_S("Error - bus width!!!\n");
+ return MV_FAIL;
+ }
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - SW Override Enabled\n");
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+ tmp_count = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ sum = 0;
+ /*
+ * 2 iterations loop: 1)actual WL results 2) fix WL
+ * if needed
+ */
+ for (cnt = 0; cnt < COUNT_WL_HI_FREQ; cnt++) {
+ DEBUG_WL_C("COUNT = ", cnt, 1);
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1);
+ ecc++) {
+ if (ecc) {
+ DEBUG_WL_S("ECC PUP:\n");
+ } else {
+ DEBUG_WL_S("DATA PUP:\n");
+ }
+
+ max_pup_num =
+ dram_info->num_of_std_pups * (1 -
+ ecc) +
+ ecc;
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg =
+ (reg_read(REG_DRAM_TRAINING_2_ADDR)
+ & ~(1 <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS));
+ reg |=
+ (dram_info->ecc_ena *
+ ecc <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR,
+ reg);
+ ddr3_reset_phy_read_fifo();
+
+ /* Write to memory */
+ sdram_offset =
+ tmp_count * (SDRAM_CS_SIZE + 1) +
+ 0x200;
+ if (MV_OK != ddr3_dram_sram_burst((u32)
+ wl_sup_pattern,
+ sdram_offset,
+ LEN_WL_SUP_PATTERN))
+ return MV_FAIL;
+
+ /* Read from memory */
+ if (MV_OK !=
+ ddr3_dram_sram_burst(sdram_offset,
+ (u32)
+ sdram_data,
+ LEN_WL_SUP_PATTERN))
+ return MV_FAIL;
+
+ /* Print the buffer */
+ for (uj = 0; uj < LEN_WL_SUP_PATTERN;
+ uj++) {
+ if ((uj % 4 == 0) && (uj != 0)) {
+ DEBUG_WL_S("\n");
+ }
+ DEBUG_WL_D(sdram_data[uj],
+ 8);
+ DEBUG_WL_S(" ");
+ }
+
+ /* Check pup which DQS/DATA is error */
+ for (pup = 0; pup < max_pup_num; pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (ecc) ? ECC_PUP : pup;
+ if (pup < 4) { /* lower 32 bit */
+ tmp_pup = pup;
+ idx =
+ WL_SUP_READ_DRAM_ENTRY;
+ } else { /* higher 32 bit */
+ tmp_pup = pup - 4;
+ idx =
+ WL_SUP_READ_DRAM_ENTRY
+ + 1;
+ }
+ DEBUG_WL_S("\nCS: ");
+ DEBUG_WL_D((u32) cs, 1);
+ DEBUG_WL_S(" PUP: ");
+ DEBUG_WL_D((u32) pup_num, 1);
+ DEBUG_WL_S("\n");
+ sdram_pup_val =
+ ((sdram_data[idx] >>
+ ((tmp_pup) * 8)) & 0xFF);
+ DEBUG_WL_C("Actual Data = ",
+ sdram_pup_val, 2);
+ DEBUG_WL_C("Expected Data = ",
+ (WL_SUP_EXPECTED_DATA
+ + pup), 2);
+ /*
+ * ALINGHMENT: calculate
+ * expected data vs actual data
+ */
+ err =
+ (WL_SUP_EXPECTED_DATA +
+ pup) - sdram_pup_val;
+ /*
+ * CLOCK LONG: calculate
+ * expected data vs actual data
+ */
+ err_n =
+ sdram_pup_val -
+ (WL_SUP_EXPECTED_DATA +
+ pup);
+ DEBUG_WL_C("err = ", err, 2);
+ DEBUG_WL_C("err_n = ", err_n,
+ 2);
+ if (err == no_err) {
+ /* PUP is correct - increment State */
+ dram_info->wl_val[cs]
+ [pup_num]
+ [S] = 1;
+ } else if (err_n == one_clk_err) {
+ /* clock is longer than DQS */
+ phase =
+ ((dram_info->wl_val
+ [cs]
+ [pup_num][P] +
+ WL_HI_FREQ_SHIFT)
+ % MAX_PHASE_2TO1);
+ dram_info->wl_val[cs]
+ [pup_num]
+ [P] = phase;
+ delay =
+ dram_info->wl_val
+ [cs][pup_num]
+ [D];
+ DEBUG_WL_S("#### Clock is longer than DQS more than one clk cycle ####\n");
+ ddr3_write_pup_reg
+ (PUP_WL_MODE, cs,
+ pup * (1 - ecc) +
+ ECC_PUP * ecc,
+ phase, delay);
+ } else if (err == align_err) {
+ /* clock is align to DQS */
+ phase =
+ dram_info->wl_val
+ [cs][pup_num]
+ [P];
+ delay =
+ dram_info->wl_val
+ [cs][pup_num]
+ [D];
+ DEBUG_WL_S("#### Alignment PUPS problem ####\n");
+ if ((phase == 0)
+ || ((phase == 1)
+ && (delay <=
+ 0x10))) {
+ DEBUG_WL_S("#### Warning - Possible Layout Violation (DQS is longer than CLK)####\n");
+ }
+
+ phase = 0x0;
+ delay = 0x0;
+ dram_info->wl_val[cs]
+ [pup_num]
+ [P] = phase;
+ dram_info->wl_val[cs]
+ [pup_num]
+ [D] = delay;
+ ddr3_write_pup_reg
+ (PUP_WL_MODE, cs,
+ pup * (1 - ecc) +
+ ECC_PUP * ecc,
+ phase, delay);
+ }
+ /* Stop condition for ECC phase */
+ pup = (ecc) ? max_pup_num : pup;
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg =
+ (reg_read(REG_DRAM_TRAINING_2_ADDR)
+ & ~(1 <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS));
+ reg_write(REG_DRAM_TRAINING_2_ADDR,
+ reg);
+ }
+ }
+
+ for (pup = 0; pup < dram_info->num_of_std_pups; pup++)
+ sum += dram_info->wl_val[cs][pup][S];
+
+ if (dram_info->ecc_ena)
+ sum += dram_info->wl_val[cs][ECC_PUP][S];
+
+ /* Checks if any pup is not locked after the change */
+ if (sum < (WL_HI_FREQ_STATE * (dram_info->num_of_total_pups))) {
+ DEBUG_WL_C("DDR3 - Write Leveling Hi-Freq Supplement - didn't work for Cs - ",
+ (u32) cs, 1);
+ return MV_FAIL;
+ }
+ tmp_count++;
+ }
+ }
+
+ dram_info->wl_max_phase = 0;
+ dram_info->wl_min_phase = 10;
+
+ /*
+ * Read results to arrays - Results are required for DQS Centralization
+ */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ reg = ddr3_read_pup_reg(PUP_WL_MODE, cs, pup);
+ phase =
+ (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ if (phase > dram_info->wl_max_phase)
+ dram_info->wl_max_phase = phase;
+ if (phase < dram_info->wl_min_phase)
+ dram_info->wl_min_phase = phase;
+ }
+ }
+ }
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - Ended Successfully\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_write_leveling_hw_reg_dimm
+ * Desc: Execute Write leveling phase by HW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_hw_reg_dimm(u32 freq, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, phase, delay, cs, pup, pup_num;
+ __maybe_unused int dpde_flag = 0;
+
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting HW WL procedure\n");
+
+ if (dram_info->num_cs > 2) {
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+ return MV_NO_CHANGE;
+ }
+
+ /* If target freq = 400 move clock start point */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+ /* PUP_DELAY_MASK 0x1F */
+ /* reg = 0x0C10001F + (uj << 16); */
+ ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+ 0x1F);
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ reg = (1 << REG_DRAM_TRAINING_WL_OFFS);
+ /* Config the retest number */
+ reg |= (COUNT_HW_WL << REG_DRAM_TRAINING_RETEST_OFFS);
+ reg |= (dram_info->cs_ena << (REG_DRAM_TRAINING_CS_OFFS));
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+ /* Wait */
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Check if Successful */
+ if (reg & (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+ /*
+ * Read results to arrays - Results are required for WL High
+ * freq Supplement and DQS Centralization
+ */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_BIT;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE, cs,
+ pup);
+ phase =
+ (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ delay = reg & PUP_DELAY_MASK;
+ dram_info->wl_val[cs][pup][P] = phase;
+ dram_info->wl_val[cs][pup][D] = delay;
+ if ((phase == 1) && (delay >= 0x1D)) {
+ /*
+ * Need to do it here for
+ * uncorrect WL values
+ */
+ ddr3_write_pup_reg(PUP_WL_MODE,
+ cs, pup, 0,
+ 0);
+ dram_info->wl_val[cs][pup][P] =
+ 0;
+ dram_info->wl_val[cs][pup][D] =
+ 0;
+ }
+ dram_info->wl_val[cs][pup][S] =
+ WL_HI_FREQ_STATE - 1;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE + 0x1,
+ cs, pup);
+ dram_info->wl_val[cs][pup][DQS] =
+ (reg & 0x3F);
+ }
+#ifdef MV_DEBUG_WL
+ /*
+ * Debug message - Print res for cs[i]:
+ * cs,PUP,Phase,Delay
+ */
+ DEBUG_WL_S("DDR3 - Write Leveling - Write Leveling Cs - ");
+ DEBUG_WL_D((u32) cs, 1);
+ DEBUG_WL_S(" Results:\n");
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ DEBUG_WL_S
+ ("DDR3 - Write Leveling - PUP: ");
+ DEBUG_WL_D((u32) pup, 1);
+ DEBUG_WL_S(", Phase: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [P], 1);
+ DEBUG_WL_S(", Delay: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [D], 2);
+ DEBUG_WL_S("\n");
+ }
+#endif
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+
+ /* If target freq = 400 move clock back */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups;
+ pup++) {
+ ddr3_write_ctrl_pup_reg(1, pup,
+ CNTRL_PUP_DESKEW + pup, 0);
+ }
+ }
+
+ return MV_OK;
+ } else {
+ /* Configure Each PUP with locked leveling settings */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ?
+ ECC_BIT : pup;
+ ddr3_write_pup_reg(PUP_WL_MODE, cs,
+ pup_num, 0, 0);
+ }
+ }
+ }
+
+ reg_write(REG_DRAM_TRAINING_ADDR, 0);
+
+ /* If target freq = 400 move clock back */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups;
+ pup++) {
+ ddr3_write_ctrl_pup_reg(1, pup,
+ CNTRL_PUP_DESKEW + pup, 0);
+ }
+ }
+
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+ return MV_NO_CHANGE;
+ }
+}
+
+/*
+ * Name: ddr3_write_leveling_sw
+ * Desc: Execute Write leveling phase by SW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, cs, cnt, pup, max_pup_num;
+ u32 res[MAX_CS];
+ max_pup_num = dram_info->num_of_total_pups;
+ __maybe_unused int dpde_flag = 0;
+
+ /* Debug message - Start Write leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting SW WL procedure\n");
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ /* Set Output buffer-off to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+
+ /* 0x15D0 - DDR3 MR0 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Qoff and RTT Values are set for all Cs\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - SW Override Enabled\n");
+
+ /* Enable PHY write leveling mode */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* [2] = 0 - TrnWLMode - Enable */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ /* Reset WL results arry */
+ memset(dram_info->wl_val, 0, sizeof(u32) * MAX_CS * MAX_PUP_NUM * 7);
+
+ /* Loop for each cs */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Starting working with Cs - ",
+ (u32) cs, 1);
+ /* Refresh X9 current cs */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Refresh X9\n");
+ for (cnt = 0; cnt < COUNT_WL_RFRS; cnt++) {
+ reg =
+ REG_SDRAM_OPERATION_CMD_RFRS & ~(1 <<
+ (REG_SDRAM_OPERATION_CS_OFFS
+ + cs));
+ /* [3-0] = 0x2 - refresh, [11-8] - enable current cs */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg); /* 0x1418 - SDRAM Operation Register */
+
+ do {
+ reg =
+ ((reg_read
+ (REG_SDRAM_OPERATION_ADDR)) &
+ REG_SDRAM_OPERATION_CMD_RFRS_DONE);
+ } while (reg); /* Wait for '0' */
+ }
+
+ /* Configure MR1 in Cs[CsNum] - write leveling on, output buffer on */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Configure MR1 for current Cs: WL-on,OB-on\n");
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ /* Set ODT Values */
+ reg &= REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ /* Enable WL MODE */
+ reg |= (1 << REG_DDR3_MR1_WL_ENA_OFFS);
+ /* [7]=1, [12]=0 - Output Buffer and write leveling enabled */
+ reg_write(REG_DDR3_MR1_ADDR, reg); /* 0x15D4 - DDR3 MR1 Register */
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+
+ /* Write leveling cs[cs] */
+ if (MV_OK !=
+ ddr3_write_leveling_single_cs(cs, freq, ratio_2to1,
+ (u32 *)(res + cs),
+ dram_info)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling single Cs - FAILED - Cs - ",
+ (u32) cs, 1);
+ for (pup = 0; pup < max_pup_num; pup++) {
+ if (((res[cs] >> pup) & 0x1) == 0) {
+ DEBUG_WL_C("Failed Byte : ",
+ pup, 1);
+ }
+ }
+ return MV_FAIL;
+ }
+
+ /* Set TrnWLDeUpd - After each CS is done */
+ reg = reg_read(REG_TRAINING_WL_ADDR) |
+ (1 << REG_TRAINING_WL_CS_DONE_OFFS);
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /*
+ * Debug message - Finished Write leveling cs[cs] -
+ * each PUP Fail/Success
+ */
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Finished Cs - ", (u32) cs,
+ 1);
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - The Results: 1-PUP locked, 0-PUP failed -",
+ (u32) res[cs], 3);
+
+ /*
+ * Configure MR1 in cs[cs] - write leveling off (0),
+ * output buffer off (1)
+ */
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+ /* No need to sort ODT since it is same CS */
+ /* 0x15D4 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ /* Disable WL Mode */
+ /* [2]=1 - TrnWLMode - Disable */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= (1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Set Output buffer-on to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg &= REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+
+ /* 0x15D0 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Finished WL procedure for all Cs\n");
+
+ return MV_OK;
+}
+
+#if !defined(MV88F672X)
+/*
+ * Name: ddr3_write_leveling_sw
+ * Desc: Execute Write leveling phase by SW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_sw_reg_dimm(u32 freq, int ratio_2to1,
+ MV_DRAM_INFO *dram_info)
+{
+ u32 reg, cs, cnt, pup;
+ u32 res[MAX_CS];
+ __maybe_unused int dpde_flag = 0;
+
+ /* Debug message - Start Write leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting SW WL procedure\n");
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ /* If target freq = 400 move clock start point */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+ /* PUP_DELAY_MASK 0x1F */
+ /* reg = 0x0C10001F + (uj << 16); */
+ ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+ 0x1F);
+ }
+ }
+
+ /* Set Output buffer-off to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+
+ /* 0x15D0 - DDR3 MR0 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Qoff and RTT Values are set for all Cs\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - SW Override Enabled\n");
+
+ /* Enable PHY write leveling mode */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* [2] = 0 - TrnWLMode - Enable */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Loop for each cs */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Starting working with Cs - ",
+ (u32) cs, 1);
+
+ /* Refresh X9 current cs */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Refresh X9\n");
+ for (cnt = 0; cnt < COUNT_WL_RFRS; cnt++) {
+ reg =
+ REG_SDRAM_OPERATION_CMD_RFRS & ~(1 <<
+ (REG_SDRAM_OPERATION_CS_OFFS
+ + cs));
+ /* [3-0] = 0x2 - refresh, [11-8] - enable current cs */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg); /* 0x1418 - SDRAM Operation Register */
+
+ do {
+ reg =
+ ((reg_read
+ (REG_SDRAM_OPERATION_ADDR)) &
+ REG_SDRAM_OPERATION_CMD_RFRS_DONE);
+ } while (reg); /* Wait for '0' */
+ }
+
+ /*
+ * Configure MR1 in Cs[CsNum] - write leveling on,
+ * output buffer on
+ */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Configure MR1 for current Cs: WL-on,OB-on\n");
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ /* Set ODT Values */
+ reg &= REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ /* Enable WL MODE */
+ reg |= (1 << REG_DDR3_MR1_WL_ENA_OFFS);
+ /*
+ * [7]=1, [12]=0 - Output Buffer and write leveling
+ * enabled
+ */
+ /* 0x15D4 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+
+ /* Write leveling cs[cs] */
+ if (MV_OK !=
+ ddr3_write_leveling_single_cs(cs, freq, ratio_2to1,
+ (u32 *)(res + cs),
+ dram_info)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling single Cs - FAILED - Cs - ",
+ (u32) cs, 1);
+ return MV_FAIL;
+ }
+
+ /* Set TrnWLDeUpd - After each CS is done */
+ reg = reg_read(REG_TRAINING_WL_ADDR) |
+ (1 << REG_TRAINING_WL_CS_DONE_OFFS);
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /*
+ * Debug message - Finished Write leveling cs[cs] -
+ * each PUP Fail/Success
+ */
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Finished Cs - ", (u32) cs,
+ 1);
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - The Results: 1-PUP locked, 0-PUP failed -",
+ (u32) res[cs], 3);
+
+ /* Configure MR1 in cs[cs] - write leveling off (0), output buffer off (1) */
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+ /* No need to sort ODT since it is same CS */
+ /* 0x15D4 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ /* Disable WL Mode */
+ /* [2]=1 - TrnWLMode - Disable */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= (1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Set Output buffer-on to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg &= REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+
+ /* 0x15D0 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+
+ /* If target freq = 400 move clock back */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+ ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+ 0);
+ }
+ }
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Finished WL procedure for all Cs\n");
+ return MV_OK;
+}
+#endif
+
+/*
+ * Name: ddr3_write_leveling_single_cs
+ * Desc: Execute Write leveling for single Chip select
+ * Args: cs - current chip select
+ * freq - current sequence frequency
+ * result - res array
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_write_leveling_single_cs(u32 cs, u32 freq, int ratio_2to1,
+ u32 *result, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, pup_num, delay, phase, phaseMax, max_pup_num, pup,
+ max_pup_mask;
+
+ max_pup_num = dram_info->num_of_total_pups;
+ *result = 0;
+ u32 flag[MAX_PUP_NUM] = { 0 };
+
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling Single Cs - WL for Cs - ",
+ (u32) cs, 1);
+
+ switch (max_pup_num) {
+ case 2:
+ max_pup_mask = 0x3;
+ break;
+ case 4:
+ max_pup_mask = 0xf;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ case 5:
+ max_pup_mask = 0x1f;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ case 8:
+ max_pup_mask = 0xff;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ case 9:
+ max_pup_mask = 0x1ff;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ default:
+ DEBUG_WL_C("ddr3_write_leveling_single_cs wrong max_pup_num = ",
+ max_pup_num, 3);
+ return MV_FAIL;
+ }
+
+ /* CS ODT Override */
+ reg = reg_read(REG_SDRAM_ODT_CTRL_HIGH_ADDR) &
+ REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK;
+ reg |= (REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA << (2 * cs));
+ /* Set 0x3 - Enable ODT on the curent cs and disable on other cs */
+ /* 0x1498 - SDRAM ODT Control high */
+ reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - ODT Asserted for current Cs\n");
+
+ /* tWLMRD Delay */
+ /* Delay of minimum 40 Dram clock cycles - 20 Tclk cycles */
+ udelay(1);
+
+ /* [1:0] - current cs number */
+ reg = (reg_read(REG_TRAINING_WL_ADDR) & REG_TRAINING_WL_CS_MASK) | cs;
+ reg |= (1 << REG_TRAINING_WL_UPD_OFFS); /* [2] - trnWLCsUpd */
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /* Broadcast to all PUPs: Reset DQS phase, reset leveling delay */
+ ddr3_write_pup_reg(PUP_WL_MODE, cs, PUP_BC, 0, 0);
+
+ /* Seek Edge */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Current Cs\n");
+
+ /* Drive DQS high for one cycle - All data PUPs */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Driving DQS high for one cycle\n");
+ if (!ratio_2to1) {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) | REG_TRAINING_WL_1TO1;
+ } else {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) | REG_TRAINING_WL_2TO1;
+ }
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /* Wait tWLdelay */
+ do {
+ /* [29] - trnWLDelayExp */
+ reg = (reg_read(REG_TRAINING_WL_ADDR)) &
+ REG_TRAINING_WL_DELAYEXP_MASK;
+ } while (reg == 0x0); /* Wait for '1' */
+
+ /* Read WL res */
+ reg = (reg_read(REG_TRAINING_WL_ADDR) >> REG_TRAINING_WL_RESULTS_OFFS) &
+ REG_TRAINING_WL_RESULTS_MASK;
+ /* [28:20] - TrnWLResult */
+
+ if (!ratio_2to1) /* Different phase options for 2:1 or 1:1 modes */
+ phaseMax = MAX_PHASE_1TO1;
+ else
+ phaseMax = MAX_PHASE_2TO1;
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Shift DQS + Octet Leveling\n");
+
+ /* Shift DQS + Octet leveling */
+ for (phase = 0; phase < phaseMax; phase++) {
+ for (delay = 0; delay < MAX_DELAY; delay++) {
+ /* Broadcast to all PUPs: DQS phase,leveling delay */
+ ddr3_write_pup_reg(PUP_WL_MODE, cs, PUP_BC, phase,
+ delay);
+
+ udelay(1); /* Delay of 3 Tclk cycles */
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge: Phase = ");
+ DEBUG_WL_FULL_D((u32) phase, 1);
+ DEBUG_WL_FULL_S(", Delay = ");
+ DEBUG_WL_FULL_D((u32) delay, 1);
+ DEBUG_WL_FULL_S(", Counter = ");
+ DEBUG_WL_FULL_D((u32) i, 1);
+ DEBUG_WL_FULL_S("\n");
+
+ /* Drive DQS high for one cycle - All data PUPs */
+ if (!ratio_2to1) {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) |
+ REG_TRAINING_WL_1TO1;
+ } else {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) |
+ REG_TRAINING_WL_2TO1;
+ }
+ reg_write(REG_TRAINING_WL_ADDR, reg); /* 0x16AC */
+
+ /* Wait tWLdelay */
+ do {
+ reg = (reg_read(REG_TRAINING_WL_ADDR)) &
+ REG_TRAINING_WL_DELAYEXP_MASK;
+ } while (reg == 0x0); /* [29] Wait for '1' */
+
+ /* Read WL res */
+ reg = reg_read(REG_TRAINING_WL_ADDR);
+ reg = (reg >> REG_TRAINING_WL_RESULTS_OFFS) &
+ REG_TRAINING_WL_RESULTS_MASK; /* [28:20] */
+
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling Single Cs - Seek Edge: Results = ",
+ (u32) reg, 3);
+
+ /* Update State machine */
+ for (pup = 0; pup < (max_pup_num); pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ?
+ ECC_BIT : pup;
+ if (dram_info->wl_val[cs][pup][S] == 0) {
+ /* Update phase to PUP */
+ dram_info->wl_val[cs][pup][P] = phase;
+ /* Update delay to PUP */
+ dram_info->wl_val[cs][pup][D] = delay;
+ }
+
+ if (((reg >> pup_num) & 0x1) == 0)
+ flag[pup_num] = 1;
+
+ if (((reg >> pup_num) & 0x1)
+ && (flag[pup_num] == 1)
+ && (dram_info->wl_val[cs][pup][S] == 0)) {
+ /*
+ * If the PUP is locked now and in last
+ * counter states
+ */
+ /* Go to next state */
+ dram_info->wl_val[cs][pup][S] = 1;
+ /* Set res */
+ *result = *result | (1 << pup_num);
+ }
+ }
+
+ /* If all locked - Break the loops - Finished */
+ if (*result == max_pup_mask) {
+ phase = phaseMax;
+ delay = MAX_DELAY;
+ DEBUG_WL_S("DDR3 - Write Leveling Single Cs - Seek Edge: All Locked\n");
+ }
+ }
+ }
+
+ /* Debug message - Print res for cs[i]: cs,PUP,Phase,Delay */
+ DEBUG_WL_C("DDR3 - Write Leveling - Results for CS - ", (u32) cs, 1);
+ for (pup = 0; pup < (max_pup_num); pup++) {
+ DEBUG_WL_S("DDR3 - Write Leveling - PUP: ");
+ DEBUG_WL_D((u32) pup, 1);
+ DEBUG_WL_S(", Phase: ");
+ DEBUG_WL_D((u32) dram_info->wl_val[cs][pup][P], 1);
+ DEBUG_WL_S(", Delay: ");
+ DEBUG_WL_D((u32) dram_info->wl_val[cs][pup][D], 2);
+ DEBUG_WL_S("\n");
+ }
+
+ /* Check if some not locked and return error */
+ if (*result != max_pup_mask) {
+ DEBUG_WL_S("DDR3 - Write Leveling - ERROR - not all PUPS were locked\n");
+ return MV_FAIL;
+ }
+
+ /* Configure Each PUP with locked leveling settings */
+ for (pup = 0; pup < (max_pup_num); pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ? ECC_BIT : pup;
+ phase = dram_info->wl_val[cs][pup][P];
+ delay = dram_info->wl_val[cs][pup][D];
+ ddr3_write_pup_reg(PUP_WL_MODE, cs, pup_num, phase, delay);
+ }
+
+ /* CS ODT Override */
+ reg = reg_read(REG_SDRAM_ODT_CTRL_HIGH_ADDR) &
+ REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK;
+ /* 0x1498 - SDRAM ODT Control high */
+ reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Perform DDR3 Control PUP Indirect Write
+ */
+static void ddr3_write_ctrl_pup_reg(int bc_acc, u32 pup, u32 reg_addr, u32 data)
+{
+ u32 reg = 0;
+
+ /* Store value for write */
+ reg = (data & 0xFFFF);
+
+ /* Set bit 26 for control PHY access */
+ reg |= (1 << REG_PHY_CNTRL_OFFS);
+
+ /* Configure BC or UC access to PHYs */
+ if (bc_acc == 1)
+ reg |= (1 << REG_PHY_BC_OFFS);
+ else
+ reg |= (pup << REG_PHY_PUP_OFFS);
+
+ /* Set PHY register address to write to */
+ reg |= (reg_addr << REG_PHY_CS_OFFS);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = (reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+}
diff --git a/drivers/ddr/marvell/axp/xor.c b/drivers/ddr/marvell/axp/xor.c
new file mode 100644
index 0000000000..66c96aef4e
--- /dev/null
+++ b/drivers/ddr/marvell/axp/xor.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "xor.h"
+#include "xor_regs.h"
+
+static u32 xor_regs_ctrl_backup;
+static u32 xor_regs_base_backup[MAX_CS];
+static u32 xor_regs_mask_backup[MAX_CS];
+
+static void mv_xor_hal_init(u32 chan_num);
+static int mv_xor_cmd_set(u32 chan, int command);
+static int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl);
+
+void mv_sys_xor_init(MV_DRAM_INFO *dram_info)
+{
+ u32 reg, ui, base, cs_count;
+
+ xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
+ for (ui = 0; ui < MAX_CS; ui++)
+ xor_regs_base_backup[ui] = reg_read(XOR_BASE_ADDR_REG(0, ui));
+ for (ui = 0; ui < MAX_CS; ui++)
+ xor_regs_mask_backup[ui] = reg_read(XOR_SIZE_MASK_REG(0, ui));
+
+ reg = 0;
+ for (ui = 0; ui < (dram_info->num_cs + 1); ui++) {
+ /* Enable Window x for each CS */
+ reg |= (0x1 << (ui));
+ /* Enable Window x for each CS */
+ reg |= (0x3 << ((ui * 2) + 16));
+ }
+
+ reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
+
+ /* Last window - Base - 0x40000000, Attribute 0x1E - SRAM */
+ base = (SRAM_BASE & 0xFFFF0000) | 0x1E00;
+ reg_write(XOR_BASE_ADDR_REG(0, dram_info->num_cs), base);
+ /* Last window - Size - 64 MB */
+ reg_write(XOR_SIZE_MASK_REG(0, dram_info->num_cs), 0x03FF0000);
+
+ cs_count = 0;
+ for (ui = 0; ui < MAX_CS; ui++) {
+ if (dram_info->cs_ena & (1 << ui)) {
+ /*
+ * Window x - Base - 0x00000000, Attribute 0x0E - DRAM
+ */
+ base = 0;
+ switch (ui) {
+ case 0:
+ base |= 0xE00;
+ break;
+ case 1:
+ base |= 0xD00;
+ break;
+ case 2:
+ base |= 0xB00;
+ break;
+ case 3:
+ base |= 0x700;
+ break;
+ }
+
+ reg_write(XOR_BASE_ADDR_REG(0, cs_count), base);
+
+ /* Window x - Size - 256 MB */
+ reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x0FFF0000);
+ cs_count++;
+ }
+ }
+
+ mv_xor_hal_init(1);
+
+ return;
+}
+
+void mv_sys_xor_finish(void)
+{
+ u32 ui;
+
+ reg_write(XOR_WINDOW_CTRL_REG(0, 0), xor_regs_ctrl_backup);
+ for (ui = 0; ui < MAX_CS; ui++)
+ reg_write(XOR_BASE_ADDR_REG(0, ui), xor_regs_base_backup[ui]);
+ for (ui = 0; ui < MAX_CS; ui++)
+ reg_write(XOR_SIZE_MASK_REG(0, ui), xor_regs_mask_backup[ui]);
+
+ reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
+}
+
+/*
+ * mv_xor_hal_init - Initialize XOR engine
+ *
+ * DESCRIPTION:
+ * This function initialize XOR unit.
+ * INPUT:
+ * None.
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ */
+static void mv_xor_hal_init(u32 chan_num)
+{
+ u32 i;
+
+ /* Abort any XOR activity & set default configuration */
+ for (i = 0; i < chan_num; i++) {
+ mv_xor_cmd_set(i, MV_STOP);
+ mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
+ (4 << XEXCR_DST_BURST_LIMIT_OFFS) |
+ (4 << XEXCR_SRC_BURST_LIMIT_OFFS));
+ }
+}
+
+/*
+ * mv_xor_ctrl_set - Set XOR channel control registers
+ *
+ * DESCRIPTION:
+ *
+ * INPUT:
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ * NOTE:
+ * This function does not modify the OperationMode field of control register.
+ *
+ */
+static int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
+{
+ u32 val;
+
+ /* Update the XOR Engine [0..1] Configuration Registers (XExCR) */
+ val = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)))
+ & XEXCR_OPERATION_MODE_MASK;
+ xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
+ xor_ctrl |= val;
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
+
+ return MV_OK;
+}
+
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, u32 init_val_high,
+ u32 init_val_low)
+{
+ u32 tmp;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN)
+ return MV_BAD_PARAM;
+
+ if (MV_ACTIVE == mv_xor_state_get(chan))
+ return MV_BUSY;
+
+ if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
+ (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
+ return MV_BAD_PARAM;
+
+ /* Set the operation mode to Memory Init */
+ tmp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ tmp &= ~XEXCR_OPERATION_MODE_MASK;
+ tmp |= XEXCR_OPERATION_MODE_MEM_INIT;
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), tmp);
+
+ /*
+ * Update the start_ptr field in XOR Engine [0..1] Destination Pointer
+ * Register (XExDPR0)
+ */
+ reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
+
+ /*
+ * Update the BlockSize field in the XOR Engine[0..1] Block Size
+ * Registers (XExBSR)
+ */
+ reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ block_size);
+
+ /*
+ * Update the field InitValL in the XOR Engine Initial Value Register
+ * Low (XEIVRL)
+ */
+ reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
+
+ /*
+ * Update the field InitValH in the XOR Engine Initial Value Register
+ * High (XEIVRH)
+ */
+ reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
+
+ /* Start transfer */
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+
+ return MV_OK;
+}
+
+/*
+ * mv_xor_transfer - Transfer data from source to destination on one of
+ * three modes (XOR,CRC32,DMA)
+ *
+ * DESCRIPTION:
+ * This function initiates XOR channel, according to function parameters,
+ * in order to perform XOR or CRC32 or DMA transaction.
+ * To gain maximum performance the user is asked to keep the following
+ * restrictions:
+ * 1) Selected engine is available (not busy).
+ * 1) This module does not take into consideration CPU MMU issues.
+ * In order for the XOR engine to access the appropreate source
+ * and destination, address parameters must be given in system
+ * physical mode.
+ * 2) This API does not take care of cache coherency issues. The source,
+ * destination and in case of chain the descriptor list are assumed
+ * to be cache coherent.
+ * 4) Parameters validity. For example, does size parameter exceeds
+ * maximum byte count of descriptor mode (16M or 64K).
+ *
+ * INPUT:
+ * chan - XOR channel number. See MV_XOR_CHANNEL enumerator.
+ * xor_type - One of three: XOR, CRC32 and DMA operations.
+ * xor_chain_ptr - address of chain pointer
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURS:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ *
+ */
+int mv_xor_transfer(u32 chan, int xor_type, u32 xor_chain_ptr)
+{
+ u32 tmp;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+ return MV_BAD_PARAM;
+ }
+
+ if (MV_ACTIVE == mv_xor_state_get(chan)) {
+ debug("%s: ERR. Channel is already active\n", __func__);
+ return MV_BUSY;
+ }
+
+ if (0x0 == xor_chain_ptr) {
+ debug("%s: ERR. xor_chain_ptr is NULL pointer\n", __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Read configuration register and mask the operation mode field */
+ tmp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ tmp &= ~XEXCR_OPERATION_MODE_MASK;
+
+ switch (xor_type) {
+ case MV_XOR:
+ if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_XOR_MASK)) {
+ debug("%s: ERR. Invalid chain pointer (bits [5:0] must be cleared)\n",
+ __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Set the operation mode to XOR */
+ tmp |= XEXCR_OPERATION_MODE_XOR;
+ break;
+
+ case MV_DMA:
+ if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_DMA_MASK)) {
+ debug("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
+ __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Set the operation mode to DMA */
+ tmp |= XEXCR_OPERATION_MODE_DMA;
+ break;
+
+ case MV_CRC32:
+ if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_CRC_MASK)) {
+ debug("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
+ __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Set the operation mode to CRC32 */
+ tmp |= XEXCR_OPERATION_MODE_CRC;
+ break;
+
+ default:
+ return MV_BAD_PARAM;
+ }
+
+ /* Write the operation mode to the register */
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), tmp);
+
+ /*
+ * Update the NextDescPtr field in the XOR Engine [0..1] Next Descriptor
+ * Pointer Register (XExNDPR)
+ */
+ reg_write(XOR_NEXT_DESC_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ xor_chain_ptr);
+
+ /* Start transfer */
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+
+ return MV_OK;
+}
+
+/*
+ * mv_xor_state_get - Get XOR channel state.
+ *
+ * DESCRIPTION:
+ * XOR channel activity state can be active, idle, paused.
+ * This function retrunes the channel activity state.
+ *
+ * INPUT:
+ * chan - the channel number
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * XOR_CHANNEL_IDLE - If the engine is idle.
+ * XOR_CHANNEL_ACTIVE - If the engine is busy.
+ * XOR_CHANNEL_PAUSED - If the engine is paused.
+ * MV_UNDEFINED_STATE - If the engine state is undefind or there is no
+ * such engine
+ *
+ */
+int mv_xor_state_get(u32 chan)
+{
+ u32 state;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+ return MV_UNDEFINED_STATE;
+ }
+
+ /* Read the current state */
+ state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ state &= XEXACTR_XESTATUS_MASK;
+
+ /* Return the state */
+ switch (state) {
+ case XEXACTR_XESTATUS_IDLE:
+ return MV_IDLE;
+ case XEXACTR_XESTATUS_ACTIVE:
+ return MV_ACTIVE;
+ case XEXACTR_XESTATUS_PAUSED:
+ return MV_PAUSED;
+ }
+
+ return MV_UNDEFINED_STATE;
+}
+
+/*
+ * mv_xor_cmd_set - Set command of XOR channel
+ *
+ * DESCRIPTION:
+ * XOR channel can be started, idle, paused and restarted.
+ * Paused can be set only if channel is active.
+ * Start can be set only if channel is idle or paused.
+ * Restart can be set only if channel is paused.
+ * Stop can be set only if channel is active.
+ *
+ * INPUT:
+ * chan - The channel number
+ * command - The command type (start, stop, restart, pause)
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
+ * undefind XOR engine mode
+ *
+ */
+static int mv_xor_cmd_set(u32 chan, int command)
+{
+ int state;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+ return MV_BAD_PARAM;
+ }
+
+ /* Get the current state */
+ state = mv_xor_state_get(chan);
+
+ /* Command is start and current state is idle */
+ if ((command == MV_START) && (state == MV_IDLE)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+ return MV_OK;
+ }
+ /* Command is stop and current state is active */
+ else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTOP_MASK);
+ return MV_OK;
+ }
+ /* Command is paused and current state is active */
+ else if ((command == MV_PAUSED) && (state == MV_ACTIVE)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XEPAUSE_MASK);
+ return MV_OK;
+ }
+ /* Command is restart and current state is paused */
+ else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XERESTART_MASK);
+ return MV_OK;
+ }
+ /* Command is stop and current state is active */
+ else if ((command == MV_STOP) && (state == MV_IDLE))
+ return MV_OK;
+
+ /* Illegal command */
+ debug("%s: ERR. Illegal command\n", __func__);
+
+ return MV_BAD_PARAM;
+}
diff --git a/drivers/ddr/marvell/axp/xor.h b/drivers/ddr/marvell/axp/xor.h
new file mode 100644
index 0000000000..353648758a
--- /dev/null
+++ b/drivers/ddr/marvell/axp/xor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __XOR_H
+#define __XOR_H
+
+#include "ddr3_hw_training.h"
+
+#define MV_XOR_MAX_CHAN 4 /* total channels for all units together */
+
+/*
+ * This enumerator describes the type of functionality the XOR channel
+ * can have while using the same data structures.
+ */
+enum xor_type {
+ MV_XOR, /* XOR channel functions as XOR accelerator */
+ MV_DMA, /* XOR channel functions as IDMA channel */
+ MV_CRC32 /* XOR channel functions as CRC 32 calculator */
+};
+
+/*
+ * This enumerator describes the set of commands that can be applied on
+ * an engine (e.g. IDMA, XOR). Appling a comman depends on the current
+ * status (see MV_STATE enumerator)
+ * Start can be applied only when status is IDLE
+ * Stop can be applied only when status is IDLE, ACTIVE or PAUSED
+ * Pause can be applied only when status is ACTIVE
+ * Restart can be applied only when status is PAUSED
+ */
+enum mv_command {
+ MV_START, /* Start */
+ MV_STOP, /* Stop */
+ MV_PAUSE, /* Pause */
+ MV_RESTART /* Restart */
+};
+
+/*
+ * This enumerator describes the set of state conditions.
+ * Moving from one state to other is stricted.
+ */
+enum mv_state {
+ MV_IDLE,
+ MV_ACTIVE,
+ MV_PAUSED,
+ MV_UNDEFINED_STATE
+};
+
+/* XOR descriptor structure for CRC and DMA descriptor */
+struct crc_dma_desc {
+ u32 status; /* Successful descriptor execution indication */
+ u32 crc32_result; /* Result of CRC-32 calculation */
+ u32 desc_cmd; /* type of operation to be carried out on the data */
+ u32 next_desc_ptr; /* Next descriptor address pointer */
+ u32 byte_cnt; /* Size of source block part represented by the descriptor */
+ u32 dst_addr; /* Destination Block address pointer (not used in CRC32 */
+ u32 src_addr0; /* Mode: Source Block address pointer */
+ u32 src_addr1; /* Mode: Source Block address pointer */
+} __packed;
+
+int mv_xor_state_get(u32 chan);
+void mv_sys_xor_init(MV_DRAM_INFO *dram_info);
+void mv_sys_xor_finish(void);
+int mv_xor_transfer(u32 chan, int xor_type, u32 xor_chain_ptr);
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, u32 init_val_high,
+ u32 init_val_low);
+
+#endif /* __XOR_H */
diff --git a/drivers/ddr/marvell/axp/xor_regs.h b/drivers/ddr/marvell/axp/xor_regs.h
new file mode 100644
index 0000000000..884aa155b4
--- /dev/null
+++ b/drivers/ddr/marvell/axp/xor_regs.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __XOR_REGS_H
+#define __XOR_REGS_H
+
+/*
+ * For controllers that have two XOR units, then chans 2 & 3 will be mapped
+ * to channels 0 & 1 of unit 1
+ */
+#define XOR_UNIT(chan) ((chan) >> 1)
+#define XOR_CHAN(chan) ((chan) & 1)
+
+#define MV_XOR_REGS_OFFSET(unit) (0x60900)
+#define MV_XOR_REGS_BASE(unit) (MV_XOR_REGS_OFFSET(unit))
+
+/* XOR Engine Control Register Map */
+#define XOR_CHANNEL_ARBITER_REG(unit) (MV_XOR_REGS_BASE(unit))
+#define XOR_CONFIG_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x10 + ((chan) * 4)))
+#define XOR_ACTIVATION_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x20 + ((chan) * 4)))
+
+/* XOR Engine Interrupt Register Map */
+#define XOR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x30)
+#define XOR_MASK_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x40)
+#define XOR_ERROR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x50)
+#define XOR_ERROR_ADDR_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x60)
+
+/* XOR Engine Descriptor Register Map */
+#define XOR_NEXT_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x200 + ((chan) * 4)))
+#define XOR_CURR_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x210 + ((chan) * 4)))
+#define XOR_BYTE_COUNT_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x220 + ((chan) * 4)))
+
+#define XOR_DST_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x2B0 + ((chan) * 4)))
+#define XOR_BLOCK_SIZE_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x2C0 + ((chan) * 4)))
+#define XOR_TIMER_MODE_CTRL_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2D0)
+#define XOR_TIMER_MODE_INIT_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2D4)
+#define XOR_TIMER_MODE_CURR_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2D8)
+#define XOR_INIT_VAL_LOW_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2E0)
+#define XOR_INIT_VAL_HIGH_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2E4)
+
+/* XOR register fileds */
+
+/* XOR Engine [0..1] Configuration Registers (XExCR) */
+#define XEXCR_OPERATION_MODE_OFFS (0)
+#define XEXCR_OPERATION_MODE_MASK (7 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_XOR (0 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_CRC (1 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_DMA (2 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_ECC (3 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_MEM_INIT (4 << XEXCR_OPERATION_MODE_OFFS)
+
+#define XEXCR_SRC_BURST_LIMIT_OFFS (4)
+#define XEXCR_SRC_BURST_LIMIT_MASK (7 << XEXCR_SRC_BURST_LIMIT_OFFS)
+#define XEXCR_DST_BURST_LIMIT_OFFS (8)
+#define XEXCR_DST_BURST_LIMIT_MASK (7 << XEXCR_DST_BURST_LIMIT_OFFS)
+#define XEXCR_DRD_RES_SWP_OFFS (12)
+#define XEXCR_DRD_RES_SWP_MASK (1 << XEXCR_DRD_RES_SWP_OFFS)
+#define XEXCR_DWR_REQ_SWP_OFFS (13)
+#define XEXCR_DWR_REQ_SWP_MASK (1 << XEXCR_DWR_REQ_SWP_OFFS)
+#define XEXCR_DES_SWP_OFFS (14)
+#define XEXCR_DES_SWP_MASK (1 << XEXCR_DES_SWP_OFFS)
+#define XEXCR_REG_ACC_PROTECT_OFFS (15)
+#define XEXCR_REG_ACC_PROTECT_MASK (1 << XEXCR_REG_ACC_PROTECT_OFFS)
+
+/* XOR Engine [0..1] Activation Registers (XExACTR) */
+#define XEXACTR_XESTART_OFFS (0)
+#define XEXACTR_XESTART_MASK (1 << XEXACTR_XESTART_OFFS)
+#define XEXACTR_XESTOP_OFFS (1)
+#define XEXACTR_XESTOP_MASK (1 << XEXACTR_XESTOP_OFFS)
+#define XEXACTR_XEPAUSE_OFFS (2)
+#define XEXACTR_XEPAUSE_MASK (1 << XEXACTR_XEPAUSE_OFFS)
+#define XEXACTR_XERESTART_OFFS (3)
+#define XEXACTR_XERESTART_MASK (1 << XEXACTR_XERESTART_OFFS)
+#define XEXACTR_XESTATUS_OFFS (4)
+#define XEXACTR_XESTATUS_MASK (3 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_IDLE (0 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_ACTIVE (1 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_PAUSED (2 << XEXACTR_XESTATUS_OFFS)
+
+/* XOR Engine [0..1] Destination Pointer Register (XExDPR0) */
+#define XEXDPR_DST_PTR_OFFS (0)
+#define XEXDPR_DST_PTR_MASK (0xFFFFFFFF << XEXDPR_DST_PTR_OFFS)
+#define XEXDPR_DST_PTR_XOR_MASK (0x3F)
+#define XEXDPR_DST_PTR_DMA_MASK (0x1F)
+#define XEXDPR_DST_PTR_CRC_MASK (0x1F)
+
+/* XOR Engine[0..1] Block Size Registers (XExBSR) */
+#define XEXBSR_BLOCK_SIZE_OFFS (0)
+#define XEXBSR_BLOCK_SIZE_MASK (0xFFFFFFFF << XEXBSR_BLOCK_SIZE_OFFS)
+#define XEXBSR_BLOCK_SIZE_MIN_VALUE (128)
+#define XEXBSR_BLOCK_SIZE_MAX_VALUE (0xFFFFFFFF)
+
+/* XOR Engine Address Decoding Register Map */
+#define XOR_WINDOW_CTRL_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x240 + ((chan) * 4)))
+#define XOR_BASE_ADDR_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x250 + ((win) * 4)))
+#define XOR_SIZE_MASK_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x270 + ((win) * 4)))
+#define XOR_HIGH_ADDR_REMAP_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x290 + ((win) * 4)))
+#define XOR_ADDR_OVRD_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x2A0 + ((win) * 4)))
+
+#endif /* __XOR_REGS_H */
OpenPOWER on IntegriCloud