From dbaf09590df9add19e738d2de03c0f2d0d8f5433 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 18 Jan 2018 17:16:07 +1300 Subject: [PATCH 1/4] ddr: marvell: only assert M_ODT[0] on write for a single CS When using only a single DDR chip select only assert M_ODT[0] on write. Do not assert it on read and do not assert M_ODT[1] at all. Also set tODT_OFF_WR to 0x9 which contradicts the recommendation from the functional spec but is what Marvell's binary training blob does and seems to give better results when ODT is active during writes. Signed-off-by: Chris Packham Signed-off-by: Stefan Roese --- drivers/ddr/marvell/a38x/ddr3_init.h | 3 ++- drivers/ddr/marvell/a38x/ddr3_training.c | 15 +++++++++------ drivers/ddr/marvell/a38x/ddr3_training_static.c | 3 ++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h index 8cb08864c29..a4c75a9fa68 100644 --- a/drivers/ddr/marvell/a38x/ddr3_init.h +++ b/drivers/ddr/marvell/a38x/ddr3_init.h @@ -183,7 +183,8 @@ 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_odt_config_2cs; +extern u32 g_odt_config_1cs; extern u32 g_rtt_nom; extern u8 debug_training_access; diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c index e70ca4b4255..043143adf08 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training.c +++ b/drivers/ddr/marvell/a38x/ddr3_training.c @@ -315,6 +315,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ enum hws_access_type access_type = ACCESS_TYPE_UNICAST; u32 data_read[MAX_INTERFACE_NUM]; struct hws_topology_map *tm = ddr3_get_topology_map(); + u32 odt_config = g_odt_config_2cs; DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("Init_controller, do_mrs_phy=%d, is_ctrl64_bit=%d\n", @@ -570,6 +571,9 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ DUNIT_CONTROL_HIGH_REG, (init_cntr_prm->msys_init << 7), (1 << 7))); + /* calculate number of CS (per interface) */ + CHECK_STATUS(calc_cs_num + (dev_num, if_id, &cs_num)); timing = tm->interface_params[if_id].timing; if (mode2_t != 0xff) { @@ -578,9 +582,6 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ /* Board topology map is forcing timing */ t2t = (timing == HWS_TIM_2T) ? 1 : 0; } else { - /* calculate number of CS (per interface) */ - CHECK_STATUS(calc_cs_num - (dev_num, if_id, &cs_num)); t2t = (cs_num == 1) ? 0 : 1; } @@ -623,9 +624,11 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ (1 << 11))); /* Set Active control for ODT write transactions */ + if (cs_num == 1) + odt_config = g_odt_config_1cs; CHECK_STATUS(ddr3_tip_if_write (dev_num, ACCESS_TYPE_MULTICAST, - PARAM_NOT_CARE, 0x1494, g_odt_config, + PARAM_NOT_CARE, 0x1494, odt_config, MASK_ALL_BITS)); } } else { @@ -1539,7 +1542,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, 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); + val = 0x91 | ((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)); @@ -1591,7 +1594,7 @@ static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type, 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); + val = 0x91 | ((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) { diff --git a/drivers/ddr/marvell/a38x/ddr3_training_static.c b/drivers/ddr/marvell/a38x/ddr3_training_static.c index 5101f3f3834..b73bbf4f1b0 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_static.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_static.c @@ -21,7 +21,8 @@ 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_odt_config_2cs = 0x120012; +u32 g_odt_config_1cs = 0x10000; u32 g_rtt_nom = 0x44; u32 g_dic = 0x2; From 2efd27f76ae027deba2a1aaadeece80362ba6297 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 18 Jan 2018 17:16:08 +1300 Subject: [PATCH 2/4] ddr: marvell: use correct TREFI value The ternary operation had the HIGH/LOW values the wrong way round. Update it to use the correct value. Signed-off-by: Chris Packham Signed-off-by: Stefan Roese --- drivers/ddr/marvell/a38x/ddr3_training.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c index 043143adf08..2eb6e05783d 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training.c +++ b/drivers/ddr/marvell/a38x/ddr3_training.c @@ -1375,7 +1375,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, /* adjust t_refi to new frequency */ t_refi = (tm->interface_params[if_id].interface_temp == - HWS_TEMP_HIGH) ? TREFI_LOW : TREFI_HIGH; + HWS_TEMP_HIGH) ? TREFI_HIGH : TREFI_LOW; t_refi *= 1000; /*psec */ /* HCLK in[ps] */ From 8bddf678dbe3c766d4f1c242cda3b9e3ed9e2425 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 18 Jan 2018 17:16:09 +1300 Subject: [PATCH 3/4] ddr: marvell: update additional ODT setting The RD_SAMPLE_DELAY field is 5 bits so it needs to be masked with 0x1f instead of 0xf. Rather than checking the read sample delay for all DDR chip selects use the values for the chip selects that are actually configured. Finally continue searching for the max_phase value even if the current read_sample is the same as the max_read_sample. Signed-off-by: Chris Packham Signed-off-by: Stefan Roese --- .../ddr/marvell/a38x/ddr3_training_hw_algo.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c index 56fce174d4c..1fc173b6002 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c @@ -17,7 +17,7 @@ #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) +#define GET_RD_SAMPLE_DELAY(data, cs) ((data >> rd_sample_mask[cs]) & 0x1f) u32 ck_delay = (u32)-1, ck_delay_16 = (u32)-1; u32 ca_delay; @@ -49,7 +49,7 @@ static u32 rd_sample_mask[] = { */ 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 cs_num = 0, max_cs = 0, max_read_sample = 0, min_read_sample = 0x1f; u32 data_read[MAX_INTERFACE_NUM] = { 0 }; u32 read_sample[MAX_CS_NUM]; u32 val; @@ -66,15 +66,19 @@ int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id) data_read, MASK_ALL_BITS)); val = data_read[if_id]; - for (cs_num = 0; cs_num < MAX_CS_NUM; cs_num++) { + max_cs = hws_ddr3_tip_max_cs_get(); + + for (cs_num = 0; cs_num < max_cs; 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 + if (read_sample[cs_num] == max_read_sample) { + /* search for max phase */; + } else { max_read_sample = read_sample[cs_num]; + max_phase = MIN_VALUE; + } for (pup_index = 0; pup_index < tm->num_of_bus_per_interface; @@ -97,10 +101,12 @@ int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id) min_read_sample = read_sample[cs_num]; } + if (min_read_sample <= tm->interface_params[if_id].cas_l) { + min_read_sample = (int)tm->interface_params[if_id].cas_l; + } + 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; From 672e5598301b63f95d7dcceb4436f3cb40643f88 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 18 Jan 2018 17:16:10 +1300 Subject: [PATCH 4/4] ddr: marvell: update ddr controller init and freq Update the calculation for tWR and tPD. This improves the DDR refresh interval and brings the initialization into line with the binary blobs currently being supplied by Marvell. Signed-off-by: Chris Packham Signed-off-by: Stefan Roese --- drivers/ddr/marvell/a38x/ddr3_topology_def.h | 3 +- drivers/ddr/marvell/a38x/ddr3_training.c | 33 +++++++++++++------- drivers/ddr/marvell/a38x/ddr3_training_db.c | 19 ++++++----- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/ddr/marvell/a38x/ddr3_topology_def.h b/drivers/ddr/marvell/a38x/ddr3_topology_def.h index 64a0447dd15..a17eca04187 100644 --- a/drivers/ddr/marvell/a38x/ddr3_topology_def.h +++ b/drivers/ddr/marvell/a38x/ddr3_topology_def.h @@ -70,7 +70,8 @@ enum speed_bin_table_elements { SPEED_BIN_TWTR, SPEED_BIN_TRTP, SPEED_BIN_TWR, - SPEED_BIN_TMOD + SPEED_BIN_TMOD, + SPEED_BIN_TXPDLL }; #endif /* _DDR3_TOPOLOGY_DEF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c index 2eb6e05783d..ef471e565ef 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training.c +++ b/drivers/ddr/marvell/a38x/ddr3_training.c @@ -22,6 +22,8 @@ #define GET_CS_FROM_MASK(mask) (cs_mask2_num[mask]) #define CS_CBE_VALUE(cs_num) (cs_cbe_reg[cs_num]) +#define TIMES_9_TREFI_CYCLES 0x8 + u32 window_mem_addr = 0; u32 phy_reg0_val = 0; u32 phy_reg1_val = 8; @@ -508,7 +510,9 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("cl_value 0x%x cwl_val 0x%x\n", cl_value, cwl_val)); - + t_wr = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index, + SPEED_BIN_TWR), + t_ckclk); data_value = ((cl_mask_table[cl_value] & 0x1) << 2) | ((cl_mask_table[cl_value] & 0xe) << 3); @@ -518,8 +522,9 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ (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)); + MR0_REG, twr_mask_table[t_wr + 1] << 9, + (0x7 << 9))); + /* * MR1: Set RTT and DIC Design GL values @@ -590,16 +595,15 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ 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); + t_pd = TIMES_9_TREFI_CYCLES; + txpdll = GET_MAX_VALUE(t_ckclk * 10, + speed_bin_table(speed_bin_index, + SPEED_BIN_TXPDLL)); 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)); + DDR_TIMING_REG, txpdll << 4 | t_pd, + 0x1f << 4 | 0xf)); CHECK_STATUS(ddr3_tip_if_write (dev_num, access_type, if_id, DDR_TIMING_REG, 0x28 << 9, 0x3f << 9)); @@ -1227,6 +1231,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, 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_ckclk; u32 t_refi = 0, end_if, start_if; u32 bus_index = 0; int is_dll_off = 0; @@ -1393,8 +1398,12 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, 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); + + t_ckclk = MEGA / freq_val[frequency]; + t_wr = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index, + SPEED_BIN_TWR), + t_ckclk); + CHECK_STATUS(ddr3_tip_if_write (dev_num, access_type, if_id, DFS_REG, (twr_mask_table[t_wr + 1] << 16), 0x70000)); diff --git a/drivers/ddr/marvell/a38x/ddr3_training_db.c b/drivers/ddr/marvell/a38x/ddr3_training_db.c index 861dfb19c36..0e11b434ab6 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_db.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_db.c @@ -152,18 +152,18 @@ u8 twr_mask_table[] = { 10, 10, 10, - 1, /*5 */ - 2, /*6 */ - 3, /*7 */ + 1, /*5*/ + 2, /*6*/ + 3, /*7*/ + 4, /*8*/ 10, + 5, /*10*/ 10, - 5, /*10 */ + 6, /*12*/ 10, - 6, /*12 */ + 7, /*14*/ 10, - 7, /*14 */ - 10, - 0 /*16 */ + 0 /*16*/ }; u8 cl_mask_table[] = { @@ -431,6 +431,9 @@ u32 speed_bin_table(u8 index, enum speed_bin_table_elements element) case SPEED_BIN_TMOD: result = 15000; break; + case SPEED_BIN_TXPDLL: + result = 24000; + break; default: break; }