driver/ddr/fsl: Add address parity support for DDR4 UDIMM/discrete

Add support of 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 by hwconfig,
e.g. hwconfig=fsl_ddr:parity=on.

Signed-off-by: Shengzhou Liu <Shengzhou.Liu@nxp.com>
Reviewed-by: York Sun <york.sun@nxp.com>
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index 0bfcd34..9073917 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -895,11 +895,15 @@
 	slow = get_ddr_freq(ctrl_num) < 1249000000;
 #endif
 
-	if (popts->registered_dimm_en) {
+	if (popts->registered_dimm_en)
 		rcw_en = 1;
-		ap_en = popts->ap_en;
-	} else {
+
+	/* DDR4 can have address parity for UDIMM and discrete */
+	if ((CONFIG_FSL_SDRAM_TYPE != SDRAM_TYPE_DDR4) &&
+	    (!popts->registered_dimm_en)) {
 		ap_en = 0;
+	} else {
+		ap_en = popts->ap_en;
 	}
 
 	x4_en = popts->x4_en ? 1 : 0;
@@ -1135,6 +1139,7 @@
 	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 +1155,19 @@
 		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 +1188,20 @@
 			} 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: mclk_ps = %d not supported\n",
+					       mclk_ps);
+				}
+			}
+
 			switch (i) {
 			case 1:
 				ddr->ddr_sdram_mode_11 = (0
@@ -1925,12 +1957,25 @@
 			     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)