From 426230a65f2dd62c3b6c1509e9775d5500db20d3 Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 29 Jan 2018 09:44:33 -0800 Subject: [PATCH] drivers/ddr/fsl: Fix DDR4 RDIMM support For DDR4, command/address delay in mode registers and parity latency in timing config register are only needed for UDIMMs, but not RDIMMs. Add additional register rcw_3 for DDR4 RDIMM. Fix mirrored bit for dual rank RDIMMs. Set sdram_cfg_3[DIS_MRS_PAR] for RDIMMs. Fix calculation of timing config registers. Use hexadecimal format for printing RCW (register control word) registers. Signed-off-by: York Sun --- drivers/ddr/fsl/ctrl_regs.c | 51 ++++++++++++++++++------------ drivers/ddr/fsl/ddr4_dimm_params.c | 2 ++ drivers/ddr/fsl/interactive.c | 9 ++++-- include/fsl_ddr_sdram.h | 1 + 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index c0ee858a02..33adfb1f06 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -732,6 +732,7 @@ static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr, if (popts->rcw_override) { ddr->ddr_sdram_rcw_1 = popts->rcw_1; ddr->ddr_sdram_rcw_2 = popts->rcw_2; + ddr->ddr_sdram_rcw_3 = popts->rcw_3; } else { ddr->ddr_sdram_rcw_1 = common_dimm->rcw[0] << 28 | \ @@ -752,8 +753,12 @@ static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr, common_dimm->rcw[14] << 4 | \ common_dimm->rcw[15]; } - debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", ddr->ddr_sdram_rcw_1); - debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", ddr->ddr_sdram_rcw_2); + debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", + ddr->ddr_sdram_rcw_1); + debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", + ddr->ddr_sdram_rcw_2); + debug("FSLDDR: ddr_sdram_rcw_3 = 0x%08x\n", + ddr->ddr_sdram_rcw_3); } } @@ -1159,8 +1164,14 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr, esdmode5 = 0x00000400; /* Data mask enabled */ } - /* set command/address parity latency */ - if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) { + /* + * For DDR3, set C/A latency if address parity is enabled. + * For DDR4, set C/A latency for UDIMM only. For RDIMM the delay is + * handled by register chip and RCW settings. + */ + if ((ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) && + ((CONFIG_FSL_SDRAM_TYPE != SDRAM_TYPE_DDR4) || + !popts->registered_dimm_en)) { if (mclk_ps >= 935) { /* for DDR4-1600/1866/2133 */ esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK; @@ -1193,7 +1204,9 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr, esdmode5 = 0x00000400; } - if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) { + if ((ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) && + ((CONFIG_FSL_SDRAM_TYPE != SDRAM_TYPE_DDR4) || + !popts->registered_dimm_en)) { if (mclk_ps >= 935) { /* for DDR4-1600/1866/2133 */ esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK; @@ -1965,6 +1978,7 @@ static void set_timing_cfg_6(fsl_ddr_cfg_regs_t *ddr) static void set_timing_cfg_7(const unsigned int ctrl_num, fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, const common_timing_params_t *common_dimm) { unsigned int txpr, tcksre, tcksrx; @@ -1975,16 +1989,11 @@ static void set_timing_cfg_7(const unsigned int ctrl_num, tcksre = max(5U, picos_to_mclk(ctrl_num, 10000)); tcksrx = max(5U, picos_to_mclk(ctrl_num, 10000)); - if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) { - if (mclk_ps >= 935) { - /* parity latency 4 clocks in case of 1600/1866/2133 */ - par_lat = 4; - } else if (mclk_ps >= 833) { - /* parity latency 5 clocks for DDR4-2400 */ - par_lat = 5; - } else { - printf("parity: mclk_ps = %d not supported\n", mclk_ps); - } + if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN && + CONFIG_FSL_SDRAM_TYPE == SDRAM_TYPE_DDR4) { + /* for DDR4 only */ + par_lat = (popts->rcw_2 & 0xf) + 1; + debug("PAR_LAT = %u for mclk_ps = %d\n", par_lat, mclk_ps); } cs_to_cmd = 0; @@ -2024,11 +2033,11 @@ static void set_timing_cfg_8(const unsigned int ctrl_num, const common_timing_params_t *common_dimm, unsigned int cas_latency) { - unsigned int rwt_bg, wrt_bg, rrt_bg, wwt_bg; + int rwt_bg, wrt_bg, rrt_bg, wwt_bg; unsigned int acttoact_bg, wrtord_bg, pre_all_rec; - unsigned int tccdl = picos_to_mclk(ctrl_num, common_dimm->tccdl_ps); - unsigned int wr_lat = ((ddr->timing_cfg_2 & 0x00780000) >> 19) + - ((ddr->timing_cfg_2 & 0x00040000) >> 14); + int tccdl = picos_to_mclk(ctrl_num, common_dimm->tccdl_ps); + int wr_lat = ((ddr->timing_cfg_2 & 0x00780000) >> 19) + + ((ddr->timing_cfg_2 & 0x00040000) >> 14); rwt_bg = cas_latency + 2 + 4 - wr_lat; if (rwt_bg < tccdl) @@ -2130,6 +2139,8 @@ static void set_ddr_sdram_cfg_3(fsl_ddr_cfg_regs_t *ddr, rd_pre = popts->quad_rank_present ? 1 : 0; ddr->ddr_sdram_cfg_3 = (rd_pre & 0x1) << 16; + /* Disable MRS on parity error for RDIMMs */ + ddr->ddr_sdram_cfg_3 |= popts->registered_dimm_en ? 1 : 0; debug("FSLDDR: ddr_sdram_cfg_3 = 0x%08x\n", ddr->ddr_sdram_cfg_3); } @@ -2535,7 +2546,7 @@ compute_fsl_memctl_config_regs(const unsigned int ctrl_num, #ifdef CONFIG_SYS_FSL_DDR4 set_ddr_sdram_cfg_3(ddr, popts); set_timing_cfg_6(ddr); - set_timing_cfg_7(ctrl_num, ddr, common_dimm); + set_timing_cfg_7(ctrl_num, ddr, popts, common_dimm); set_timing_cfg_8(ctrl_num, ddr, popts, common_dimm, cas_latency); set_timing_cfg_9(ddr); set_ddr_dq_mapping(ddr, dimm_params); diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c index 42834ca7b2..6e26ba88a5 100644 --- a/drivers/ddr/fsl/ddr4_dimm_params.c +++ b/drivers/ddr/fsl/ddr4_dimm_params.c @@ -179,6 +179,8 @@ unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num, case DDR4_SPD_MODULETYPE_RDIMM: /* Registered/buffered DIMMs */ pdimm->registered_dimm = 1; + if (spd->mod_section.registered.reg_map & 0x1) + pdimm->mirrored_dimm = 1; break; case DDR4_SPD_MODULETYPE_UDIMM: diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c index c99bd2fb6d..660060d7eb 100644 --- a/drivers/ddr/fsl/interactive.c +++ b/drivers/ddr/fsl/interactive.c @@ -558,6 +558,7 @@ static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo, */ CTRL_OPTIONS(twot_en), CTRL_OPTIONS(threet_en), + CTRL_OPTIONS(mirrored_dimm), CTRL_OPTIONS(ap_en), CTRL_OPTIONS(x4_en), CTRL_OPTIONS(bstopre), @@ -568,6 +569,7 @@ static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo, CTRL_OPTIONS(rcw_override), CTRL_OPTIONS(rcw_1), CTRL_OPTIONS(rcw_2), + CTRL_OPTIONS(rcw_3), CTRL_OPTIONS(ddr_cdr1), CTRL_OPTIONS(ddr_cdr2), CTRL_OPTIONS(tfaw_window_four_activates_ps), @@ -660,6 +662,7 @@ static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) CFG_REGS(ddr_sr_cntr), CFG_REGS(ddr_sdram_rcw_1), CFG_REGS(ddr_sdram_rcw_2), + CFG_REGS(ddr_sdram_rcw_3), CFG_REGS(ddr_cdr1), CFG_REGS(ddr_cdr2), CFG_REGS(dq_map_0), @@ -750,6 +753,7 @@ static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo, CFG_REGS(ddr_sr_cntr), CFG_REGS(ddr_sdram_rcw_1), CFG_REGS(ddr_sdram_rcw_2), + CFG_REGS(ddr_sdram_rcw_3), CFG_REGS(ddr_cdr1), CFG_REGS(ddr_cdr2), CFG_REGS(dq_map_0), @@ -857,8 +861,9 @@ static void print_memctl_options(const memctl_options_t *popts) CTRL_OPTIONS(wrlvl_start), CTRL_OPTIONS_HEX(cswl_override), CTRL_OPTIONS(rcw_override), - CTRL_OPTIONS(rcw_1), - CTRL_OPTIONS(rcw_2), + CTRL_OPTIONS_HEX(rcw_1), + CTRL_OPTIONS_HEX(rcw_2), + CTRL_OPTIONS_HEX(rcw_3), CTRL_OPTIONS_HEX(ddr_cdr1), CTRL_OPTIONS_HEX(ddr_cdr2), CTRL_OPTIONS(tfaw_window_four_activates_ps), diff --git a/include/fsl_ddr_sdram.h b/include/fsl_ddr_sdram.h index 6a1f04b81a..de7ef9b53f 100644 --- a/include/fsl_ddr_sdram.h +++ b/include/fsl_ddr_sdram.h @@ -408,6 +408,7 @@ typedef struct memctl_options_s { unsigned int rcw_override; unsigned int rcw_1; unsigned int rcw_2; + unsigned int rcw_3; /* control register 1 */ unsigned int ddr_cdr1; unsigned int ddr_cdr2; -- 2.39.5