ddr: marvell: a38x: Add support for DDR4 from Marvell mv-ddr-marvell repository
This syncs drivers/ddr/marvell/a38x/ with the master branch of repository
https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
up to the commit "mv_ddr: a3700: Use the right size for memset to not overflow"
d5acc10c287e40cc2feeb28710b92e45c93c702c
This patch was created by following steps:
1. Replace all a38x files in U-Boot tree by files from upstream github
Marvell mv-ddr-marvell repository.
2. Run following command to omit portions not relevant for a38x, ddr3, and ddr4:
files=drivers/ddr/marvell/a38x/*
unifdef -m -UMV_DDR -UMV_DDR_ATF -UCONFIG_APN806 \
-UCONFIG_MC_STATIC -UCONFIG_MC_STATIC_PRINT -UCONFIG_PHY_STATIC \
-UCONFIG_PHY_STATIC_PRINT -UCONFIG_CUSTOMER_BOARD_SUPPORT \
-UCONFIG_A3700 -UA3900 -UA80X0 -UA70X0 -DCONFIG_ARMADA_38X -UCONFIG_ARMADA_39X \
-UCONFIG_64BIT $files
3. Manually change license to SPDX-License-Identifier
(upstream license in upstream github repository contains long license
texts and U-Boot is using just SPDX-License-Identifier.
After applying this patch, a38x, ddr3, and ddr4 code in upstream Marvell github
repository and in U-Boot would be fully identical. So in future applying
above steps could be used to sync code again.
The only change in this patch are:
1. Some fixes with include files.
2. Some function return and basic type defines changes in
mv_ddr_plat.c (to correct Marvell bug).
3. Remove of dead code in newly copied files (as a result of the
filter script stripping out everything other than a38x, dd3, and ddr4).
Reference:
"ddr: marvell: a38x: Sync code with Marvell mv-ddr-marvell repository"
https://source.denx.de/u-boot/u-boot/-/commit/107c3391b95bcc2ba09a876da4fa0c31b6c1e460
Signed-off-by: Tony Dinh <mibodhi@gmail.com>
Reviewed-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Stefan Roese <sr@denx.de>
diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c
index 0ddd5ae..790b01d 100644
--- a/drivers/ddr/marvell/a38x/ddr3_training.c
+++ b/drivers/ddr/marvell/a38x/ddr3_training.c
@@ -25,7 +25,11 @@
/* in case of ddr4 do not run ddr3_tip_write_additional_odt_setting function - mc odt always 'on'
* in ddr4 case the terminations are rttWR and rttPARK and the odt must be always 'on' 0x1498 = 0xf
*/
+#if defined(CONFIG_DDR4)
+u32 odt_config = 0;
+#else
u32 odt_config = 1;
+#endif
u32 nominal_avs;
u32 extension_avs;
@@ -85,7 +89,11 @@
READ_LEVELING_MASK_BIT |
SET_TARGET_FREQ_MASK_BIT |
WRITE_LEVELING_TF_MASK_BIT |
+#if defined(CONFIG_DDR4)
+ SW_READ_LEVELING_MASK_BIT |
+#else /* CONFIG_DDR4 */
READ_LEVELING_TF_MASK_BIT |
+#endif /* CONFIG_DDR4 */
CENTRALIZATION_RX_MASK_BIT |
CENTRALIZATION_TX_MASK_BIT);
@@ -102,6 +110,10 @@
u32 if_id, enum mv_ddr_freq frequency);
static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
u32 if_id, enum mv_ddr_freq frequency);
+#if defined(CONFIG_DDR4)
+static int ddr4_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum mv_ddr_freq frequency);
+#endif /* CONFIG_DDR4 */
static u8 mem_size_config[MV_DDR_DIE_CAP_LAST] = {
0x2, /* 512Mbit */
@@ -173,12 +185,24 @@
};
/* MR cmd and addr definitions */
+#if defined(CONFIG_DDR4)
+struct mv_ddr_mr_data mr_data[] = {
+ {MRS0_CMD, DDR4_MR0_REG},
+ {MRS1_CMD, DDR4_MR1_REG},
+ {MRS2_CMD, DDR4_MR2_REG},
+ {MRS3_CMD, DDR4_MR3_REG},
+ {MRS4_CMD, DDR4_MR4_REG},
+ {MRS5_CMD, DDR4_MR5_REG},
+ {MRS6_CMD, DDR4_MR6_REG}
+};
+#else
struct mv_ddr_mr_data mr_data[] = {
{MRS0_CMD, MR0_REG},
{MRS1_CMD, MR1_REG},
{MRS2_CMD, MR2_REG},
{MRS3_CMD, MR3_REG}
};
+#endif
/* inverse pads */
static int ddr3_tip_pad_inv(void)
@@ -664,6 +688,11 @@
calibration_update_control << 3, 0x3 << 3));
}
+#if defined(CONFIG_DDR4)
+ /* dev_num, vref_en, pod_only */
+ CHECK_STATUS(mv_ddr4_mode_regs_init(dev_num));
+ CHECK_STATUS(mv_ddr4_sdram_config(dev_num));
+#endif /* CONFIG_DDR4 */
if (delay_enable != 0) {
adll_tap = MEGA / (mv_ddr_freq_get(freq) * 64);
@@ -1325,8 +1354,22 @@
/* disable ODT in case of dll off */
if (is_dll_off == 1) {
+#if defined(CONFIG_DDR4)
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, access_type, PARAM_NOT_CARE,
+ 0x1974, &g_rtt_nom_cs0, MASK_ALL_BITS));
CHECK_STATUS(ddr3_tip_if_write
(dev_num, access_type, if_id,
+ 0x1974, 0, (0x7 << 8)));
+ CHECK_STATUS(ddr3_tip_if_read
+ (dev_num, access_type, PARAM_NOT_CARE,
+ 0x1A74, &g_rtt_nom_cs1, MASK_ALL_BITS));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x1A74, 0, (0x7 << 8)));
+#else /* CONFIG_DDR4 */
+ 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,
@@ -1337,6 +1380,7 @@
CHECK_STATUS(ddr3_tip_if_write
(dev_num, access_type, if_id,
0x18a4, 0, 0x244));
+#endif /* CONFIG_DDR4 */
}
/* DFS - Enter Self-Refresh */
@@ -1404,6 +1448,16 @@
/* Restore original RTT values if returning from DLL OFF mode */
if (is_dll_off == 1) {
+#if defined(CONFIG_DDR4)
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x1974, g_rtt_nom_cs0, (0x7 << 8)));
+ CHECK_STATUS(ddr3_tip_if_write
+ (dev_num, access_type, if_id,
+ 0x1A74, g_rtt_nom_cs1, (0x7 << 8)));
+
+ mv_ddr4_mode_regs_init(dev_num);
+#else /* CONFIG_DDR4 */
CHECK_STATUS(ddr3_tip_if_write
(dev_num, access_type, if_id, 0x1874,
g_dic | g_rtt_nom, 0x266));
@@ -1416,6 +1470,7 @@
CHECK_STATUS(ddr3_tip_if_write
(dev_num, access_type, if_id, 0x18a4,
g_dic | g_rtt_nom, 0x266));
+#endif /* CONFIG_DDR4 */
}
/* Reset divider_b assert -> de-assert */
@@ -1669,8 +1724,13 @@
t_rtp = GET_MAX_VALUE(t_ckclk * 4, mv_ddr_speed_bin_timing_get(speed_bin_index,
SPEED_BIN_TRTP));
t_mod = GET_MAX_VALUE(t_ckclk * 12, 15000);
+#if defined(CONFIG_DDR4)
+ t_wtr = GET_MAX_VALUE(t_ckclk * 2, mv_ddr_speed_bin_timing_get(speed_bin_index,
+ SPEED_BIN_TWTR));
+#else /* CONFIG_DDR4 */
t_wtr = GET_MAX_VALUE(t_ckclk * 4, mv_ddr_speed_bin_timing_get(speed_bin_index,
SPEED_BIN_TWTR));
+#endif /* CONFIG_DDR4 */
t_ras = time_to_nclk(mv_ddr_speed_bin_timing_get(speed_bin_index,
SPEED_BIN_TRAS),
t_ckclk);
@@ -1758,10 +1818,70 @@
DDR_TIMING_TPD_MASK << DDR_TIMING_TPD_OFFS |
DDR_TIMING_TXPDLL_MASK << DDR_TIMING_TXPDLL_OFFS));
+#if defined(CONFIG_DDR4)
+ ddr4_tip_set_timing(dev_num, access_type, if_id, frequency);
+#endif /* CONFIG_DDR4 */
return MV_OK;
}
+#if defined(CONFIG_DDR4)
+static int ddr4_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
+ u32 if_id, enum mv_ddr_freq frequency)
+{
+ u32 t_rrd_l = 0, t_wtr_l = 0, t_ckclk = 0, t_mod = 0, t_ccd = 0;
+ u32 page_size = 0, val = 0, mask = 0;
+ enum mv_ddr_speed_bin speed_bin_index;
+ enum mv_ddr_die_capacity memory_size;
+ struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
+ u32 freq = mv_ddr_freq_get(frequency);
+
+ speed_bin_index = tm->interface_params[if_id].speed_bin_index;
+ memory_size = tm->interface_params[if_id].memory_size;
+ page_size = mv_ddr_page_size_get(tm->interface_params[if_id].bus_width, memory_size);
+
+ t_ckclk = (MEGA / freq);
+
+ t_rrd_l = (page_size == 1) ? mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRRDL1K) :
+ mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRRDL2K);
+ t_rrd_l = GET_MAX_VALUE(t_ckclk * 4, t_rrd_l);
+
+ t_wtr_l = mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TWTRL);
+ t_wtr_l = GET_MAX_VALUE(t_ckclk * 4, t_wtr_l);
+
+ t_rrd_l = time_to_nclk(t_rrd_l, t_ckclk);
+ t_wtr_l = time_to_nclk(t_wtr_l, t_ckclk);
+
+ val = (((t_rrd_l - 1) & DDR4_TRRD_L_MASK) << DDR4_TRRD_L_OFFS) |
+ (((t_wtr_l - 1) & DDR4_TWTR_L_MASK) << DDR4_TWTR_L_OFFS);
+ mask = (DDR4_TRRD_L_MASK << DDR4_TRRD_L_OFFS) |
+ (DDR4_TWTR_L_MASK << DDR4_TWTR_L_OFFS);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ DRAM_LONG_TIMING_REG, val, mask));
+
+ val = 0;
+ mask = 0;
+ t_mod = mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TMOD);
+ t_mod = GET_MAX_VALUE(t_ckclk * 24, t_mod);
+ t_mod = time_to_nclk(t_mod, t_ckclk);
+
+ val = (((t_mod - 1) & SDRAM_TIMING_HIGH_TMOD_MASK) << SDRAM_TIMING_HIGH_TMOD_OFFS) |
+ ((((t_mod - 1) >> 4) & SDRAM_TIMING_HIGH_TMOD_HIGH_MASK) << SDRAM_TIMING_HIGH_TMOD_HIGH_OFFS);
+ mask = (SDRAM_TIMING_HIGH_TMOD_MASK << SDRAM_TIMING_HIGH_TMOD_OFFS) |
+ (SDRAM_TIMING_HIGH_TMOD_HIGH_MASK << SDRAM_TIMING_HIGH_TMOD_HIGH_OFFS);
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ SDRAM_TIMING_HIGH_REG, val, mask));
+
+ t_ccd = 6;
+
+ CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+ DDR_TIMING_REG,
+ ((t_ccd - 1) & DDR_TIMING_TCCD_MASK) << DDR_TIMING_TCCD_OFFS,
+ DDR_TIMING_TCCD_MASK << DDR_TIMING_TCCD_OFFS));
+
+ return MV_OK;
+}
+#endif /* CONFIG_DDR4 */
/*
* Write CS Result
@@ -2245,6 +2365,7 @@
}
}
+#if !defined(CONFIG_DDR4)
for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
if (mask_tune_func & PBS_RX_MASK_BIT) {
training_stage = PBS_RX;
@@ -2284,6 +2405,7 @@
}
/* Set to 0 after each loop to avoid illegal value may be used */
effective_cs = 0;
+#endif /* CONFIG_DDR4 */
if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) {
training_stage = SET_TARGET_FREQ;
@@ -2367,6 +2489,7 @@
}
}
+#if !defined(CONFIG_DDR4)
if (mask_tune_func & DM_PBS_TX_MASK_BIT) {
DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("DM_PBS_TX_MASK_BIT\n"));
}
@@ -2412,6 +2535,7 @@
}
/* Set to 0 after each loop to avoid illegal value may be used */
effective_cs = 0;
+#endif /* CONFIG_DDR4 */
for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) {
@@ -2434,7 +2558,12 @@
/* Set to 0 after each loop to avoid illegal value may be used */
effective_cs = 0;
+#if defined(CONFIG_DDR4)
+ for (effective_cs = 0; effective_cs < max_cs; effective_cs++)
+ CHECK_STATUS(mv_ddr4_training_main_flow(dev_num));
+#endif /* CONFIG_DDR4 */
+#if !defined(CONFIG_DDR4)
for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) {
training_stage = CENTRALIZATION_TX;
@@ -2455,6 +2584,7 @@
}
/* Set to 0 after each loop to avoid illegal value may be used */
effective_cs = 0;
+#endif /* CONFIG_DDR4 */
DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("restore registers to default\n"));
/* restore register values */
@@ -2895,3 +3025,4 @@
return odt_n;
}
+