drivers/ddr/fsl: Add calculation of register control words

DDR4 RDIMM has some information in SPD to be used to calculate the
control words for register chip. The rest can be found from JEDEC
spec DDR4RCD02.

Signed-off-by: York Sun <york.sun@nxp.com>
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index bcab904..8b87271 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -724,10 +724,14 @@
 }
 
 /* DDR SDRAM Register Control Word */
-static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr,
-			       const memctl_options_t *popts,
-			       const common_timing_params_t *common_dimm)
+static void set_ddr_sdram_rcw(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 ddr_freq = get_ddr_freq(ctrl_num) / 1000000;
+	unsigned int rc0a, rc0f;
+
 	if (common_dimm->all_dimms_registered &&
 	    !common_dimm->all_dimms_unbuffered)	{
 		if (popts->rcw_override) {
@@ -735,6 +739,16 @@
 			ddr->ddr_sdram_rcw_2 = popts->rcw_2;
 			ddr->ddr_sdram_rcw_3 = popts->rcw_3;
 		} else {
+			rc0a = ddr_freq > 3200 ? 0x7 :
+			       (ddr_freq > 2933 ? 0x6 :
+				(ddr_freq > 2666 ? 0x5 :
+				 (ddr_freq > 2400 ? 0x4 :
+				  (ddr_freq > 2133 ? 0x3 :
+				   (ddr_freq > 1866 ? 0x2 :
+				    (ddr_freq > 1600 ? 1 : 0))))));
+			rc0f = ddr_freq > 3200 ? 0x3 :
+			       (ddr_freq > 2400 ? 0x2 :
+				(ddr_freq > 2133 ? 0x1 : 0));
 			ddr->ddr_sdram_rcw_1 =
 				common_dimm->rcw[0] << 28 | \
 				common_dimm->rcw[1] << 24 | \
@@ -747,12 +761,14 @@
 			ddr->ddr_sdram_rcw_2 =
 				common_dimm->rcw[8] << 28 | \
 				common_dimm->rcw[9] << 24 | \
-				common_dimm->rcw[10] << 20 | \
+				rc0a << 20 | \
 				common_dimm->rcw[11] << 16 | \
 				common_dimm->rcw[12] << 12 | \
 				common_dimm->rcw[13] << 8 | \
 				common_dimm->rcw[14] << 4 | \
-				common_dimm->rcw[15];
+				rc0f;
+			ddr->ddr_sdram_rcw_3 =
+				((ddr_freq - 1260 + 19) / 20) << 8;
 		}
 		debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n",
 		      ddr->ddr_sdram_rcw_1);
@@ -2561,6 +2577,8 @@
 	set_ddr_sdram_mode_9(ddr, popts, common_dimm, unq_mrs_en);
 	set_ddr_sdram_mode_10(ctrl_num, ddr, popts, common_dimm, unq_mrs_en);
 #endif
+	set_ddr_sdram_rcw(ctrl_num, ddr, popts, common_dimm);
+
 	set_ddr_sdram_interval(ctrl_num, ddr, popts, common_dimm);
 	set_ddr_data_init(ddr);
 	set_ddr_sdram_clk_cntl(ddr, popts);
@@ -2582,8 +2600,6 @@
 
 	set_ddr_sr_cntr(ddr, sr_it);
 
-	set_ddr_sdram_rcw(ddr, popts, common_dimm);
-
 #ifdef CONFIG_SYS_FSL_DDR_EMU
 	/* disble DDR training for emulator */
 	ddr->debug[2] = 0x00000400;
diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c
index 1f1d9b8..5c8fc88 100644
--- a/drivers/ddr/fsl/ddr4_dimm_params.c
+++ b/drivers/ddr/fsl/ddr4_dimm_params.c
@@ -139,6 +139,7 @@
 	};
 	int spd_error = 0;
 	u8 *ptr;
+	u8 val;
 
 	if (spd->mem_type) {
 		if (spd->mem_type != SPD_MEMTYPE_DDR4) {
@@ -191,6 +192,26 @@
 		pdimm->registered_dimm = 1;
 		if (spd->mod_section.registered.reg_map & 0x1)
 			pdimm->mirrored_dimm = 1;
+		val = spd->mod_section.registered.ca_stren;
+		pdimm->rcw[3] = val >> 4;
+		pdimm->rcw[4] = ((val & 0x3) << 2) | ((val & 0xc) >> 2);
+		val = spd->mod_section.registered.clk_stren;
+		pdimm->rcw[5] = ((val & 0x3) << 2) | ((val & 0xc) >> 2);
+		/* Not all in SPD. For convience only. Boards may overwrite. */
+		pdimm->rcw[6] = 0xf;
+		/*
+		 * A17 only used for 16Gb and above devices.
+		 * C[2:0] only used for 3DS.
+		 */
+		pdimm->rcw[8] = pdimm->die_density >= 0x6 ? 0x0 : 0x8 |
+				(pdimm->package_3ds > 0x3 ? 0x0 :
+				 (pdimm->package_3ds > 0x1 ? 0x1 :
+				  (pdimm->package_3ds > 0 ? 0x2 : 0x3)));
+		if (pdimm->package_3ds || pdimm->n_ranks != 4)
+			pdimm->rcw[13] = 0xc;
+		else
+			pdimm->rcw[13] = 0xd;	/* Fix encoded by board */
+
 		break;
 
 	case DDR4_SPD_MODULETYPE_UDIMM:
diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c
index 5158ea2..85ec48c 100644
--- a/drivers/ddr/fsl/options.c
+++ b/drivers/ddr/fsl/options.c
@@ -750,7 +750,9 @@
 	defined(CONFIG_SYS_FSL_DDR4)
 	const struct dynamic_odt *pdodt = odt_unknown;
 #endif
+#if (CONFIG_FSL_SDRAM_TYPE != SDRAM_TYPE_DDR4)
 	ulong ddr_freq;
+#endif
 
 	/*
 	 * Extract hwconfig from environment since we have not properly setup
@@ -1295,6 +1297,7 @@
 
 	popts->package_3ds = pdimm->package_3ds;
 
+#if (CONFIG_FSL_SDRAM_TYPE != SDRAM_TYPE_DDR4)
 	ddr_freq = get_ddr_freq(ctrl_num) / 1000000;
 	if (popts->registered_dimm_en) {
 		popts->rcw_override = 1;
@@ -1308,6 +1311,7 @@
 		else
 			popts->rcw_2 = 0x00300000;
 	}
+#endif
 
 	fsl_ddr_board_options(popts, pdimm, ctrl_num);