powerpc/mpc8xxx: Update DDR registers

DDRC ver 4.7 adds DDR_SLOW bit in sdram_cfg_2 register. This bit needs to be
set for speed lower than 1250MT/s.

CDR1 and CDR2 are control driver registers. ODT termination valueis for
IOs are defined. Starting from DDRC 4.7, the decoding of ODT for IOs is
	000 -> Termsel off
	001 -> 120 Ohm
	010 -> 180 Ohm
	011 -> 75 Ohm
	100 -> 110 Ohm
	101 -> 60 Ohm
	110 -> 70 Ohm
	111 -> 47 Ohm

Add two write leveling registers. Each QDS now has its own write leveling
start value. In case of zero value, the value of QDS0 will be used. These
values are board-specific and are set in board files.

Extend DDR register timing_cfg_1 to have 4 bits for each field.

DDR control driver registers and write leveling registers are added to
interactive debugging for easy access.

Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
index ca4ed62..088cf45 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -121,6 +121,11 @@
 	out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5);
 	out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
 	out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
+	if (regs->ddr_wrlvl_cntl_2)
+		out_be32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2);
+	if (regs->ddr_wrlvl_cntl_3)
+		out_be32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3);
+
 	out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
 	out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
 	out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
index 2592873..c28f9cd 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -451,8 +451,8 @@
 		| ((caslat_ctrl & 0xF) << 16)
 		| ((refrec_ctrl & 0xF) << 12)
 		| ((wrrec_mclk & 0x0F) << 8)
-		| ((acttoact_mclk & 0x07) << 4)
-		| ((wrtord_mclk & 0x07) << 0)
+		| ((acttoact_mclk & 0x0F) << 4)
+		| ((wrtord_mclk & 0x0F) << 0)
 		);
 	debug("FSLDDR: timing_cfg_1 = 0x%08x\n", ddr->timing_cfg_1);
 }
@@ -659,6 +659,7 @@
 	unsigned int dqs_cfg;		/* DQS configuration */
 	unsigned int odt_cfg = 0;	/* ODT configuration */
 	unsigned int num_pr;		/* Number of posted refreshes */
+	unsigned int slow = 0;		/* DDR will be run less than 1250 */
 	unsigned int obc_cfg;		/* On-The-Fly Burst Chop Cfg */
 	unsigned int ap_en;		/* Address Parity Enable */
 	unsigned int d_init;		/* DRAM data initialization */
@@ -692,6 +693,10 @@
 	obc_cfg = 0;
 #endif
 
+#if (CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7)
+	slow = get_ddr_freq(0) < 1249000000;
+#endif
+
 	if (popts->registered_dimm_en) {
 		rcw_en = 1;
 		ap_en = popts->ap_en;
@@ -720,6 +725,7 @@
 		| ((dqs_cfg & 0x3) << 26)
 		| ((odt_cfg & 0x3) << 21)
 		| ((num_pr & 0xf) << 12)
+		| ((slow & 1) << 11)
 		| (qd_en << 9)
 		| (unq_mrs_en << 8)
 		| ((obc_cfg & 0x1) << 6)
@@ -1347,6 +1353,11 @@
 			       | ((wrlvl_start & 0x1F) << 0)
 			       );
 	debug("FSLDDR: wrlvl_cntl = 0x%08x\n", ddr->ddr_wrlvl_cntl);
+	ddr->ddr_wrlvl_cntl_2 = popts->wrlvl_ctl_2;
+	debug("FSLDDR: wrlvl_cntl_2 = 0x%08x\n", ddr->ddr_wrlvl_cntl_2);
+	ddr->ddr_wrlvl_cntl_3 = popts->wrlvl_ctl_3;
+	debug("FSLDDR: wrlvl_cntl_3 = 0x%08x\n", ddr->ddr_wrlvl_cntl_3);
+
 }
 
 /* DDR Self Refresh Counter (DDR_SR_CNTR) */
@@ -1370,6 +1381,12 @@
 	debug("FSLDDR: ddr_cdr1 = 0x%08x\n", ddr->ddr_cdr1);
 }
 
+static void set_ddr_cdr2(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts)
+{
+	ddr->ddr_cdr2 = popts->ddr_cdr2;
+	debug("FSLDDR: ddr_cdr2 = 0x%08x\n", ddr->ddr_cdr2);
+}
+
 unsigned int
 check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
 {
@@ -1569,6 +1586,7 @@
 				cas_latency, additive_latency);
 
 	set_ddr_cdr1(ddr, popts);
+	set_ddr_cdr2(ddr, popts);
 	set_ddr_sdram_cfg(ddr, popts, common_dimm);
 	ip_rev = fsl_ddr_get_version();
 	if (ip_rev > 0x40400)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
index f59d105..cb71f94 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
@@ -452,6 +452,8 @@
 		CTRL_OPTIONS(rcw_override),
 		CTRL_OPTIONS(rcw_1),
 		CTRL_OPTIONS(rcw_2),
+		CTRL_OPTIONS(ddr_cdr1),
+		CTRL_OPTIONS(ddr_cdr2),
 		CTRL_OPTIONS(tCKE_clock_pulse_width_ps),
 		CTRL_OPTIONS(tFAW_window_four_activates_ps),
 		CTRL_OPTIONS(trwt_override),
@@ -518,6 +520,8 @@
 		CFG_REGS(timing_cfg_5),
 		CFG_REGS(ddr_zq_cntl),
 		CFG_REGS(ddr_wrlvl_cntl),
+		CFG_REGS(ddr_wrlvl_cntl_2),
+		CFG_REGS(ddr_wrlvl_cntl_3),
 		CFG_REGS(ddr_sr_cntr),
 		CFG_REGS(ddr_sdram_rcw_1),
 		CFG_REGS(ddr_sdram_rcw_2),
@@ -525,6 +529,7 @@
 		CFG_REGS(ddr_cdr2),
 		CFG_REGS(err_disable),
 		CFG_REGS(err_int_en),
+		CFG_REGS(ddr_eor),
 	};
 	static const unsigned int n_opts = ARRAY_SIZE(options);
 
@@ -584,6 +589,8 @@
 		CFG_REGS(timing_cfg_5),
 		CFG_REGS(ddr_zq_cntl),
 		CFG_REGS(ddr_wrlvl_cntl),
+		CFG_REGS(ddr_wrlvl_cntl_2),
+		CFG_REGS(ddr_wrlvl_cntl_3),
 		CFG_REGS(ddr_sr_cntr),
 		CFG_REGS(ddr_sdram_rcw_1),
 		CFG_REGS(ddr_sdram_rcw_2),
@@ -593,7 +600,7 @@
 		CFG_REGS(err_int_en),
 		CFG_REGS(ddr_sdram_rcw_2),
 		CFG_REGS(ddr_sdram_rcw_2),
-
+		CFG_REGS(ddr_eor),
 	};
 	static const unsigned int n_opts = ARRAY_SIZE(options);
 
@@ -689,6 +696,8 @@
 		CTRL_OPTIONS(rcw_override),
 		CTRL_OPTIONS(rcw_1),
 		CTRL_OPTIONS(rcw_2),
+		CTRL_OPTIONS_HEX(ddr_cdr1),
+		CTRL_OPTIONS_HEX(ddr_cdr2),
 		CTRL_OPTIONS(tCKE_clock_pulse_width_ps),
 		CTRL_OPTIONS(tFAW_window_four_activates_ps),
 		CTRL_OPTIONS(trwt_override),
@@ -1597,6 +1606,7 @@
 			 * doesn't return
 			 */
 			do_reset(NULL, 0, 0, NULL);
+			printf("Reset didn't work\n");
 		}
 
 		if (strcmp(argv[0], "recompute") == 0) {
diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h
index c63f9e5..ba13ddf 100644
--- a/arch/powerpc/include/asm/config_mpc85xx.h
+++ b/arch/powerpc/include/asm/config_mpc85xx.h
@@ -27,6 +27,8 @@
 #error "Do not define CONFIG_SYS_CCSRBAR_DEFAULT in the board header file."
 #endif
 
+#define FSL_DDR_VER_4_7	47
+
 /* Number of TLB CAM entries we have on FSL Book-E chips */
 #if defined(CONFIG_E500MC)
 #define CONFIG_SYS_NUM_TLBCAMS		64
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h
index e271342..9cf9bd4 100644
--- a/arch/powerpc/include/asm/fsl_ddr_sdram.h
+++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h
@@ -145,6 +145,31 @@
 
 /* DDR_CDR1 */
 #define DDR_CDR1_DHC_EN	0x80000000
+#define DDR_CDR1_ODT_SHIFT	17
+#define DDR_CDR1_ODT_MASK	0x6
+#define DDR_CDR2_ODT_MASK	0x1
+#define DDR_CDR1_ODT(x) ((x & DDR_CDR1_ODT_MASK) << DDR_CDR1_ODT_SHIFT)
+#define DDR_CDR2_ODT(x) (x & DDR_CDR2_ODT_MASK)
+
+#if (defined(CONFIG_SYS_FSL_DDR_VER) && \
+	(CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7))
+#define DDR_CDR_ODT_OFF		0x0
+#define DDR_CDR_ODT_120ohm	0x1
+#define DDR_CDR_ODT_180ohm	0x2
+#define DDR_CDR_ODT_75ohm	0x3
+#define DDR_CDR_ODT_110ohm	0x4
+#define DDR_CDR_ODT_60hm	0x5
+#define DDR_CDR_ODT_70ohm	0x6
+#define DDR_CDR_ODT_47ohm	0x7
+#else
+#define DDR_CDR_ODT_75ohm	0x0
+#define DDR_CDR_ODT_55ohm	0x1
+#define DDR_CDR_ODT_60ohm	0x2
+#define DDR_CDR_ODT_50ohm	0x3
+#define DDR_CDR_ODT_150ohm	0x4
+#define DDR_CDR_ODT_43ohm	0x5
+#define DDR_CDR_ODT_120ohm	0x6
+#endif
 
 /* Record of register values computed */
 typedef struct fsl_ddr_cfg_regs_s {
@@ -177,6 +202,8 @@
 	unsigned int timing_cfg_5;
 	unsigned int ddr_zq_cntl;
 	unsigned int ddr_wrlvl_cntl;
+	unsigned int ddr_wrlvl_cntl_2;
+	unsigned int ddr_wrlvl_cntl_3;
 	unsigned int ddr_sr_cntr;
 	unsigned int ddr_sdram_rcw_1;
 	unsigned int ddr_sdram_rcw_2;
@@ -262,6 +289,8 @@
 	unsigned int wrlvl_override;
 	unsigned int wrlvl_sample;		/* Write leveling */
 	unsigned int wrlvl_start;
+	unsigned int wrlvl_ctl_2;
+	unsigned int wrlvl_ctl_3;
 
 	unsigned int half_strength_driver_enable;
 	unsigned int twoT_en;
@@ -288,6 +317,7 @@
 	unsigned int rcw_2;
 	/* control register 1 */
 	unsigned int ddr_cdr1;
+	unsigned int ddr_cdr2;
 
 	unsigned int trwt_override;
 	unsigned int trwt;			/* read-to-write turnaround */