Hi Dario On Tue, May 20, 2025 at 5:07 PM Dario Binacchi <dario.binac...@amarulasolutions.com> wrote: > > From: Michael Trimarchi <mich...@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 <mich...@amarulasolutions.com> > Signed-off-by: Dario Binacchi <dario.binac...@amarulasolutions.com> > > --- > > Changes in v2: > - Add 'static struct' globally in the module where the definitions > can mabe static. > - Use standard C comment style > > 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 | 260 ++++++++++++++++++------ > 3 files changed, 203 insertions(+), 62 deletions(-) > > 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; > +
This should be in this patch? Don't think so Michael > 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..936e54662e98 100644 > --- a/board/bsh/imx6ulz_smm_m2/spl.c > +++ b/board/bsh/imx6ulz_smm_m2/spl.c > @@ -31,70 +31,209 @@ 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 recommended 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 */ > > -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, > + /* > + * > ============================================================================= > + * 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 performance improvement > + */ > + {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 */ > + > + {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 > + */ > + {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, > +static 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; > + 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 +247,17 @@ static void ccgr_init(void) > writel(0xFFFFFFFF, &ccm->CCGR6); > } > > -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 > > base-commit: eeb5ff1a468b2303efa9deb2483b5edbebb568c6 > branch: bsh-202505-RAM -- Michael Nazzareno Trimarchi Co-Founder & Chief Executive Officer M. +39 347 913 2170 mich...@amarulasolutions.com __________________________________ Amarula Solutions BV Joop Geesinkweg 125, 1114 AB, Amsterdam, NL T. +31 (0)85 111 9172 i...@amarulasolutions.com www.amarulasolutions.com