Skip to contentSkip to conversation

imx: mx6: add virtual mx6memcal board

RFC PATCH In review Eric Nelson 5 participants 23 messages Jun 21, 2016 – Aug 26, 2016 Arm (32-bit)

lore
Share & tools
lore
#0 lore raw

cover imx: mx6: add virtual mx6memcal board

This patch set makes use of the dynamic DDR calibration routines added in commit d339f16 to define an alternative to the Freescale DDR stress tester tool.

The goals of this effort are to make the process of DDR validation easier and more robust:
- The use of SPL simplifies the process of running DDR calibration through the imx_usb or SB_LOADER.exe tools (no need for JTAG)

- The use of Kconfig makes the set of board-specific parameters more obvious.

- The output of the SPL image can be directly pasted into either the DCD configuration file or U-Boot sources.

The notable feature of the DDR stress tool which isn't present in this virtual board file is the testing across CPU frequencies.

Patches 1-3 contain structural changes to those routines to return the calibration data and allow configuration of memory without a pre-defined set of calibration data.

Patches 4 and 5 add a struct mx6_ddr_sysinfo parameter to the calibration routines and use it to fix the use of the calibration routines on CPU variants which don't have two MMDC ports (tested on i.MX6SL).

Patches 6-7 simplify the selection of the DDR calibration routines and allow use on other CPU variants (again, tested on i.MX6SL).

Patch 8 is the meat of the patch set and defines the board itself and a single configuration sample that can be used on mx6sabresd or mx6qsabreauto.

Patches 9-12 define a set of other configurations to match other boards that I've tested during development. Note that the configurations with LPDDR (mx6slevk and WaRP) are not currently functional.

I believe that patches 1-7 are minor and can be applied after a short review, but the patch set is an RFC because of some fundamental questions:

- Is it okay with Freescale that I'm the maintainer for a board in the board/freescale tree? I don't particularly want to be the maintainer of this set of tools, but I want them, so I will try to maintain those portions that I'm in a position to test.

- What about the board name? Though I haven't looked deeply at it, but I think that some of this code could be shared with i.MX7.

- I'm including some configurations for boards that don't currently function (mx6slevk) or haven't been tested (warp) for reference and further updates. I'm also including a configuration for a board that isn't supported in main-line U-Boot (nitrogen6_max).

Eric Nelson (12):
imx: mx6: ddr: return output of calibration routines
novena: supply calibration parameter to DDR calibration routines
imx: mx6: ddr: make calibration optional in config routines
imx: mx6: ddr: pass sysinfo to calibration routines
novena: pass mx6_ddr_sysinfo to calibration routines
imx: mx6: ddr: use Kconfig for inclusion of DDR calibration
novena_defconfig: select MX6_DDRCAL
mx6: Add board mx6memcal for use in validating DDR
mx6memcal: add configuration mx6memcal_mx6slevk_defconfig
mx6memcal: add configuration mx6memcal_nitrogen6_max_defconfig
mx6memcal: add configuration mx6memcal_sabrelite_defconfig
mx6memcal: add configuration mx6memcal_warpboard_defconfig

 arch/arm/cpu/armv7/mx6/Kconfig            |  14 +
 arch/arm/cpu/armv7/mx6/ddr.c              | 174 +++++++-----
 arch/arm/include/asm/arch-mx6/mx6-ddr.h   |   8 +-
 board/freescale/mx6memcal/Kconfig         | 135 +++++++++
 board/freescale/mx6memcal/MAINTAINERS     |   7 +
 board/freescale/mx6memcal/Makefile        |  13 +
 board/freescale/mx6memcal/mx6memcal.c     |  31 +++
 board/freescale/mx6memcal/spl.c           | 449 ++++++++++++++++++++++++++++++
 board/kosagi/novena/novena_spl.c          |   4 +-
 configs/mx6memcal_defconfig               |  30 ++
 configs/mx6memcal_mx6slevk_defconfig      |  30 ++
 configs/mx6memcal_nitrogen6_max_defconfig |  26 ++
 configs/mx6memcal_sabrelite_defconfig     |  27 ++
 configs/mx6memcal_warpboard_defconfig     |  32 +++
 configs/novena_defconfig                  |   1 +
 include/configs/mx6memcal.h               |  65 +++++
 16 files changed, 976 insertions(+), 70 deletions(-)
 create mode 100644 board/freescale/mx6memcal/Kconfig
 create mode 100644 board/freescale/mx6memcal/MAINTAINERS
 create mode 100644 board/freescale/mx6memcal/Makefile
 create mode 100644 board/freescale/mx6memcal/mx6memcal.c
 create mode 100644 board/freescale/mx6memcal/spl.c
 create mode 100644 configs/mx6memcal_defconfig
 create mode 100644 configs/mx6memcal_mx6slevk_defconfig
 create mode 100644 configs/mx6memcal_nitrogen6_max_defconfig
 create mode 100644 configs/mx6memcal_sabrelite_defconfig
 create mode 100644 configs/mx6memcal_warpboard_defconfig
 create mode 100644 include/configs/mx6memcal.h
Signature · 1 line
2.7.4
#1 lore raw

RFC PATCH 1/12 imx: mx6: ddr: return output of calibration routines

Allow the calibration data from mmdc_do_write_level_calibration and mmdc_do_dqs_calibration to be returned to the caller for display.

---
 arch/arm/cpu/armv7/mx6/ddr.c            | 29 +++++++++++++++++++++++------
 arch/arm/include/asm/arch-mx6/mx6-ddr.h |  4 ++--
 2 files changed, 25 insertions(+), 8 deletions(-)
arch/arm/cpu/armv7/mx6/ddr.c +23 -6
index 1e7ae28..bde6fe3 100644
@@ -86,7 +86,7 @@ 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(void)
+int mmdc_do_write_level_calibration(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;
@@ -195,10 +195,17 @@ int mmdc_do_write_level_calibration(void)
 	      readl(&mmdc1->mpwldectrl1));
 
 	/* We must force a readback of these values, to get them to stick */
-	readl(&mmdc0->mpwldectrl0);
-	readl(&mmdc0->mpwldectrl1);
-	readl(&mmdc1->mpwldectrl0);
-	readl(&mmdc1->mpwldectrl1);
+	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);
+	} else {
+		readl(&mmdc0->mpwldectrl0);
+		readl(&mmdc0->mpwldectrl1);
+		readl(&mmdc1->mpwldectrl0);
+		readl(&mmdc1->mpwldectrl1);
+	}
 
 	/* enable DDR logic power down timer: */
 	setbits_le32(&mmdc0->mdpdc, 0x00005500);
@@ -212,7 +219,7 @@ int mmdc_do_write_level_calibration(void)
 	return errors;
 }
 
-int mmdc_do_dqs_calibration(void)
+int mmdc_do_dqs_calibration(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;
@@ -548,6 +555,16 @@ int mmdc_do_dqs_calibration(void)
 
 	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);
+		calib->p0_mprddlctl = readl(&mmdc0->mprddlctl);
+		calib->p1_mprddlctl = readl(&mmdc1->mprddlctl);
+		calib->p0_mpwrdlctl = readl(&mmdc0->mpwrdlctl);
+		calib->p1_mpwrdlctl = readl(&mmdc1->mpwrdlctl);
+	}
 	return errors;
 }
 #endif
arch/arm/include/asm/arch-mx6/mx6-ddr.h +2 -2
index 12c30d2..948862c 100644
@@ -457,8 +457,8 @@ 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(void);
-int mmdc_do_dqs_calibration(void);
+int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib);
+int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib);
 #endif
 
 /* configure mx6 mmdc registers */
Signature · 1 line
2.7.4
#2 lore raw

RFC PATCH 1/12 imx: mx6: ddr: return output of calibration routines

Quoted 5 lines · Eric Nelson

Allow the calibration data from mmdc_do_write_level_calibration and mmdc_do_dqs_calibration to be returned to the caller for display.

Why don't you create a separate function to read those params ?

Quoted 82 lines
---
 arch/arm/cpu/armv7/mx6/ddr.c            | 29 +++++++++++++++++++++++------
 arch/arm/include/asm/arch-mx6/mx6-ddr.h |  4 ++--
 2 files changed, 25 insertions(+), 8 deletions(-)
arch/arm/cpu/armv7/mx6/ddr.c +23 -6
index 1e7ae28..bde6fe3 100644
@@ -86,7 +86,7 @@ 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(void)
+int mmdc_do_write_level_calibration(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;
@@ -195,10 +195,17 @@ int mmdc_do_write_level_calibration(void)
 	      readl(&mmdc1->mpwldectrl1));
 
 	/* We must force a readback of these values, to get them to stick */
-	readl(&mmdc0->mpwldectrl0);
-	readl(&mmdc0->mpwldectrl1);
-	readl(&mmdc1->mpwldectrl0);
-	readl(&mmdc1->mpwldectrl1);
+	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);
+	} else {
+		readl(&mmdc0->mpwldectrl0);
+		readl(&mmdc0->mpwldectrl1);
+		readl(&mmdc1->mpwldectrl0);
+		readl(&mmdc1->mpwldectrl1);
+	}
 
 	/* enable DDR logic power down timer: */
 	setbits_le32(&mmdc0->mdpdc, 0x00005500);
@@ -212,7 +219,7 @@ int mmdc_do_write_level_calibration(void)
 	return errors;
 }
 
-int mmdc_do_dqs_calibration(void)
+int mmdc_do_dqs_calibration(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;
@@ -548,6 +555,16 @@ int mmdc_do_dqs_calibration(void)
 
 	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);
+		calib->p0_mprddlctl = readl(&mmdc0->mprddlctl);
+		calib->p1_mprddlctl = readl(&mmdc1->mprddlctl);
+		calib->p0_mpwrdlctl = readl(&mmdc0->mpwrdlctl);
+		calib->p1_mpwrdlctl = readl(&mmdc1->mpwrdlctl);
+	}
 	return errors;
 }
 #endif
arch/arm/include/asm/arch-mx6/mx6-ddr.h +2 -2
index 12c30d2..948862c 100644
@@ -457,8 +457,8 @@ 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(void);
-int mmdc_do_dqs_calibration(void);
+int mmdc_do_write_level_calibration(struct mx6_mmdc_calibration *calib);
+int mmdc_do_dqs_calibration(struct mx6_mmdc_calibration *calib);
 #endif
 
 /* configure mx6 mmdc registers */
Signature · 2 lines
Best regards,
Marek Vasut
#3 lore raw

RFC PATCH 1/12 imx: mx6: ddr: return output of calibration routines

Hi Marek,

Quoted 9 lines · Marek Vasut
Quoted 5 lines · Eric Nelson

Allow the calibration data from mmdc_do_write_level_calibration and mmdc_do_dqs_calibration to be returned to the caller for display.

Why don't you create a separate function to read those params ?

Probably because in my implementation, the calibration routine didn't actually write the registers. It was left to the caller to hand them to mx6_dram_cfg.

You're right though. A routine to gather calibration data would be simpler and prevent the "if (calibration)" junk in the two routines.

Regards,

Eric

#4 lore raw

RFC PATCH 1/12 imx: mx6: ddr: return output of calibration routines

Quoted 13 lines · Eric Nelson

Hi Marek,

Quoted 9 lines · Marek Vasut
Quoted 5 lines · Eric Nelson

Allow the calibration data from mmdc_do_write_level_calibration and mmdc_do_dqs_calibration to be returned to the caller for display.

Why don't you create a separate function to read those params ?

Quoted 7 lines

Probably because in my implementation, the calibration routine didn't actually write the registers. It was left to the caller to hand them to mx6_dram_cfg.

You're right though. A routine to gather calibration data would be simpler and prevent the "if (calibration)" junk in the two routines.

Try avoiding polluting the code with the if (calib) junk more :)

Signature · 2 lines
Best regards,
Marek Vasut
#5 lore raw

RFC PATCH 1/12 imx: mx6: ddr: return output of calibration routines

Quoted 18 lines · Marek Vasut
Quoted 17 lines · Eric Nelson

Hi Marek,

Quoted 9 lines · Marek Vasut
Quoted 5 lines · Eric Nelson

Allow the calibration data from mmdc_do_write_level_calibration and mmdc_do_dqs_calibration to be returned to the caller for display.

Why don't you create a separate function to read those params ?

Probably because in my implementation, the calibration routine didn't actually write the registers. It was left to the caller to hand them to mx6_dram_cfg.

Quoted 6 lines
Quoted 3 lines

You're right though. A routine to gather calibration data would be simpler and prevent the "if (calibration)" junk in the two routines.

Try avoiding polluting the code with the if (calib) junk more :)

Will fix in V2 with the addition of a routine to gather the calibration data.

This will also remove the need for patch 2/12, but the remainder could still use some review.

#6 lore raw

RFC PATCH 2/12 novena: supply calibration parameter to DDR calibration routines

In reply to Eric Nelson
---
 board/kosagi/novena/novena_spl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
board/kosagi/novena/novena_spl.c +2 -2
index f779bb4..9b18187 100644
@@ -603,8 +603,8 @@ void board_init_f(ulong dummy)
 
 	/* Perform DDR DRAM calibration */
 	udelay(100);
-	mmdc_do_write_level_calibration();
-	mmdc_do_dqs_calibration();
+	mmdc_do_write_level_calibration(&novena_mmdc_calib);
+	mmdc_do_dqs_calibration(&novena_mmdc_calib);
 
 	/* Clear the BSS. */
 	memset(__bss_start, 0, __bss_end - __bss_start);
Signature · 1 line
2.7.4
#7 lore raw

RFC PATCH 3/12 imx: mx6: ddr: make calibration optional in config routines

In reply to Eric Nelson
---
 arch/arm/cpu/armv7/mx6/ddr.c | 44 ++++++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 20 deletions(-)
arch/arm/cpu/armv7/mx6/ddr.c +24 -20
index bde6fe3..eb2d000 100644
@@ -1074,13 +1074,15 @@ void mx6_lpddr2_cfg(const struct mx6_ddr_sysinfo *sysinfo,
 	 * board-specific configuration:
 	 *  These values are determined empirically and vary per board layout
 	 */
-	mmdc0->mpwldectrl0 = calib->p0_mpwldectrl0;
-	mmdc0->mpwldectrl1 = calib->p0_mpwldectrl1;
-	mmdc0->mpdgctrl0 = calib->p0_mpdgctrl0;
-	mmdc0->mpdgctrl1 = calib->p0_mpdgctrl1;
-	mmdc0->mprddlctl = calib->p0_mprddlctl;
-	mmdc0->mpwrdlctl = calib->p0_mpwrdlctl;
-	mmdc0->mpzqlp2ctl = calib->mpzqlp2ctl;
+	if (calib) {
+		mmdc0->mpwldectrl0 = calib->p0_mpwldectrl0;
+		mmdc0->mpwldectrl1 = calib->p0_mpwldectrl1;
+		mmdc0->mpdgctrl0 = calib->p0_mpdgctrl0;
+		mmdc0->mpdgctrl1 = calib->p0_mpdgctrl1;
+		mmdc0->mprddlctl = calib->p0_mprddlctl;
+		mmdc0->mpwrdlctl = calib->p0_mpwrdlctl;
+		mmdc0->mpzqlp2ctl = calib->mpzqlp2ctl;
+	}
 
 	/* Read data DQ Byte0-3 delay */
 	mmdc0->mprddqby0dl = 0x33333333;
@@ -1360,19 +1362,21 @@ void mx6_ddr3_cfg(const struct mx6_ddr_sysinfo *sysinfo,
 	 *  see:
 	 *   appnote, ddr3 spreadsheet
 	 */
-	mmdc0->mpwldectrl0 = calib->p0_mpwldectrl0;
-	mmdc0->mpwldectrl1 = calib->p0_mpwldectrl1;
-	mmdc0->mpdgctrl0 = calib->p0_mpdgctrl0;
-	mmdc0->mpdgctrl1 = calib->p0_mpdgctrl1;
-	mmdc0->mprddlctl = calib->p0_mprddlctl;
-	mmdc0->mpwrdlctl = calib->p0_mpwrdlctl;
-	if (sysinfo->dsize > 1) {
-		MMDC1(mpwldectrl0, calib->p1_mpwldectrl0);
-		MMDC1(mpwldectrl1, calib->p1_mpwldectrl1);
-		MMDC1(mpdgctrl0, calib->p1_mpdgctrl0);
-		MMDC1(mpdgctrl1, calib->p1_mpdgctrl1);
-		MMDC1(mprddlctl, calib->p1_mprddlctl);
-		MMDC1(mpwrdlctl, calib->p1_mpwrdlctl);
+	if (calib) {
+		mmdc0->mpwldectrl0 = calib->p0_mpwldectrl0;
+		mmdc0->mpwldectrl1 = calib->p0_mpwldectrl1;
+		mmdc0->mpdgctrl0 = calib->p0_mpdgctrl0;
+		mmdc0->mpdgctrl1 = calib->p0_mpdgctrl1;
+		mmdc0->mprddlctl = calib->p0_mprddlctl;
+		mmdc0->mpwrdlctl = calib->p0_mpwrdlctl;
+		if (sysinfo->dsize > 1) {
+			MMDC1(mpwldectrl0, calib->p1_mpwldectrl0);
+			MMDC1(mpwldectrl1, calib->p1_mpwldectrl1);
+			MMDC1(mpdgctrl0, calib->p1_mpdgctrl0);
+			MMDC1(mpdgctrl1, calib->p1_mpdgctrl1);
+			MMDC1(mprddlctl, calib->p1_mprddlctl);
+			MMDC1(mpwrdlctl, calib->p1_mpwrdlctl);
+		}
 	}
 
 	/* Read data DQ Byte0-3 delay */
Signature · 1 line
2.7.4
#8 lore raw

RFC PATCH 4/12 imx: mx6: ddr: pass sysinfo to calibration routines

In reply to Eric Nelson

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.

---
 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(-)
arch/arm/cpu/armv7/mx6/ddr.c +71 -48
index eb2d000..f9fb552 100644
@@ -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;
 }
arch/arm/include/asm/arch-mx6/mx6-ddr.h +4 -2
index 948862c..41adacf 100644
@@ -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 */
Signature · 1 line
2.7.4
#9 lore raw

RFC PATCH 5/12 novena: pass mx6_ddr_sysinfo to calibration routines

In reply to Eric Nelson
---
 board/kosagi/novena/novena_spl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
board/kosagi/novena/novena_spl.c +2 -2
index 9b18187..39b846f 100644
@@ -603,8 +603,8 @@ void board_init_f(ulong dummy)
 
 	/* Perform DDR DRAM calibration */
 	udelay(100);
-	mmdc_do_write_level_calibration(&novena_mmdc_calib);
-	mmdc_do_dqs_calibration(&novena_mmdc_calib);
+	mmdc_do_write_level_calibration(&novena_ddr_info, &novena_mmdc_calib);
+	mmdc_do_dqs_calibration(&novena_ddr_info, &novena_mmdc_calib);
 
 	/* Clear the BSS. */
 	memset(__bss_start, 0, __bss_end - __bss_start);
Signature · 1 line
2.7.4
#10 lore raw

RFC PATCH 6/12 imx: mx6: ddr: use Kconfig for inclusion of DDR calibration

In reply to Eric Nelson
---
 arch/arm/cpu/armv7/mx6/Kconfig          | 5 +++++
 arch/arm/cpu/armv7/mx6/ddr.c            | 2 +-
 arch/arm/include/asm/arch-mx6/mx6-ddr.h | 2 +-
 3 files changed, 7 insertions(+), 2 deletions(-)
arch/arm/cpu/armv7/mx6/Kconfig +5 -0
index 663f970..dc0bc7e 100644
@@ -31,6 +31,11 @@ config MX6UL
 	select ROM_UNIFIED_SECTIONS
 	bool
 
+config MX6_DDRCAL
+	bool "Include dynamic DDR calibration routines"
+	depends on SPL
+	default n
+
 choice
 	prompt "MX6 board select"
 	optional
arch/arm/cpu/armv7/mx6/ddr.c +1 -1
index f9fb552..c1534bc 100644
@@ -14,7 +14,7 @@
 #include <asm/types.h>
 #include <wait_bit.h>
 
-#if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D)
+#if defined(CONFIG_MX6_DDRCAL)
 
 static void reset_read_data_fifos(void)
 {
arch/arm/include/asm/arch-mx6/mx6-ddr.h +1 -1
index 41adacf..77f3b6e 100644
@@ -456,7 +456,7 @@ void mx6sl_dram_iocfg(unsigned width,
 		      const struct mx6sl_iomux_ddr_regs *,
 		      const struct mx6sl_iomux_grp_regs *);
 
-#if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D)
+#if defined(CONFIG_MX6_DDRCAL)
 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,
Signature · 1 line
2.7.4
#11 lore raw

RFC PATCH 7/12 novena_defconfig: select MX6_DDRCAL

In reply to Eric Nelson
---
 configs/novena_defconfig | 1 +
 1 file changed, 1 insertion(+)
configs/novena_defconfig +1 -0
index 69e5ea9..207e8eb 100644
@@ -1,5 +1,6 @@
 CONFIG_ARM=y
 CONFIG_ARCH_MX6=y
+CONFIG_MX6_DDRCAL=y
 CONFIG_TARGET_KOSAGI_NOVENA=y
 CONFIG_SPL=y
 CONFIG_FIT=y
Signature · 1 line
2.7.4
#12 lore raw

RFC PATCH 8/12 mx6: Add board mx6memcal for use in validating DDR

In reply to Eric Nelson

This is a virtual "board" that uses configuration files and Kconfig to define the memory layout used by a real board during the board bring-up process.

It generates an SPL image that can be loaded using imx_usb or SB_LOADER.exe.

When run, it will generate a set of calibration constants for use in either or both a DCD configuration file for boards that use u-boot.imx or struct mx6_mmdc_calibration for boards that boot via SPL.

In essence, it is a configurable, open-source variant of the Freescale ddr-stress tool.

	https://community.nxp.com/docs/DOC-105652

File mx6memcal_defconfig configures the board for use with mx6sabresd or mx6qsabreauto.

---
 arch/arm/cpu/armv7/mx6/Kconfig        |   9 +
 board/freescale/mx6memcal/Kconfig     | 135 ++++++++++
 board/freescale/mx6memcal/MAINTAINERS |   7 +
 board/freescale/mx6memcal/Makefile    |  13 +
 board/freescale/mx6memcal/mx6memcal.c |  31 +++
 board/freescale/mx6memcal/spl.c       | 449 ++++++++++++++++++++++++++++++++++
 configs/mx6memcal_defconfig           |  30 +++
 include/configs/mx6memcal.h           |  65 +++++
 8 files changed, 739 insertions(+)
 create mode 100644 board/freescale/mx6memcal/Kconfig
 create mode 100644 board/freescale/mx6memcal/MAINTAINERS
 create mode 100644 board/freescale/mx6memcal/Makefile
 create mode 100644 board/freescale/mx6memcal/mx6memcal.c
 create mode 100644 board/freescale/mx6memcal/spl.c
 create mode 100644 configs/mx6memcal_defconfig
 create mode 100644 include/configs/mx6memcal.h
arch/arm/cpu/armv7/mx6/Kconfig +9 -0
index dc0bc7e..c7241ca 100644
@@ -92,6 +92,14 @@ config TARGET_MX6CUBOXI
 config TARGET_MX6QARM2
 	bool "mx6qarm2"
 
+config TARGET_MX6MEMCAL
+	bool "mx6memcal"
+	select SUPPORT_SPL
+	help
+	  The mx6memcal board is a virtual board that can be used to validate
+	  and characterize the memory layout of a new design during the initial
+	  development and pre-production stages.
+
 config TARGET_MX6QSABREAUTO
 	bool "mx6qsabreauto"
 	select DM
@@ -199,6 +207,7 @@ source "board/compulab/cm_fx6/Kconfig"
 source "board/congatec/cgtqmx6eval/Kconfig"
 source "board/embest/mx6boards/Kconfig"
 source "board/freescale/mx6qarm2/Kconfig"
+source "board/freescale/mx6memcal/Kconfig"
 source "board/freescale/mx6qsabreauto/Kconfig"
 source "board/freescale/mx6sabresd/Kconfig"
 source "board/freescale/mx6slevk/Kconfig"
board/freescale/mx6memcal/Kconfig new file +135 -0

135 lines not on this page · raw message

board/freescale/mx6memcal/MAINTAINERS new file +7 -0
new file mode 100644
index 0000000..5da38f7
@@ -0,0 +1,7 @@
+MX6MEMCAL BOARD
+M:	Eric Nelson <[email protected]>
+S:	Maintained
+F:	board/freescale/mx6memcal/
+F:	include/configs/mx6memcal.h
+F:	configs/mx6memcal_defconfig
+
board/freescale/mx6memcal/Makefile new file +13 -0
new file mode 100644
index 0000000..2d7a6fa
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2007, Guennadi Liakhovetski <[email protected]>
+#
+# (C) Copyright 2011 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-y	:= spl.o
+else
+obj-y	:= mx6memcal.o
+endif
board/freescale/mx6memcal/mx6memcal.c new file +31 -0
new file mode 100644
index 0000000..5aa13c1
@@ -0,0 +1,31 @@
+/*
+ * mx6memcal board support - provides a minimal, UART-only
+ * U-Boot that's capable of running a memory test.
+ *
+ * Copyright (C) 2016, Nelson Integration (eric at nelint.com)
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int board_init(void)
+{
+	return 0;
+}
+
+int checkboard(void)
+{
+	puts("Board: mx6memcal\n");
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = imx_ddr_size();
+	return 0;
+}
+
board/freescale/mx6memcal/spl.c new file +449 -0

449 lines not on this page · raw message

configs/mx6memcal_defconfig new file +30 -0
new file mode 100644
index 0000000..826d316
@@ -0,0 +1,30 @@
+CONFIG_ARM=y
+CONFIG_ARCH_MX6=y
+CONFIG_MX6_DDRCAL=y
+CONFIG_TARGET_MX6MEMCAL=y
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/imx-common/spl_sd.cfg,SPL,MX6QDL"
+CONFIG_DDRWIDTH=64
+CONFIG_DDRCS=2
+#CONFIG_MT41K512M16TNA is not set
+CONFIG_MT41K128M16JT=y
+#CONFIG_H5TQ4G63AFR is not set
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_GO is not set
+# CONFIG_CMD_RUN is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_SAVEENV is not set
+# CONFIG_CMD_ENV_EXISTS is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
include/configs/mx6memcal.h new file +65 -0

65 lines not on this page · raw message

Signature · 1 line
2.7.4
#13 lore raw

RFC PATCH 9/12 mx6memcal: add configuration mx6memcal_mx6slevk_defconfig

In reply to Eric Nelson
---
 configs/mx6memcal_mx6slevk_defconfig | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 configs/mx6memcal_mx6slevk_defconfig
configs/mx6memcal_mx6slevk_defconfig new file +30 -0
new file mode 100644
index 0000000..1bdf013
@@ -0,0 +1,30 @@
+CONFIG_ARM=y
+CONFIG_ARCH_MX6=y
+CONFIG_MX6_DDRCAL=y
+CONFIG_TARGET_MX6MEMCAL=y
+CONFIG_DDRWIDTH=32
+CONFIG_DDRCS=1
+CONFIG_LPDDR2=y
+CONFIG_RALAT=2
+CONFIG_UART1_UART1=y
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/imx-common/spl_sd.cfg,SPL,MX6SL"
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_GO is not set
+# CONFIG_CMD_RUN is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_SAVEENV is not set
+# CONFIG_CMD_ENV_EXISTS is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
Signature · 1 line
2.7.4
#14 lore raw

RFC PATCH 10/12 mx6memcal: add configuration mx6memcal_nitrogen6_max_defconfig

In reply to Eric Nelson
---
 configs/mx6memcal_nitrogen6_max_defconfig | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 configs/mx6memcal_nitrogen6_max_defconfig
configs/mx6memcal_nitrogen6_max_defconfig new file +26 -0
new file mode 100644
index 0000000..eb25cc5
@@ -0,0 +1,26 @@
+CONFIG_ARM=y
+CONFIG_ARCH_MX6=y
+CONFIG_MX6_DDRCAL=y
+CONFIG_TARGET_MX6MEMCAL=y
+CONFIG_SERIAL_CONSOLE_UART2=y
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/imx-common/spl_sd.cfg,SPL,MX6QDL"
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_GO is not set
+# CONFIG_CMD_RUN is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_SAVEENV is not set
+# CONFIG_CMD_ENV_EXISTS is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
Signature · 1 line
2.7.4
#15 lore raw

RFC PATCH 11/12 mx6memcal: add configuration mx6memcal_sabrelite_defconfig

In reply to Eric Nelson
---
 configs/mx6memcal_sabrelite_defconfig | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 configs/mx6memcal_sabrelite_defconfig
configs/mx6memcal_sabrelite_defconfig new file +27 -0
new file mode 100644
index 0000000..e8372b6
@@ -0,0 +1,27 @@
+CONFIG_ARM=y
+CONFIG_ARCH_MX6=y
+CONFIG_MX6_DDRCAL=y
+CONFIG_TARGET_MX6MEMCAL=y
+CONFIG_MT41K128M16JT=y
+CONFIG_SERIAL_CONSOLE_UART2=y
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/imx-common/spl_sd.cfg,SPL,MX6QDL"
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_GO is not set
+# CONFIG_CMD_RUN is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_SAVEENV is not set
+# CONFIG_CMD_ENV_EXISTS is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
Signature · 1 line
2.7.4
#16 lore raw

RFC PATCH 12/12 mx6memcal: add configuration mx6memcal_warpboard_defconfig

In reply to Eric Nelson

---
Note that I haven't tested this board because I don't currently have one.

 configs/mx6memcal_warpboard_defconfig | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 configs/mx6memcal_warpboard_defconfig
configs/mx6memcal_warpboard_defconfig new file +32 -0
new file mode 100644
index 0000000..0ec1b3c
@@ -0,0 +1,32 @@
+CONFIG_ARM=y
+CONFIG_ARCH_MX6=y
+CONFIG_MX6_DDRCAL=y
+CONFIG_TARGET_MX6MEMCAL=y
+CONFIG_DDRWIDTH=32
+CONFIG_DDRCS=1
+CONFIG_LPDDR2=y
+CONFIG_MT29PZZZ4D4BKESK=y
+CONFIG_DRAM_DRIVE_STRENGTH=4
+CONFIG_RALAT=2
+CONFIG_UART1_UART1=y
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/imx-common/spl_sd.cfg,SPL,MX6SL"
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_GO is not set
+# CONFIG_CMD_RUN is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_SAVEENV is not set
+# CONFIG_CMD_ENV_EXISTS is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
Signature · 1 line
2.7.4
#17 lore raw

[U-Boot] i.MX SPL tools (was Re: [RFC PATCH 00/12] imx: mx6: add virtual mx6memcal board)

In reply to Eric Nelson
Quoted 3 lines · Eric Nelson

This patch set makes use of the dynamic DDR calibration routines added in commit d339f16 to define an alternative to the Freescale DDR stress tester tool.

Hi all,

While preparing this patch set, I thought again about the tools we have for managing SPL images, and especially "first boot" issues (when a full U-Boot isn't available or isn't programmed into the normal boot device).

Since the "mx6memcal" device is deliberately small, with only the DDR and UART defined, there's no way to load a full U-Boot and doing so would defeat the primary purpose.

We've discussed this at length on a number of occasions, (most recently in [5]) but I don't think we have a good solution.

I just looked at Troy's ancient patches ([1] and [2]) and it seems that these two patches are the bulk of the work needed to build a combined SPL+U-Boot image, and if I understand patch 2 correctly, SPL could tell at run-time that it was executed via a plugin and return control to the Boot ROM instead of trying to load U-Boot or a kernel.

If I recall correctly, Troy dropped these patches because of push-back that came from the sheer size of the 21-patch set, and not because of any particular objection to support for plugins.

It seems that a little work here would remove the need for things like Stefano's patch in [3] or Michael thoughts of adding DFU support in [4].

I'm interested in hearing your thoughts on the subject.

Regards,

Eric

[1] [U-Boot,V2,06/21] imximage: add plugin commands

	https://patchwork.ozlabs.org/patch/186051/
[2] [U-Boot,V2,08/21] mx6: add plugin file for use with imximage.cfg
	https://patchwork.ozlabs.org/patch/186054/
[3] [U-Boot] [PATCH v2] imx_common: check for Serial Downloader in
spl_boot_device
	http://lists.denx.de/pipermail/u-boot/2015-December/237555.html
[4] Discussion of SPU and DFU
	http://lists.denx.de/pipermail/u-boot/2013-October/thread.html#165805
[5] Discussion of booting Wand through USB
	http://lists.denx.de/pipermail/u-boot/2015-May/thread.html#215573
#18 lore raw

[U-Boot] i.MX SPL tools (was Re: [RFC PATCH 00/12] imx: mx6: add virtual mx6memcal board)

Quoted 28 lines · Eric Nelson
Quoted 3 lines · Eric Nelson

This patch set makes use of the dynamic DDR calibration routines added in commit d339f16 to define an alternative to the Freescale DDR stress tester tool.

Hi all,

While preparing this patch set, I thought again about the tools we have for managing SPL images, and especially "first boot" issues (when a full U-Boot isn't available or isn't programmed into the normal boot device).

Since the "mx6memcal" device is deliberately small, with only the DDR and UART defined, there's no way to load a full U-Boot and doing so would defeat the primary purpose.

We've discussed this at length on a number of occasions, (most recently in [5]) but I don't think we have a good solution.

I just looked at Troy's ancient patches ([1] and [2]) and it seems that these two patches are the bulk of the work needed to build a combined SPL+U-Boot image, and if I understand patch 2 correctly, SPL could tell at run-time that it was executed via a plugin and return control to the Boot ROM instead of trying to load U-Boot or a kernel.

If I recall correctly, Troy dropped these patches because of push-back that came from the sheer size of the 21-patch set, and not because of any particular objection to support for plugins.

Quoted 5 lines

It seems that a little work here would remove the need for things like Stefano's patch in [3] or Michael thoughts of adding DFU support in [4].

I'm interested in hearing your thoughts on the subject.

So, if I read the commentary right, "plugin" is how we can eventually get to the point where we can support, in a single binary, somewhat disparate board / SoC types because we can have enough smarts there to see if it's a Q or D or DL and so forth, right? That would be worthwhile to support, yes.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160624/aaada3aa/attachment.sig>
#19 lore raw

cover imx: mx6: add virtual mx6memcal board

In reply to Eric Nelson
Quoted 43 lines · Eric Nelson

This patch set makes use of the dynamic DDR calibration routines added in commit d339f16 to define an alternative to the Freescale DDR stress tester tool.

The goals of this effort are to make the process of DDR validation easier and more robust:
- The use of SPL simplifies the process of running DDR calibration through the imx_usb or SB_LOADER.exe tools (no need for JTAG)

- The use of Kconfig makes the set of board-specific parameters more obvious.

- The output of the SPL image can be directly pasted into either the DCD configuration file or U-Boot sources.

The notable feature of the DDR stress tool which isn't present in this virtual board file is the testing across CPU frequencies.

Patches 1-3 contain structural changes to those routines to return the calibration data and allow configuration of memory without a pre-defined set of calibration data.

Patches 4 and 5 add a struct mx6_ddr_sysinfo parameter to the calibration routines and use it to fix the use of the calibration routines on CPU variants which don't have two MMDC ports (tested on i.MX6SL).

Patches 6-7 simplify the selection of the DDR calibration routines and allow use on other CPU variants (again, tested on i.MX6SL).

Patch 8 is the meat of the patch set and defines the board itself and a single configuration sample that can be used on mx6sabresd or mx6qsabreauto.

Patches 9-12 define a set of other configurations to match other boards that I've tested during development. Note that the configurations with LPDDR (mx6slevk and WaRP) are not currently functional.

I believe that patches 1-7 are minor and can be applied after a short review, but the patch set is an RFC because of some fundamental questions:

- Is it okay with Freescale that I'm the maintainer for a board in the board/freescale tree? I don't particularly want to be the maintainer of this set of tools, but I want them, so I will try to maintain those portions that I'm in a position to test.

Quoted 8 lines

- What about the board name? Though I haven't looked deeply at it, but I think that some of this code could be shared with i.MX7.

- I'm including some configurations for boards that don't currently function (mx6slevk) or haven't been tested (warp) for reference and further updates. I'm also including a configuration for a board that isn't supported in main-line U-Boot (nitrogen6_max).

Eric,

I currently have the time and resources to run some large-scale tests and prove out the reliability of auto-calibration.

It looks like you never got a whole lot of feedback on this series in the general sense - probably because there are only a few of us who need to deal with imx6 ddr calibration. Where do you stand with it?

I love the idea of providing an easier way of obtaining calibration values and removing the dependence on the Freescale tool. This SPL would use the auto-calibration features that Marek added to obtain the calibration instead of the 'brute force' method used by the Freescale tool - which I think is likely an improvement as well. I would love to see this re-submitted with Marek's suggestions and perhaps the addition of a stress test as well that could iterate over memtest loops (could be added later but I think I recall you saying you may have ported some of the memory tests from Freescale's tool to u-boot already).

Regarding Merak's imx6 auto-calibration features: I did run a test across a range of boards in a thermal chamber using nothing but auto-calibration and found many failures, but I need to go back and spend more time with that. I believe my failing there was that I the same thing you did in '03/12 imx: mx6: ddr: make calibration optional in config routines' and made passing in a null calib structure skip writing to the various registers completely and I'm thinking that if the power on default values of these registers are so off for your system that you can hang just trying to talk to the DDR in general. If I recall the boot failures I saw when testing this were all hangs in mx6_ddr3_cfg() before I even got to running mmdc_do_write_level_calibration() or mmdc_do_dqs_calibration(). I was also using an older u-boot fork that I rebased Marek's patches on top of, so its possible I was missing some relevant fix-ups in mx6_ddr3_cfg.

Regards,

Tim

#20 lore raw

cover imx: mx6: add virtual mx6memcal board

Hi Tim,

Quoted 37 lines · Tim Harvey
Quoted 36 lines · Eric Nelson

This patch set makes use of the dynamic DDR calibration routines added in commit d339f16 to define an alternative to the Freescale DDR stress tester tool.

The goals of this effort are to make the process of DDR validation easier and more robust:

- The use of SPL simplifies the process of running DDR calibration through the imx_usb or SB_LOADER.exe tools (no need for JTAG)

- The use of Kconfig makes the set of board-specific parameters more obvious.

- The output of the SPL image can be directly pasted into either the DCD configuration file or U-Boot sources.

The notable feature of the DDR stress tool which isn't present in this virtual board file is the testing across CPU frequencies.

Patches 1-3 contain structural changes to those routines to return the calibration data and allow configuration of memory without a pre-defined set of calibration data.

Patches 4 and 5 add a struct mx6_ddr_sysinfo parameter to the calibration routines and use it to fix the use of the calibration routines on CPU variants which don't have two MMDC ports (tested on i.MX6SL).

Patches 6-7 simplify the selection of the DDR calibration routines and allow use on other CPU variants (again, tested on i.MX6SL).

Patch 8 is the meat of the patch set and defines the board itself and a single configuration sample that can be used on mx6sabresd or mx6qsabreauto.

Patches 9-12 define a set of other configurations to match other boards that I've tested during development. Note that the configurations with LPDDR (mx6slevk and WaRP) are not currently functional.

Quoted 8 lines
Quoted 8 lines

I believe that patches 1-7 are minor and can be applied after a short review, but the patch set is an RFC because of some fundamental questions:

- Is it okay with Freescale that I'm the maintainer for a board in the board/freescale tree? I don't particularly want to be the maintainer of this set of tools, but I want them, so I will try to maintain those portions that I'm in a position to test.

Fabio and Peng, do you have any comments?

Quoted 9 lines
Quoted 8 lines

- What about the board name? Though I haven't looked deeply at it, but I think that some of this code could be shared with i.MX7.

- I'm including some configurations for boards that don't currently function (mx6slevk) or haven't been tested (warp) for reference and further updates. I'm also including a configuration for a board that isn't supported in main-line U-Boot (nitrogen6_max).

Quoted 9 lines

Eric,

I currently have the time and resources to run some large-scale tests and prove out the reliability of auto-calibration.

It looks like you never got a whole lot of feedback on this series in the general sense - probably because there are only a few of us who need to deal with imx6 ddr calibration. Where do you stand with it?

It's been lingering due to un-related client demands.

I was also hoping to get some feedback from Fabio and Peng regarding placement in the board/freescale tree and get some additional hardware to test against before V2.

I now have the hardware, but haven't put any cycles into it.

In particular, I now have a WaRP (i.MX6SL), mx6ulevk, and mx7dsabresd to test against, though the i.MX7 may require some code movement.

Quoted 11 lines

I love the idea of providing an easier way of obtaining calibration values and removing the dependence on the Freescale tool. This SPL would use the auto-calibration features that Marek added to obtain the calibration instead of the 'brute force' method used by the Freescale tool - which I think is likely an improvement as well. I would love to see this re-submitted with Marek's suggestions and perhaps the addition of a stress test as well that could iterate over memtest loops (could be added later but I think I recall you saying you may have ported some of the memory tests from Freescale's tool to u-boot already).

I'm glad to hear an ack of the premise. I have found the tool (virtual memory test board) useful for gathering calibration data on a handful of new board designs.

I haven't implemented a stress test, but think that could easily follow.

I think the V1 patch set also didn't define a "full" U-Boot (only SPL is buildable). Expanding that should allow U-Boot's mtest, but my experience has been that it rarely exposes issues.

The frequency-changing routines in the DDR stress tool and especially memory tests under a heavily loaded Linux have proven to be much better at detecting issues.

Quoted 7 lines

Regarding Marek's imx6 auto-calibration features: I did run a test across a range of boards in a thermal chamber using nothing but auto-calibration and found many failures, but I need to go back and spend more time with that. I believe my failing there was that I the same thing you did in '03/12 imx: mx6: ddr: make calibration optional in config routines' and made passing in a null calib structure skip writing to the various registers completely and I'm thinking that if

Quoted 9 lines

the power on default values of these registers are so off for your system that you can hang just trying to talk to the DDR in general. If I recall the boot failures I saw when testing this were all hangs in mx6_ddr3_cfg() before I even got to running mmdc_do_write_level_calibration() or mmdc_do_dqs_calibration(). I was also using an older u-boot fork that I rebased Marek's patches on top of, so its possible I was missing some relevant fix-ups in mx6_ddr3_cfg.

It's hard to comment about what may be going on there.

I seem to recall having some issues if RALAT and/or WALAT are out of whack, but I don't think these should be affected by temperature.

Regards,

Eric

#21 lore raw

cover imx: mx6: add virtual mx6memcal board

Hi Eric and Tim,

Quoted 7 lines · Eric Nelson
Quoted 5 lines
Quoted 5 lines

- Is it okay with Freescale that I'm the maintainer for a board in the board/freescale tree? I don't particularly want to be the maintainer of this set of tools, but I want them, so I will try to maintain those portions that I'm in a position to test.

Fabio and Peng, do you have any comments?

That's perfectly fine, thanks.

#22 lore raw

cover imx: mx6: add virtual mx6memcal board

In reply to Eric Nelson
Quoted 2 lines · Eric Nelson

Hi Tim,

<snip>

Quoted 10 lines

It's been lingering due to un-related client demands.

I was also hoping to get some feedback from Fabio and Peng regarding placement in the board/freescale tree and get some additional hardware to test against before V2.

I now have the hardware, but haven't put any cycles into it.

In particular, I now have a WaRP (i.MX6SL), mx6ulevk, and mx7dsabresd to test against, though the i.MX7 may require some code movement.

and I have quite a variety of IMX6 base boards to test against with 16bit, 32bit, 64bit memory layouts on both IMX6DL and IMX6Q.

Quoted 17 lines
Quoted 12 lines

I love the idea of providing an easier way of obtaining calibration values and removing the dependence on the Freescale tool. This SPL would use the auto-calibration features that Marek added to obtain the calibration instead of the 'brute force' method used by the Freescale tool - which I think is likely an improvement as well. I would love to see this re-submitted with Marek's suggestions and perhaps the addition of a stress test as well that could iterate over memtest loops (could be added later but I think I recall you saying you may have ported some of the memory tests from Freescale's tool to u-boot already).

I'm glad to hear an ack of the premise. I have found the tool (virtual memory test board) useful for gathering calibration data on a handful of new board designs.

Quoted 6 lines

I haven't implemented a stress test, but think that could easily follow.

I think the V1 patch set also didn't define a "full" U-Boot (only SPL is buildable). Expanding that should allow U-Boot's mtest, but my experience has been that it rarely exposes issues.

I would rather see something in the SPL that ran out of IRAM.

Quoted 4 lines

The frequency-changing routines in the DDR stress tool and especially memory tests under a heavily loaded Linux have proven to be much better at detecting issues.

really? I've never bothered with testing at frequencies other than what gets typically configured per the CPU.

What do you use under Linux that you like? I always prefer the memory to be tested at a very low level with cache disabled.

Quoted 18 lines
Quoted 17 lines

Regarding Marek's imx6 auto-calibration features: I did run a test across a range of boards in a thermal chamber using nothing but auto-calibration and found many failures, but I need to go back and spend more time with that. I believe my failing there was that I the same thing you did in '03/12 imx: mx6: ddr: make calibration optional in config routines' and made passing in a null calib structure skip writing to the various registers completely and I'm thinking that if the power on default values of these registers are so off for your system that you can hang just trying to talk to the DDR in general. If I recall the boot failures I saw when testing this were all hangs in mx6_ddr3_cfg() before I even got to running mmdc_do_write_level_calibration() or mmdc_do_dqs_calibration(). I was also using an older u-boot fork that I rebased Marek's patches on top of, so its possible I was missing some relevant fix-ups in mx6_ddr3_cfg.

Quoted 4 lines

It's hard to comment about what may be going on there.

I seem to recall having some issues if RALAT and/or WALAT are out of whack, but I don't think these should be affected by temperature.

I'll hopefully start running some tests next week and won't think too hard about it unless I can show the same failures under the current mainline code.

Tim