[U-Boot] [PATCH 0/9] imx: mx6: support LPDDR2 and add mx6slevk spl

This patch set is to support SPL for mx6slevk board. But mx6slevk features one LPDDR2 chip. Then we need to first add LPDDR2 SPL support. Also introduce one ddr_type entry to differentiate DDR3 and LPDDR2. This patch set also correct tRFC and tXS for DDR3 4Gb chip.
The LPDDR2 part is implemented referencing MX6SL LPDDR2 Script Aid V0.04.xlsx and JESD209-2E. I am not DDR expert, can not guarantee that this can achieve production quality. Please review.
Patchset tested boot on mx6sxsabresd revb and mx6slevk board.
Peng Fan (9): imx: mx6: ddr add more register entry for mmdc_p_regs imx: mx6: ddr no support MMDC1 for i.MX6SL imx: mx6: ddr correct tRFC and tXS imx: mx6: ddr add dram io configuration and header file for i.MX6SL imx: mx6: ddr add mpzqlp2ctl entry imx: mx6: ddr add an entry ddr_type for mx6_ddr_sysinfo imx: mx6: ddr init MMDC according to ddr_type imx: mx6: ddr: add LPDDR2 support imx: mx6slevk: add SPL support
arch/arm/cpu/armv7/mx6/Kconfig | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 379 +++++++++++++++++++++- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 140 +++++++- arch/arm/include/asm/arch-mx6/mx6sl-ddr.h | 45 +++ board/barco/platinum/spl_picon.c | 1 + board/barco/platinum/spl_titanium.c | 1 + board/freescale/mx6sabresd/mx6sabresd.c | 1 + board/freescale/mx6slevk/mx6slevk.c | 164 ++++++++++ board/freescale/mx6sxsabresd/mx6sxsabresd.c | 1 + board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c | 1 + board/gateworks/gw_ventana/gw_ventana_spl.c | 1 + board/solidrun/mx6cuboxi/mx6cuboxi.c | 1 + configs/mx6slevk_spl_defconfig | 8 + include/configs/imx6_spl.h | 2 +- include/configs/mx6slevk.h | 7 + 15 files changed, 733 insertions(+), 20 deletions(-) create mode 100644 arch/arm/include/asm/arch-mx6/mx6sl-ddr.h create mode 100644 configs/mx6slevk_spl_defconfig

Add more register entry for MMDC structure.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com --- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 65 ++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 9 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 7bfbdc3..f3194da 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -40,30 +40,77 @@ struct mmdc_p_regs { u32 res1[2]; u32 mdrwd; u32 mdor; - u32 res2[3]; + u32 mdmrr; + u32 mdcfg3lp; + u32 mdmr4; u32 mdasp; - u32 res3[240]; + u32 res2[239]; + u32 maarcr; u32 mapsr; - u32 res4[254]; + u32 maexidr0; + u32 maexidr1; + u32 madpcr0; + u32 madpcr1; + u32 madpsr0; + u32 madpsr1; + u32 madpsr2; + u32 madpsr3; + u32 madpsr4; + u32 madpsr5; + u32 masbs0; + u32 masbs1; + u32 res3[2]; + u32 magenp; + u32 res4[239]; u32 mpzqhwctrl; - u32 res5[2]; + u32 mpzqswctrl; + u32 mpwlgcr; u32 mpwldectrl0; u32 mpwldectrl1; - u32 res6; + u32 mpwldlst; u32 mpodtctrl; u32 mprddqby0dl; u32 mprddqby1dl; u32 mprddqby2dl; u32 mprddqby3dl; - u32 res7[4]; + u32 mpwrdqby0dl; + u32 mpwrdqby1dl; + u32 mpwrdqby2dl; + u32 mpwrdqby3dl; u32 mpdgctrl0; u32 mpdgctrl1; - u32 res8; + u32 mpdgdlst0; u32 mprddlctl; - u32 res9; + u32 mprddlst; u32 mpwrdlctl; - u32 res10[25]; + u32 mpwrdlst; + u32 mpsdctrl; + u32 mpzqlp2ctl; + u32 mprddlhwctl; + u32 mpwrdlhwctl; + u32 mprddlhwst0; + u32 mprddlhwst1; + u32 mpwrdlhwst0; + u32 mpwrdlhwst1; + u32 mpwlhwerr; + u32 mpdghwst0; + u32 mpdghwst1; + u32 mpdghwst2; + u32 mpdghwst3; + u32 mppdcmpr1; + u32 mppdcmpr2; + u32 mpswdar0; + u32 mpswdrdr0; + u32 mpswdrdr1; + u32 mpswdrdr2; + u32 mpswdrdr3; + u32 mpswdrdr4; + u32 mpswdrdr5; + u32 mpswdrdr6; + u32 mpswdrdr7; u32 mpmur0; + u32 mpwrcadl; + u32 mpdccr; };
#define MX6UL_IOM_DDR_BASE 0x020e0200

On 17/08/2015 10:10, Peng Fan wrote:
Add more register entry for MMDC structure.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com
arch/arm/include/asm/arch-mx6/mx6-ddr.h | 65 ++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 9 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 7bfbdc3..f3194da 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -40,30 +40,77 @@ struct mmdc_p_regs { u32 res1[2]; u32 mdrwd; u32 mdor;
- u32 res2[3];
- u32 mdmrr;
- u32 mdcfg3lp;
- u32 mdmr4; u32 mdasp;
- u32 res3[240];
- u32 res2[239];
- u32 maarcr; u32 mapsr;
- u32 res4[254];
- u32 maexidr0;
- u32 maexidr1;
- u32 madpcr0;
- u32 madpcr1;
- u32 madpsr0;
- u32 madpsr1;
- u32 madpsr2;
- u32 madpsr3;
- u32 madpsr4;
- u32 madpsr5;
- u32 masbs0;
- u32 masbs1;
- u32 res3[2];
- u32 magenp;
- u32 res4[239]; u32 mpzqhwctrl;
- u32 res5[2];
- u32 mpzqswctrl;
- u32 mpwlgcr; u32 mpwldectrl0; u32 mpwldectrl1;
- u32 res6;
- u32 mpwldlst; u32 mpodtctrl; u32 mprddqby0dl; u32 mprddqby1dl; u32 mprddqby2dl; u32 mprddqby3dl;
- u32 res7[4];
- u32 mpwrdqby0dl;
- u32 mpwrdqby1dl;
- u32 mpwrdqby2dl;
- u32 mpwrdqby3dl; u32 mpdgctrl0; u32 mpdgctrl1;
- u32 res8;
- u32 mpdgdlst0; u32 mprddlctl;
- u32 res9;
- u32 mprddlst; u32 mpwrdlctl;
- u32 res10[25];
- u32 mpwrdlst;
- u32 mpsdctrl;
- u32 mpzqlp2ctl;
- u32 mprddlhwctl;
- u32 mpwrdlhwctl;
- u32 mprddlhwst0;
- u32 mprddlhwst1;
- u32 mpwrdlhwst0;
- u32 mpwrdlhwst1;
- u32 mpwlhwerr;
- u32 mpdghwst0;
- u32 mpdghwst1;
- u32 mpdghwst2;
- u32 mpdghwst3;
- u32 mppdcmpr1;
- u32 mppdcmpr2;
- u32 mpswdar0;
- u32 mpswdrdr0;
- u32 mpswdrdr1;
- u32 mpswdrdr2;
- u32 mpswdrdr3;
- u32 mpswdrdr4;
- u32 mpswdrdr5;
- u32 mpswdrdr6;
- u32 mpswdrdr7; u32 mpmur0;
- u32 mpwrcadl;
- u32 mpdccr;
};
#define MX6UL_IOM_DDR_BASE 0x020e0200
Reviewed-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

i.MX 6SoloLite only supports MMDC0, so do not access MMDC1 for i.MX 6SL.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/armv7/mx6/ddr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index b808627..28fa3cf 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -288,7 +288,8 @@ void mx6sdl_dram_iocfg(unsigned width, #define MR(val, ba, cmd, cs1) \ ((val << 16) | (1 << 15) | (cmd << 4) | (cs1 << 3) | ba) #define MMDC1(entry, value) do { \ - if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL)) \ + if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL) && \ + !is_cpu_type(MXC_CPU_MX6SL)) \ mmdc1->entry = value; \ } while (0)
@@ -312,7 +313,8 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, u16 mem_speed = ddr3_cfg->mem_speed;
mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR; - if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL)) + if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL) && + !is_cpu_type(MXC_CPU_MX6SL)) mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
/* Limit mem_speed for MX6D/MX6Q */

On 17/08/2015 10:10, Peng Fan wrote:
i.MX 6SoloLite only supports MMDC0, so do not access MMDC1 for i.MX 6SL.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com
arch/arm/cpu/armv7/mx6/ddr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index b808627..28fa3cf 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -288,7 +288,8 @@ void mx6sdl_dram_iocfg(unsigned width, #define MR(val, ba, cmd, cs1) \ ((val << 16) | (1 << 15) | (cmd << 4) | (cs1 << 3) | ba) #define MMDC1(entry, value) do { \
- if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL)) \
- if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL) && \
mmdc1->entry = value; \ } while (0)!is_cpu_type(MXC_CPU_MX6SL)) \
@@ -312,7 +313,8 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, u16 mem_speed = ddr3_cfg->mem_speed;
mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
- if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL))
if (!is_cpu_type(MXC_CPU_MX6SX) && !is_cpu_type(MXC_CPU_MX6UL) &&
!is_cpu_type(MXC_CPU_MX6SL))
mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
/* Limit mem_speed for MX6D/MX6Q */
Reviewed-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

To Chip density 4Gb, tRFC should be 300ns, see "Table 61 — Refresh parameters by device density" of JESD79-3E. tXS(min) is max(5nCK, tRFC(min) + 10ns).
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/armv7/mx6/ddr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index 28fa3cf..3ec3e79 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -357,8 +357,8 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, txs = DIV_ROUND_UP(170000, clkper) - 1; break; case 4: /* 4Gb per chip */ - trfc = DIV_ROUND_UP(260000, clkper) - 1; - txs = DIV_ROUND_UP(270000, clkper) - 1; + trfc = DIV_ROUND_UP(300000, clkper) - 1; + txs = DIV_ROUND_UP(310000, clkper) - 1; break; case 8: /* 8Gb per chip */ trfc = DIV_ROUND_UP(350000, clkper) - 1;

On 17/08/2015 10:10, Peng Fan wrote:
To Chip density 4Gb, tRFC should be 300ns, see "Table 61 — Refresh parameters by device density" of JESD79-3E. tXS(min) is max(5nCK, tRFC(min) + 10ns).
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com
arch/arm/cpu/armv7/mx6/ddr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index 28fa3cf..3ec3e79 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -357,8 +357,8 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, txs = DIV_ROUND_UP(170000, clkper) - 1; break; case 4: /* 4Gb per chip */
trfc = DIV_ROUND_UP(260000, clkper) - 1;
txs = DIV_ROUND_UP(270000, clkper) - 1;
trfc = DIV_ROUND_UP(300000, clkper) - 1;
break; case 8: /* 8Gb per chip */ trfc = DIV_ROUND_UP(350000, clkper) - 1;txs = DIV_ROUND_UP(310000, clkper) - 1;
Reviewed-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

Define two structure mx6sl_iomux_ddr_regs and mx6sl_iomux_grp_regs. Add a new function mx6sl_dram_iocfg to configure dram io. Add header file to define macros for register address.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de --- arch/arm/cpu/armv7/mx6/ddr.c | 55 +++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/mx6-ddr.h | 50 ++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/mx6sl-ddr.h | 45 +++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 arch/arm/include/asm/arch-mx6/mx6sl-ddr.h
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index 3ec3e79..3f23abf 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -115,6 +115,61 @@ void mx6ul_dram_iocfg(unsigned width, } #endif
+#if defined(CONFIG_MX6SL) +void mx6sl_dram_iocfg(unsigned width, + const struct mx6sl_iomux_ddr_regs *ddr, + const struct mx6sl_iomux_grp_regs *grp) +{ + struct mx6sl_iomux_ddr_regs *mx6_ddr_iomux; + struct mx6sl_iomux_grp_regs *mx6_grp_iomux; + + mx6_ddr_iomux = (struct mx6sl_iomux_ddr_regs *)MX6SL_IOM_DDR_BASE; + mx6_grp_iomux = (struct mx6sl_iomux_grp_regs *)MX6SL_IOM_GRP_BASE; + + /* DDR IO TYPE */ + mx6_grp_iomux->grp_ddr_type = grp->grp_ddr_type; + mx6_grp_iomux->grp_ddrpke = grp->grp_ddrpke; + + /* CLOCK */ + mx6_ddr_iomux->dram_sdclk_0 = ddr->dram_sdclk_0; + + /* ADDRESS */ + mx6_ddr_iomux->dram_cas = ddr->dram_cas; + mx6_ddr_iomux->dram_ras = ddr->dram_ras; + mx6_grp_iomux->grp_addds = grp->grp_addds; + + /* Control */ + mx6_ddr_iomux->dram_reset = ddr->dram_reset; + mx6_ddr_iomux->dram_sdba2 = ddr->dram_sdba2; + mx6_grp_iomux->grp_ctlds = grp->grp_ctlds; + + /* Data Strobes */ + mx6_grp_iomux->grp_ddrmode_ctl = grp->grp_ddrmode_ctl; + mx6_ddr_iomux->dram_sdqs0 = ddr->dram_sdqs0; + mx6_ddr_iomux->dram_sdqs1 = ddr->dram_sdqs1; + if (width >= 32) { + mx6_ddr_iomux->dram_sdqs2 = ddr->dram_sdqs2; + mx6_ddr_iomux->dram_sdqs3 = ddr->dram_sdqs3; + } + + /* Data */ + mx6_grp_iomux->grp_ddrmode = grp->grp_ddrmode; + mx6_grp_iomux->grp_b0ds = grp->grp_b0ds; + mx6_grp_iomux->grp_b1ds = grp->grp_b1ds; + if (width >= 32) { + mx6_grp_iomux->grp_b2ds = grp->grp_b2ds; + mx6_grp_iomux->grp_b3ds = grp->grp_b3ds; + } + + mx6_ddr_iomux->dram_dqm0 = ddr->dram_dqm0; + mx6_ddr_iomux->dram_dqm1 = ddr->dram_dqm1; + if (width >= 32) { + mx6_ddr_iomux->dram_dqm2 = ddr->dram_dqm2; + mx6_ddr_iomux->dram_dqm3 = ddr->dram_dqm3; + } +} +#endif + #if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D) /* Configure MX6DQ mmdc iomux */ void mx6dq_dram_iocfg(unsigned width, diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index f3194da..235a44a 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -19,7 +19,11 @@ #ifdef CONFIG_MX6UL #include "mx6ul-ddr.h" #else +#ifdef CONFIG_MX6SL +#include "mx6sl-ddr.h" +#else #error "Please select cpu" +#endif /* CONFIG_MX6SL */ #endif /* CONFIG_MX6UL */ #endif /* CONFIG_MX6SX */ #endif /* CONFIG_MX6DL or CONFIG_MX6S */ @@ -113,6 +117,49 @@ struct mmdc_p_regs { u32 mpdccr; };
+#define MX6SL_IOM_DDR_BASE 0x020e0300 +struct mx6sl_iomux_ddr_regs { + u32 dram_cas; + u32 dram_cs0_b; + u32 dram_cs1_b; + u32 dram_dqm0; + u32 dram_dqm1; + u32 dram_dqm2; + u32 dram_dqm3; + u32 dram_ras; + u32 dram_reset; + u32 dram_sdba0; + u32 dram_sdba1; + u32 dram_sdba2; + u32 dram_sdcke0; + u32 dram_sdcke1; + u32 dram_sdclk_0; + u32 dram_odt0; + u32 dram_odt1; + u32 dram_sdqs0; + u32 dram_sdqs1; + u32 dram_sdqs2; + u32 dram_sdqs3; + u32 dram_sdwe_b; +}; + +#define MX6SL_IOM_GRP_BASE 0x020e0500 +struct mx6sl_iomux_grp_regs { + u32 res1[43]; + u32 grp_addds; + u32 grp_ddrmode_ctl; + u32 grp_ddrpke; + u32 grp_ddrpk; + u32 grp_ddrhys; + u32 grp_ddrmode; + u32 grp_b0ds; + u32 grp_ctlds; + u32 grp_b1ds; + u32 grp_ddr_type; + u32 grp_b2ds; + u32 grp_b3ds; +}; + #define MX6UL_IOM_DDR_BASE 0x020e0200 struct mx6ul_iomux_ddr_regs { u32 res1[17]; @@ -382,6 +429,9 @@ void mx6sx_dram_iocfg(unsigned width, void mx6ul_dram_iocfg(unsigned width, const struct mx6ul_iomux_ddr_regs *, const struct mx6ul_iomux_grp_regs *); +void mx6sl_dram_iocfg(unsigned width, + const struct mx6sl_iomux_ddr_regs *, + const struct mx6sl_iomux_grp_regs *);
/* configure mx6 mmdc registers */ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *, diff --git a/arch/arm/include/asm/arch-mx6/mx6sl-ddr.h b/arch/arm/include/asm/arch-mx6/mx6sl-ddr.h new file mode 100644 index 0000000..c3c4d69 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/mx6sl-ddr.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_ARCH_MX6SL_DDR_H__ +#define __ASM_ARCH_MX6SL_DDR_H__ + +#ifndef CONFIG_MX6SL +#error "wrong CPU" +#endif + +#define MX6_IOM_DRAM_CAS_B 0x020e0300 +#define MX6_IOM_DRAM_CS0_B 0x020e0304 +#define MX6_IOM_DRAM_CS1_B 0x020e0308 + +#define MX6_IOM_DRAM_DQM0 0x020e030c +#define MX6_IOM_DRAM_DQM1 0x020e0310 +#define MX6_IOM_DRAM_DQM2 0x020e0314 +#define MX6_IOM_DRAM_DQM3 0x020e0318 + +#define MX6_IOM_DRAM_RAS_B 0x020e031c +#define MX6_IOM_DRAM_RESET 0x020e0320 + +#define MX6_IOM_DRAM_SDBA0 0x020e0324 +#define MX6_IOM_DRAM_SDBA1 0x020e0328 +#define MX6_IOM_DRAM_SDBA2 0x020e032c + +#define MX6_IOM_DRAM_SDCKE0 0x020e0330 +#define MX6_IOM_DRAM_SDCKE1 0x020e0334 + +#define MX6_IOM_DRAM_SDCLK0_P 0x020e0338 + +#define MX6_IOM_DRAM_ODT0 0x020e033c +#define MX6_IOM_DRAM_ODT1 0x020e0340 + +#define MX6_IOM_DRAM_SDQS0_P 0x020e0344 +#define MX6_IOM_DRAM_SDQS1_P 0x020e0348 +#define MX6_IOM_DRAM_SDQS2_P 0x020e034c +#define MX6_IOM_DRAM_SDQS3_P 0x020e0350 + +#define MX6_IOM_DRAM_SDWE_B 0x020e0354 + +#endif /*__ASM_ARCH_MX6SL_DDR_H__ */

Add mpzqlp2ctl entry for mx6_mmdc_calibration. MMDC_MPZQLP2CTL register is for init tZQINIT, tZQCL, tZQCS for LPDDR2 chips.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com --- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 235a44a..b7bae7b 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -414,6 +414,8 @@ struct mx6_mmdc_calibration { /* write delay */ u32 p0_mpwrdlctl; u32 p1_mpwrdlctl; + /* lpddr2 zq hw calibration */ + u32 mpzqlp2ctl; };
/* configure iomux (pinctl/padctl) */

Add ddr_type entry for mx6_ddr_sysinfo. It will be used for differenrate DDR3 and LPDDR2.
Introduce an enum type for ddr_type.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com --- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index b7bae7b..806fafb 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -30,6 +30,11 @@ #endif /* CONFIG_MX6Q */ #else
+enum { + DDR_TYPE_DDR3, + DDR_TYPE_LPDDR2, +}; + /* MMDC P0/P1 Registers */ struct mmdc_p_regs { u32 mdctl; @@ -387,6 +392,7 @@ struct mx6_ddr_sysinfo { u8 rst_to_cke; /* Time from SDE enable to CKE rise */ u8 sde_to_rst; /* Time from SDE enable until DDR reset# is high */ u8 pd_fast_exit;/* enable precharge powerdown fast-exit */ + u8 ddr_type; /* DDR type: DDR3(0) or LPDDR2(1) */ };
/*

To i.MX6, DDR3 and LPDDR2 is supported, so rename function mx6_dram_cfg to mx6_ddr3_cfg and the original mx6_dram_cfg function only is a wrapper. The new reimplemented function mx6_dram_cfg only invokes mx6_ddr3_cfg when ddr_type is for DDR3. Later we can use ddr_type to initialize MMDC for LPDDR2.
Initialize ddr_type for different boards which enable SPL.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com Cc: Stefan Roese sr@denx.de Cc: Fabio Estevam fabio.estevam@freescale.com Reviewed-by: Stefan Roese sr@denx.de --- arch/arm/cpu/armv7/mx6/ddr.c | 14 +++++++++++++- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 2 +- board/barco/platinum/spl_picon.c | 1 + board/barco/platinum/spl_titanium.c | 1 + board/freescale/mx6sabresd/mx6sabresd.c | 1 + board/freescale/mx6sxsabresd/mx6sxsabresd.c | 1 + board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c | 1 + board/gateworks/gw_ventana/gw_ventana_spl.c | 1 + board/solidrun/mx6cuboxi/mx6cuboxi.c | 1 + 9 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index 3f23abf..17909a3 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -348,7 +348,7 @@ void mx6sdl_dram_iocfg(unsigned width, mmdc1->entry = value; \ } while (0)
-void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, +void mx6_ddr3_cfg(const struct mx6_ddr_sysinfo *sysinfo, const struct mx6_mmdc_calibration *calib, const struct mx6_ddr3_cfg *ddr3_cfg) { @@ -655,3 +655,15 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, /* wait for auto-ZQ calibration to complete */ mdelay(1); } + +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, + const struct mx6_mmdc_calibration *calib, + const void *ddr_cfg) +{ + if (sysinfo->ddr_type == DDR_TYPE_DDR3) { + mx6_ddr3_cfg(sysinfo, calib, ddr_cfg); + } else { + puts("Unsupported ddr type\n"); + hang(); + } +} diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 806fafb..36fcb2b 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -444,7 +444,7 @@ void mx6sl_dram_iocfg(unsigned width, /* configure mx6 mmdc registers */ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *, const struct mx6_mmdc_calibration *, - const struct mx6_ddr3_cfg *); + const void *);
#endif /* CONFIG_SPL_BUILD */
diff --git a/board/barco/platinum/spl_picon.c b/board/barco/platinum/spl_picon.c index f421c21..098542f 100644 --- a/board/barco/platinum/spl_picon.c +++ b/board/barco/platinum/spl_picon.c @@ -137,6 +137,7 @@ static void spl_dram_init(int width) .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .ddr_type = DDR_TYPE_DDR3, };
mx6sdl_dram_iocfg(width, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); diff --git a/board/barco/platinum/spl_titanium.c b/board/barco/platinum/spl_titanium.c index 26fe26b..a3a4255 100644 --- a/board/barco/platinum/spl_titanium.c +++ b/board/barco/platinum/spl_titanium.c @@ -140,6 +140,7 @@ static void spl_dram_init(int width) .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .ddr_type = DDR_TYPE_DDR3, };
mx6dq_dram_iocfg(width, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); diff --git a/board/freescale/mx6sabresd/mx6sabresd.c b/board/freescale/mx6sabresd/mx6sabresd.c index eb8a8b3..5644167 100644 --- a/board/freescale/mx6sabresd/mx6sabresd.c +++ b/board/freescale/mx6sabresd/mx6sabresd.c @@ -824,6 +824,7 @@ static void spl_dram_init(void) .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .ddr_type = DDR_TYPE_DDR3, };
mx6dq_dram_iocfg(64, &mx6_ddr_ioregs, &mx6_grp_ioregs); diff --git a/board/freescale/mx6sxsabresd/mx6sxsabresd.c b/board/freescale/mx6sxsabresd/mx6sxsabresd.c index d58a79a..8983089 100644 --- a/board/freescale/mx6sxsabresd/mx6sxsabresd.c +++ b/board/freescale/mx6sxsabresd/mx6sxsabresd.c @@ -566,6 +566,7 @@ static void spl_dram_init(void) .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .ddr_type = DDR_TYPE_DDR3, };
mx6sx_dram_iocfg(mem_ddr.width, &mx6_ddr_ioregs, &mx6_grp_ioregs); diff --git a/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c b/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c index 8f712cb..41a242e 100644 --- a/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c +++ b/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c @@ -598,6 +598,7 @@ static void spl_dram_init(void) .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .ddr_type = DDR_TYPE_DDR3, };
mx6ul_dram_iocfg(mem_ddr.width, &mx6_ddr_ioregs, &mx6_grp_ioregs); diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.c b/board/gateworks/gw_ventana/gw_ventana_spl.c index d4418e5..d28eb14 100644 --- a/board/gateworks/gw_ventana/gw_ventana_spl.c +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -365,6 +365,7 @@ static void spl_dram_init(int width, int size_mb, int board_model) .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ .pd_fast_exit = 1, /* enable precharge power-down fast exit */ + .ddr_type = DDR_TYPE_DDR3, };
/* diff --git a/board/solidrun/mx6cuboxi/mx6cuboxi.c b/board/solidrun/mx6cuboxi/mx6cuboxi.c index 9b1ecf0..8a8a03c 100644 --- a/board/solidrun/mx6cuboxi/mx6cuboxi.c +++ b/board/solidrun/mx6cuboxi/mx6cuboxi.c @@ -615,6 +615,7 @@ static void spl_dram_init(int width) .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .ddr_type = DDR_TYPE_DDR3, };
if (is_cpu_type(MXC_CPU_MX6D) || is_cpu_type(MXC_CPU_MX6Q))

Add LPDDR2 support: 1. Implement a function mx6_lpddr2_cfg to initialize MMDC for LPDDR2. 2. Introduce a structure mx6_lpddr2_cfg, most entrys are same to mx6_ddr3_cfg, but still keep it a single one for easy to choose parameters for LPDDR2. 3. If ddr_type is LPDDR2, use mx6_lpddr2_cfg to init MMDC. 4. Update comments.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/armv7/mx6/ddr.c | 300 +++++++++++++++++++++++++++++++- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 15 ++ 2 files changed, 311 insertions(+), 4 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index 17909a3..cf5587b 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -7,6 +7,7 @@
#include <common.h> #include <linux/types.h> +#include <asm/arch/clock.h> #include <asm/arch/mx6-ddr.h> #include <asm/arch/sys_proto.h> #include <asm/io.h> @@ -330,15 +331,20 @@ void mx6sdl_dram_iocfg(unsigned width, * Configure mx6 mmdc registers based on: * - board-specific memory configuration * - board-specific calibration data - * - ddr3 chip details + * - ddr3/lpddr2 chip details * * The various calculations here are derived from the Freescale - * i.Mx6DQSDL DDR3 Script Aid spreadsheet (DOC-94917) designed to generate MMDC - * configuration registers based on memory system and memory chip parameters. + * 1. i.Mx6DQSDL DDR3 Script Aid spreadsheet (DOC-94917) designed to generate + * MMDC configuration registers based on memory system and memory chip + * parameters. + * + * 2. i.Mx6SL LPDDR2 Script Aid spreadsheet V0.04 designed to generate MMDC + * configuration registers based on memory system and memory chip + * parameters. * * The defaults here are those which were specified in the spreadsheet. * For details on each register, refer to the IMX6DQRM and/or IMX6SDLRM - * section titled MMDC initialization + * and/or IMX6SLRM section titled MMDC initialization. */ #define MR(val, ba, cmd, cs1) \ ((val << 16) | (1 << 15) | (cmd << 4) | (cs1 << 3) | ba) @@ -348,6 +354,290 @@ void mx6sdl_dram_iocfg(unsigned width, mmdc1->entry = value; \ } while (0)
+/* + * According JESD209-2B-LPDDR2: Table 103 + * WL: write latency + */ +static int lpddr2_wl(uint32_t mem_speed) +{ + switch (mem_speed) { + case 1066: + case 933: + return 4; + case 800: + return 3; + case 677: + case 533: + return 2; + case 400: + case 333: + return 1; + default: + puts("invalid memory speed\n"); + hang(); + } + + return 0; +} + +/* + * According JESD209-2B-LPDDR2: Table 103 + * RL: read latency + */ +static int lpddr2_rl(uint32_t mem_speed) +{ + switch (mem_speed) { + case 1066: + return 8; + case 933: + return 7; + case 800: + return 6; + case 677: + return 5; + case 533: + return 4; + case 400: + case 333: + return 3; + default: + puts("invalid memory speed\n"); + hang(); + } + + return 0; +} + +void mx6_lpddr2_cfg(const struct mx6_ddr_sysinfo *sysinfo, + const struct mx6_mmdc_calibration *calib, + const struct mx6_lpddr2_cfg *lpddr2_cfg) +{ + volatile struct mmdc_p_regs *mmdc0; + u32 val; + u8 tcke, tcksrx, tcksre, trrd; + u8 twl, txp, tfaw, tcl; + u16 tras, twr, tmrd, trtp, twtr, trfc, txsr; + u16 trcd_lp, trppb_lp, trpab_lp, trc_lp; + u16 cs0_end; + u8 coladdr; + int clkper; /* clock period in picoseconds */ + int clock; /* clock freq in mHz */ + int cs; + + /* only support 16/32 bits */ + if (sysinfo->dsize > 1) + hang(); + + mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR; + + clock = mxc_get_clock(MXC_DDR_CLK) / 1000000U; + clkper = (1000 * 1000) / clock; /* pico seconds */ + + twl = lpddr2_wl(lpddr2_cfg->mem_speed) - 1; + + /* LPDDR2-S2 and LPDDR2-S4 have the same tRFC value. */ + switch (lpddr2_cfg->density) { + case 1: + case 2: + case 4: + trfc = DIV_ROUND_UP(130000, clkper) - 1; + txsr = DIV_ROUND_UP(140000, clkper) - 1; + break; + case 8: + trfc = DIV_ROUND_UP(210000, clkper) - 1; + txsr = DIV_ROUND_UP(220000, clkper) - 1; + break; + default: + /* + * 64Mb, 128Mb, 256Mb, 512Mb are not supported currently. + */ + hang(); + break; + } + /* + * txpdll, txpr, taonpd and taofpd are not relevant in LPDDR2 mode, + * set them to 0. */ + txp = DIV_ROUND_UP(7500, clkper) - 1; + tcke = 3; + if (lpddr2_cfg->mem_speed == 333) + tfaw = DIV_ROUND_UP(60000, clkper) - 1; + else + tfaw = DIV_ROUND_UP(50000, clkper) - 1; + trrd = DIV_ROUND_UP(10000, clkper) - 1; + + /* tckesr for LPDDR2 */ + tcksre = DIV_ROUND_UP(15000, clkper); + tcksrx = tcksre; + twr = DIV_ROUND_UP(15000, clkper) - 1; + /* + * tMRR: 2, tMRW: 5 + * tMRD should be set to max(tMRR, tMRW) + */ + tmrd = 5; + tras = DIV_ROUND_UP(lpddr2_cfg->trasmin, clkper / 10) - 1; + /* LPDDR2 mode use tRCD_LP filed in MDCFG3. */ + trcd_lp = DIV_ROUND_UP(lpddr2_cfg->trcd_lp, clkper / 10) - 1; + trc_lp = DIV_ROUND_UP(lpddr2_cfg->trasmin + lpddr2_cfg->trppb_lp, + clkper / 10) - 1; + trppb_lp = DIV_ROUND_UP(lpddr2_cfg->trppb_lp, clkper / 10) - 1; + trpab_lp = DIV_ROUND_UP(lpddr2_cfg->trpab_lp, clkper / 10) - 1; + /* To LPDDR2, CL in MDCFG0 refers to RL */ + tcl = lpddr2_rl(lpddr2_cfg->mem_speed) - 3; + twtr = DIV_ROUND_UP(7500, clkper) - 1; + trtp = DIV_ROUND_UP(7500, clkper) - 1; + + cs0_end = 4 * sysinfo->cs_density - 1; + + debug("density:%d Gb (%d Gb per chip)\n", + sysinfo->cs_density, lpddr2_cfg->density); + debug("clock: %dMHz (%d ps)\n", clock, clkper); + debug("memspd:%d\n", lpddr2_cfg->mem_speed); + debug("trcd_lp=%d\n", trcd_lp); + debug("trppb_lp=%d\n", trppb_lp); + debug("trpab_lp=%d\n", trpab_lp); + debug("trc_lp=%d\n", trc_lp); + debug("tcke=%d\n", tcke); + debug("tcksrx=%d\n", tcksrx); + debug("tcksre=%d\n", tcksre); + debug("trfc=%d\n", trfc); + debug("txsr=%d\n", txsr); + debug("txp=%d\n", txp); + debug("tfaw=%d\n", tfaw); + debug("tcl=%d\n", tcl); + debug("tras=%d\n", tras); + debug("twr=%d\n", twr); + debug("tmrd=%d\n", tmrd); + debug("twl=%d\n", twl); + debug("trtp=%d\n", trtp); + debug("twtr=%d\n", twtr); + debug("trrd=%d\n", trrd); + debug("cs0_end=%d\n", cs0_end); + debug("ncs=%d\n", sysinfo->ncs); + + /* + * 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; + + /* Read data DQ Byte0-3 delay */ + mmdc0->mprddqby0dl = 0x33333333; + mmdc0->mprddqby1dl = 0x33333333; + if (sysinfo->dsize > 0) { + mmdc0->mprddqby2dl = 0x33333333; + mmdc0->mprddqby3dl = 0x33333333; + } + + /* Write data DQ Byte0-3 delay */ + mmdc0->mpwrdqby0dl = 0xf3333333; + mmdc0->mpwrdqby1dl = 0xf3333333; + if (sysinfo->dsize > 0) { + mmdc0->mpwrdqby2dl = 0xf3333333; + mmdc0->mpwrdqby3dl = 0xf3333333; + } + + /* + * In LPDDR2 mode this register should be cleared, + * so no termination will be activated. + */ + mmdc0->mpodtctrl = 0; + + /* complete calibration */ + val = (1 << 11); /* Force measurement on delay-lines */ + mmdc0->mpmur0 = val; + + /* Step 1: configuration request */ + mmdc0->mdscr = (u32)(1 << 15); /* config request */ + + /* Step 2: Timing configuration */ + mmdc0->mdcfg0 = (trfc << 24) | (txsr << 16) | (txp << 13) | + (tfaw << 4) | tcl; + mmdc0->mdcfg1 = (tras << 16) | (twr << 9) | (tmrd << 5) | twl; + mmdc0->mdcfg2 = (trtp << 6) | (twtr << 3) | trrd; + mmdc0->mdcfg3lp = (trc_lp << 16) | (trcd_lp << 8) | + (trppb_lp << 4) | trpab_lp; + mmdc0->mdotc = 0; + + mmdc0->mdasp = cs0_end; /* CS addressing */ + + /* Step 3: Configure DDR type */ + mmdc0->mdmisc = (sysinfo->cs1_mirror << 19) | (sysinfo->walat << 16) | + (sysinfo->bi_on << 12) | (sysinfo->mif3_mode << 9) | + (sysinfo->ralat << 6) | (1 << 3); + + /* Step 4: Configure delay while leaving reset */ + mmdc0->mdor = (sysinfo->sde_to_rst << 8) | + (sysinfo->rst_to_cke << 0); + + /* Step 5: Configure DDR physical parameters (density and burst len) */ + coladdr = lpddr2_cfg->coladdr; + if (lpddr2_cfg->coladdr == 8) /* 8-bit COL is 0x3 */ + coladdr += 4; + else if (lpddr2_cfg->coladdr == 12) /* 12-bit COL is 0x4 */ + coladdr += 1; + mmdc0->mdctl = (lpddr2_cfg->rowaddr - 11) << 24 | /* ROW */ + (coladdr - 9) << 20 | /* COL */ + (0 << 19) | /* Burst Length = 4 for LPDDR2 */ + (sysinfo->dsize << 16); /* DDR data bus size */ + + /* Step 6: Perform ZQ calibration */ + val = 0xa1390003; /* one-time HW ZQ calib */ + mmdc0->mpzqhwctrl = val; + + /* Step 7: Enable MMDC with desired chip select */ + mmdc0->mdctl |= (1 << 31) | /* SDE_0 for CS0 */ + ((sysinfo->ncs == 2) ? 1 : 0) << 30; /* SDE_1 for CS1 */ + + /* Step 8: Write Mode Registers to Init LPDDR2 devices */ + for (cs = 0; cs < sysinfo->ncs; cs++) { + /* MR63: reset */ + mmdc0->mdscr = MR(63, 0, 3, cs); + /* MR10: calibration, + * 0xff is calibration command after intilization. + */ + val = 0xA | (0xff << 8); + mmdc0->mdscr = MR(val, 0, 3, cs); + /* MR1 */ + val = 0x1 | (0x82 << 8); + mmdc0->mdscr = MR(val, 0, 3, cs); + /* MR2 */ + val = 0x2 | (0x04 << 8); + mmdc0->mdscr = MR(val, 0, 3, cs); + /* MR3 */ + val = 0x3 | (0x02 << 8); + mmdc0->mdscr = MR(val, 0, 3, cs); + } + + /* Step 10: Power down control and self-refresh */ + mmdc0->mdpdc = (tcke & 0x7) << 16 | + 5 << 12 | /* PWDT_1: 256 cycles */ + 5 << 8 | /* PWDT_0: 256 cycles */ + 1 << 6 | /* BOTH_CS_PD */ + (tcksrx & 0x7) << 3 | + (tcksre & 0x7); + mmdc0->mapsr = 0x00001006; /* ADOPT power down enabled */ + + /* Step 11: Configure ZQ calibration: one-time and periodic 1ms */ + val = 0xa1310003; + mmdc0->mpzqhwctrl = val; + + /* Step 12: Configure and activate periodic refresh */ + mmdc0->mdref = (0 << 14) | /* REF_SEL: Periodic refresh cycle: 64kHz */ + (3 << 11); /* REFR: Refresh Rate - 4 refreshes */ + + /* Step 13: Deassert config request - init complete */ + mmdc0->mdscr = 0x00000000; + + /* wait for auto-ZQ calibration to complete */ + mdelay(1); +} + void mx6_ddr3_cfg(const struct mx6_ddr_sysinfo *sysinfo, const struct mx6_mmdc_calibration *calib, const struct mx6_ddr3_cfg *ddr3_cfg) @@ -662,6 +952,8 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, { if (sysinfo->ddr_type == DDR_TYPE_DDR3) { mx6_ddr3_cfg(sysinfo, calib, ddr_cfg); + } else if (sysinfo->ddr_type == DDR_TYPE_LPDDR2) { + mx6_lpddr2_cfg(sysinfo, calib, ddr_cfg); } else { puts("Unsupported ddr type\n"); hang(); diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 36fcb2b..68d9bda 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -377,6 +377,21 @@ struct mx6_ddr3_cfg { u8 SRT; /* self-refresh temperature: 0=normal, 1=extended */ };
+/* Device Information: Varies per LPDDR2 part number and speed grade */ +struct mx6_lpddr2_cfg { + u16 mem_speed; /* ie 800 for LPDDR2-800 */ + u8 density; /* chip density (Gb) (1,2,4,8) */ + u8 width; /* bus width (bits) (4,8,16) */ + u8 banks; /* number of banks */ + u8 rowaddr; /* row address bits (11-16)*/ + u8 coladdr; /* col address bits (9-12) */ + u16 trcd_lp; + u16 trppb_lp; + u16 trpab_lp; + u16 trcmin; /* tRC min (ns*100) */ + u16 trasmin; /* tRAS min (ns*100) */ +}; + /* System Information: Varies per board design, layout, and term choices */ struct mx6_ddr_sysinfo { u8 dsize; /* size of bus (in dwords: 0=16bit,1=32bit,2=64bit) */

Add SPL boot support for mx6slevk board. 1. Introduce a configuration file mx6slevk_spl_defconfig. 2. i.MX6SL has same DRAM space with i.MX6SX, need to change SPL DRAM SPACE. 3. Include imx6_spl.h and related SPL macro in mx6slevk.h. 4. select SUPPORT_SPL for TARGET_MX6SLEVK. 5. Add SPL board code to do related initialization.
Boot Log:
U-Boot SPL 2015.07-00544-g1594a76 (Aug 17 2015 - 01:56:59) reading u-boot.img reading u-boot.img
U-Boot 2015.07-00544-g1594a76 (Aug 17 2015 - 01:56:59 +0000)
CPU: Freescale i.MX6SL rev1.2 996 MHz (running at 396 MHz) CPU: Commercial temperature grade (0C to 95C) at 50C Reset cause: POR Board: MX6SLEVK I2C: ready DRAM: 1 GiB PMIC: PFUZE100 ID=0x10 MMC: FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: FEC [PRIME] Hit any key to stop autoboot: 0
Signed-off-by: Peng Fan Peng.Fan@freescale.com Cc: Stefano Babic sbabic@denx.de Cc: Fabio Estevam fabio.estevam@freescale.com --- arch/arm/cpu/armv7/mx6/Kconfig | 1 + board/freescale/mx6slevk/mx6slevk.c | 164 ++++++++++++++++++++++++++++++++++++ configs/mx6slevk_spl_defconfig | 8 ++ include/configs/imx6_spl.h | 2 +- include/configs/mx6slevk.h | 7 ++ 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 configs/mx6slevk_spl_defconfig
diff --git a/arch/arm/cpu/armv7/mx6/Kconfig b/arch/arm/cpu/armv7/mx6/Kconfig index c43cea8..6c63277 100644 --- a/arch/arm/cpu/armv7/mx6/Kconfig +++ b/arch/arm/cpu/armv7/mx6/Kconfig @@ -91,6 +91,7 @@ config TARGET_MX6SABRESD config TARGET_MX6SLEVK bool "mx6slevk" select CPU_V7 + select SUPPORT_SPL
config TARGET_MX6SXSABRESD bool "mx6sxsabresd" diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index 7c18c90..721cd16 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -8,7 +8,9 @@
#include <asm/arch/clock.h> #include <asm/arch/iomux.h> +#include <asm/arch/crm_regs.h> #include <asm/arch/imx-regs.h> +#include <asm/arch/mx6-ddr.h> #include <asm/arch/mx6-pins.h> #include <asm/arch/sys_proto.h> #include <asm/gpio.h> @@ -190,6 +192,7 @@ int board_mmc_getcd(struct mmc *mmc)
int board_mmc_init(bd_t *bis) { +#ifndef CONFIG_SPL_BUILD int i, ret;
/* @@ -234,6 +237,44 @@ int board_mmc_init(bd_t *bis) }
return 0; +#else + struct src *src_regs = (struct src *)SRC_BASE_ADDR; + u32 val; + u32 port; + + val = readl(&src_regs->sbmr1); + + /* Boot from USDHC */ + port = (val >> 11) & 0x3; + switch (port) { + case 0: + imx_iomux_v3_setup_multiple_pads(usdhc1_pads, + ARRAY_SIZE(usdhc1_pads)); + gpio_direction_input(USDHC1_CD_GPIO); + usdhc_cfg[0].esdhc_base = USDHC1_BASE_ADDR; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); + break; + case 1: + imx_iomux_v3_setup_multiple_pads(usdhc2_pads, + ARRAY_SIZE(usdhc2_pads)); + gpio_direction_input(USDHC2_CD_GPIO); + usdhc_cfg[0].esdhc_base = USDHC2_BASE_ADDR; + usdhc_cfg[0].max_bus_width = 4; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); + break; + case 2: + imx_iomux_v3_setup_multiple_pads(usdhc3_pads, + ARRAY_SIZE(usdhc3_pads)); + gpio_direction_input(USDHC3_CD_GPIO); + usdhc_cfg[0].esdhc_base = USDHC3_BASE_ADDR; + usdhc_cfg[0].max_bus_width = 4; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + break; + } + + gd->arch.sdhc_clk = usdhc_cfg[0].sdhc_clk; + return fsl_esdhc_initialize(bis, &usdhc_cfg[0]); +#endif }
#ifdef CONFIG_SYS_I2C_MXC @@ -361,3 +402,126 @@ int checkboard(void)
return 0; } + +#ifdef CONFIG_SPL_BUILD +#include <spl.h> +#include <libfdt.h> + +const struct mx6sl_iomux_ddr_regs mx6_ddr_ioregs = { + .dram_sdqs0 = 0x00003030, + .dram_sdqs1 = 0x00003030, + .dram_sdqs2 = 0x00003030, + .dram_sdqs3 = 0x00003030, + .dram_dqm0 = 0x00000030, + .dram_dqm1 = 0x00000030, + .dram_dqm2 = 0x00000030, + .dram_dqm3 = 0x00000030, + .dram_cas = 0x00000030, + .dram_ras = 0x00000030, + .dram_sdclk_0 = 0x00000028, + .dram_reset = 0x00000030, + .dram_sdba2 = 0x00000000, + .dram_odt0 = 0x00000008, + .dram_odt1 = 0x00000008, +}; + +const struct mx6sl_iomux_grp_regs mx6_grp_ioregs = { + .grp_b0ds = 0x00000030, + .grp_b1ds = 0x00000030, + .grp_b2ds = 0x00000030, + .grp_b3ds = 0x00000030, + .grp_addds = 0x00000030, + .grp_ctlds = 0x00000030, + .grp_ddrmode_ctl = 0x00020000, + .grp_ddrpke = 0x00000000, + .grp_ddrmode = 0x00020000, + .grp_ddr_type = 0x00080000, +}; + +const struct mx6_mmdc_calibration mx6_mmcd_calib = { + .p0_mpdgctrl0 = 0x20000000, + .p0_mpdgctrl1 = 0x00000000, + .p0_mprddlctl = 0x4241444a, + .p0_mpwrdlctl = 0x3030312b, + .mpzqlp2ctl = 0x1b4700c7, +}; + +static struct mx6_lpddr2_cfg mem_ddr = { + .mem_speed = 800, + .density = 4, + .width = 32, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .trcd_lp = 2000, + .trppb_lp = 2000, + .trpab_lp = 2250, + .trasmin = 4200, +}; + +static void ccgr_init(void) +{ + struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + writel(0xFFFFFFFF, &ccm->CCGR0); + writel(0xFFFFFFFF, &ccm->CCGR1); + writel(0xFFFFFFFF, &ccm->CCGR2); + writel(0xFFFFFFFF, &ccm->CCGR3); + writel(0xFFFFFFFF, &ccm->CCGR4); + writel(0xFFFFFFFF, &ccm->CCGR5); + writel(0xFFFFFFFF, &ccm->CCGR6); + + writel(0x00260324, &ccm->cbcmr); +} + +static void spl_dram_init(void) +{ + struct mx6_ddr_sysinfo sysinfo = { + .dsize = mem_ddr.width / 32, + .cs_density = 20, + .ncs = 2, + .cs1_mirror = 0, + .walat = 0, + .ralat = 2, + .mif3_mode = 3, + .bi_on = 1, + .rtt_wr = 0, /* LPDDR2 does not need rtt_wr rtt_nom */ + .rtt_nom = 0, + .sde_to_rst = 0, /* LPDDR2 does not need this field */ + .rst_to_cke = 0x10, /* JEDEC value for LPDDR2: 200us */ + .ddr_type = DDR_TYPE_LPDDR2, + }; + mx6sl_dram_iocfg(32, &mx6_ddr_ioregs, &mx6_grp_ioregs); + mx6_dram_cfg(&sysinfo, &mx6_mmcd_calib, &mem_ddr); +} + +void board_init_f(ulong dummy) +{ + /* setup AIPS and disable watchdog */ + arch_cpu_init(); + + ccgr_init(); + + /* iomux and setup of i2c */ + board_early_init_f(); + + /* setup GP timer */ + timer_init(); + + /* UART clocks enabled and gd valid - init serial console */ + preloader_console_init(); + + /* DDR initialization */ + spl_dram_init(); + + /* Clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + /* load/boot image from boot device */ + board_init_r(NULL, 0); +} + +void reset_cpu(ulong addr) +{ +} +#endif diff --git a/configs/mx6slevk_spl_defconfig b/configs/mx6slevk_spl_defconfig new file mode 100644 index 0000000..1fbd0d1 --- /dev/null +++ b/configs/mx6slevk_spl_defconfig @@ -0,0 +1,8 @@ +CONFIG_ARM=y +CONFIG_ARCH_MX6=y +CONFIG_TARGET_MX6SLEVK=y +CONFIG_SPL=y +CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/imx-common/spl_sd.cfg,SPL,MX6SL" +CONFIG_DM=y +CONFIG_SPI_FLASH=y +CONFIG_DM_THERMAL=y diff --git a/include/configs/imx6_spl.h b/include/configs/imx6_spl.h index 0a585b7..1744f2c 100644 --- a/include/configs/imx6_spl.h +++ b/include/configs/imx6_spl.h @@ -61,7 +61,7 @@ #define CONFIG_SPL_LIBDISK_SUPPORT #endif
-#if defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) +#if defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) || defined(CONFIG_MX6SL) #define CONFIG_SPL_BSS_START_ADDR 0x88200000 #define CONFIG_SPL_BSS_MAX_SIZE 0x100000 /* 1 MB */ #define CONFIG_SYS_SPL_MALLOC_START 0x88300000 diff --git a/include/configs/mx6slevk.h b/include/configs/mx6slevk.h index 3cecd94..04d53a7 100644 --- a/include/configs/mx6slevk.h +++ b/include/configs/mx6slevk.h @@ -11,6 +11,13 @@
#include "mx6_common.h"
+#ifdef CONFIG_SPL +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SPL_FAT_SUPPORT +#include "imx6_spl.h" +#endif + #define MACH_TYPE_MX6SLEVK 4307 #define CONFIG_MACH_TYPE MACH_TYPE_MX6SLEVK

On 17/08/2015 10:10, Peng Fan wrote:
This patch set is to support SPL for mx6slevk board. But mx6slevk features one LPDDR2 chip. Then we need to first add LPDDR2 SPL support. Also introduce one ddr_type entry to differentiate DDR3 and LPDDR2. This patch set also correct tRFC and tXS for DDR3 4Gb chip.
The LPDDR2 part is implemented referencing MX6SL LPDDR2 Script Aid V0.04.xlsx and JESD209-2E. I am not DDR expert, can not guarantee that this can achieve production quality. Please review.
Patchset tested boot on mx6sxsabresd revb and mx6slevk board.
Peng Fan (9): imx: mx6: ddr add more register entry for mmdc_p_regs imx: mx6: ddr no support MMDC1 for i.MX6SL imx: mx6: ddr correct tRFC and tXS imx: mx6: ddr add dram io configuration and header file for i.MX6SL imx: mx6: ddr add mpzqlp2ctl entry imx: mx6: ddr add an entry ddr_type for mx6_ddr_sysinfo imx: mx6: ddr init MMDC according to ddr_type imx: mx6: ddr: add LPDDR2 support imx: mx6slevk: add SPL support
arch/arm/cpu/armv7/mx6/Kconfig | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 379 +++++++++++++++++++++- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 140 +++++++- arch/arm/include/asm/arch-mx6/mx6sl-ddr.h | 45 +++ board/barco/platinum/spl_picon.c | 1 + board/barco/platinum/spl_titanium.c | 1 + board/freescale/mx6sabresd/mx6sabresd.c | 1 + board/freescale/mx6slevk/mx6slevk.c | 164 ++++++++++ board/freescale/mx6sxsabresd/mx6sxsabresd.c | 1 + board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c | 1 + board/gateworks/gw_ventana/gw_ventana_spl.c | 1 + board/solidrun/mx6cuboxi/mx6cuboxi.c | 1 + configs/mx6slevk_spl_defconfig | 8 + include/configs/imx6_spl.h | 2 +- include/configs/mx6slevk.h | 7 + 15 files changed, 733 insertions(+), 20 deletions(-) create mode 100644 arch/arm/include/asm/arch-mx6/mx6sl-ddr.h create mode 100644 configs/mx6slevk_spl_defconfig
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic
participants (2)
-
Peng Fan
-
Stefano Babic