driver/ddr/fsl: Add workaround for DDR erratum A008511

This erratum only applies to general purpose DDR controllers in LS2.
It shouldn't be applied to DP-DDR controller. Check DDRC versoin number
before applying workaround.

Signed-off-by: York Sun <yorksun@freescale.com>
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index 1d67983..49e4688 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Freescale Semiconductor, Inc.
+ * Copyright 2014-2015 Freescale Semiconductor, Inc.
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
@@ -11,6 +11,22 @@
 #include <fsl_immap.h>
 #include <fsl_ddr.h>
 
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
+static void set_wait_for_bits_clear(void *ptr, u32 value, u32 bits)
+{
+	int timeout = 1000;
+
+	ddr_out32(ptr, value);
+
+	while (ddr_in32(ptr) & bits) {
+		udelay(100);
+		timeout--;
+	}
+	if (timeout <= 0)
+		puts("Error: A007865 wait for clear timeout.\n");
+}
+#endif /* CONFIG_SYS_FSL_ERRATUM_A008511 */
+
 #if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
 #error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
 #endif
@@ -36,6 +52,9 @@
 	defined(CONFIG_SYS_FSL_ERRATUM_A008514)
 	u32 *eddrtqcr1;
 #endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
+	u32 temp32, mr6;
+#endif
 #ifdef CONFIG_FSL_DDR_BIST
 	u32 mtcr, err_detect, err_sbe;
 	u32 cs0_bnds, cs1_bnds, cs2_bnds, cs3_bnds, cs0_config;
@@ -221,6 +240,21 @@
 		ddr_setbits32(ddr->debug[28], 0x9 << 20);
 #endif
 
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
+	/* Part 1 of 2 */
+	/* This erraum only applies to verion 5.2.0 */
+	if (fsl_ddr_get_version(ctrl_num) == 0x50200) {
+		/* Disable DRAM VRef training */
+		ddr_out32(&ddr->ddr_cdr2,
+			  regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
+		/* Disable deskew */
+		ddr_out32(&ddr->debug[28], 0x400);
+		/* Disable D_INIT */
+		ddr_out32(&ddr->sdram_cfg_2,
+			  regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
+		ddr_out32(&ddr->debug[25], 0x9000);
+	}
+#endif
 	/*
 	 * For RDIMMs, JEDEC spec requires clocks to be stable before reset is
 	 * deasserted. Clocks start when any chip select is enabled and clock
@@ -268,6 +302,66 @@
 	mb();
 	isb();
 
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
+	/* Part 2 of 2 */
+	/* This erraum only applies to verion 5.2.0 */
+	if (fsl_ddr_get_version(ctrl_num) == 0x50200) {
+		/* Wait for idle */
+		timeout = 200;
+		while (!(ddr_in32(&ddr->debug[1]) & 0x2) &&
+		       (timeout > 0)) {
+			udelay(100);
+			timeout--;
+		}
+		if (timeout <= 0) {
+			printf("Controler %d timeout, debug_2 = %x\n",
+			       ctrl_num, ddr_in32(&ddr->debug[1]));
+		}
+		/* Set VREF */
+		for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+			if (!(regs->cs[i].config & SDRAM_CS_CONFIG_EN))
+				continue;
+
+			mr6 = (regs->ddr_sdram_mode_10 >> 16)		|
+				 MD_CNTL_MD_EN				|
+				 MD_CNTL_CS_SEL(i)			|
+				 MD_CNTL_MD_SEL(6)			|
+				 0x00200000;
+			temp32 = mr6 | 0xc0;
+			set_wait_for_bits_clear(&ddr->sdram_md_cntl,
+						temp32, MD_CNTL_MD_EN);
+			udelay(1);
+			debug("MR6 = 0x%08x\n", temp32);
+			temp32 = mr6 | 0xf0;
+			set_wait_for_bits_clear(&ddr->sdram_md_cntl,
+						temp32, MD_CNTL_MD_EN);
+			udelay(1);
+			debug("MR6 = 0x%08x\n", temp32);
+			temp32 = mr6 | 0x70;
+			set_wait_for_bits_clear(&ddr->sdram_md_cntl,
+						temp32, MD_CNTL_MD_EN);
+			udelay(1);
+			debug("MR6 = 0x%08x\n", temp32);
+		}
+		ddr_out32(&ddr->sdram_md_cntl, 0);
+		ddr_out32(&ddr->debug[28], 0);		/* Enable deskew */
+		ddr_out32(&ddr->debug[1], 0x400);	/* restart deskew */
+		/* wait for idle */
+		timeout = 200;
+		while (!(ddr_in32(&ddr->debug[1]) & 0x2) &&
+		       (timeout > 0)) {
+			udelay(100);
+			timeout--;
+		}
+		if (timeout <= 0) {
+			printf("Controler %d timeout, debug_2 = %x\n",
+			       ctrl_num, ddr_in32(&ddr->debug[1]));
+		}
+		/* Restore D_INIT */
+		ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+	}
+#endif /* CONFIG_SYS_FSL_ERRATUM_A008511 */
+
 	total_gb_size_per_controller = 0;
 	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
 		if (!(regs->cs[i].config & 0x80000000))
diff --git a/include/fsl_ddr_sdram.h b/include/fsl_ddr_sdram.h
index 095b33e..6358b6f 100644
--- a/include/fsl_ddr_sdram.h
+++ b/include/fsl_ddr_sdram.h
@@ -155,6 +155,8 @@
 #define MD_CNTL_CKE_CNTL_HIGH	0x00200000
 #define MD_CNTL_WRCW		0x00080000
 #define MD_CNTL_MD_VALUE(x)	(x & 0x0000FFFF)
+#define MD_CNTL_CS_SEL(x)	(((x) & 0x7) << 28)
+#define MD_CNTL_MD_SEL(x)	(((x) & 0xf) << 24)
 
 /* DDR_CDR1 */
 #define DDR_CDR1_DHC_EN	0x80000000