Jelajahi Sumber

mpc85xx: Implement workaround for erratum DDR-A003

Erratum DDR-A003 requires workaround to correctly set RCW10 for registered DIMM.
Also adding polling after enabling DDR controller to ensure completion.

Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
York Sun 14 tahun lalu
induk
melakukan
fa8d23c0ee

+ 3 - 0
arch/powerpc/cpu/mpc85xx/cmd_errata.c

@@ -68,6 +68,9 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 #ifdef CONFIG_SYS_FSL_ERRATUM_ELBC_A001
 	puts("Work-around for Erratum ELBC-A001 enabled\n");
 #endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+	puts("Work-around for Erratum DDR-A003 enabled\n");
+#endif
 
 	return 0;
 }

+ 80 - 1
arch/powerpc/cpu/mpc85xx/ddr-gen3.c

@@ -97,6 +97,82 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	temp_sdram_cfg = regs->ddr_sdram_cfg;
 	temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
 	out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+	if (regs->ddr_sdram_rcw_2 & 0x00f00000) {
+		out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff);
+		out_be32(&ddr->debug[2], 0x00000400);
+		out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl & 0x7fffffff);
+		out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl & 0x7fffffff);
+		out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2 & 0xffffffeb);
+		out_be32(&ddr->mtcr, 0);
+		out_be32(&ddr->debug[12], 0x00000015);
+		out_be32(&ddr->debug[21], 0x24000000);
+		out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval & 0xffff);
+		out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_BI | SDRAM_CFG_MEM_EN);
+
+		asm volatile("sync;isync");
+		while (!(in_be32(&ddr->debug[1]) & 0x2))
+			;
+
+		switch (regs->ddr_sdram_rcw_2 & 0x00f00000) {
+		case 0x00000000:
+			out_be32(&ddr->sdram_md_cntl,
+				MD_CNTL_MD_EN		|
+				MD_CNTL_CS_SEL_CS0_CS1	|
+				0x04000000		|
+				MD_CNTL_WRCW		|
+				MD_CNTL_MD_VALUE(0x02));
+			break;
+		case 0x00100000:
+			out_be32(&ddr->sdram_md_cntl,
+				MD_CNTL_MD_EN		|
+				MD_CNTL_CS_SEL_CS0_CS1	|
+				0x04000000		|
+				MD_CNTL_WRCW		|
+				MD_CNTL_MD_VALUE(0x0a));
+			break;
+		case 0x00200000:
+			out_be32(&ddr->sdram_md_cntl,
+				MD_CNTL_MD_EN		|
+				MD_CNTL_CS_SEL_CS0_CS1	|
+				0x04000000		|
+				MD_CNTL_WRCW		|
+				MD_CNTL_MD_VALUE(0x12));
+			break;
+		case 0x00300000:
+			out_be32(&ddr->sdram_md_cntl,
+				MD_CNTL_MD_EN		|
+				MD_CNTL_CS_SEL_CS0_CS1	|
+				0x04000000		|
+				MD_CNTL_WRCW		|
+				MD_CNTL_MD_VALUE(0x1a));
+			break;
+		default:
+			out_be32(&ddr->sdram_md_cntl,
+				MD_CNTL_MD_EN		|
+				MD_CNTL_CS_SEL_CS0_CS1	|
+				0x04000000		|
+				MD_CNTL_WRCW		|
+				MD_CNTL_MD_VALUE(0x02));
+			printf("Unsupported RC10\n");
+			break;
+		}
+
+		while (in_be32(&ddr->sdram_md_cntl) & 0x80000000)
+			;
+		udelay(6);
+		out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+		out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+		out_be32(&ddr->debug[2], 0x0);
+		out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
+		out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
+		out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+		out_be32(&ddr->debug[12], 0x0);
+		out_be32(&ddr->debug[21], 0x0);
+		out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+
+	}
+#endif
 	/*
 	 * For 8572 DDR1 erratum - DDR controller may enter illegal state
 	 * when operatiing in 32-bit bus mode with 4-beat bursts,
@@ -120,8 +196,11 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	asm volatile("sync;isync");
 
 	/* Let the controller go */
-	temp_sdram_cfg = in_be32(&ddr->sdram_cfg);
+	temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
 	out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
+	asm volatile("sync;isync");
+	while (!(in_be32(&ddr->debug[1]) & 0x2))
+		;
 
 	/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done.  */
 	while (in_be32(&ddr->sdram_cfg_2) & 0x10) {

+ 1 - 0
arch/powerpc/include/asm/config_mpc85xx.h

@@ -163,6 +163,7 @@
 #define CONFIG_NUM_DDR_CONTROLLERS	2
 #define CONFIG_SYS_FSL_ERRATUM_CPC_A002
 #define CONFIG_SYS_FSL_ERRATUM_CPC_A003
+#define CONFIG_SYS_FSL_ERRATUM_DDR_A003
 #define CONFIG_SYS_FSL_ERRATUM_ELBC_A001
 #define CONFIG_SYS_FSL_ERRATUM_ESDHC111
 #define CONFIG_SYS_FSL_ERRATUM_ESDHC135

+ 19 - 0
arch/powerpc/include/asm/fsl_ddr_sdram.h

@@ -101,6 +101,25 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t;
 #define WR_DATA_DELAY_SHIFT	10
 #endif
 
+/* DDR_MD_CNTL */
+#define MD_CNTL_MD_EN		0x80000000
+#define MD_CNTL_CS_SEL_CS0	0x00000000
+#define MD_CNTL_CS_SEL_CS1	0x10000000
+#define MD_CNTL_CS_SEL_CS2	0x20000000
+#define MD_CNTL_CS_SEL_CS3	0x30000000
+#define MD_CNTL_CS_SEL_CS0_CS1	0x40000000
+#define MD_CNTL_CS_SEL_CS2_CS3	0x50000000
+#define MD_CNTL_MD_SEL_MR	0x00000000
+#define MD_CNTL_MD_SEL_EMR	0x01000000
+#define MD_CNTL_MD_SEL_EMR2	0x02000000
+#define MD_CNTL_MD_SEL_EMR3	0x03000000
+#define MD_CNTL_SET_REF		0x00800000
+#define MD_CNTL_SET_PRE		0x00400000
+#define MD_CNTL_CKE_CNTL_LOW	0x00100000
+#define MD_CNTL_CKE_CNTL_HIGH	0x00200000
+#define MD_CNTL_WRCW		0x00080000
+#define MD_CNTL_MD_VALUE(x)	(x & 0x0000FFFF)
+
 /* Record of register values computed */
 typedef struct fsl_ddr_cfg_regs_s {
 	struct {