diff mbox

[U-Boot,1/2] driver/ddr/fsl: add command/address parity for DDR4 UDIMM

Message ID 1457416355-40157-1-git-send-email-Shengzhou.Liu@nxp.com
State Superseded
Delegated to: York Sun
Headers show

Commit Message

Shengzhou Liu March 8, 2016, 5:52 a.m. UTC
Add support of command/address parity for DDR4 UDIMM or discrete memory.
It requires to configurate corresponding MR5[2:0] and TIMING_CFG_7[PAR_LAT].
Parity can be turned on/off by hwconfig, e.g. hwconfig=fsl_ddr:parity=on.

Signed-off-by: Shengzhou Liu <Shengzhou.Liu@nxp.com>
---
 doc/README.fsl-ddr          |  8 +++++++
 drivers/ddr/fsl/ctrl_regs.c | 52 +++++++++++++++++++++++++++++++++++++++------
 drivers/ddr/fsl/options.c   | 12 +++++++++--
 include/fsl_ddr_sdram.h     | 11 +++++++++-
 4 files changed, 73 insertions(+), 10 deletions(-)

Comments

York Sun March 8, 2016, 6:46 p.m. UTC | #1
Shengzhou,

Subject is inaccurate. Not only UDIMM for DDR4.

On 03/07/2016 10:01 PM, Shengzhou Liu wrote:
> Add support of command/address parity for DDR4 UDIMM or discrete memory.
> It requires to configurate corresponding MR5[2:0] and TIMING_CFG_7[PAR_LAT].
> Parity can be turned on/off by hwconfig, e.g. hwconfig=fsl_ddr:parity=on.
> 
> Signed-off-by: Shengzhou Liu <Shengzhou.Liu@nxp.com>
> ---
>  doc/README.fsl-ddr          |  8 +++++++
>  drivers/ddr/fsl/ctrl_regs.c | 52 +++++++++++++++++++++++++++++++++++++++------
>  drivers/ddr/fsl/options.c   | 12 +++++++++--
>  include/fsl_ddr_sdram.h     | 11 +++++++++-
>  4 files changed, 73 insertions(+), 10 deletions(-)
> 
> diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr
> index cd71ec8..80f91d3 100644
> --- a/doc/README.fsl-ddr
> +++ b/doc/README.fsl-ddr
> @@ -143,6 +143,14 @@ platform
>  
>  hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=on
>  
> +
> +Memory address parity on/off
> +============================
> +address parity can be turned on/off by hwconfig, it's disabled by default.
> +Syntax is:
> +hwconfig=fsl_ddr:parity=on
> +
> +
>  Table for dynamic ODT for DDR3
>  ==============================
>  For single-slot system with quad-rank DIMM and dual-slot system, dynamic ODT may
> diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
> index 0bfcd34..1f5b9fc 100644
> --- a/drivers/ddr/fsl/ctrl_regs.c
> +++ b/drivers/ddr/fsl/ctrl_regs.c
> @@ -895,12 +895,10 @@ static void set_ddr_sdram_cfg_2(const unsigned int ctrl_num,
>  	slow = get_ddr_freq(ctrl_num) < 1249000000;
>  #endif
>  
> -	if (popts->registered_dimm_en) {
> +	ap_en = popts->ap_en;
> +
> +	if (popts->registered_dimm_en)
>  		rcw_en = 1;
> -		ap_en = popts->ap_en;
> -	} else {
> -		ap_en = 0;
> -	}
>  

This change removes the protection. popts->ap_en can be set by board ddr
setting. Without checking popts->registered_dimm_en, this could set ap_en
incorrectly. This was written for DDR3 RDIMM. Since DDR4 allows address parity
for UDIMM, I think it is better to check for DDR3.


>  	x4_en = popts->x4_en ? 1 : 0;
>  
> @@ -1135,6 +1133,7 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
>  	unsigned short esdmode5;	/* Extended SDRAM mode 5 */
>  	int rtt_park = 0;
>  	bool four_cs = false;
> +	const unsigned int mclk_ps = get_memory_clk_period_ps(0);
>  
>  #if CONFIG_CHIP_SELECTS_PER_CTRL == 4
>  	if ((ddr->cs[0].config & SDRAM_CS_CONFIG_EN) &&
> @@ -1150,6 +1149,19 @@ 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) {
> +		if (mclk_ps >= 935) {
> +			/* for DDR4-1600/1866/2133 */
> +			esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
> +		} else if (mclk_ps >= 833) {
> +			/* for DDR4-2400 */
> +			esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
> +		} else {
> +			printf("parity: mclk_ps = %d not supported\n", mclk_ps);
> +		}
> +	}
> +
>  	ddr->ddr_sdram_mode_9 = (0
>  				 | ((esdmode4 & 0xffff) << 16)
>  				 | ((esdmode5 & 0xffff) << 0)
> @@ -1170,6 +1182,19 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
>  			} else {
>  				esdmode5 = 0x00000400;
>  			}
> +
> +			if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
> +				if (mclk_ps >= 935) {
> +					/* for DDR4-1600/1866/2133 */
> +					esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
> +				} else if (mclk_ps >= 833) {
> +					/* for DDR4-2400 */
> +					esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
> +				} else {
> +					printf("parity: the speed reserved\n");
> +				}
> +			}
> +
>  			switch (i) {
>  			case 1:
>  				ddr->ddr_sdram_mode_11 = (0
> @@ -1925,12 +1950,25 @@ static void set_timing_cfg_7(const unsigned int ctrl_num,
>  			     const common_timing_params_t *common_dimm)
>  {
>  	unsigned int txpr, tcksre, tcksrx;
> -	unsigned int cke_rst, cksre, cksrx, par_lat, cs_to_cmd;
> +	unsigned int cke_rst, cksre, cksrx, par_lat = 0, cs_to_cmd;
> +	const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
>  
>  	txpr = max(5U, picos_to_mclk(ctrl_num, common_dimm->trfc1_ps + 10000));
>  	tcksre = max(5U, picos_to_mclk(ctrl_num, 10000));
>  	tcksrx = max(5U, picos_to_mclk(ctrl_num, 10000));
> -	par_lat = 0;
> +
> +	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);
> +		}
> +	}
> +
>  	cs_to_cmd = 0;
>  
>  	if (txpr <= 200)
> diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c
> index 791d644..9ea80af 100644
> --- a/drivers/ddr/fsl/options.c
> +++ b/drivers/ddr/fsl/options.c
> @@ -1002,8 +1002,16 @@ unsigned int populate_memctl_options(const common_timing_params_t *common_dimm,
>  	popts->twot_en = 0;
>  	popts->threet_en = 0;
>  
> -	/* for RDIMM, address parity enable */
> -	popts->ap_en = 1;
> +	/* for RDIMM and DDR4 UDIMM/discrete memory, address parity enable */
> +	popts->ap_en = 0; /* 0 = disable,  1 = enable */
> +
> +	if (hwconfig_sub_f("fsl_ddr", "parity", buf)) {
> +		if (hwconfig_subarg_cmp_f("fsl_ddr", "parity", "on", buf)) {
> +			if (popts->registered_dimm_en ||
> +			    (CONFIG_FSL_SDRAM_TYPE == SDRAM_TYPE_DDR4))
> +				popts->ap_en = 1;
> +		}
> +	}

I don't remember why I enabled AP for all DDR3 RDIMM. Now you are making it
optional. Please double check this.

York
diff mbox

Patch

diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr
index cd71ec8..80f91d3 100644
--- a/doc/README.fsl-ddr
+++ b/doc/README.fsl-ddr
@@ -143,6 +143,14 @@  platform
 
 hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=on
 
+
+Memory address parity on/off
+============================
+address parity can be turned on/off by hwconfig, it's disabled by default.
+Syntax is:
+hwconfig=fsl_ddr:parity=on
+
+
 Table for dynamic ODT for DDR3
 ==============================
 For single-slot system with quad-rank DIMM and dual-slot system, dynamic ODT may
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index 0bfcd34..1f5b9fc 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -895,12 +895,10 @@  static void set_ddr_sdram_cfg_2(const unsigned int ctrl_num,
 	slow = get_ddr_freq(ctrl_num) < 1249000000;
 #endif
 
-	if (popts->registered_dimm_en) {
+	ap_en = popts->ap_en;
+
+	if (popts->registered_dimm_en)
 		rcw_en = 1;
-		ap_en = popts->ap_en;
-	} else {
-		ap_en = 0;
-	}
 
 	x4_en = popts->x4_en ? 1 : 0;
 
@@ -1135,6 +1133,7 @@  static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
 	unsigned short esdmode5;	/* Extended SDRAM mode 5 */
 	int rtt_park = 0;
 	bool four_cs = false;
+	const unsigned int mclk_ps = get_memory_clk_period_ps(0);
 
 #if CONFIG_CHIP_SELECTS_PER_CTRL == 4
 	if ((ddr->cs[0].config & SDRAM_CS_CONFIG_EN) &&
@@ -1150,6 +1149,19 @@  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) {
+		if (mclk_ps >= 935) {
+			/* for DDR4-1600/1866/2133 */
+			esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
+		} else if (mclk_ps >= 833) {
+			/* for DDR4-2400 */
+			esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
+		} else {
+			printf("parity: mclk_ps = %d not supported\n", mclk_ps);
+		}
+	}
+
 	ddr->ddr_sdram_mode_9 = (0
 				 | ((esdmode4 & 0xffff) << 16)
 				 | ((esdmode5 & 0xffff) << 0)
@@ -1170,6 +1182,19 @@  static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
 			} else {
 				esdmode5 = 0x00000400;
 			}
+
+			if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
+				if (mclk_ps >= 935) {
+					/* for DDR4-1600/1866/2133 */
+					esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
+				} else if (mclk_ps >= 833) {
+					/* for DDR4-2400 */
+					esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
+				} else {
+					printf("parity: the speed reserved\n");
+				}
+			}
+
 			switch (i) {
 			case 1:
 				ddr->ddr_sdram_mode_11 = (0
@@ -1925,12 +1950,25 @@  static void set_timing_cfg_7(const unsigned int ctrl_num,
 			     const common_timing_params_t *common_dimm)
 {
 	unsigned int txpr, tcksre, tcksrx;
-	unsigned int cke_rst, cksre, cksrx, par_lat, cs_to_cmd;
+	unsigned int cke_rst, cksre, cksrx, par_lat = 0, cs_to_cmd;
+	const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
 
 	txpr = max(5U, picos_to_mclk(ctrl_num, common_dimm->trfc1_ps + 10000));
 	tcksre = max(5U, picos_to_mclk(ctrl_num, 10000));
 	tcksrx = max(5U, picos_to_mclk(ctrl_num, 10000));
-	par_lat = 0;
+
+	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);
+		}
+	}
+
 	cs_to_cmd = 0;
 
 	if (txpr <= 200)
diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c
index 791d644..9ea80af 100644
--- a/drivers/ddr/fsl/options.c
+++ b/drivers/ddr/fsl/options.c
@@ -1002,8 +1002,16 @@  unsigned int populate_memctl_options(const common_timing_params_t *common_dimm,
 	popts->twot_en = 0;
 	popts->threet_en = 0;
 
-	/* for RDIMM, address parity enable */
-	popts->ap_en = 1;
+	/* for RDIMM and DDR4 UDIMM/discrete memory, address parity enable */
+	popts->ap_en = 0; /* 0 = disable,  1 = enable */
+
+	if (hwconfig_sub_f("fsl_ddr", "parity", buf)) {
+		if (hwconfig_subarg_cmp_f("fsl_ddr", "parity", "on", buf)) {
+			if (popts->registered_dimm_en ||
+			    (CONFIG_FSL_SDRAM_TYPE == SDRAM_TYPE_DDR4))
+				popts->ap_en = 1;
+		}
+	}
 
 	/*
 	 * BSTTOPRE precharge interval
diff --git a/include/fsl_ddr_sdram.h b/include/fsl_ddr_sdram.h
index 3699c04..cf316a4 100644
--- a/include/fsl_ddr_sdram.h
+++ b/include/fsl_ddr_sdram.h
@@ -123,6 +123,7 @@  typedef struct ddr4_spd_eeprom_s generic_spd_eeprom_t;
 
 #define SDRAM_CFG2_FRC_SR		0x80000000
 #define SDRAM_CFG2_D_INIT		0x00000010
+#define SDRAM_CFG2_AP_EN		0x00000020
 #define SDRAM_CFG2_ODT_CFG_MASK		0x00600000
 #define SDRAM_CFG2_ODT_NEVER		0
 #define SDRAM_CFG2_ODT_ONLY_WRITE	1
@@ -177,6 +178,14 @@  typedef struct ddr4_spd_eeprom_s generic_spd_eeprom_t;
 #define DDR_CDR2_VREF_TRAIN_EN	0x00000080
 #define DDR_CDR2_VREF_RANGE_2	0x00000040
 
+/* DDR ERR_DISABLE */
+#define DDR_ERR_DISABLE_APED	(1 << 8)  /* Address parity error disable */
+
+/* Mode Registers */
+#define DDR_MR5_CA_PARITY_LAT_4_CLK	0x1 /* for DDR4-1600/1866/2133 */
+#define DDR_MR5_CA_PARITY_LAT_5_CLK	0x2 /* for DDR4-2400 */
+
+
 #if (defined(CONFIG_SYS_FSL_DDR_VER) && \
 	(CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7))
 #ifdef CONFIG_SYS_FSL_DDR3L
@@ -343,7 +352,7 @@  typedef struct memctl_options_s {
 	/* mirrior DIMMs for DDR3 */
 	unsigned int mirrored_dimm;
 	unsigned int quad_rank_present;
-	unsigned int ap_en;	/* address parity enable for RDIMM */
+	unsigned int ap_en;	/* address parity enable for RDIMM/DDR4-UDIMM */
 	unsigned int x4_en;	/* enable x4 devices */
 
 	/* Global Timing Parameters */