diff options
Diffstat (limited to 'drivers/ddr/marvell')
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, ®_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, ®_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, + ®_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, ®_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, ®_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, + ®_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, ®_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, ®_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, ®_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, ¶ms); + 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 & (~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, + ®_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, + ®_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, + ®_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 */ |