[U-Boot] [RFC PATCH 04/12] imx: mx6: ddr: pass sysinfo to calibration routines

Eric Nelson eric at nelint.com
Tue Jun 21 20:41:34 CEST 2016


Before calling the dynamic DDR calibration routines, board files
must call mx6_dram_cfg, so they already have a struct mx6_ddr_sysinfo
available for use in determining the bus width.

Use it for determining the DRAM bus width instead of a mix of
dynamic determination in mmdc_do_dqs_calibration() and assumed
64-bit support in mmdc_do_write_level_calibration().

This allows the use of the DDR calibration routines on CPU variants
like i.MX6SL that only have a single MMDC port.

Signed-off-by: Eric Nelson <eric at nelint.com>
---
 arch/arm/cpu/armv7/mx6/ddr.c            | 119 +++++++++++++++++++-------------
 arch/arm/include/asm/arch-mx6/mx6-ddr.h |   6 +-
 2 files changed, 75 insertions(+), 50 deletions(-)

diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c
index eb2d000..f9fb552 100644
--- a/arch/arm/cpu/armv7/mx6/ddr.c
+++ b/arch/arm/cpu/armv7/mx6/ddr.c
@@ -86,14 +86,16 @@ static void modify_dg_result(u32 *reg_st0, u32 *reg_st1, u32 *reg_ctrl)
 	writel(val_ctrl, reg_ctrl);
 }
 
-int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib)
+int mmdc_do_write_level_calibration(struct mx6_ddr_sysinfo const *sysinfo,
+				    struct mx6_mmdc_calibration *calib)
 {
 	struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
 	struct mmdc_p_regs *mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
 	u32 esdmisc_val, zq_val;
 	u32 errors = 0;
-	u32 ldectrl[4];
+	u32 ldectrl[4] = {0};
 	u32 ddr_mr1 = 0x4;
+	u32 rwalat_max;
 
 	/*
 	 * Stash old values in case calibration fails,
@@ -101,8 +103,10 @@ int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib)
 	 */
 	ldectrl[0] = readl(&mmdc0->mpwldectrl0);
 	ldectrl[1] = readl(&mmdc0->mpwldectrl1);
-	ldectrl[2] = readl(&mmdc1->mpwldectrl0);
-	ldectrl[3] = readl(&mmdc1->mpwldectrl1);
+	if (sysinfo->dsize == 2) {
+		ldectrl[2] = readl(&mmdc1->mpwldectrl0);
+		ldectrl[3] = readl(&mmdc1->mpwldectrl1);
+	}
 
 	/* disable DDR logic power down timer */
 	clrbits_le32(&mmdc0->mdpdc, 0xff00);
@@ -122,10 +126,11 @@ int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib)
 	writel(zq_val & ~0x3, &mmdc0->mpzqhwctrl);
 
 	/* 3. increase walat and ralat to maximum */
-	setbits_le32(&mmdc0->mdmisc,
-		     (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17));
-	setbits_le32(&mmdc1->mdmisc,
-		     (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17));
+	rwalat_max = (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17);
+	setbits_le32(&mmdc0->mdmisc, rwalat_max);
+	if (sysinfo->dsize == 2)
+		setbits_le32(&mmdc1->mdmisc, rwalat_max);
+
 	/*
 	 * 4 & 5. Configure the external DDR device to enter write-leveling
 	 * mode through Load Mode Register command.
@@ -152,21 +157,25 @@ int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib)
 	 */
 	if (readl(&mmdc0->mpwlgcr) & 0x00000F00)
 		errors |= 1;
-	if (readl(&mmdc1->mpwlgcr) & 0x00000F00)
-		errors |= 2;
+	if (sysinfo->dsize == 2)
+		if (readl(&mmdc1->mpwlgcr) & 0x00000F00)
+			errors |= 2;
 
 	debug("Ending write leveling calibration. Error mask: 0x%x\n", errors);
 
 	/* check to see if cal failed */
 	if ((readl(&mmdc0->mpwldectrl0) == 0x001F001F) &&
 	    (readl(&mmdc0->mpwldectrl1) == 0x001F001F) &&
-	    (readl(&mmdc1->mpwldectrl0) == 0x001F001F) &&
-	    (readl(&mmdc1->mpwldectrl1) == 0x001F001F)) {
+	    ((sysinfo->dsize < 2) ||
+	     ((readl(&mmdc1->mpwldectrl0) == 0x001F001F) &&
+	      (readl(&mmdc1->mpwldectrl1) == 0x001F001F)))) {
 		debug("Cal seems to have soft-failed due to memory not supporting write leveling on all channels. Restoring original write leveling values.\n");
 		writel(ldectrl[0], &mmdc0->mpwldectrl0);
 		writel(ldectrl[1], &mmdc0->mpwldectrl1);
-		writel(ldectrl[2], &mmdc1->mpwldectrl0);
-		writel(ldectrl[3], &mmdc1->mpwldectrl1);
+		if (sysinfo->dsize == 2) {
+			writel(ldectrl[2], &mmdc1->mpwldectrl0);
+			writel(ldectrl[3], &mmdc1->mpwldectrl1);
+		}
 		errors |= 4;
 	}
 
@@ -189,22 +198,28 @@ int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib)
 	      readl(&mmdc0->mpwldectrl0));
 	debug("\tMMDC_MPWLDECTRL1 after write level cal: 0x%08X\n",
 	      readl(&mmdc0->mpwldectrl1));
-	debug("\tMMDC_MPWLDECTRL0 after write level cal: 0x%08X\n",
-	      readl(&mmdc1->mpwldectrl0));
-	debug("\tMMDC_MPWLDECTRL1 after write level cal: 0x%08X\n",
-	      readl(&mmdc1->mpwldectrl1));
+	if (sysinfo->dsize == 2) {
+		debug("\tMMDC_MPWLDECTRL0 after write level cal: 0x%08X\n",
+		      readl(&mmdc1->mpwldectrl0));
+		debug("\tMMDC_MPWLDECTRL1 after write level cal: 0x%08X\n",
+		      readl(&mmdc1->mpwldectrl1));
+	}
 
 	/* We must force a readback of these values, to get them to stick */
 	if (calib) {
 		calib->p0_mpwldectrl0 = readl(&mmdc0->mpwldectrl0);
 		calib->p0_mpwldectrl1 = readl(&mmdc0->mpwldectrl1);
-		calib->p1_mpwldectrl0 = readl(&mmdc1->mpwldectrl0);
-		calib->p1_mpwldectrl1 = readl(&mmdc1->mpwldectrl1);
+		if (sysinfo->dsize == 2) {
+			calib->p1_mpwldectrl0 = readl(&mmdc1->mpwldectrl0);
+			calib->p1_mpwldectrl1 = readl(&mmdc1->mpwldectrl1);
+		}
 	} else {
 		readl(&mmdc0->mpwldectrl0);
 		readl(&mmdc0->mpwldectrl1);
-		readl(&mmdc1->mpwldectrl0);
-		readl(&mmdc1->mpwldectrl1);
+		if (sysinfo->dsize == 2) {
+			readl(&mmdc1->mpwldectrl0);
+			readl(&mmdc1->mpwldectrl1);
+		}
 	}
 
 	/* enable DDR logic power down timer: */
@@ -219,7 +234,8 @@ int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib)
 	return errors;
 }
 
-int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
+int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo,
+			    struct mx6_mmdc_calibration *calib)
 {
 	struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
 	struct mmdc_p_regs *mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
@@ -230,7 +246,6 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	bool cs0_enable_initial;
 	bool cs1_enable_initial;
 	u32 esdmisc_val;
-	u32 bus_size;
 	u32 temp_ref;
 	u32 pddword = 0x00ffff00; /* best so far, place into MPPDCMPR1 */
 	u32 errors = 0;
@@ -299,10 +314,6 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	cs0_enable = readl(&mmdc0->mdctl) & 0x80000000;
 	cs1_enable = readl(&mmdc0->mdctl) & 0x40000000;
 
-	/* Check to see what the data bus size is */
-	bus_size = (readl(&mmdc0->mdctl) & 0x30000) >> 16;
-	debug("Data bus size: %d (%d bits)\n", bus_size, 1 << (bus_size + 4));
-
 	precharge_all(cs0_enable, cs1_enable);
 
 	/* Write the pre-defined value into MPPDCMPR1 */
@@ -321,11 +332,11 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	 * Both PHYs for x64 configuration, if x32, do only PHY0.
 	 */
 	writel(initdelay, &mmdc0->mprddlctl);
-	if (bus_size == 0x2)
+	if (sysinfo->dsize == 0x2)
 		writel(initdelay, &mmdc1->mprddlctl);
 
 	/* Force a measurment, for previous delay setup to take effect. */
-	force_delay_measurement(bus_size);
+	force_delay_measurement(sysinfo->dsize);
 
 	/*
 	 * ***************************
@@ -369,7 +380,7 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	if (readl(&mmdc0->mpdgctrl0) & 0x00001000)
 		errors |= 1;
 
-	if ((bus_size == 0x2) && (readl(&mmdc1->mpdgctrl0) & 0x00001000))
+	if ((sysinfo->dsize == 0x2) && (readl(&mmdc1->mpdgctrl0) & 0x00001000))
 		errors |= 2;
 
 	/*
@@ -381,7 +392,7 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 			 &mmdc0->mpdgctrl0);
 	modify_dg_result(&mmdc0->mpdghwst2, &mmdc0->mpdghwst3,
 			 &mmdc0->mpdgctrl1);
-	if (bus_size == 0x2) {
+	if (sysinfo->dsize == 0x2) {
 		modify_dg_result(&mmdc1->mpdghwst0, &mmdc1->mpdghwst1,
 				 &mmdc1->mpdgctrl0);
 		modify_dg_result(&mmdc1->mpdghwst2, &mmdc1->mpdghwst3,
@@ -424,7 +435,8 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	if (readl(&mmdc0->mprddlhwctl) & 0x0000000f)
 		errors |= 4;
 
-	if ((bus_size == 0x2) && (readl(&mmdc1->mprddlhwctl) & 0x0000000f))
+	if ((sysinfo->dsize == 0x2) &&
+	    (readl(&mmdc1->mprddlhwctl) & 0x0000000f))
 		errors |= 8;
 
 	debug("Ending Read Delay calibration. Error mask: 0x%x\n", errors);
@@ -450,14 +462,14 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	 * Both PHYs for x64 configuration, if x32, do only PHY0.
 	 */
 	writel(initdelay, &mmdc0->mpwrdlctl);
-	if (bus_size == 0x2)
+	if (sysinfo->dsize == 0x2)
 		writel(initdelay, &mmdc1->mpwrdlctl);
 
 	/*
 	 * XXX This isn't in the manual. Force a measurement,
 	 * for previous delay setup to effect.
 	 */
-	force_delay_measurement(bus_size);
+	force_delay_measurement(sysinfo->dsize);
 
 	/*
 	 * 9. 10. Start the automatic write calibration process
@@ -477,7 +489,8 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	if (readl(&mmdc0->mpwrdlhwctl) & 0x0000000f)
 		errors |= 16;
 
-	if ((bus_size == 0x2) && (readl(&mmdc1->mpwrdlhwctl) & 0x0000000f))
+	if ((sysinfo->dsize == 0x2) &&
+	    (readl(&mmdc1->mpwrdlhwctl) & 0x0000000f))
 		errors |= 32;
 
 	debug("Ending Write Delay calibration. Error mask: 0x%x\n", errors);
@@ -529,14 +542,18 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	debug("Read DQS gating calibration:\n");
 	debug("\tMPDGCTRL0 PHY0 = 0x%08X\n", readl(&mmdc0->mpdgctrl0));
 	debug("\tMPDGCTRL1 PHY0 = 0x%08X\n", readl(&mmdc0->mpdgctrl1));
-	debug("\tMPDGCTRL0 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl0));
-	debug("\tMPDGCTRL1 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl1));
+	if (sysinfo->dsize == 2) {
+		debug("\tMPDGCTRL0 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl0));
+		debug("\tMPDGCTRL1 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl1));
+	}
 	debug("Read calibration:\n");
 	debug("\tMPRDDLCTL PHY0 = 0x%08X\n", readl(&mmdc0->mprddlctl));
-	debug("\tMPRDDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mprddlctl));
+	if (sysinfo->dsize == 2)
+		debug("\tMPRDDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mprddlctl));
 	debug("Write calibration:\n");
 	debug("\tMPWRDLCTL PHY0 = 0x%08X\n", readl(&mmdc0->mpwrdlctl));
-	debug("\tMPWRDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mpwrdlctl));
+	if (sysinfo->dsize == 2)
+		debug("\tMPWRDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mpwrdlctl));
 
 	/*
 	 * Registers below are for debugging purposes.  These print out
@@ -548,22 +565,28 @@ int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib)
 	debug("\tMPDGHWST1 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst1));
 	debug("\tMPDGHWST2 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst2));
 	debug("\tMPDGHWST3 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst3));
-	debug("\tMPDGHWST0 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst0));
-	debug("\tMPDGHWST1 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst1));
-	debug("\tMPDGHWST2 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst2));
-	debug("\tMPDGHWST3 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst3));
+	if (sysinfo->dsize == 2) {
+		debug("\tMPDGHWST0 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst0));
+		debug("\tMPDGHWST1 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst1));
+		debug("\tMPDGHWST2 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst2));
+		debug("\tMPDGHWST3 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst3));
+	}
 
 	debug("Final do_dqs_calibration error mask: 0x%x\n", errors);
 
 	if (calib) {
 		calib->p0_mpdgctrl0 = readl(&mmdc0->mpdgctrl0);
 		calib->p0_mpdgctrl1 = readl(&mmdc0->mpdgctrl1);
-		calib->p1_mpdgctrl0 = readl(&mmdc1->mpdgctrl0);
-		calib->p1_mpdgctrl1 = readl(&mmdc1->mpdgctrl1);
+		if (sysinfo->dsize == 2) {
+			calib->p1_mpdgctrl0 = readl(&mmdc1->mpdgctrl0);
+			calib->p1_mpdgctrl1 = readl(&mmdc1->mpdgctrl1);
+		}
 		calib->p0_mprddlctl = readl(&mmdc0->mprddlctl);
-		calib->p1_mprddlctl = readl(&mmdc1->mprddlctl);
+		if (sysinfo->dsize == 2)
+			calib->p1_mprddlctl = readl(&mmdc1->mprddlctl);
 		calib->p0_mpwrdlctl = readl(&mmdc0->mpwrdlctl);
-		calib->p1_mpwrdlctl = readl(&mmdc1->mpwrdlctl);
+		if (sysinfo->dsize == 2)
+			calib->p1_mpwrdlctl = readl(&mmdc1->mpwrdlctl);
 	}
 	return errors;
 }
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h
index 948862c..41adacf 100644
--- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h
+++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h
@@ -457,8 +457,10 @@ void mx6sl_dram_iocfg(unsigned width,
 		      const struct mx6sl_iomux_grp_regs *);
 
 #if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D)
-int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib);
-int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib);
+int mmdc_do_write_level_calibration(struct mx6_ddr_sysinfo const *sysinfo,
+				    struct mx6_mmdc_calibration *calib);
+int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo,
+			    struct mx6_mmdc_calibration *calib);
 #endif
 
 /* configure mx6 mmdc registers */
-- 
2.7.4



More information about the U-Boot mailing list