AW: [PATCH 1/4] board: bsh: imx6ulz_smm_m2: Match SPL DDR settings to DCD table

Message ID DU0PR10MB651068DEC38A1436F778767AEE96A@DU0PR10MB6510.EURPRD10.PROD.OUTLOOK.COM
State New
Headers show
Series
  • AW: [PATCH 1/4] board: bsh: imx6ulz_smm_m2: Match SPL DDR settings to DCD table
Related show

Commit Message

'Thomas Petazzoni' via Amarula Linux May 13, 2025, 12:52 p.m. UTC
Hi Dario,

the rationale behind this is the following:

1. We need to use SPL to allow a selection of DRAM settings according to its size. With DCD table in flash this would not work
2. NXP provides the DRAM register settings that are generated from an Excelsheet. The Excelsheet does not provide C-code, it just provides the pure DRAM data.
    Although calculating the right settings programmatically would be much more systematic, we need to use the hard-coded values as they are already tested well
    from our hardware department. I already tried to find out the binary differences between this proper DRAM init and just using the values but unfortunately, I failed.
   Probably it will be possible to upstream this hard-coded approach but if the community denies to accept this maybe we could also have another look into the C-routines that
   Do a proper initialization. In the end it needs to be binary the same.

Just as a comment ...

Br,
Michael (Bode)


Mit freundlichen Grüßen / Kind regards,

Michael Bode
OS, BSH GDE-EDSD5

BSH Hausgeräte GmbH, Im Gewerbepark B10, 93059 Regensburg, Deutschland
Michael.Bode@bshg.com; www.bsh-group.com

BSH Hausgeräte GmbH, Carl-Wery-Str. 34, 81739 München; Vorsitzender des Aufsichtsrats: Dr. Christian Fischer; Geschäftsführung: Dr. Matthias Metz (Vorsitzender), Dr. Alexander Dony, Rudolf Klötscher, Dr. Thorsten Lücke, Lars Schubert; Sitz: MünchenAmtsgericht München, HRB 75534; WEEE-Reg.-Nr. DE 57986696

Diese Mitteilung ist ausschließlich für den beabsichtigten Empfänger bestimmt. Sie kann Betriebs- oder Geschäftsgeheimnisse oder sonstige vertrauliche Informationen enthalten. Jede(r) unberechtigte Gebrauch, Kopie, Weitergabe oder Veröffentlichung ist untersagt. Sollten Sie diese E-Mail irrtümlich erhalten haben, benachrichtigen Sie uns bitte sofort durch Antwortmail und löschen Sie diese E-Mail nebst etwaigen Anlagen und einschließlich aller angefertigten Kopien von Ihrem System.

-----Ursprüngliche Nachricht-----
Von: Dario Binacchi <dario.binacchi@amarulasolutions.com> 
Gesendet: Dienstag, 13. Mai 2025 14:31
An: linux-amarula@amarulasolutions.com
Cc: michael@amarulasolutions.com; dario.binacchi@amarulasolutions.com; Bode Michael (BSH GDE-EDSD7) <michael.bode@bshg.com>; Holesch Simon (BSH GDE-EDSD7) <simon.holesch@bshg.com>
Betreff: [PATCH 1/4] board: bsh: imx6ulz_smm_m2: Match SPL DDR settings to DCD table

From: Michael Trimarchi <michael@amarulasolutions.com>

When using SPL on i.mx6 we frequently notice some DDR initialization mismatches between the SPL code and the non-SPL code.

As the non-SPL code have been tested for long time and proves to be reliable, let's configure the DDR in the exact same way as the non-SPL case.

The idea is simple: just use the DCD table and write directly to the DDR registers.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---
 arch/arm/include/asm/arch-mx6/mx6-ddr.h |   2 +
 arch/arm/mach-imx/mx6/ddr.c             |   3 +
 board/bsh/imx6ulz_smm_m2/spl.c          | 235 +++++++++++++++++-------
 3 files changed, 178 insertions(+), 62 deletions(-)

 }
 
-static void imx6ul_spl_dram_cfg(void)
-{
-	mx6ul_dram_iocfg(mem_ddr.width, &mx6_ddr_ioregs, &mx6_grp_ioregs);
-	mx6_dram_cfg(&ddr_sysinfo, &mx6_mmcd_calib, &mem_ddr);
-}
-
 void board_init_f(ulong dummy)
 {
 	ccgr_init();
+
+	/* DDR initialization */
+	spl_dram_init();
+
 	arch_cpu_init();
 	timer_init();
 	setup_iomux_uart();
 	preloader_console_init();
-	imx6ul_spl_dram_cfg();
 }
 
 void reset_cpu(void)
--
2.43.0

To unsubscribe from this group and stop receiving emails from it, send an email to linux-amarula+unsubscribe@amarulasolutions.com.

Patch

diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h
index ad9c1ac906a3..bd3ff65bcd96 100644
--- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h
+++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h
@@ -457,6 +457,8 @@  struct mx6_mmdc_calibration {
 	u32 p1_mpwrdlctl;
 	/* lpddr2 zq hw calibration */
 	u32 mpzqlp2ctl;
+	/* MDC Duty Cycle Control Register */
+	u32 mpdccr;
 };
 
 /* configure iomux (pinctl/padctl) */
diff --git a/arch/arm/mach-imx/mx6/ddr.c b/arch/arm/mach-imx/mx6/ddr.c index 5a1258e002d2..749ceee0cdbf 100644
--- a/arch/arm/mach-imx/mx6/ddr.c
+++ b/arch/arm/mach-imx/mx6/ddr.c
@@ -1444,6 +1444,9 @@  void mx6_ddr3_cfg(const struct mx6_ddr_sysinfo *sysinfo,
 	mmdc0->mpdgctrl1 = calib->p0_mpdgctrl1;
 	mmdc0->mprddlctl = calib->p0_mprddlctl;
 	mmdc0->mpwrdlctl = calib->p0_mpwrdlctl;
+	if (calib->mpdccr)
+		mmdc0->mpdccr = calib->mpdccr;
+
 	if (sysinfo->dsize > 1) {
 		MMDC1(mpwldectrl0, calib->p1_mpwldectrl0);
 		MMDC1(mpwldectrl1, calib->p1_mpwldectrl1); diff --git a/board/bsh/imx6ulz_smm_m2/spl.c b/board/bsh/imx6ulz_smm_m2/spl.c index 724841b57456..0fa510446813 100644
--- a/board/bsh/imx6ulz_smm_m2/spl.c
+++ b/board/bsh/imx6ulz_smm_m2/spl.c
@@ -31,70 +31,184 @@  static void setup_iomux_uart(void)
 	imx_iomux_v3_setup_multiple_pads(uart4_pads, ARRAY_SIZE(uart4_pads));  }
 
-static struct mx6ul_iomux_grp_regs mx6_grp_ioregs = {
-	.grp_addds		= 0x00000028,
-	.grp_ddrmode_ctl	= 0x00020000,
-	.grp_b0ds		= 0x00000028,
-	.grp_ctlds		= 0x00000028,
-	.grp_b1ds		= 0x00000028,
-	.grp_ddrpke		= 0x00000000,
-	.grp_ddrmode		= 0x00020000,
-	.grp_ddr_type		= 0x000c0000,
+struct dram_cfg_param {
+	unsigned int reg;
+	unsigned int val;
 };
 
-static struct mx6ul_iomux_ddr_regs mx6_ddr_ioregs = {
-	.dram_dqm0		= 0x00000028,
-	.dram_dqm1		= 0x00000028,
-	.dram_ras		= 0x00000028,
-	.dram_cas		= 0x00000028,
-	.dram_odt0		= 0x00000028,
-	.dram_odt1		= 0x00000028,
-	.dram_sdba2		= 0x00000000,
-	.dram_sdclk_0		= 0x00000028,
-	.dram_sdqs0		= 0x00000028,
-	.dram_sdqs1		= 0x00000028,
-	.dram_reset		= 0x000c0028,
+struct dram_timing_info {
+	const struct dram_cfg_param *ddrc_cfg;
+	unsigned int ddrc_cfg_num;
 };
 
-static struct mx6_mmdc_calibration mx6_mmcd_calib = {
-	.p0_mpwldectrl0		= 0x00000000,
-	.p0_mpwldectrl1		= 0x00100010,
-	.p0_mpdgctrl0		= 0x414c014c,
-	.p0_mpdgctrl1		= 0x00000000,
-	.p0_mprddlctl		= 0x40403a42,
-	.p0_mpwrdlctl		= 0x4040342e,
-};
+static const struct dram_cfg_param ddr_ddrc_cfg_128mb[] = {
+	// IOMUX
+
+	//DDR IO TYPE:
+	{ 0x020e04b4, 0x000C0000 },	// IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE
+	{ 0x020e04ac, 0x00000000 },	// IOMUXC_SW_PAD_CTL_GRP_DDRPKE
+
+	//CLOCK:
+	{ 0x020e027c, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0
+
+	//ADDRESS:
+	{ 0x020e0250, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS
+	{ 0x020e024c, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS
+	{ 0x020e0490, 0x00000028 },	// IOMUXC_SW_PAD_CTL_GRP_ADDDS
+
+	//Control:
+	{ 0x020e0288, 0x000C0028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_RESET
+	{ 0x020e0270, 0x00000000 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_SDBA2 -
+					// DSE can be configured using Group
+					//  Control Register: IOMUXC_SW_PAD_CTL_GRP_CTLDS
+
+	{ 0x020e0260, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0
+	{ 0x020e0264, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT1
+	{ 0x020e04a0, 0x00000028 },	// IOMUXC_SW_PAD_CTL_GRP_CTLDS
+
+	//Data Strobes:
+	{ 0x020e0494, 0x00020000 },	// IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL
+	{ 0x020e0280, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0
+	{ 0x020e0284, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1
+
+	//Data:
+	{ 0x020e04b0, 0x00020000 },	// IOMUXC_SW_PAD_CTL_GRP_DDRMODE
+	{ 0x020e0498, 0x00000028 },	// IOMUXC_SW_PAD_CTL_GRP_B0DS
+	{ 0x020e04a4, 0x00000028 },	// IOMUXC_SW_PAD_CTL_GRP_B1DS
+
+	{ 0x020e0244, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0
+	{ 0x020e0248, 0x00000028 },	// IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1
+
+	//=============================================================================
+	// DDR Controller Registers
+	//=============================================================================
+	// Manufacturer:ISSI
+	// Device Part Number:IS43TR16640BL-125JBLI
+	// Clock Freq.: 400MHz
+	// Density per CS in Gb: 1
+	// Chip Selects used:1
+	// Number of Banks:8
+	// Row address:    13
+	// Column address: 10
+	// Data bus width16
+	//=============================================================================
+	{ 0x021b001c, 0x00008000 },	// MMDC0_MDSCR, set the Configuration
+					// request bit during MMDC set up
+
+	//=============================================================================
+	// Calibration setup.
+	//=============================================================================
+	{ 0x021b0800, 0xA1390003 },	// DDR_PHY_P0_MPZQHWCTRL,
+					// enable both one-time & periodic HW ZQ calibration.
+
+	// For target board, may need to run write leveling calibration to fine tune these settings.
+	{ 0x021b080c, 0x00000000 },	//
+
+	//Read DQS Gating calibration
+	{ 0x021b083c, 0x41480148 },	// MPDGCTRL0 PHY0
+
+	//Read calibration
+	{ 0x021b0848, 0x40403A3E },	// MPRDDLCTL PHY0
+
+	//Write calibration
+	{ 0x021b0850, 0x4040362E },	// MPWRDLCTL PHY0
+
+	//read data bit delay: 3 is the reccommended default value, although out of reset value is 0
+	{ 0x021b081c, 0x33333333 },	// MMDC_MPRDDQBY0DL
+	{ 0x021b0820, 0x33333333 },	// MMDC_MPRDDQBY1DL
+
+	//write data bit delay:
+	{ 0x021b082c, 0xF3333333 },	// MMDC_MPWRDQBY0DL
+	{ 0x021b0830, 0xF3333333 },	// MMDC_MPWRDQBY1DL
+
+	//DQS&CLK Duty Cycle
+	{ 0x021b08c0, 0x00944009 },	// [MMDC_MPDCCR] MMDC Duty Cycle Control Register
+
+	// Complete calibration by forced measurement:
+	{ 0x021b08b8, 0x00000800 },	// DDR_PHY_P0_MPMUR0, frc_msr
+	//=============================================================================
+	// Calibration setup end
+	
+//=====================================================================
+========
+
+	//MMDC init:
+	{ 0x021b0004, 0x0002002D },	// MMDC0_MDPDC
+	{ 0x021b0008, 0x1B333030 },	// MMDC0_MDOTC
+	{ 0x021b000c, 0x2B2F52F3 },	// MMDC0_MDCFG0
+	{ 0x021b0010, 0xB66D0B63 },	// MMDC0_MDCFG1
+	{ 0x021b0014, 0x01FF00DB },	// MMDC0_MDCFG2
+
+	//MDMISC: RALAT kept to the high level of 5.
+	//MDMISC: consider reducing RALAT if your 528MHz board design allow that.
+	//Lower RALAT benefits:
+	//a. better operation at low frequency, for LPDDR2 freq < 100MHz, change RALAT to 3
+	//b. Small performence improvment
+	{ 0x021b0018, 0x00211740 },	// MMDC0_MDMISC
+	{ 0x021b001c, 0x00008000 },	// MMDC0_MDSCR, set the Configuration request bit during
+					// MMDC set up
+	{ 0x021b002c, 0x000026D2 },	// MMDC0_MDRWD
+	{ 0x021b0030, 0x002F1023 },	// MMDC0_MDOR
+	{ 0x021b0040, 0x00000043 },	// Chan0 CS0_END
+	{ 0x021b0000, 0x82180000 },	// MMDC0_MDCTL
 
-static struct mx6_ddr_sysinfo ddr_sysinfo = {
-	.dsize			= 0,
-	.cs1_mirror		= 0,
-	.cs_density		= 32,
-	.ncs			= 1,
-	.bi_on			= 1,
-	.rtt_nom		= 1,
-	.rtt_wr			= 0,
-	.ralat			= 5,
-	.walat			= 1,
-	.mif3_mode		= 3,
-	.rst_to_cke		= 0x23,	/* 33 cycles (JEDEC value for DDR3) - total of 500 us */
-	.sde_to_rst		= 0x10,	/* 14 cycles (JEDEC value for DDR3) - total of 200 us */
-	.refsel			= 1,
-	.refr			= 3,
+	{ 0x021b0890, 0x00400000 },	// MPPDCMPR2
+
+	//Mode register writes
+	{ 0x021b001c, 0x02808032 },	// MMDC0_MDSCR, MR2 write, CS0
+	{ 0x021b001c, 0x00008033 },	// MMDC0_MDSCR, MR3 write, CS0
+	{ 0x021b001c, 0x00048031 },	// MMDC0_MDSCR, MR1 write, CS0
+	{ 0x021b001c, 0x15208030 },	// MMDC0_MDSCR, MR0write, CS0
+	{ 0x021b001c, 0x04008040 },	// MMDC0_MDSCR, ZQ calibration command sent to device on CS0
+
+	//    {0x021b001c,0x0200803A}, // MMDC0_MDSCR, MR2 write, CS1
+	//    {0x021b001c,0x0000803B}, // MMDC0_MDSCR, MR3 write, CS1
+	//    {0x021b001c,0x00048039}, // MMDC0_MDSCR, MR1 write, CS1
+	//    {0x021b001c,0x15208038}, // MMDC0_MDSCR, MR0write, CS1
+	//    {0x021b001c,0x04008048}, // MMDC0_MDSCR, ZQ calibration command sent to device on CS1
+
+	{ 0x021b0020, 0x00007800 },	// MMDC0_MDREF
+
+	{ 0x021b0818, 0x00000227 },	// DDR_PHY_P0_MPODTCTRL
+
+	{ 0x021b0004, 0x0002552D },	// MMDC0_MDPDC now SDCTL power down enabled
+
+	{ 0x021b0404, 0x00011006 },	// MMDC0_MAPSR ADOPT power down enabled,
+					// MMDC will enter automatically to self-refresh
+					// while the number of idle cycle reached.
+
+	{ 0x021b001c, 0x00000000 },	// MMDC0_MDSCR, clear this register
+					// (especially the configuration bit as initialization
+					// is complete)
 };
 
-static struct mx6_ddr3_cfg mem_ddr = {
-	.mem_speed		= 1333,
-	.density		= 2,
-	.width			= 16,
-	.banks			= 8,
-	.rowaddr		= 13,
-	.coladdr		= 10,
-	.pagesz			= 2,
-	.trcd			= 1350,
-	.trcmin			= 4950,
-	.trasmin		= 3600,
+struct dram_timing_info dram_timing_128mb = {
+	.ddrc_cfg = ddr_ddrc_cfg_128mb,
+	.ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_128mb),
 };
 
+static void ddr_cfg_write(const struct dram_timing_info 
+*dram_timing_info) {
+	int i = 0;
+	const struct dram_cfg_param *ddrc_cfg = dram_timing_info->ddrc_cfg;
+	const int ddrc_cfg_num = dram_timing_info->ddrc_cfg_num;
+
+	for (i = 0; i < ddrc_cfg_num; i++) {
+		debug("Writing 0x%x to register 0x%x\n", ddrc_cfg->val,
+		      ddrc_cfg->reg);
+		writel(ddrc_cfg->val, ddrc_cfg->reg);
+		ddrc_cfg++;
+	}
+}
+
+static void spl_dram_init(void)
+{
+	struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
+
+	clrbits_le32(&mmdc0->mdctl, 1 << 31);	/* clear SDE_0 */
+	clrbits_le32(&mmdc0->mdctl, 1 << 30);	/* clear SDE_1 */
+
+	ddr_cfg_write(&dram_timing_128mb);
+}
+
 static void ccgr_init(void)
 {
 	struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; @@ -108,20 +222,17 @@ static void ccgr_init(void)
 	writel(0xFFFFFFFF, &ccm->CCGR6);