diff mbox

[U-Boot,2/5] vf610: refactor DDRMC code

Message ID 1434716311-26189-3-git-send-email-albert.aribaud@3adev.fr
State Changes Requested
Delegated to: Stefano Babic
Headers show

Commit Message

Albert ARIBAUD (3ADEV) June 19, 2015, 12:18 p.m. UTC
The VF610 DDRMC driver code contains settings which are
board-specific. Move these out to boards so that new boards
can define their own without having to modify the driver.

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/imx-common/ddrmc-vf610.c             | 239 ++++++--------------------
 arch/arm/include/asm/arch-vf610/ddrmc-vf610.h |  60 +------
 board/freescale/vf610twr/vf610twr.c           | 181 +++++++++++++------
 board/toradex/colibri_vf/colibri_vf.c         | 169 +++++++++++++-----
 4 files changed, 312 insertions(+), 337 deletions(-)

Comments

Stefan Agner June 19, 2015, 3:13 p.m. UTC | #1
Hi Albert,

On 19.06.2015 14:18, Albert ARIBAUD (3ADEV) wrote:
> The VF610 DDRMC driver code contains settings which are
> board-specific. Move these out to boards so that new boards
> can define their own without having to modify the driver.
>
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
>
>  arch/arm/imx-common/ddrmc-vf610.c             | 239 ++++++--------------------
>  arch/arm/include/asm/arch-vf610/ddrmc-vf610.h |  60 +------
>  board/freescale/vf610twr/vf610twr.c           | 181 +++++++++++++------
>  board/toradex/colibri_vf/colibri_vf.c         | 169 +++++++++++++-----
>  4 files changed, 312 insertions(+), 337 deletions(-)


So this goes basically back to setting all DDR registers directly from
boards? What we tried to do here is to factor out the memory chip
specific data (JEDEC). The idea behind this is it would make it simpler
to add new RAM timings if a new RAM vendor is used on a different board
revision...  With your changes it will be unnecessarily hard to add just
a new RAM timing for a new board revision...

--
Stefan


>
> diff --git a/arch/arm/imx-common/ddrmc-vf610.c b/arch/arm/imx-common/ddrmc-vf610.c
> index e462631..44b9a0f 100644
> --- a/arch/arm/imx-common/ddrmc-vf610.c
> +++ b/arch/arm/imx-common/ddrmc-vf610.c
> @@ -12,9 +12,9 @@
>  #include <asm/arch/iomux-vf610.h>
>  #include <asm/arch/ddrmc-vf610.h>
>  
> -void ddrmc_setup_iomux(void)
> +void ddrmc_setup_iomux(const iomux_v3_cfg_t *pads, int pads_count)
>  {
> -	static const iomux_v3_cfg_t ddr_pads[] = {
> +	static const iomux_v3_cfg_t default_pads[] = {
>  		VF610_PAD_DDR_A15__DDR_A_15,
>  		VF610_PAD_DDR_A14__DDR_A_14,
>  		VF610_PAD_DDR_A13__DDR_A_13,
> @@ -65,212 +65,77 @@ void ddrmc_setup_iomux(void)
>  		VF610_PAD_DDR_RESETB,
>  	};
>  
> -	imx_iomux_v3_setup_multiple_pads(ddr_pads, ARRAY_SIZE(ddr_pads));
> -}
> +	if ((pads == NULL) || (pads_count == 0)) {
> +		pads = default_pads;
> +		pads_count = ARRAY_SIZE(default_pads);
> +	}
>  
> -void ddrmc_phy_init(void)
> -{
> -	struct ddrmr_regs *ddrmr = (struct ddrmr_regs *)DDR_BASE_ADDR;
> +	imx_iomux_v3_setup_multiple_pads(pads, pads_count);
> +}
>  
> -	writel(DDRMC_PHY_DQ_TIMING, &ddrmr->phy[0]);
> -	writel(DDRMC_PHY_DQ_TIMING, &ddrmr->phy[16]);
> -	writel(DDRMC_PHY_DQ_TIMING, &ddrmr->phy[32]);
> +static struct ddrmc_reg_setting default_phy_settings[] = {
> +	{ DDRMC_PHY_DQ_TIMING,  0 },
> +	{ DDRMC_PHY_DQ_TIMING, 16 },
> +	{ DDRMC_PHY_DQ_TIMING, 32 },
>  
> -	writel(DDRMC_PHY_DQS_TIMING, &ddrmr->phy[1]);
> -	writel(DDRMC_PHY_DQS_TIMING, &ddrmr->phy[17]);
> +	{ DDRMC_PHY_DQS_TIMING,  1 },
> +	{ DDRMC_PHY_DQS_TIMING, 17 },
>  
> -	writel(DDRMC_PHY_CTRL, &ddrmr->phy[2]);
> -	writel(DDRMC_PHY_CTRL, &ddrmr->phy[18]);
> -	writel(DDRMC_PHY_CTRL, &ddrmr->phy[34]);
> +	{ DDRMC_PHY_CTRL,  2 },
> +	{ DDRMC_PHY_CTRL, 18 },
> +	{ DDRMC_PHY_CTRL, 34 },
>  
> -	writel(DDRMC_PHY_MASTER_CTRL, &ddrmr->phy[3]);
> -	writel(DDRMC_PHY_MASTER_CTRL, &ddrmr->phy[19]);
> -	writel(DDRMC_PHY_MASTER_CTRL, &ddrmr->phy[35]);
> +	{ DDRMC_PHY_MASTER_CTRL,  3 },
> +	{ DDRMC_PHY_MASTER_CTRL, 19 },
> +	{ DDRMC_PHY_MASTER_CTRL, 35 },
>  
> -	writel(DDRMC_PHY_SLAVE_CTRL, &ddrmr->phy[4]);
> -	writel(DDRMC_PHY_SLAVE_CTRL, &ddrmr->phy[20]);
> -	writel(DDRMC_PHY_SLAVE_CTRL, &ddrmr->phy[36]);
> +	{ DDRMC_PHY_SLAVE_CTRL,  4 },
> +	{ DDRMC_PHY_SLAVE_CTRL, 20 },
> +	{ DDRMC_PHY_SLAVE_CTRL, 36 },
>  
>  	/* LPDDR2 only parameter */
> -	writel(DDRMC_PHY_OFF, &ddrmr->phy[49]);
> +	{ DDRMC_PHY_OFF, 49 },
>  
> -	writel(DDRMC_PHY50_DDR3_MODE |
> -		   DDRMC_PHY50_EN_SW_HALF_CYCLE, &ddrmr->phy[50]);
> +	{ DDRMC_PHY50_DDR3_MODE | DDRMC_PHY50_EN_SW_HALF_CYCLE, 50 },
>  
>  	/* Processor Pad ODT settings */
> -	writel(DDRMC_PHY_PROC_PAD_ODT, &ddrmr->phy[52]);
> -}
> +	{ DDRMC_PHY_PROC_PAD_ODT, 52 },
>  
> -static void ddrmc_ctrl_lvl_init(struct ddrmc_lvl_info *lvl)
> -{
> -	struct ddrmr_regs *ddrmr = (struct ddrmr_regs *)DDR_BASE_ADDR;
> -	u32 cr102 = 0, cr105 = 0, cr106 = 0, cr110 = 0;
> +	/* end marker */
> +	{ 0, -1 }
> +};
>  
> -	if (lvl->wrlvl_reg_en) {
> -		writel(DDRMC_CR97_WRLVL_EN, &ddrmr->cr[97]);
> -		writel(DDRMC_CR98_WRLVL_DL_0(lvl->wrlvl_dl_0), &ddrmr->cr[98]);
> -		writel(DDRMC_CR99_WRLVL_DL_1(lvl->wrlvl_dl_1), &ddrmr->cr[99]);
> -	}
> -
> -	if (lvl->rdlvl_reg_en) {
> -		cr102 |= DDRMC_CR102_RDLVL_REG_EN;
> -		cr105 |= DDRMC_CR105_RDLVL_DL_0(lvl->rdlvl_dl_0);
> -		cr110 |= DDRMC_CR110_RDLVL_DL_1(lvl->rdlvl_dl_1);
> -	}
> -
> -	if (lvl->rdlvl_gt_reg_en) {
> -		cr102 |= DDRMC_CR102_RDLVL_GT_REGEN;
> -		cr106 |= DDRMC_CR106_RDLVL_GTDL_0(lvl->rdlvl_gt_dl_0);
> -		cr110 |= DDRMC_CR110_RDLVL_GTDL_1(lvl->rdlvl_gt_dl_1);
> -	}
> -
> -	writel(cr102, &ddrmr->cr[102]);
> -	writel(cr105, &ddrmr->cr[105]);
> -	writel(cr106, &ddrmr->cr[106]);
> -	writel(cr110, &ddrmr->cr[110]);
> -}
> -
> -void ddrmc_ctrl_init_ddr3(struct ddr3_jedec_timings const *timings,
> -						  struct ddrmc_lvl_info *lvl,
> -						  int col_diff, int row_diff)
> +void ddrmc_ctrl_init_ddr3(struct ddrmc_reg_setting const *cr_settings,
> +	struct ddrmc_reg_setting const *phy_settings)
>  {
>  	struct ddrmr_regs *ddrmr = (struct ddrmr_regs *)DDR_BASE_ADDR;
> +	struct ddrmc_reg_setting const *cr_setting = cr_settings;
> +	struct ddrmc_reg_setting const *phy_setting = phy_settings;
>  
> +	/* configure controller for DDR3 and start init sequence */
>  	writel(DDRMC_CR00_DRAM_CLASS_DDR3, &ddrmr->cr[0]);
> -	writel(DDRMC_CR02_DRAM_TINIT(timings->tinit), &ddrmr->cr[2]);
> -	writel(DDRMC_CR10_TRST_PWRON(timings->trst_pwron), &ddrmr->cr[10]);
> -
> -	writel(DDRMC_CR11_CKE_INACTIVE(timings->cke_inactive), &ddrmr->cr[11]);
> -	writel(DDRMC_CR12_WRLAT(timings->wrlat) |
> -		   DDRMC_CR12_CASLAT_LIN(timings->caslat_lin), &ddrmr->cr[12]);
> -	writel(DDRMC_CR13_TRC(timings->trc) | DDRMC_CR13_TRRD(timings->trrd) |
> -		   DDRMC_CR13_TCCD(timings->tccd), &ddrmr->cr[13]);
> -	writel(DDRMC_CR14_TFAW(timings->tfaw) | DDRMC_CR14_TRP(timings->trp) |
> -		   DDRMC_CR14_TWTR(timings->twtr) |
> -		   DDRMC_CR14_TRAS_MIN(timings->tras_min), &ddrmr->cr[14]);
> -	writel(DDRMC_CR16_TMRD(timings->tmrd) |
> -		   DDRMC_CR16_TRTP(timings->trtp), &ddrmr->cr[16]);
> -	writel(DDRMC_CR17_TRAS_MAX(timings->tras_max) |
> -		   DDRMC_CR17_TMOD(timings->tmod), &ddrmr->cr[17]);
> -	writel(DDRMC_CR18_TCKESR(timings->tckesr) |
> -		   DDRMC_CR18_TCKE(timings->tcke), &ddrmr->cr[18]);
>  
> -	writel(DDRMC_CR20_AP_EN, &ddrmr->cr[20]);
> -	writel(DDRMC_CR21_TRCD_INT(timings->trcd_int) |
> -		   DDRMC_CR21_CCMAP_EN, &ddrmr->cr[21]);
> -
> -	writel(DDRMC_CR22_TDAL(timings->tdal), &ddrmr->cr[22]);
> -	writel(DDRMC_CR23_BSTLEN(3) |
> -		   DDRMC_CR23_TDLL(timings->tdll), &ddrmr->cr[23]);
> -	writel(DDRMC_CR24_TRP_AB(timings->trp_ab), &ddrmr->cr[24]);
> -
> -	writel(DDRMC_CR25_TREF_EN, &ddrmr->cr[25]);
> -	writel(DDRMC_CR26_TREF(timings->tref) |
> -		   DDRMC_CR26_TRFC(timings->trfc), &ddrmr->cr[26]);
> -	writel(DDRMC_CR28_TREF_INT(0), &ddrmr->cr[28]);
> -	writel(DDRMC_CR29_TPDEX(timings->tpdex), &ddrmr->cr[29]);
> -
> -	writel(DDRMC_CR30_TXPDLL(timings->txpdll), &ddrmr->cr[30]);
> -	writel(DDRMC_CR31_TXSNR(timings->txsnr) |
> -		   DDRMC_CR31_TXSR(timings->txsr), &ddrmr->cr[31]);
> -	writel(DDRMC_CR33_EN_QK_SREF, &ddrmr->cr[33]);
> -	writel(DDRMC_CR34_CKSRX(timings->cksrx) |
> -		   DDRMC_CR34_CKSRE(timings->cksre), &ddrmr->cr[34]);
> -
> -	writel(DDRMC_CR38_FREQ_CHG_EN(0), &ddrmr->cr[38]);
> -	writel(DDRMC_CR39_PHY_INI_COM(1024) | DDRMC_CR39_PHY_INI_STA(16) |
> -		   DDRMC_CR39_FRQ_CH_DLLOFF(2), &ddrmr->cr[39]);
> -
> -	writel(DDRMC_CR41_PHY_INI_STRT_INI_DIS, &ddrmr->cr[41]);
> -	writel(DDRMC_CR48_MR1_DA_0(70) |
> -		   DDRMC_CR48_MR0_DA_0(1056), &ddrmr->cr[48]);
> -
> -	writel(DDRMC_CR66_ZQCL(timings->zqcl) |
> -		   DDRMC_CR66_ZQINIT(timings->zqinit), &ddrmr->cr[66]);
> -	writel(DDRMC_CR67_ZQCS(timings->zqcs), &ddrmr->cr[67]);
> -	writel(DDRMC_CR69_ZQ_ON_SREF_EX(2), &ddrmr->cr[69]);
> -
> -	writel(DDRMC_CR70_REF_PER_ZQ(timings->ref_per_zq), &ddrmr->cr[70]);
> -	writel(DDRMC_CR72_ZQCS_ROTATE(0), &ddrmr->cr[72]);
> -
> -	writel(DDRMC_CR73_APREBIT(timings->aprebit) |
> -		   DDRMC_CR73_COL_DIFF(col_diff) |
> -		   DDRMC_CR73_ROW_DIFF(row_diff), &ddrmr->cr[73]);
> -	writel(DDRMC_CR74_BANKSPLT_EN | DDRMC_CR74_ADDR_CMP_EN |
> -		   DDRMC_CR74_CMD_AGE_CNT(64) | DDRMC_CR74_AGE_CNT(64),
> -		   &ddrmr->cr[74]);
> -	writel(DDRMC_CR75_RW_PG_EN | DDRMC_CR75_RW_EN | DDRMC_CR75_PRI_EN |
> -		   DDRMC_CR75_PLEN, &ddrmr->cr[75]);
> -	writel(DDRMC_CR76_NQENT_ACTDIS(3) | DDRMC_CR76_D_RW_G_BKCN(3) |
> -		   DDRMC_CR76_W2R_SPLT_EN, &ddrmr->cr[76]);
> -	writel(DDRMC_CR77_CS_MAP | DDRMC_CR77_DI_RD_INTLEAVE |
> -		   DDRMC_CR77_SWAP_EN, &ddrmr->cr[77]);
> -	writel(DDRMC_CR78_Q_FULLNESS(7) |
> -		   DDRMC_CR78_BUR_ON_FLY_BIT(12), &ddrmr->cr[78]);
> -	writel(DDRMC_CR79_CTLUPD_AREF(0), &ddrmr->cr[79]);
> +	/* execute CR sequence (MUST be supplied) */
> +	if (cr_setting)
> +		while (cr_setting->reg_num >= 0) {
> +			writel(cr_setting->setting,
> +			       &ddrmr->cr[cr_setting->reg_num]);
> +			cr_setting++;
> +		}
> +
> +	/* execute PHY sequence (SHOULD be supplied but can be default) */
> +	if (phy_setting == NULL)
> +		phy_setting = default_phy_settings;
> +
> +	while (phy_setting->reg_num >= 0) {
> +		writel(phy_setting->setting,
> +		       &ddrmr->phy[phy_setting->reg_num]);
> +		phy_setting++;
> +	}
>  
> +	/* final config: disable DDR interrupts and finish init squence */
>  	writel(DDRMC_CR82_INT_MASK, &ddrmr->cr[82]);
>  
> -	writel(DDRMC_CR87_ODT_WR_MAPCS0, &ddrmr->cr[87]);
> -	writel(DDRMC_CR88_TODTL_CMD(4), &ddrmr->cr[88]);
> -	writel(DDRMC_CR89_AODT_RWSMCS(2), &ddrmr->cr[89]);
> -
> -	writel(DDRMC_CR91_R2W_SMCSDL(2), &ddrmr->cr[91]);
> -	writel(DDRMC_CR96_WLMRD(timings->wlmrd) |
> -		   DDRMC_CR96_WLDQSEN(timings->wldqsen), &ddrmr->cr[96]);
> -
> -	if (lvl != NULL)
> -		ddrmc_ctrl_lvl_init(lvl);
> -
> -	writel(DDRMC_CR117_AXI0_W_PRI(0) |
> -		   DDRMC_CR117_AXI0_R_PRI(0), &ddrmr->cr[117]);
> -	writel(DDRMC_CR118_AXI1_W_PRI(1) |
> -		   DDRMC_CR118_AXI1_R_PRI(1), &ddrmr->cr[118]);
> -
> -	writel(DDRMC_CR120_AXI0_PRI1_RPRI(2) |
> -		   DDRMC_CR120_AXI0_PRI0_RPRI(2), &ddrmr->cr[120]);
> -	writel(DDRMC_CR121_AXI0_PRI3_RPRI(2) |
> -		   DDRMC_CR121_AXI0_PRI2_RPRI(2), &ddrmr->cr[121]);
> -	writel(DDRMC_CR122_AXI1_PRI1_RPRI(1) | DDRMC_CR122_AXI1_PRI0_RPRI(1) |
> -		   DDRMC_CR122_AXI0_PRIRLX(100), &ddrmr->cr[122]);
> -	writel(DDRMC_CR123_AXI1_P_ODR_EN | DDRMC_CR123_AXI1_PRI3_RPRI(1) |
> -		   DDRMC_CR123_AXI1_PRI2_RPRI(1), &ddrmr->cr[123]);
> -	writel(DDRMC_CR124_AXI1_PRIRLX(100), &ddrmr->cr[124]);
> -
> -	writel(DDRMC_CR126_PHY_RDLAT(8), &ddrmr->cr[126]);
> -	writel(DDRMC_CR132_WRLAT_ADJ(5) |
> -		   DDRMC_CR132_RDLAT_ADJ(6), &ddrmr->cr[132]);
> -	writel(DDRMC_CR137_PHYCTL_DL(2), &ddrmr->cr[137]);
> -	writel(DDRMC_CR138_PHY_WRLV_MXDL(256) |
> -		   DDRMC_CR138_PHYDRAM_CK_EN(1), &ddrmr->cr[138]);
> -	writel(DDRMC_CR139_PHY_WRLV_RESPLAT(4) | DDRMC_CR139_PHY_WRLV_LOAD(7) |
> -		   DDRMC_CR139_PHY_WRLV_DLL(3) |
> -		   DDRMC_CR139_PHY_WRLV_EN(3), &ddrmr->cr[139]);
> -	writel(DDRMC_CR140_PHY_WRLV_WW(64), &ddrmr->cr[140]);
> -	writel(DDRMC_CR143_RDLV_GAT_MXDL(1536) |
> -		   DDRMC_CR143_RDLV_MXDL(128), &ddrmr->cr[143]);
> -	writel(DDRMC_CR144_PHY_RDLVL_RES(4) | DDRMC_CR144_PHY_RDLV_LOAD(7) |
> -		   DDRMC_CR144_PHY_RDLV_DLL(3) |
> -		   DDRMC_CR144_PHY_RDLV_EN(3), &ddrmr->cr[144]);
> -	writel(DDRMC_CR145_PHY_RDLV_RR(64), &ddrmr->cr[145]);
> -	writel(DDRMC_CR146_PHY_RDLVL_RESP(64), &ddrmr->cr[146]);
> -	writel(DDRMC_CR147_RDLV_RESP_MASK(983040), &ddrmr->cr[147]);
> -	writel(DDRMC_CR148_RDLV_GATE_RESP_MASK(983040), &ddrmr->cr[148]);
> -	writel(DDRMC_CR151_RDLV_GAT_DQ_ZERO_CNT(1) |
> -		   DDRMC_CR151_RDLVL_DQ_ZERO_CNT(1), &ddrmr->cr[151]);
> -
> -	writel(DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
> -		   DDRMC_CR154_PAD_ZQ_MODE(1) |
> -		   DDRMC_CR154_DDR_SEL_PAD_CONTR(3) |
> -		   DDRMC_CR154_PAD_ZQ_HW_FOR(1), &ddrmr->cr[154]);
> -	writel(DDRMC_CR155_PAD_ODT_BYTE1(2) |
> -		   DDRMC_CR155_PAD_ODT_BYTE0(2), &ddrmr->cr[155]);
> -	writel(DDRMC_CR158_TWR(6), &ddrmr->cr[158]);
> -	writel(DDRMC_CR161_ODT_EN(1) | DDRMC_CR161_TODTH_RD(2) |
> -		   DDRMC_CR161_TODTH_WR(2), &ddrmr->cr[161]);
> -
> -	ddrmc_phy_init();
> -
>  	writel(DDRMC_CR00_DRAM_CLASS_DDR3 | DDRMC_CR00_START, &ddrmr->cr[0]);
>  
>  	while (!(readl(&ddrmr->cr[80]) && 0x100))
> diff --git a/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h b/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h
> index 6730cde..bc7f106 100644
> --- a/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h
> +++ b/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h
> @@ -11,62 +11,14 @@
>  #ifndef __ASM_ARCH_VF610_DDRMC_H
>  #define __ASM_ARCH_VF610_DDRMC_H
>  
> -struct ddrmc_lvl_info {
> -	u16 wrlvl_reg_en;
> -	u16 wrlvl_dl_0;
> -	u16 wrlvl_dl_1;
> -	u16 rdlvl_gt_reg_en;
> -	u16 rdlvl_gt_dl_0;
> -	u16 rdlvl_gt_dl_1;
> -	u16 rdlvl_reg_en;
> -	u16 rdlvl_dl_0;
> -	u16 rdlvl_dl_1;
> +struct ddrmc_reg_setting {
> +	u32	setting;
> +	int	reg_num; /* CR or PHY ; -1 for last entry */
>  };
>  
> -struct ddr3_jedec_timings {
> -	u8 tinit;
> -	u32 trst_pwron;
> -	u32 cke_inactive;
> -	u8 wrlat;
> -	u8 caslat_lin;
> -	u8 trc;
> -	u8 trrd;
> -	u8 tccd;
> -	u8 tfaw;
> -	u8 trp;
> -	u8 twtr;
> -	u8 tras_min;
> -	u8 tmrd;
> -	u8 trtp;
> -	u32 tras_max;
> -	u8 tmod;
> -	u8 tckesr;
> -	u8 tcke;
> -	u8 trcd_int;
> -	u8 tdal;
> -	u16 tdll;
> -	u8 trp_ab;
> -	u16 tref;
> -	u8 trfc;
> -	u8 tpdex;
> -	u8 txpdll;
> -	u8 txsnr;
> -	u16 txsr;
> -	u8 cksrx;
> -	u8 cksre;
> -	u16 zqcl;
> -	u16 zqinit;
> -	u8 zqcs;
> -	u8 ref_per_zq;
> -	u8 aprebit;
> -	u8 wlmrd;
> -	u8 wldqsen;
> -};
> -
> -void ddrmc_setup_iomux(void);
> +void ddrmc_setup_iomux(const iomux_v3_cfg_t *pads, int pads_count);
>  void ddrmc_phy_init(void);
> -void ddrmc_ctrl_init_ddr3(struct ddr3_jedec_timings const *timings,
> -						  struct ddrmc_lvl_info *lvl,
> -						  int col_diff, int row_diff);
> +void ddrmc_ctrl_init_ddr3(struct ddrmc_reg_setting const *cr_settings,
> +	struct ddrmc_reg_setting const *phy_settings);
>  
>  #endif
> diff --git a/board/freescale/vf610twr/vf610twr.c b/board/freescale/vf610twr/vf610twr.c
> index 4160acd..aab20ad 100644
> --- a/board/freescale/vf610twr/vf610twr.c
> +++ b/board/freescale/vf610twr/vf610twr.c
> @@ -28,63 +28,136 @@ DECLARE_GLOBAL_DATA_PTR;
>  #define ENET_PAD_CTRL	(PAD_CTL_PUS_47K_UP | PAD_CTL_SPEED_HIGH | \
>  			PAD_CTL_DSE_50ohm | PAD_CTL_OBE_IBE_ENABLE)
>  
> +static struct ddrmc_reg_setting vf610twr_cr_settings[] = {
> +	{ DDRMC_CR02_DRAM_TINIT(5), 2 },
> +	{ DDRMC_CR10_TRST_PWRON(80000), 10 },
> +	{ DDRMC_CR11_CKE_INACTIVE(200000), 11 },
> +	{ DDRMC_CR12_WRLAT(5) | DDRMC_CR12_CASLAT_LIN(12), 12 },
> +	{ DDRMC_CR13_TRC(21) | DDRMC_CR13_TRRD(4) | DDRMC_CR13_TCCD(4) |
> +		   DDRMC_CR13_TBST_INT_INTERVAL(0), 13 },
> +	{ DDRMC_CR14_TFAW(20) | DDRMC_CR14_TRP(6) | DDRMC_CR14_TWTR(5) |
> +		   DDRMC_CR14_TRAS_MIN(15), 14 },
> +	{ DDRMC_CR16_TMRD(4) | DDRMC_CR16_TRTP(4), 16 },
> +	{ DDRMC_CR17_TRAS_MAX(28080) | DDRMC_CR17_TMOD(12), 17 },
> +	{ DDRMC_CR18_TCKESR(4) | DDRMC_CR18_TCKE(3), 18 },
> +
> +	{ DDRMC_CR20_AP_EN, 20 },
> +	{ DDRMC_CR21_TRCD_INT(6) | DDRMC_CR21_CCMAP_EN, 21 },
> +
> +	{ DDRMC_CR22_TDAL(12), 22 },
> +	{ DDRMC_CR23_BSTLEN(3) |
> +		   DDRMC_CR23_TDLL(512), 23 },
> +	{ DDRMC_CR24_TRP_AB(6), 24 },
> +
> +	{ DDRMC_CR25_TREF_EN, 25 },
> +	{ DDRMC_CR26_TREF(3120) | DDRMC_CR26_TRFC(44), 26 },
> +	{ DDRMC_CR28_TREF_INT(0), 28 },
> +	{ DDRMC_CR29_TPDEX(3), 29 },
> +
> +	{ DDRMC_CR30_TXPDLL(10), 30 },
> +	{ DDRMC_CR31_TXSNR(48) | DDRMC_CR31_TXSR(468), 31 },
> +	{ DDRMC_CR33_EN_QK_SREF, 33 },
> +	{ DDRMC_CR34_CKSRX(5) | DDRMC_CR34_CKSRE(5), 34 },
> +
> +	{ DDRMC_CR38_FREQ_CHG_EN(0), 38 },
> +	{ DDRMC_CR39_PHY_INI_COM(1024) | DDRMC_CR39_PHY_INI_STA(16) |
> +		   DDRMC_CR39_FRQ_CH_DLLOFF(2), 39 },
> +
> +	{ DDRMC_CR41_PHY_INI_STRT_INI_DIS, 41 },
> +	{ DDRMC_CR48_MR1_DA_0(70) |
> +		   DDRMC_CR48_MR0_DA_0(1056), 48 },
> +
> +	{ DDRMC_CR66_ZQCL(256) | DDRMC_CR66_ZQINIT(512), 66 },
> +	{ DDRMC_CR67_ZQCS(64), 67 },
> +	{ DDRMC_CR69_ZQ_ON_SREF_EX(2), 69 },
> +
> +	{ DDRMC_CR70_REF_PER_ZQ(64), 70 },
> +	{ DDRMC_CR72_ZQCS_ROTATE(0), 72 },
> +
> +	{ DDRMC_CR73_APREBIT(10) | DDRMC_CR73_COL_DIFF(1) |
> +		   DDRMC_CR73_ROW_DIFF(3), 73 },
> +	{ DDRMC_CR74_BANKSPLT_EN | DDRMC_CR74_ADDR_CMP_EN |
> +		   DDRMC_CR74_CMD_AGE_CNT(64) |
> +		   DDRMC_CR74_AGE_CNT(64), 74 },
> +	{ DDRMC_CR75_RW_PG_EN | DDRMC_CR75_RW_EN | DDRMC_CR75_PRI_EN |
> +		   DDRMC_CR75_PLEN, 75 },
> +	{ DDRMC_CR76_NQENT_ACTDIS(3) | DDRMC_CR76_D_RW_G_BKCN(3) |
> +		   DDRMC_CR76_W2R_SPLT_EN, 76 },
> +	{ DDRMC_CR77_CS_MAP | DDRMC_CR77_DI_RD_INTLEAVE |
> +		   DDRMC_CR77_SWAP_EN, 77 },
> +	{ DDRMC_CR78_Q_FULLNESS(7) | DDRMC_CR78_BUR_ON_FLY_BIT(12), 78 },
> +	{ DDRMC_CR79_CTLUPD_AREF(0), 79 },
> +
> +	{ DDRMC_CR87_ODT_WR_MAPCS0, 87 },
> +	{ DDRMC_CR88_TODTL_CMD(4), 88 },
> +	{ DDRMC_CR89_AODT_RWSMCS(2), 89 },
> +
> +	{ DDRMC_CR91_R2W_SMCSDL(2), 91 },
> +	{ DDRMC_CR96_WLMRD(40) | DDRMC_CR96_WLDQSEN(25), 96 },
> +
> +	/* levelling */
> +	{ DDRMC_CR97_WRLVL_EN, 97 },
> +	{ DDRMC_CR98_WRLVL_DL_0(0), 98 },
> +	{ DDRMC_CR99_WRLVL_DL_1(0), 99 },
> +	{ DDRMC_CR102_RDLVL_REG_EN | DDRMC_CR102_RDLVL_GT_REGEN, 102 },
> +	{ DDRMC_CR105_RDLVL_DL_0(0), 105 },
> +	{ DDRMC_CR106_RDLVL_GTDL_0(4), 106 },
> +	{ DDRMC_CR110_RDLVL_DL_1(0) | DDRMC_CR110_RDLVL_GTDL_1(4), 110 },
> +
> +	/* AXI */
> +	{ DDRMC_CR117_AXI0_W_PRI(0) | DDRMC_CR117_AXI0_R_PRI(0), 117 },
> +	{ DDRMC_CR118_AXI1_W_PRI(1) | DDRMC_CR118_AXI1_R_PRI(1), 118 },
> +	{ DDRMC_CR120_AXI0_PRI1_RPRI(2) |
> +		   DDRMC_CR120_AXI0_PRI0_RPRI(2), 120 },
> +	{ DDRMC_CR121_AXI0_PRI3_RPRI(2) |
> +		   DDRMC_CR121_AXI0_PRI2_RPRI(2), 121 },
> +	{ DDRMC_CR122_AXI1_PRI1_RPRI(1) | DDRMC_CR122_AXI1_PRI0_RPRI(1) |
> +		   DDRMC_CR122_AXI0_PRIRLX(100), 122 },
> +	{ DDRMC_CR123_AXI1_P_ODR_EN | DDRMC_CR123_AXI1_PRI3_RPRI(1) |
> +		   DDRMC_CR123_AXI1_PRI2_RPRI(1), 123 },
> +	{ DDRMC_CR124_AXI1_PRIRLX(100), 124 },
> +	{ DDRMC_CR126_PHY_RDLAT(8), 126 },
> +	{ DDRMC_CR132_WRLAT_ADJ(5) |
> +		   DDRMC_CR132_RDLAT_ADJ(6), 132 },
> +	{ DDRMC_CR137_PHYCTL_DL(2), 137 },
> +	{ DDRMC_CR138_PHY_WRLV_MXDL(256) |
> +		   DDRMC_CR138_PHYDRAM_CK_EN(1), 138 },
> +	{ DDRMC_CR139_PHY_WRLV_RESPLAT(4) | DDRMC_CR139_PHY_WRLV_LOAD(7) |
> +		   DDRMC_CR139_PHY_WRLV_DLL(3) |
> +		   DDRMC_CR139_PHY_WRLV_EN(3), 139 },
> +	{ DDRMC_CR140_PHY_WRLV_WW(64), 140 },
> +	{ DDRMC_CR143_RDLV_GAT_MXDL(1536) |
> +		   DDRMC_CR143_RDLV_MXDL(128), 143 },
> +	{ DDRMC_CR144_PHY_RDLVL_RES(4) | DDRMC_CR144_PHY_RDLV_LOAD(7) |
> +		   DDRMC_CR144_PHY_RDLV_DLL(3) |
> +		   DDRMC_CR144_PHY_RDLV_EN(3), 144 },
> +	{ DDRMC_CR145_PHY_RDLV_RR(64), 145 },
> +	{ DDRMC_CR146_PHY_RDLVL_RESP(64), 146 },
> +	{ DDRMC_CR147_RDLV_RESP_MASK(983040), 147 },
> +	{ DDRMC_CR148_RDLV_GATE_RESP_MASK(983040), 148 },
> +	{ DDRMC_CR151_RDLV_GAT_DQ_ZERO_CNT(1) |
> +		   DDRMC_CR151_RDLVL_DQ_ZERO_CNT(1), 151 },
> +
> +	{ DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
> +		   DDRMC_CR154_PAD_ZQ_MODE(1) |
> +		   DDRMC_CR154_DDR_SEL_PAD_CONTR(3) |
> +		   DDRMC_CR154_PAD_ZQ_HW_FOR(1), 154 },
> +	{ DDRMC_CR155_PAD_ODT_BYTE1(1) | DDRMC_CR155_PAD_ODT_BYTE0(1), 155 },
> +	{ DDRMC_CR158_TWR(6), 158 },
> +	{ DDRMC_CR161_ODT_EN(1) | DDRMC_CR161_TODTH_RD(2) |
> +		   DDRMC_CR161_TODTH_WR(2), 161 },
> +
> +	/* end marker */
> +	{ 0, -1 }
> +}
> +
>  int dram_init(void)
>  {
> -	struct ddrmc_lvl_info lvl = {
> -		.wrlvl_reg_en = 1,
> -		.wrlvl_dl_0 = 0,
> -		.wrlvl_dl_1 = 0,
> -		.rdlvl_gt_reg_en = 1,
> -		.rdlvl_gt_dl_0 = 4,
> -		.rdlvl_gt_dl_1 = 4,
> -		.rdlvl_reg_en = 1,
> -		.rdlvl_dl_0 = 0,
> -		.rdlvl_dl_1 = 0,
> -	};
> -
> -	static const struct ddr3_jedec_timings timings = {
> -		.tinit           = 5,
> -		.trst_pwron      = 80000,
> -		.cke_inactive    = 200000,
> -		.wrlat           = 5,
> -		.caslat_lin      = 12,
> -		.trc             = 21,
> -		.trrd            = 4,
> -		.tccd            = 4,
> -		.tfaw            = 20,
> -		.trp             = 6,
> -		.twtr            = 4,
> -		.tras_min        = 15,
> -		.tmrd            = 4,
> -		.trtp            = 4,
> -		.tras_max        = 28080,
> -		.tmod            = 12,
> -		.tckesr          = 4,
> -		.tcke            = 3,
> -		.trcd_int        = 6,
> -		.tdal            = 12,
> -		.tdll            = 512,
> -		.trp_ab          = 6,
> -		.tref            = 3120,
> -		.trfc            = 44,
> -		.tpdex           = 3,
> -		.txpdll          = 10,
> -		.txsnr           = 48,
> -		.txsr            = 468,
> -		.cksrx           = 5,
> -		.cksre           = 5,
> -		.zqcl            = 256,
> -		.zqinit          = 512,
> -		.zqcs            = 64,
> -		.ref_per_zq      = 64,
> -		.aprebit         = 10,
> -		.wlmrd           = 40,
> -		.wldqsen         = 25,
> -	};
> -
> -	ddrmc_setup_iomux();
> +	/* use driver default IOMUX settings */
> +	ddrmc_setup_iomux(NULL, 0);
>  
> -	ddrmc_ctrl_init_ddr3(&timings, &lvl, 1, 3);
> +	/* provide own CR setup but use default PHY setup */
> +	ddrmc_ctrl_init_ddr3(vf610twr_cr_settings, NULL);
>  	gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
>  
>  	return 0;
> diff --git a/board/toradex/colibri_vf/colibri_vf.c b/board/toradex/colibri_vf/colibri_vf.c
> index 8618fd0..01b3106 100644
> --- a/board/toradex/colibri_vf/colibri_vf.c
> +++ b/board/toradex/colibri_vf/colibri_vf.c
> @@ -39,51 +39,136 @@ static const iomux_v3_cfg_t usb_pads[] = {
>  	VF610_PAD_PTD4__GPIO_83,
>  };
>  
> +static struct ddrmc_reg_setting colibri_vf_cr_settings[] = {
> +	{ DDRMC_CR02_DRAM_TINIT(5), 2 },
> +	{ DDRMC_CR10_TRST_PWRON(80000), 10 },
> +	{ DDRMC_CR11_CKE_INACTIVE(200000), 11 },
> +	{ DDRMC_CR12_WRLAT(5) | DDRMC_CR12_CASLAT_LIN(12), 12 },
> +	{ DDRMC_CR13_TRC(21) | DDRMC_CR13_TRRD(4) | DDRMC_CR13_TCCD(4) |
> +		   DDRMC_CR13_TBST_INT_INTERVAL(0), 13 },
> +	{ DDRMC_CR14_TFAW(20) | DDRMC_CR14_TRP(6) | DDRMC_CR14_TWTR(5) |
> +		   DDRMC_CR14_TRAS_MIN(15), 14 },
> +	{ DDRMC_CR16_TMRD(4) | DDRMC_CR16_TRTP(4), 16 },
> +	{ DDRMC_CR17_TRAS_MAX(28080) | DDRMC_CR17_TMOD(12), 17 },
> +	{ DDRMC_CR18_TCKESR(4) | DDRMC_CR18_TCKE(3), 18 },
> +
> +	{ DDRMC_CR20_AP_EN, 20 },
> +	{ DDRMC_CR21_TRCD_INT(6) | DDRMC_CR21_CCMAP_EN, 21 },
> +
> +	{ DDRMC_CR22_TDAL(12), 22 },
> +	{ DDRMC_CR23_BSTLEN(3) |
> +		   DDRMC_CR23_TDLL(512), 23 },
> +	{ DDRMC_CR24_TRP_AB(6), 24 },
> +
> +	{ DDRMC_CR25_TREF_EN, 25 },
> +	{ DDRMC_CR26_TREF(3120) | DDRMC_CR26_TRFC(44), 26 },
> +	{ DDRMC_CR28_TREF_INT(0), 28 },
> +	{ DDRMC_CR29_TPDEX(3), 29 },
> +
> +	{ DDRMC_CR30_TXPDLL(10), 30 },
> +	{ DDRMC_CR31_TXSNR(48) | DDRMC_CR31_TXSR(468), 31 },
> +	{ DDRMC_CR33_EN_QK_SREF, 33 },
> +	{ DDRMC_CR34_CKSRX(5) | DDRMC_CR34_CKSRE(5), 34 },
> +
> +	{ DDRMC_CR38_FREQ_CHG_EN(0), 38 },
> +	{ DDRMC_CR39_PHY_INI_COM(1024) | DDRMC_CR39_PHY_INI_STA(16) |
> +		   DDRMC_CR39_FRQ_CH_DLLOFF(2), 39 },
> +
> +	{ DDRMC_CR41_PHY_INI_STRT_INI_DIS, 41 },
> +	{ DDRMC_CR48_MR1_DA_0(70) |
> +		   DDRMC_CR48_MR0_DA_0(1056), 48 },
> +
> +	{ DDRMC_CR66_ZQCL(256) | DDRMC_CR66_ZQINIT(512), 66 },
> +	{ DDRMC_CR67_ZQCS(64), 67 },
> +	{ DDRMC_CR69_ZQ_ON_SREF_EX(2), 69 },
> +
> +	{ DDRMC_CR70_REF_PER_ZQ(64), 70 },
> +	{ DDRMC_CR72_ZQCS_ROTATE(0), 72 },
> +
> +	{ DDRMC_CR73_APREBIT(10) | DDRMC_CR73_COL_DIFF(1) |
> +		   DDRMC_CR73_ROW_DIFF(3), 73 },
> +	{ DDRMC_CR74_BANKSPLT_EN | DDRMC_CR74_ADDR_CMP_EN |
> +		   DDRMC_CR74_CMD_AGE_CNT(64) |
> +		   DDRMC_CR74_AGE_CNT(64), 74 },
> +	{ DDRMC_CR75_RW_PG_EN | DDRMC_CR75_RW_EN | DDRMC_CR75_PRI_EN |
> +		   DDRMC_CR75_PLEN, 75 },
> +	{ DDRMC_CR76_NQENT_ACTDIS(3) | DDRMC_CR76_D_RW_G_BKCN(3) |
> +		   DDRMC_CR76_W2R_SPLT_EN, 76 },
> +	{ DDRMC_CR77_CS_MAP | DDRMC_CR77_DI_RD_INTLEAVE |
> +		   DDRMC_CR77_SWAP_EN, 77 },
> +	{ DDRMC_CR78_Q_FULLNESS(7) | DDRMC_CR78_BUR_ON_FLY_BIT(12), 78 },
> +	{ DDRMC_CR79_CTLUPD_AREF(0), 79 },
> +
> +	{ DDRMC_CR87_ODT_WR_MAPCS0, 87 },
> +	{ DDRMC_CR88_TODTL_CMD(4), 88 },
> +	{ DDRMC_CR89_AODT_RWSMCS(2), 89 },
> +
> +	{ DDRMC_CR91_R2W_SMCSDL(2), 91 },
> +	{ DDRMC_CR96_WLMRD(40) | DDRMC_CR96_WLDQSEN(25), 96 },
> +
> +	/* levelling */
> +	{ DDRMC_CR97_WRLVL_EN, 97 },
> +	{ DDRMC_CR98_WRLVL_DL_0(0), 98 },
> +	{ DDRMC_CR99_WRLVL_DL_1(0), 99 },
> +	{ DDRMC_CR102_RDLVL_REG_EN | DDRMC_CR102_RDLVL_GT_REGEN, 102 },
> +	{ DDRMC_CR105_RDLVL_DL_0(0), 105 },
> +	{ DDRMC_CR106_RDLVL_GTDL_0(4), 106 },
> +	{ DDRMC_CR110_RDLVL_DL_1(0) | DDRMC_CR110_RDLVL_GTDL_1(4), 110 },
> +
> +	/* AXI */
> +	{ DDRMC_CR117_AXI0_W_PRI(0) | DDRMC_CR117_AXI0_R_PRI(0), 117 },
> +	{ DDRMC_CR118_AXI1_W_PRI(1) | DDRMC_CR118_AXI1_R_PRI(1), 118 },
> +	{ DDRMC_CR120_AXI0_PRI1_RPRI(2) |
> +		   DDRMC_CR120_AXI0_PRI0_RPRI(2), 120 },
> +	{ DDRMC_CR121_AXI0_PRI3_RPRI(2) |
> +		   DDRMC_CR121_AXI0_PRI2_RPRI(2), 121 },
> +	{ DDRMC_CR122_AXI1_PRI1_RPRI(1) | DDRMC_CR122_AXI1_PRI0_RPRI(1) |
> +		   DDRMC_CR122_AXI0_PRIRLX(100), 122 },
> +	{ DDRMC_CR123_AXI1_P_ODR_EN | DDRMC_CR123_AXI1_PRI3_RPRI(1) |
> +		   DDRMC_CR123_AXI1_PRI2_RPRI(1), 123 },
> +	{ DDRMC_CR124_AXI1_PRIRLX(100), 124 },
> +	{ DDRMC_CR126_PHY_RDLAT(8), 126 },
> +	{ DDRMC_CR132_WRLAT_ADJ(5) |
> +		   DDRMC_CR132_RDLAT_ADJ(6), 132 },
> +	{ DDRMC_CR137_PHYCTL_DL(2), 137 },
> +	{ DDRMC_CR138_PHY_WRLV_MXDL(256) |
> +		   DDRMC_CR138_PHYDRAM_CK_EN(1), 138 },
> +	{ DDRMC_CR139_PHY_WRLV_RESPLAT(4) | DDRMC_CR139_PHY_WRLV_LOAD(7) |
> +		   DDRMC_CR139_PHY_WRLV_DLL(3) |
> +		   DDRMC_CR139_PHY_WRLV_EN(3), 139 },
> +	{ DDRMC_CR140_PHY_WRLV_WW(64), 140 },
> +	{ DDRMC_CR143_RDLV_GAT_MXDL(1536) |
> +		   DDRMC_CR143_RDLV_MXDL(128), 143 },
> +	{ DDRMC_CR144_PHY_RDLVL_RES(4) | DDRMC_CR144_PHY_RDLV_LOAD(7) |
> +		   DDRMC_CR144_PHY_RDLV_DLL(3) |
> +		   DDRMC_CR144_PHY_RDLV_EN(3), 144 },
> +	{ DDRMC_CR145_PHY_RDLV_RR(64), 145 },
> +	{ DDRMC_CR146_PHY_RDLVL_RESP(64), 146 },
> +	{ DDRMC_CR147_RDLV_RESP_MASK(983040), 147 },
> +	{ DDRMC_CR148_RDLV_GATE_RESP_MASK(983040), 148 },
> +	{ DDRMC_CR151_RDLV_GAT_DQ_ZERO_CNT(1) |
> +		   DDRMC_CR151_RDLVL_DQ_ZERO_CNT(1), 151 },
> +
> +	{ DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
> +		   DDRMC_CR154_PAD_ZQ_MODE(1) |
> +		   DDRMC_CR154_DDR_SEL_PAD_CONTR(3) |
> +		   DDRMC_CR154_PAD_ZQ_HW_FOR(1), 154 },
> +	{ DDRMC_CR155_PAD_ODT_BYTE1(1) | DDRMC_CR155_PAD_ODT_BYTE0(1), 155 },
> +	{ DDRMC_CR158_TWR(6), 158 },
> +	{ DDRMC_CR161_ODT_EN(1) | DDRMC_CR161_TODTH_RD(2) |
> +		   DDRMC_CR161_TODTH_WR(2), 161 },
> +
> +	/* end marker */
> +	{ 0, -1 }
> +}
> +
>  int dram_init(void)
>  {
> -	static const struct ddr3_jedec_timings timings = {
> -		.tinit           = 5,
> -		.trst_pwron      = 80000,
> -		.cke_inactive    = 200000,
> -		.wrlat           = 5,
> -		.caslat_lin      = 12,
> -		.trc             = 21,
> -		.trrd            = 4,
> -		.tccd            = 4,
> -		.tfaw            = 20,
> -		.trp             = 6,
> -		.twtr            = 4,
> -		.tras_min        = 15,
> -		.tmrd            = 4,
> -		.trtp            = 4,
> -		.tras_max        = 28080,
> -		.tmod            = 12,
> -		.tckesr          = 4,
> -		.tcke            = 3,
> -		.trcd_int        = 6,
> -		.tdal            = 12,
> -		.tdll            = 512,
> -		.trp_ab          = 6,
> -		.tref            = 3120,
> -		.trfc            = 64,
> -		.tpdex           = 3,
> -		.txpdll          = 10,
> -		.txsnr           = 48,
> -		.txsr            = 468,
> -		.cksrx           = 5,
> -		.cksre           = 5,
> -		.zqcl            = 256,
> -		.zqinit          = 512,
> -		.zqcs            = 64,
> -		.ref_per_zq      = 64,
> -		.aprebit         = 10,
> -		.wlmrd           = 40,
> -		.wldqsen         = 25,
> -	};
> -
> -	ddrmc_setup_iomux();
> +	/* use driver default IOMUX settings */
> +	ddrmc_setup_iomux(NULL, 0);
>  
> -	ddrmc_ctrl_init_ddr3(&timings, NULL, 1, 2);
> +	/* provide own CR setup but use default PHY setup */
> +	ddrmc_ctrl_init_ddr3(&colibri_vf_cr_settings, NULL, 1, 2);
>  	gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
>  
>  	return 0;
Albert ARIBAUD (3ADEV) June 19, 2015, 4:50 p.m. UTC | #2
Bonjour Stefan,

Le Fri, 19 Jun 2015 17:13:12 +0200, Stefan Agner
<stefan.agner@toradex.com> a écrit :

> Hi Albert,
> 
> On 19.06.2015 14:18, Albert ARIBAUD (3ADEV) wrote:
> > The VF610 DDRMC driver code contains settings which are
> > board-specific. Move these out to boards so that new boards
> > can define their own without having to modify the driver.
> >
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> >
> >  arch/arm/imx-common/ddrmc-vf610.c             | 239 ++++++--------------------
> >  arch/arm/include/asm/arch-vf610/ddrmc-vf610.h |  60 +------
> >  board/freescale/vf610twr/vf610twr.c           | 181 +++++++++++++------
> >  board/toradex/colibri_vf/colibri_vf.c         | 169 +++++++++++++-----
> >  4 files changed, 312 insertions(+), 337 deletions(-)
> 
> So this goes basically back to setting all DDR registers directly from
> boards? What we tried to do here is to factor out the memory chip
> specific data (JEDEC). The idea behind this is it would make it simpler
> to add new RAM timings if a new RAM vendor is used on a different board
> revision...  With your changes it will be unnecessarily hard to add just
> a new RAM timing for a new board revision...

I could probably factor back out the JEDEC settings, but there are
still differences in the lists of registers to write between the
existing vf610twr/colibri_vf and the new pcm052, especially the PHY
regs but elsewhere too, and there are some writes in the driver that
the PCM052 does not have.

As I wanted to leave the existing boards strictly unaffected, and as I
did not want to start sprinkling '#if defined(some-board)' over the
driver code, I went for a fully board-controlled design so that no
board could possibly be affected by any future change to the driver.

How about a mix? I could keep the JEDEC and lvl pointers in the DDR
controller init call arguments and append "per-boards" CR and PHY
arrays. The driver would do the JEDEC writes (thus keeping JEDEC DDR3
additions simple), the LVL writes if not NULL, then the "per-board" CR
writes if not NULL, then the current common PHY writes, then the
"per-board" PHY writes if not null.

This would keep common parts (JEDEC and minimal settings) in the driver
while allowing board their own specific settings -- even overriding the
driver settings, since the per-board writes would come last before
CR000 is rewritten.

Would that be ok ?

> --
> Stefan

Cordialement,
Albert ARIBAUD
3ADEV
Albert ARIBAUD (3ADEV) June 19, 2015, 5:33 p.m. UTC | #3
Bonjour Stefan,

Le Fri, 19 Jun 2015 17:13:12 +0200, Stefan Agner
<stefan.agner@toradex.com> a écrit :

> Hi Albert,
> 
> On 19.06.2015 14:18, Albert ARIBAUD (3ADEV) wrote:
> > The VF610 DDRMC driver code contains settings which are
> > board-specific. Move these out to boards so that new boards
> > can define their own without having to modify the driver.
> >
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> >
> >  arch/arm/imx-common/ddrmc-vf610.c             | 239 ++++++--------------------
> >  arch/arm/include/asm/arch-vf610/ddrmc-vf610.h |  60 +------
> >  board/freescale/vf610twr/vf610twr.c           | 181 +++++++++++++------
> >  board/toradex/colibri_vf/colibri_vf.c         | 169 +++++++++++++-----
> >  4 files changed, 312 insertions(+), 337 deletions(-)
> 
> So this goes basically back to setting all DDR registers directly from
> boards? What we tried to do here is to factor out the memory chip
> specific data (JEDEC). The idea behind this is it would make it simpler
> to add new RAM timings if a new RAM vendor is used on a different board
> revision...  With your changes it will be unnecessarily hard to add just
> a new RAM timing for a new board revision...

I could probably factor back out the JEDEC settings, but there are
still differences in the lists of registers to write between the
existing vf610twr/colibri_vf and the new pcm052, especially the PHY
regs but elsewhere too, and there are some writes in the driver that
the PCM052 does not have.

As I wanted to leave the existing boards strictly unaffected, and as I
did not want to start sprinkling '#if defined(some-board)' over the
driver code, I went for a fully board-controlled design so that no
board could possibly be affected by any future change to the driver.

How about a mix? I could keep the JEDEC and lvl pointers in the DDR
controller init call arguments and append "per-boards" CR and PHY
arrays. The driver would do the JEDEC writes (thus keeping JEDEC DDR3
additions simple), the LVL writes if not NULL, then the "per-board" CR
writes if not NULL, then the current common PHY writes, then the
"per-board" PHY writes if not null.

This would keep common parts (JEDEC and minimal settings) in the driver
while allowing board their own specific settings -- even overriding the
driver settings, since the per-board writes would come last before
CR000 is rewritten.

Would that be ok ?

> --
> Stefan

Cordialement,
Albert ARIBAUD
3ADEV
Stefano Babic July 10, 2015, 8:09 a.m. UTC | #4
Hi Albert, Stefan,

On 19/06/2015 19:33, Albert ARIBAUD wrote:

> 
> I could probably factor back out the JEDEC settings, but there are
> still differences in the lists of registers to write between the
> existing vf610twr/colibri_vf and the new pcm052, especially the PHY
> regs but elsewhere too, and there are some writes in the driver that
> the PCM052 does not have.
> 
> As I wanted to leave the existing boards strictly unaffected, and as I
> did not want to start sprinkling '#if defined(some-board)' over the
> driver code, I went for a fully board-controlled design so that no
> board could possibly be affected by any future change to the driver.
> 
> How about a mix? I could keep the JEDEC and lvl pointers in the DDR
> controller init call arguments and append "per-boards" CR and PHY
> arrays. The driver would do the JEDEC writes (thus keeping JEDEC DDR3
> additions simple), the LVL writes if not NULL, then the "per-board" CR
> writes if not NULL, then the current common PHY writes, then the
> "per-board" PHY writes if not null.

This matches IMHO what we have already tried to do with most of
Frescale's i.MXes, putting general code and setting in the arch/cpu/ (or
in the imx_common for MX5 and MX6), but letting the board code to write
the board specific part.

Some mix seems to me a goog compromise between flexibility and common code.
> 
> This would keep common parts (JEDEC and minimal settings) in the driver
> while allowing board their own specific settings -- even overriding the
> driver settings, since the per-board writes would come last before
> CR000 is rewritten.
> 
> Would that be ok ?
> 
>> --
Best regards,
Stefano Babic
Stefan Agner July 13, 2015, 7:01 p.m. UTC | #5
Hi Albert, Hi Stefano,

On 10.07.2015 10:09, Stefano Babic wrote:
> Hi Albert, Stefan,
>
> On 19/06/2015 19:33, Albert ARIBAUD wrote:
>
>> I could probably factor back out the JEDEC settings, but there are
>> still differences in the lists of registers to write between the
>> existing vf610twr/colibri_vf and the new pcm052, especially the PHY
>> regs but elsewhere too, and there are some writes in the driver that
>> the PCM052 does not have.
>>
>> As I wanted to leave the existing boards strictly unaffected, and as I
>> did not want to start sprinkling '#if defined(some-board)' over the
>> driver code, I went for a fully board-controlled design so that no
>> board could possibly be affected by any future change to the driver.
>>
>> How about a mix? I could keep the JEDEC and lvl pointers in the DDR
>> controller init call arguments and append "per-boards" CR and PHY
>> arrays. The driver would do the JEDEC writes (thus keeping JEDEC DDR3
>> additions simple), the LVL writes if not NULL, then the "per-board" CR
>> writes if not NULL, then the current common PHY writes, then the
>> "per-board" PHY writes if not null.
> This matches IMHO what we have already tried to do with most of
> Frescale's i.MXes, putting general code and setting in the arch/cpu/ (or
> in the imx_common for MX5 and MX6), but letting the board code to write
> the board specific part.
>
> Some mix seems to me a goog compromise between flexibility and common code.

As far as I understood Alberts proposition it would mean that we write
some registers directly from board code right? I'm not sure if this
works out for all registers, since some might have JEDEC and Board
specific fields in one register...?

Looking throug some CR registers lead me to belive that most settings
are exact the same or already covered by the JEDEC struct... The few
remaning ones could be part of a renamed ddrmc_lvl_info struct (e.g.
ddrmc_cr_info).

The same for the PHY settings (ddrmc_phy_info). This would lead to a
common place where all registers gets written, while having the
flexibility to use board specific data... No back and forth between the
board file and the common code.

I did not an exact survey how much of the registers are actually
different, but I feel that the difference is not that big that moving
the whole initialization to the board files is worth the effort...

--
Stefan


>> This would keep common parts (JEDEC and minimal settings) in the driver
>> while allowing board their own specific settings -- even overriding the
>> driver settings, since the per-board writes would come last before
>> CR000 is rewritten.
>>
>> Would that be ok ?
>>
>>> --
> Best regards,
> Stefano Babic
>
>
Albert ARIBAUD (3ADEV) July 14, 2015, 7:16 a.m. UTC | #6
Hi Stefan,

Le Mon, 13 Jul 2015 21:01:56 +0200, Stefan Agner
<stefan.agner@toradex.com> a écrit :

> Hi Albert, Hi Stefano,
> 
> On 10.07.2015 10:09, Stefano Babic wrote:
> > Hi Albert, Stefan,
> >
> > On 19/06/2015 19:33, Albert ARIBAUD wrote:
> >
> >> I could probably factor back out the JEDEC settings, but there are
> >> still differences in the lists of registers to write between the
> >> existing vf610twr/colibri_vf and the new pcm052, especially the PHY
> >> regs but elsewhere too, and there are some writes in the driver that
> >> the PCM052 does not have.
> >>
> >> As I wanted to leave the existing boards strictly unaffected, and as I
> >> did not want to start sprinkling '#if defined(some-board)' over the
> >> driver code, I went for a fully board-controlled design so that no
> >> board could possibly be affected by any future change to the driver.
> >>
> >> How about a mix? I could keep the JEDEC and lvl pointers in the DDR
> >> controller init call arguments and append "per-boards" CR and PHY
> >> arrays. The driver would do the JEDEC writes (thus keeping JEDEC DDR3
> >> additions simple), the LVL writes if not NULL, then the "per-board" CR
> >> writes if not NULL, then the current common PHY writes, then the
> >> "per-board" PHY writes if not null.
> > This matches IMHO what we have already tried to do with most of
> > Frescale's i.MXes, putting general code and setting in the arch/cpu/ (or
> > in the imx_common for MX5 and MX6), but letting the board code to write
> > the board specific part.
> >
> > Some mix seems to me a goog compromise between flexibility and common code.
> 
> As far as I understood Alberts proposition it would mean that we write
> some registers directly from board code right? I'm not sure if this
> works out for all registers, since some might have JEDEC and Board
> specific fields in one register...?

Well, it would not be /from/ board code as boards would actually pass
descriptions and the writing would occur in the driver within the
general write sequence, but I see your point about some register values
possibly needing to be constructed from both the jedec struct) /and/
some other source -- see below.

Also, we can hardly avoid that each board will require regiser writes
which will be somewhat unique to it. The question is not whether we can
avoid that, it is how we should specify that and where we should put
that.

> Looking throug some CR registers lead me to belive that most settings
> are exact the same or already covered by the JEDEC struct... The few
> remaning ones could be part of a renamed ddrmc_lvl_info struct (e.g.
> ddrmc_cr_info).

I do understand the benefit of passing JEDEC parameters rather that
register values, because this allows "working in the problem domain",
i.e. using JEDEC values straight from datasheets, and having thdriver
to the "heavy lifting", i.e. converting this set of JEDEC values into
a consistent set of interrelated register values.

I might understand it for PHY settings when you might know that
several PHY registers need values consistent with one another (more
below).

Generally, though, I don't think there is added values in turning
register values into a struct rather than an (offset, value) pair list
which is IMO more versatile.

Take the lvl struct for example: it embodies a 'leveling' abstraction
which does not exist in the IP per se, and does not exist outside the
IP as JEDEC parameters do; it' artificial. And while it does provide
some consistency, it does not even hide all hardware implementation
details, so you still need to go see the IP's register definition if
you want to fill that struct (as opposed to only having to read the
DDR3 datasheet to fill the JEDEC structure). And if you need to go read
the register structure, working with (offset, value) pairs makes a
simpler driver.

Last point: the driver is supposed to work with various incarnations of
the IP, not all of which may have the same set of known, and unknown,
registers. I stumbled uplon this problem with the current driver code:
it writes some (non-JEDEC) CR registers which my board does not write
as far as I can tell, and it does not do some writes my board does.

I could have gone through the driver's 'extra' writes and tested
whether they could be done on my board without any ill effect. I could
also hve gone through my board's extra writes and seen whether they
could be removed without any any ill effect. In fact, I *had* to do
some of each, because some of the driver's writes (in the lvl struct
notably, but elsewhere too) caused issues.

The problem was, I could not test what effect my changes would have on
the other boards that use the driver -- it's not even a question of
time: I just don't have these other boards which happen to use the
driver that I'm modifying (and I expect that's a pretty common case).

Or I could make my changes so that existing boards using the driver
kept writing the registers as they do in the current code and that my
board write the registers as it needs to, and keep only the common part
in the driver.

This way, I could ensure that existing code would retain the exact
behavior it currently expects from the IP it runs on while in the same
time getting the exact behavior I expected on my board.

> The same for the PHY settings (ddrmc_phy_info). This would lead to a
> common place where all registers gets written, while having the
> flexibility to use board specific data... No back and forth between the
> board file and the common code.

Here too, there is a problem: current code does not write all the
registers my code wants written. If I added writes to the driver
unconditionally, I would risk breaking existing boards by adding writes
to them that they never intended to do. If I added it conditionally, I
would add artificial complexity to the driver, basically injecting
board-specifics in it. That's why I initially went the "driver provides
the tools, board provides the values" route.

Now I do understand that one might want to avoid duplication, which is
why I would agree with keeping the existing sequence in the driver and
only defining board-specific sequences in the board code. 

> I did not an exact survey how much of the registers are actually
> different, but I feel that the difference is not that big that moving
> the whole initialization to the board files is worth the effort...

OTOH, if the difference is not that big, then keeping it in the board
is not that painful either. :)

Seriously, though: There's zero reason we should have board dependency
compiled into drivers, since we can always write the driver API so that
board-specifics are passed by argument to driver functions, and having
a board-agnostic driver is a Good Thing (tm).

Now, what part is board-specific and how it is passed, that's quite an
open point.

I personally think that the way we should abstract things, and whether
we should abstract them at all, depends on the benefit from an overall
SW architecture standpoint.

For instance, I have come to think the JEDEC abstraction is good,
because it can be be reused by other (future /or/ existing) drivers, and
ecause the JEDEC definition for a given DDR3 chip can be hared across
all boards that use it (and then, all can benefit from 'bugfixes', if
any, in the chip's JEDEC definition).

The only thing I'm not 100% sure is, as you mention it, whether the
IP's JEDEC-related are *purely* JEDEC or whether they also depend in
part on the board's HW design (track lengths, buffers, whatever). But
even if they do, then we can always pass the existing, pure, JEDEC
info in the JEDEC struct, /plus/ HW related info in another argument,
and have the driver do the mix. The separation would allow us to keep 
sharing the pure JEDEC info in all boards that use the same DDR3 chip.

OTOH, structs like the lvl struct, with the driver interpreting them
into register writes, seems not to benefit the SW architecture: you
can't generalize that to other drivers. You can't share lvl struct
values across boards. The lvl struct's only benefit is to ensure
that a small group of writes will be consistent, something that the
developer will quite probably have checked from the spec anyway; it is
prone to introducing restrictions that will inevitably be hit one day,
and then we will have to maintain the struct *and* the writing code,
and run a risk of affecting existing boards each time we do it.

The (offset, value) sequence is indeed very low-level and does indeed
make the board hardware-dependent, but the board already *is*, anyway --
anyone looking at the board's DDR3 init certainly should have read the
DDR3 controller (and chip) HW specs -- and the maintenance cost in the
is low: the driver won't need any once it knows how to run the sequence
properly, existing boards which use it will only need maintenance in
case of bugs, and new boards will only need to get their new sequence
right without fear of affecting existing code.

> --
> Stefan
> 
> 
> >> This would keep common parts (JEDEC and minimal settings) in the driver
> >> while allowing board their own specific settings -- even overriding the
> >> driver settings, since the per-board writes would come last before
> >> CR000 is rewritten.
> >>
> >> Would that be ok ?
> >>
> >>> --
> > Best regards,
> > Stefano Babic
> >
> >
> 



Cordialement,
Albert ARIBAUD
3ADEV
diff mbox

Patch

diff --git a/arch/arm/imx-common/ddrmc-vf610.c b/arch/arm/imx-common/ddrmc-vf610.c
index e462631..44b9a0f 100644
--- a/arch/arm/imx-common/ddrmc-vf610.c
+++ b/arch/arm/imx-common/ddrmc-vf610.c
@@ -12,9 +12,9 @@ 
 #include <asm/arch/iomux-vf610.h>
 #include <asm/arch/ddrmc-vf610.h>
 
-void ddrmc_setup_iomux(void)
+void ddrmc_setup_iomux(const iomux_v3_cfg_t *pads, int pads_count)
 {
-	static const iomux_v3_cfg_t ddr_pads[] = {
+	static const iomux_v3_cfg_t default_pads[] = {
 		VF610_PAD_DDR_A15__DDR_A_15,
 		VF610_PAD_DDR_A14__DDR_A_14,
 		VF610_PAD_DDR_A13__DDR_A_13,
@@ -65,212 +65,77 @@  void ddrmc_setup_iomux(void)
 		VF610_PAD_DDR_RESETB,
 	};
 
-	imx_iomux_v3_setup_multiple_pads(ddr_pads, ARRAY_SIZE(ddr_pads));
-}
+	if ((pads == NULL) || (pads_count == 0)) {
+		pads = default_pads;
+		pads_count = ARRAY_SIZE(default_pads);
+	}
 
-void ddrmc_phy_init(void)
-{
-	struct ddrmr_regs *ddrmr = (struct ddrmr_regs *)DDR_BASE_ADDR;
+	imx_iomux_v3_setup_multiple_pads(pads, pads_count);
+}
 
-	writel(DDRMC_PHY_DQ_TIMING, &ddrmr->phy[0]);
-	writel(DDRMC_PHY_DQ_TIMING, &ddrmr->phy[16]);
-	writel(DDRMC_PHY_DQ_TIMING, &ddrmr->phy[32]);
+static struct ddrmc_reg_setting default_phy_settings[] = {
+	{ DDRMC_PHY_DQ_TIMING,  0 },
+	{ DDRMC_PHY_DQ_TIMING, 16 },
+	{ DDRMC_PHY_DQ_TIMING, 32 },
 
-	writel(DDRMC_PHY_DQS_TIMING, &ddrmr->phy[1]);
-	writel(DDRMC_PHY_DQS_TIMING, &ddrmr->phy[17]);
+	{ DDRMC_PHY_DQS_TIMING,  1 },
+	{ DDRMC_PHY_DQS_TIMING, 17 },
 
-	writel(DDRMC_PHY_CTRL, &ddrmr->phy[2]);
-	writel(DDRMC_PHY_CTRL, &ddrmr->phy[18]);
-	writel(DDRMC_PHY_CTRL, &ddrmr->phy[34]);
+	{ DDRMC_PHY_CTRL,  2 },
+	{ DDRMC_PHY_CTRL, 18 },
+	{ DDRMC_PHY_CTRL, 34 },
 
-	writel(DDRMC_PHY_MASTER_CTRL, &ddrmr->phy[3]);
-	writel(DDRMC_PHY_MASTER_CTRL, &ddrmr->phy[19]);
-	writel(DDRMC_PHY_MASTER_CTRL, &ddrmr->phy[35]);
+	{ DDRMC_PHY_MASTER_CTRL,  3 },
+	{ DDRMC_PHY_MASTER_CTRL, 19 },
+	{ DDRMC_PHY_MASTER_CTRL, 35 },
 
-	writel(DDRMC_PHY_SLAVE_CTRL, &ddrmr->phy[4]);
-	writel(DDRMC_PHY_SLAVE_CTRL, &ddrmr->phy[20]);
-	writel(DDRMC_PHY_SLAVE_CTRL, &ddrmr->phy[36]);
+	{ DDRMC_PHY_SLAVE_CTRL,  4 },
+	{ DDRMC_PHY_SLAVE_CTRL, 20 },
+	{ DDRMC_PHY_SLAVE_CTRL, 36 },
 
 	/* LPDDR2 only parameter */
-	writel(DDRMC_PHY_OFF, &ddrmr->phy[49]);
+	{ DDRMC_PHY_OFF, 49 },
 
-	writel(DDRMC_PHY50_DDR3_MODE |
-		   DDRMC_PHY50_EN_SW_HALF_CYCLE, &ddrmr->phy[50]);
+	{ DDRMC_PHY50_DDR3_MODE | DDRMC_PHY50_EN_SW_HALF_CYCLE, 50 },
 
 	/* Processor Pad ODT settings */
-	writel(DDRMC_PHY_PROC_PAD_ODT, &ddrmr->phy[52]);
-}
+	{ DDRMC_PHY_PROC_PAD_ODT, 52 },
 
-static void ddrmc_ctrl_lvl_init(struct ddrmc_lvl_info *lvl)
-{
-	struct ddrmr_regs *ddrmr = (struct ddrmr_regs *)DDR_BASE_ADDR;
-	u32 cr102 = 0, cr105 = 0, cr106 = 0, cr110 = 0;
+	/* end marker */
+	{ 0, -1 }
+};
 
-	if (lvl->wrlvl_reg_en) {
-		writel(DDRMC_CR97_WRLVL_EN, &ddrmr->cr[97]);
-		writel(DDRMC_CR98_WRLVL_DL_0(lvl->wrlvl_dl_0), &ddrmr->cr[98]);
-		writel(DDRMC_CR99_WRLVL_DL_1(lvl->wrlvl_dl_1), &ddrmr->cr[99]);
-	}
-
-	if (lvl->rdlvl_reg_en) {
-		cr102 |= DDRMC_CR102_RDLVL_REG_EN;
-		cr105 |= DDRMC_CR105_RDLVL_DL_0(lvl->rdlvl_dl_0);
-		cr110 |= DDRMC_CR110_RDLVL_DL_1(lvl->rdlvl_dl_1);
-	}
-
-	if (lvl->rdlvl_gt_reg_en) {
-		cr102 |= DDRMC_CR102_RDLVL_GT_REGEN;
-		cr106 |= DDRMC_CR106_RDLVL_GTDL_0(lvl->rdlvl_gt_dl_0);
-		cr110 |= DDRMC_CR110_RDLVL_GTDL_1(lvl->rdlvl_gt_dl_1);
-	}
-
-	writel(cr102, &ddrmr->cr[102]);
-	writel(cr105, &ddrmr->cr[105]);
-	writel(cr106, &ddrmr->cr[106]);
-	writel(cr110, &ddrmr->cr[110]);
-}
-
-void ddrmc_ctrl_init_ddr3(struct ddr3_jedec_timings const *timings,
-						  struct ddrmc_lvl_info *lvl,
-						  int col_diff, int row_diff)
+void ddrmc_ctrl_init_ddr3(struct ddrmc_reg_setting const *cr_settings,
+	struct ddrmc_reg_setting const *phy_settings)
 {
 	struct ddrmr_regs *ddrmr = (struct ddrmr_regs *)DDR_BASE_ADDR;
+	struct ddrmc_reg_setting const *cr_setting = cr_settings;
+	struct ddrmc_reg_setting const *phy_setting = phy_settings;
 
+	/* configure controller for DDR3 and start init sequence */
 	writel(DDRMC_CR00_DRAM_CLASS_DDR3, &ddrmr->cr[0]);
-	writel(DDRMC_CR02_DRAM_TINIT(timings->tinit), &ddrmr->cr[2]);
-	writel(DDRMC_CR10_TRST_PWRON(timings->trst_pwron), &ddrmr->cr[10]);
-
-	writel(DDRMC_CR11_CKE_INACTIVE(timings->cke_inactive), &ddrmr->cr[11]);
-	writel(DDRMC_CR12_WRLAT(timings->wrlat) |
-		   DDRMC_CR12_CASLAT_LIN(timings->caslat_lin), &ddrmr->cr[12]);
-	writel(DDRMC_CR13_TRC(timings->trc) | DDRMC_CR13_TRRD(timings->trrd) |
-		   DDRMC_CR13_TCCD(timings->tccd), &ddrmr->cr[13]);
-	writel(DDRMC_CR14_TFAW(timings->tfaw) | DDRMC_CR14_TRP(timings->trp) |
-		   DDRMC_CR14_TWTR(timings->twtr) |
-		   DDRMC_CR14_TRAS_MIN(timings->tras_min), &ddrmr->cr[14]);
-	writel(DDRMC_CR16_TMRD(timings->tmrd) |
-		   DDRMC_CR16_TRTP(timings->trtp), &ddrmr->cr[16]);
-	writel(DDRMC_CR17_TRAS_MAX(timings->tras_max) |
-		   DDRMC_CR17_TMOD(timings->tmod), &ddrmr->cr[17]);
-	writel(DDRMC_CR18_TCKESR(timings->tckesr) |
-		   DDRMC_CR18_TCKE(timings->tcke), &ddrmr->cr[18]);
 
-	writel(DDRMC_CR20_AP_EN, &ddrmr->cr[20]);
-	writel(DDRMC_CR21_TRCD_INT(timings->trcd_int) |
-		   DDRMC_CR21_CCMAP_EN, &ddrmr->cr[21]);
-
-	writel(DDRMC_CR22_TDAL(timings->tdal), &ddrmr->cr[22]);
-	writel(DDRMC_CR23_BSTLEN(3) |
-		   DDRMC_CR23_TDLL(timings->tdll), &ddrmr->cr[23]);
-	writel(DDRMC_CR24_TRP_AB(timings->trp_ab), &ddrmr->cr[24]);
-
-	writel(DDRMC_CR25_TREF_EN, &ddrmr->cr[25]);
-	writel(DDRMC_CR26_TREF(timings->tref) |
-		   DDRMC_CR26_TRFC(timings->trfc), &ddrmr->cr[26]);
-	writel(DDRMC_CR28_TREF_INT(0), &ddrmr->cr[28]);
-	writel(DDRMC_CR29_TPDEX(timings->tpdex), &ddrmr->cr[29]);
-
-	writel(DDRMC_CR30_TXPDLL(timings->txpdll), &ddrmr->cr[30]);
-	writel(DDRMC_CR31_TXSNR(timings->txsnr) |
-		   DDRMC_CR31_TXSR(timings->txsr), &ddrmr->cr[31]);
-	writel(DDRMC_CR33_EN_QK_SREF, &ddrmr->cr[33]);
-	writel(DDRMC_CR34_CKSRX(timings->cksrx) |
-		   DDRMC_CR34_CKSRE(timings->cksre), &ddrmr->cr[34]);
-
-	writel(DDRMC_CR38_FREQ_CHG_EN(0), &ddrmr->cr[38]);
-	writel(DDRMC_CR39_PHY_INI_COM(1024) | DDRMC_CR39_PHY_INI_STA(16) |
-		   DDRMC_CR39_FRQ_CH_DLLOFF(2), &ddrmr->cr[39]);
-
-	writel(DDRMC_CR41_PHY_INI_STRT_INI_DIS, &ddrmr->cr[41]);
-	writel(DDRMC_CR48_MR1_DA_0(70) |
-		   DDRMC_CR48_MR0_DA_0(1056), &ddrmr->cr[48]);
-
-	writel(DDRMC_CR66_ZQCL(timings->zqcl) |
-		   DDRMC_CR66_ZQINIT(timings->zqinit), &ddrmr->cr[66]);
-	writel(DDRMC_CR67_ZQCS(timings->zqcs), &ddrmr->cr[67]);
-	writel(DDRMC_CR69_ZQ_ON_SREF_EX(2), &ddrmr->cr[69]);
-
-	writel(DDRMC_CR70_REF_PER_ZQ(timings->ref_per_zq), &ddrmr->cr[70]);
-	writel(DDRMC_CR72_ZQCS_ROTATE(0), &ddrmr->cr[72]);
-
-	writel(DDRMC_CR73_APREBIT(timings->aprebit) |
-		   DDRMC_CR73_COL_DIFF(col_diff) |
-		   DDRMC_CR73_ROW_DIFF(row_diff), &ddrmr->cr[73]);
-	writel(DDRMC_CR74_BANKSPLT_EN | DDRMC_CR74_ADDR_CMP_EN |
-		   DDRMC_CR74_CMD_AGE_CNT(64) | DDRMC_CR74_AGE_CNT(64),
-		   &ddrmr->cr[74]);
-	writel(DDRMC_CR75_RW_PG_EN | DDRMC_CR75_RW_EN | DDRMC_CR75_PRI_EN |
-		   DDRMC_CR75_PLEN, &ddrmr->cr[75]);
-	writel(DDRMC_CR76_NQENT_ACTDIS(3) | DDRMC_CR76_D_RW_G_BKCN(3) |
-		   DDRMC_CR76_W2R_SPLT_EN, &ddrmr->cr[76]);
-	writel(DDRMC_CR77_CS_MAP | DDRMC_CR77_DI_RD_INTLEAVE |
-		   DDRMC_CR77_SWAP_EN, &ddrmr->cr[77]);
-	writel(DDRMC_CR78_Q_FULLNESS(7) |
-		   DDRMC_CR78_BUR_ON_FLY_BIT(12), &ddrmr->cr[78]);
-	writel(DDRMC_CR79_CTLUPD_AREF(0), &ddrmr->cr[79]);
+	/* execute CR sequence (MUST be supplied) */
+	if (cr_setting)
+		while (cr_setting->reg_num >= 0) {
+			writel(cr_setting->setting,
+			       &ddrmr->cr[cr_setting->reg_num]);
+			cr_setting++;
+		}
+
+	/* execute PHY sequence (SHOULD be supplied but can be default) */
+	if (phy_setting == NULL)
+		phy_setting = default_phy_settings;
+
+	while (phy_setting->reg_num >= 0) {
+		writel(phy_setting->setting,
+		       &ddrmr->phy[phy_setting->reg_num]);
+		phy_setting++;
+	}
 
+	/* final config: disable DDR interrupts and finish init squence */
 	writel(DDRMC_CR82_INT_MASK, &ddrmr->cr[82]);
 
-	writel(DDRMC_CR87_ODT_WR_MAPCS0, &ddrmr->cr[87]);
-	writel(DDRMC_CR88_TODTL_CMD(4), &ddrmr->cr[88]);
-	writel(DDRMC_CR89_AODT_RWSMCS(2), &ddrmr->cr[89]);
-
-	writel(DDRMC_CR91_R2W_SMCSDL(2), &ddrmr->cr[91]);
-	writel(DDRMC_CR96_WLMRD(timings->wlmrd) |
-		   DDRMC_CR96_WLDQSEN(timings->wldqsen), &ddrmr->cr[96]);
-
-	if (lvl != NULL)
-		ddrmc_ctrl_lvl_init(lvl);
-
-	writel(DDRMC_CR117_AXI0_W_PRI(0) |
-		   DDRMC_CR117_AXI0_R_PRI(0), &ddrmr->cr[117]);
-	writel(DDRMC_CR118_AXI1_W_PRI(1) |
-		   DDRMC_CR118_AXI1_R_PRI(1), &ddrmr->cr[118]);
-
-	writel(DDRMC_CR120_AXI0_PRI1_RPRI(2) |
-		   DDRMC_CR120_AXI0_PRI0_RPRI(2), &ddrmr->cr[120]);
-	writel(DDRMC_CR121_AXI0_PRI3_RPRI(2) |
-		   DDRMC_CR121_AXI0_PRI2_RPRI(2), &ddrmr->cr[121]);
-	writel(DDRMC_CR122_AXI1_PRI1_RPRI(1) | DDRMC_CR122_AXI1_PRI0_RPRI(1) |
-		   DDRMC_CR122_AXI0_PRIRLX(100), &ddrmr->cr[122]);
-	writel(DDRMC_CR123_AXI1_P_ODR_EN | DDRMC_CR123_AXI1_PRI3_RPRI(1) |
-		   DDRMC_CR123_AXI1_PRI2_RPRI(1), &ddrmr->cr[123]);
-	writel(DDRMC_CR124_AXI1_PRIRLX(100), &ddrmr->cr[124]);
-
-	writel(DDRMC_CR126_PHY_RDLAT(8), &ddrmr->cr[126]);
-	writel(DDRMC_CR132_WRLAT_ADJ(5) |
-		   DDRMC_CR132_RDLAT_ADJ(6), &ddrmr->cr[132]);
-	writel(DDRMC_CR137_PHYCTL_DL(2), &ddrmr->cr[137]);
-	writel(DDRMC_CR138_PHY_WRLV_MXDL(256) |
-		   DDRMC_CR138_PHYDRAM_CK_EN(1), &ddrmr->cr[138]);
-	writel(DDRMC_CR139_PHY_WRLV_RESPLAT(4) | DDRMC_CR139_PHY_WRLV_LOAD(7) |
-		   DDRMC_CR139_PHY_WRLV_DLL(3) |
-		   DDRMC_CR139_PHY_WRLV_EN(3), &ddrmr->cr[139]);
-	writel(DDRMC_CR140_PHY_WRLV_WW(64), &ddrmr->cr[140]);
-	writel(DDRMC_CR143_RDLV_GAT_MXDL(1536) |
-		   DDRMC_CR143_RDLV_MXDL(128), &ddrmr->cr[143]);
-	writel(DDRMC_CR144_PHY_RDLVL_RES(4) | DDRMC_CR144_PHY_RDLV_LOAD(7) |
-		   DDRMC_CR144_PHY_RDLV_DLL(3) |
-		   DDRMC_CR144_PHY_RDLV_EN(3), &ddrmr->cr[144]);
-	writel(DDRMC_CR145_PHY_RDLV_RR(64), &ddrmr->cr[145]);
-	writel(DDRMC_CR146_PHY_RDLVL_RESP(64), &ddrmr->cr[146]);
-	writel(DDRMC_CR147_RDLV_RESP_MASK(983040), &ddrmr->cr[147]);
-	writel(DDRMC_CR148_RDLV_GATE_RESP_MASK(983040), &ddrmr->cr[148]);
-	writel(DDRMC_CR151_RDLV_GAT_DQ_ZERO_CNT(1) |
-		   DDRMC_CR151_RDLVL_DQ_ZERO_CNT(1), &ddrmr->cr[151]);
-
-	writel(DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
-		   DDRMC_CR154_PAD_ZQ_MODE(1) |
-		   DDRMC_CR154_DDR_SEL_PAD_CONTR(3) |
-		   DDRMC_CR154_PAD_ZQ_HW_FOR(1), &ddrmr->cr[154]);
-	writel(DDRMC_CR155_PAD_ODT_BYTE1(2) |
-		   DDRMC_CR155_PAD_ODT_BYTE0(2), &ddrmr->cr[155]);
-	writel(DDRMC_CR158_TWR(6), &ddrmr->cr[158]);
-	writel(DDRMC_CR161_ODT_EN(1) | DDRMC_CR161_TODTH_RD(2) |
-		   DDRMC_CR161_TODTH_WR(2), &ddrmr->cr[161]);
-
-	ddrmc_phy_init();
-
 	writel(DDRMC_CR00_DRAM_CLASS_DDR3 | DDRMC_CR00_START, &ddrmr->cr[0]);
 
 	while (!(readl(&ddrmr->cr[80]) && 0x100))
diff --git a/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h b/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h
index 6730cde..bc7f106 100644
--- a/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h
+++ b/arch/arm/include/asm/arch-vf610/ddrmc-vf610.h
@@ -11,62 +11,14 @@ 
 #ifndef __ASM_ARCH_VF610_DDRMC_H
 #define __ASM_ARCH_VF610_DDRMC_H
 
-struct ddrmc_lvl_info {
-	u16 wrlvl_reg_en;
-	u16 wrlvl_dl_0;
-	u16 wrlvl_dl_1;
-	u16 rdlvl_gt_reg_en;
-	u16 rdlvl_gt_dl_0;
-	u16 rdlvl_gt_dl_1;
-	u16 rdlvl_reg_en;
-	u16 rdlvl_dl_0;
-	u16 rdlvl_dl_1;
+struct ddrmc_reg_setting {
+	u32	setting;
+	int	reg_num; /* CR or PHY ; -1 for last entry */
 };
 
-struct ddr3_jedec_timings {
-	u8 tinit;
-	u32 trst_pwron;
-	u32 cke_inactive;
-	u8 wrlat;
-	u8 caslat_lin;
-	u8 trc;
-	u8 trrd;
-	u8 tccd;
-	u8 tfaw;
-	u8 trp;
-	u8 twtr;
-	u8 tras_min;
-	u8 tmrd;
-	u8 trtp;
-	u32 tras_max;
-	u8 tmod;
-	u8 tckesr;
-	u8 tcke;
-	u8 trcd_int;
-	u8 tdal;
-	u16 tdll;
-	u8 trp_ab;
-	u16 tref;
-	u8 trfc;
-	u8 tpdex;
-	u8 txpdll;
-	u8 txsnr;
-	u16 txsr;
-	u8 cksrx;
-	u8 cksre;
-	u16 zqcl;
-	u16 zqinit;
-	u8 zqcs;
-	u8 ref_per_zq;
-	u8 aprebit;
-	u8 wlmrd;
-	u8 wldqsen;
-};
-
-void ddrmc_setup_iomux(void);
+void ddrmc_setup_iomux(const iomux_v3_cfg_t *pads, int pads_count);
 void ddrmc_phy_init(void);
-void ddrmc_ctrl_init_ddr3(struct ddr3_jedec_timings const *timings,
-						  struct ddrmc_lvl_info *lvl,
-						  int col_diff, int row_diff);
+void ddrmc_ctrl_init_ddr3(struct ddrmc_reg_setting const *cr_settings,
+	struct ddrmc_reg_setting const *phy_settings);
 
 #endif
diff --git a/board/freescale/vf610twr/vf610twr.c b/board/freescale/vf610twr/vf610twr.c
index 4160acd..aab20ad 100644
--- a/board/freescale/vf610twr/vf610twr.c
+++ b/board/freescale/vf610twr/vf610twr.c
@@ -28,63 +28,136 @@  DECLARE_GLOBAL_DATA_PTR;
 #define ENET_PAD_CTRL	(PAD_CTL_PUS_47K_UP | PAD_CTL_SPEED_HIGH | \
 			PAD_CTL_DSE_50ohm | PAD_CTL_OBE_IBE_ENABLE)
 
+static struct ddrmc_reg_setting vf610twr_cr_settings[] = {
+	{ DDRMC_CR02_DRAM_TINIT(5), 2 },
+	{ DDRMC_CR10_TRST_PWRON(80000), 10 },
+	{ DDRMC_CR11_CKE_INACTIVE(200000), 11 },
+	{ DDRMC_CR12_WRLAT(5) | DDRMC_CR12_CASLAT_LIN(12), 12 },
+	{ DDRMC_CR13_TRC(21) | DDRMC_CR13_TRRD(4) | DDRMC_CR13_TCCD(4) |
+		   DDRMC_CR13_TBST_INT_INTERVAL(0), 13 },
+	{ DDRMC_CR14_TFAW(20) | DDRMC_CR14_TRP(6) | DDRMC_CR14_TWTR(5) |
+		   DDRMC_CR14_TRAS_MIN(15), 14 },
+	{ DDRMC_CR16_TMRD(4) | DDRMC_CR16_TRTP(4), 16 },
+	{ DDRMC_CR17_TRAS_MAX(28080) | DDRMC_CR17_TMOD(12), 17 },
+	{ DDRMC_CR18_TCKESR(4) | DDRMC_CR18_TCKE(3), 18 },
+
+	{ DDRMC_CR20_AP_EN, 20 },
+	{ DDRMC_CR21_TRCD_INT(6) | DDRMC_CR21_CCMAP_EN, 21 },
+
+	{ DDRMC_CR22_TDAL(12), 22 },
+	{ DDRMC_CR23_BSTLEN(3) |
+		   DDRMC_CR23_TDLL(512), 23 },
+	{ DDRMC_CR24_TRP_AB(6), 24 },
+
+	{ DDRMC_CR25_TREF_EN, 25 },
+	{ DDRMC_CR26_TREF(3120) | DDRMC_CR26_TRFC(44), 26 },
+	{ DDRMC_CR28_TREF_INT(0), 28 },
+	{ DDRMC_CR29_TPDEX(3), 29 },
+
+	{ DDRMC_CR30_TXPDLL(10), 30 },
+	{ DDRMC_CR31_TXSNR(48) | DDRMC_CR31_TXSR(468), 31 },
+	{ DDRMC_CR33_EN_QK_SREF, 33 },
+	{ DDRMC_CR34_CKSRX(5) | DDRMC_CR34_CKSRE(5), 34 },
+
+	{ DDRMC_CR38_FREQ_CHG_EN(0), 38 },
+	{ DDRMC_CR39_PHY_INI_COM(1024) | DDRMC_CR39_PHY_INI_STA(16) |
+		   DDRMC_CR39_FRQ_CH_DLLOFF(2), 39 },
+
+	{ DDRMC_CR41_PHY_INI_STRT_INI_DIS, 41 },
+	{ DDRMC_CR48_MR1_DA_0(70) |
+		   DDRMC_CR48_MR0_DA_0(1056), 48 },
+
+	{ DDRMC_CR66_ZQCL(256) | DDRMC_CR66_ZQINIT(512), 66 },
+	{ DDRMC_CR67_ZQCS(64), 67 },
+	{ DDRMC_CR69_ZQ_ON_SREF_EX(2), 69 },
+
+	{ DDRMC_CR70_REF_PER_ZQ(64), 70 },
+	{ DDRMC_CR72_ZQCS_ROTATE(0), 72 },
+
+	{ DDRMC_CR73_APREBIT(10) | DDRMC_CR73_COL_DIFF(1) |
+		   DDRMC_CR73_ROW_DIFF(3), 73 },
+	{ DDRMC_CR74_BANKSPLT_EN | DDRMC_CR74_ADDR_CMP_EN |
+		   DDRMC_CR74_CMD_AGE_CNT(64) |
+		   DDRMC_CR74_AGE_CNT(64), 74 },
+	{ DDRMC_CR75_RW_PG_EN | DDRMC_CR75_RW_EN | DDRMC_CR75_PRI_EN |
+		   DDRMC_CR75_PLEN, 75 },
+	{ DDRMC_CR76_NQENT_ACTDIS(3) | DDRMC_CR76_D_RW_G_BKCN(3) |
+		   DDRMC_CR76_W2R_SPLT_EN, 76 },
+	{ DDRMC_CR77_CS_MAP | DDRMC_CR77_DI_RD_INTLEAVE |
+		   DDRMC_CR77_SWAP_EN, 77 },
+	{ DDRMC_CR78_Q_FULLNESS(7) | DDRMC_CR78_BUR_ON_FLY_BIT(12), 78 },
+	{ DDRMC_CR79_CTLUPD_AREF(0), 79 },
+
+	{ DDRMC_CR87_ODT_WR_MAPCS0, 87 },
+	{ DDRMC_CR88_TODTL_CMD(4), 88 },
+	{ DDRMC_CR89_AODT_RWSMCS(2), 89 },
+
+	{ DDRMC_CR91_R2W_SMCSDL(2), 91 },
+	{ DDRMC_CR96_WLMRD(40) | DDRMC_CR96_WLDQSEN(25), 96 },
+
+	/* levelling */
+	{ DDRMC_CR97_WRLVL_EN, 97 },
+	{ DDRMC_CR98_WRLVL_DL_0(0), 98 },
+	{ DDRMC_CR99_WRLVL_DL_1(0), 99 },
+	{ DDRMC_CR102_RDLVL_REG_EN | DDRMC_CR102_RDLVL_GT_REGEN, 102 },
+	{ DDRMC_CR105_RDLVL_DL_0(0), 105 },
+	{ DDRMC_CR106_RDLVL_GTDL_0(4), 106 },
+	{ DDRMC_CR110_RDLVL_DL_1(0) | DDRMC_CR110_RDLVL_GTDL_1(4), 110 },
+
+	/* AXI */
+	{ DDRMC_CR117_AXI0_W_PRI(0) | DDRMC_CR117_AXI0_R_PRI(0), 117 },
+	{ DDRMC_CR118_AXI1_W_PRI(1) | DDRMC_CR118_AXI1_R_PRI(1), 118 },
+	{ DDRMC_CR120_AXI0_PRI1_RPRI(2) |
+		   DDRMC_CR120_AXI0_PRI0_RPRI(2), 120 },
+	{ DDRMC_CR121_AXI0_PRI3_RPRI(2) |
+		   DDRMC_CR121_AXI0_PRI2_RPRI(2), 121 },
+	{ DDRMC_CR122_AXI1_PRI1_RPRI(1) | DDRMC_CR122_AXI1_PRI0_RPRI(1) |
+		   DDRMC_CR122_AXI0_PRIRLX(100), 122 },
+	{ DDRMC_CR123_AXI1_P_ODR_EN | DDRMC_CR123_AXI1_PRI3_RPRI(1) |
+		   DDRMC_CR123_AXI1_PRI2_RPRI(1), 123 },
+	{ DDRMC_CR124_AXI1_PRIRLX(100), 124 },
+	{ DDRMC_CR126_PHY_RDLAT(8), 126 },
+	{ DDRMC_CR132_WRLAT_ADJ(5) |
+		   DDRMC_CR132_RDLAT_ADJ(6), 132 },
+	{ DDRMC_CR137_PHYCTL_DL(2), 137 },
+	{ DDRMC_CR138_PHY_WRLV_MXDL(256) |
+		   DDRMC_CR138_PHYDRAM_CK_EN(1), 138 },
+	{ DDRMC_CR139_PHY_WRLV_RESPLAT(4) | DDRMC_CR139_PHY_WRLV_LOAD(7) |
+		   DDRMC_CR139_PHY_WRLV_DLL(3) |
+		   DDRMC_CR139_PHY_WRLV_EN(3), 139 },
+	{ DDRMC_CR140_PHY_WRLV_WW(64), 140 },
+	{ DDRMC_CR143_RDLV_GAT_MXDL(1536) |
+		   DDRMC_CR143_RDLV_MXDL(128), 143 },
+	{ DDRMC_CR144_PHY_RDLVL_RES(4) | DDRMC_CR144_PHY_RDLV_LOAD(7) |
+		   DDRMC_CR144_PHY_RDLV_DLL(3) |
+		   DDRMC_CR144_PHY_RDLV_EN(3), 144 },
+	{ DDRMC_CR145_PHY_RDLV_RR(64), 145 },
+	{ DDRMC_CR146_PHY_RDLVL_RESP(64), 146 },
+	{ DDRMC_CR147_RDLV_RESP_MASK(983040), 147 },
+	{ DDRMC_CR148_RDLV_GATE_RESP_MASK(983040), 148 },
+	{ DDRMC_CR151_RDLV_GAT_DQ_ZERO_CNT(1) |
+		   DDRMC_CR151_RDLVL_DQ_ZERO_CNT(1), 151 },
+
+	{ DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
+		   DDRMC_CR154_PAD_ZQ_MODE(1) |
+		   DDRMC_CR154_DDR_SEL_PAD_CONTR(3) |
+		   DDRMC_CR154_PAD_ZQ_HW_FOR(1), 154 },
+	{ DDRMC_CR155_PAD_ODT_BYTE1(1) | DDRMC_CR155_PAD_ODT_BYTE0(1), 155 },
+	{ DDRMC_CR158_TWR(6), 158 },
+	{ DDRMC_CR161_ODT_EN(1) | DDRMC_CR161_TODTH_RD(2) |
+		   DDRMC_CR161_TODTH_WR(2), 161 },
+
+	/* end marker */
+	{ 0, -1 }
+}
+
 int dram_init(void)
 {
-	struct ddrmc_lvl_info lvl = {
-		.wrlvl_reg_en = 1,
-		.wrlvl_dl_0 = 0,
-		.wrlvl_dl_1 = 0,
-		.rdlvl_gt_reg_en = 1,
-		.rdlvl_gt_dl_0 = 4,
-		.rdlvl_gt_dl_1 = 4,
-		.rdlvl_reg_en = 1,
-		.rdlvl_dl_0 = 0,
-		.rdlvl_dl_1 = 0,
-	};
-
-	static const struct ddr3_jedec_timings timings = {
-		.tinit           = 5,
-		.trst_pwron      = 80000,
-		.cke_inactive    = 200000,
-		.wrlat           = 5,
-		.caslat_lin      = 12,
-		.trc             = 21,
-		.trrd            = 4,
-		.tccd            = 4,
-		.tfaw            = 20,
-		.trp             = 6,
-		.twtr            = 4,
-		.tras_min        = 15,
-		.tmrd            = 4,
-		.trtp            = 4,
-		.tras_max        = 28080,
-		.tmod            = 12,
-		.tckesr          = 4,
-		.tcke            = 3,
-		.trcd_int        = 6,
-		.tdal            = 12,
-		.tdll            = 512,
-		.trp_ab          = 6,
-		.tref            = 3120,
-		.trfc            = 44,
-		.tpdex           = 3,
-		.txpdll          = 10,
-		.txsnr           = 48,
-		.txsr            = 468,
-		.cksrx           = 5,
-		.cksre           = 5,
-		.zqcl            = 256,
-		.zqinit          = 512,
-		.zqcs            = 64,
-		.ref_per_zq      = 64,
-		.aprebit         = 10,
-		.wlmrd           = 40,
-		.wldqsen         = 25,
-	};
-
-	ddrmc_setup_iomux();
+	/* use driver default IOMUX settings */
+	ddrmc_setup_iomux(NULL, 0);
 
-	ddrmc_ctrl_init_ddr3(&timings, &lvl, 1, 3);
+	/* provide own CR setup but use default PHY setup */
+	ddrmc_ctrl_init_ddr3(vf610twr_cr_settings, NULL);
 	gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
 
 	return 0;
diff --git a/board/toradex/colibri_vf/colibri_vf.c b/board/toradex/colibri_vf/colibri_vf.c
index 8618fd0..01b3106 100644
--- a/board/toradex/colibri_vf/colibri_vf.c
+++ b/board/toradex/colibri_vf/colibri_vf.c
@@ -39,51 +39,136 @@  static const iomux_v3_cfg_t usb_pads[] = {
 	VF610_PAD_PTD4__GPIO_83,
 };
 
+static struct ddrmc_reg_setting colibri_vf_cr_settings[] = {
+	{ DDRMC_CR02_DRAM_TINIT(5), 2 },
+	{ DDRMC_CR10_TRST_PWRON(80000), 10 },
+	{ DDRMC_CR11_CKE_INACTIVE(200000), 11 },
+	{ DDRMC_CR12_WRLAT(5) | DDRMC_CR12_CASLAT_LIN(12), 12 },
+	{ DDRMC_CR13_TRC(21) | DDRMC_CR13_TRRD(4) | DDRMC_CR13_TCCD(4) |
+		   DDRMC_CR13_TBST_INT_INTERVAL(0), 13 },
+	{ DDRMC_CR14_TFAW(20) | DDRMC_CR14_TRP(6) | DDRMC_CR14_TWTR(5) |
+		   DDRMC_CR14_TRAS_MIN(15), 14 },
+	{ DDRMC_CR16_TMRD(4) | DDRMC_CR16_TRTP(4), 16 },
+	{ DDRMC_CR17_TRAS_MAX(28080) | DDRMC_CR17_TMOD(12), 17 },
+	{ DDRMC_CR18_TCKESR(4) | DDRMC_CR18_TCKE(3), 18 },
+
+	{ DDRMC_CR20_AP_EN, 20 },
+	{ DDRMC_CR21_TRCD_INT(6) | DDRMC_CR21_CCMAP_EN, 21 },
+
+	{ DDRMC_CR22_TDAL(12), 22 },
+	{ DDRMC_CR23_BSTLEN(3) |
+		   DDRMC_CR23_TDLL(512), 23 },
+	{ DDRMC_CR24_TRP_AB(6), 24 },
+
+	{ DDRMC_CR25_TREF_EN, 25 },
+	{ DDRMC_CR26_TREF(3120) | DDRMC_CR26_TRFC(44), 26 },
+	{ DDRMC_CR28_TREF_INT(0), 28 },
+	{ DDRMC_CR29_TPDEX(3), 29 },
+
+	{ DDRMC_CR30_TXPDLL(10), 30 },
+	{ DDRMC_CR31_TXSNR(48) | DDRMC_CR31_TXSR(468), 31 },
+	{ DDRMC_CR33_EN_QK_SREF, 33 },
+	{ DDRMC_CR34_CKSRX(5) | DDRMC_CR34_CKSRE(5), 34 },
+
+	{ DDRMC_CR38_FREQ_CHG_EN(0), 38 },
+	{ DDRMC_CR39_PHY_INI_COM(1024) | DDRMC_CR39_PHY_INI_STA(16) |
+		   DDRMC_CR39_FRQ_CH_DLLOFF(2), 39 },
+
+	{ DDRMC_CR41_PHY_INI_STRT_INI_DIS, 41 },
+	{ DDRMC_CR48_MR1_DA_0(70) |
+		   DDRMC_CR48_MR0_DA_0(1056), 48 },
+
+	{ DDRMC_CR66_ZQCL(256) | DDRMC_CR66_ZQINIT(512), 66 },
+	{ DDRMC_CR67_ZQCS(64), 67 },
+	{ DDRMC_CR69_ZQ_ON_SREF_EX(2), 69 },
+
+	{ DDRMC_CR70_REF_PER_ZQ(64), 70 },
+	{ DDRMC_CR72_ZQCS_ROTATE(0), 72 },
+
+	{ DDRMC_CR73_APREBIT(10) | DDRMC_CR73_COL_DIFF(1) |
+		   DDRMC_CR73_ROW_DIFF(3), 73 },
+	{ DDRMC_CR74_BANKSPLT_EN | DDRMC_CR74_ADDR_CMP_EN |
+		   DDRMC_CR74_CMD_AGE_CNT(64) |
+		   DDRMC_CR74_AGE_CNT(64), 74 },
+	{ DDRMC_CR75_RW_PG_EN | DDRMC_CR75_RW_EN | DDRMC_CR75_PRI_EN |
+		   DDRMC_CR75_PLEN, 75 },
+	{ DDRMC_CR76_NQENT_ACTDIS(3) | DDRMC_CR76_D_RW_G_BKCN(3) |
+		   DDRMC_CR76_W2R_SPLT_EN, 76 },
+	{ DDRMC_CR77_CS_MAP | DDRMC_CR77_DI_RD_INTLEAVE |
+		   DDRMC_CR77_SWAP_EN, 77 },
+	{ DDRMC_CR78_Q_FULLNESS(7) | DDRMC_CR78_BUR_ON_FLY_BIT(12), 78 },
+	{ DDRMC_CR79_CTLUPD_AREF(0), 79 },
+
+	{ DDRMC_CR87_ODT_WR_MAPCS0, 87 },
+	{ DDRMC_CR88_TODTL_CMD(4), 88 },
+	{ DDRMC_CR89_AODT_RWSMCS(2), 89 },
+
+	{ DDRMC_CR91_R2W_SMCSDL(2), 91 },
+	{ DDRMC_CR96_WLMRD(40) | DDRMC_CR96_WLDQSEN(25), 96 },
+
+	/* levelling */
+	{ DDRMC_CR97_WRLVL_EN, 97 },
+	{ DDRMC_CR98_WRLVL_DL_0(0), 98 },
+	{ DDRMC_CR99_WRLVL_DL_1(0), 99 },
+	{ DDRMC_CR102_RDLVL_REG_EN | DDRMC_CR102_RDLVL_GT_REGEN, 102 },
+	{ DDRMC_CR105_RDLVL_DL_0(0), 105 },
+	{ DDRMC_CR106_RDLVL_GTDL_0(4), 106 },
+	{ DDRMC_CR110_RDLVL_DL_1(0) | DDRMC_CR110_RDLVL_GTDL_1(4), 110 },
+
+	/* AXI */
+	{ DDRMC_CR117_AXI0_W_PRI(0) | DDRMC_CR117_AXI0_R_PRI(0), 117 },
+	{ DDRMC_CR118_AXI1_W_PRI(1) | DDRMC_CR118_AXI1_R_PRI(1), 118 },
+	{ DDRMC_CR120_AXI0_PRI1_RPRI(2) |
+		   DDRMC_CR120_AXI0_PRI0_RPRI(2), 120 },
+	{ DDRMC_CR121_AXI0_PRI3_RPRI(2) |
+		   DDRMC_CR121_AXI0_PRI2_RPRI(2), 121 },
+	{ DDRMC_CR122_AXI1_PRI1_RPRI(1) | DDRMC_CR122_AXI1_PRI0_RPRI(1) |
+		   DDRMC_CR122_AXI0_PRIRLX(100), 122 },
+	{ DDRMC_CR123_AXI1_P_ODR_EN | DDRMC_CR123_AXI1_PRI3_RPRI(1) |
+		   DDRMC_CR123_AXI1_PRI2_RPRI(1), 123 },
+	{ DDRMC_CR124_AXI1_PRIRLX(100), 124 },
+	{ DDRMC_CR126_PHY_RDLAT(8), 126 },
+	{ DDRMC_CR132_WRLAT_ADJ(5) |
+		   DDRMC_CR132_RDLAT_ADJ(6), 132 },
+	{ DDRMC_CR137_PHYCTL_DL(2), 137 },
+	{ DDRMC_CR138_PHY_WRLV_MXDL(256) |
+		   DDRMC_CR138_PHYDRAM_CK_EN(1), 138 },
+	{ DDRMC_CR139_PHY_WRLV_RESPLAT(4) | DDRMC_CR139_PHY_WRLV_LOAD(7) |
+		   DDRMC_CR139_PHY_WRLV_DLL(3) |
+		   DDRMC_CR139_PHY_WRLV_EN(3), 139 },
+	{ DDRMC_CR140_PHY_WRLV_WW(64), 140 },
+	{ DDRMC_CR143_RDLV_GAT_MXDL(1536) |
+		   DDRMC_CR143_RDLV_MXDL(128), 143 },
+	{ DDRMC_CR144_PHY_RDLVL_RES(4) | DDRMC_CR144_PHY_RDLV_LOAD(7) |
+		   DDRMC_CR144_PHY_RDLV_DLL(3) |
+		   DDRMC_CR144_PHY_RDLV_EN(3), 144 },
+	{ DDRMC_CR145_PHY_RDLV_RR(64), 145 },
+	{ DDRMC_CR146_PHY_RDLVL_RESP(64), 146 },
+	{ DDRMC_CR147_RDLV_RESP_MASK(983040), 147 },
+	{ DDRMC_CR148_RDLV_GATE_RESP_MASK(983040), 148 },
+	{ DDRMC_CR151_RDLV_GAT_DQ_ZERO_CNT(1) |
+		   DDRMC_CR151_RDLVL_DQ_ZERO_CNT(1), 151 },
+
+	{ DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
+		   DDRMC_CR154_PAD_ZQ_MODE(1) |
+		   DDRMC_CR154_DDR_SEL_PAD_CONTR(3) |
+		   DDRMC_CR154_PAD_ZQ_HW_FOR(1), 154 },
+	{ DDRMC_CR155_PAD_ODT_BYTE1(1) | DDRMC_CR155_PAD_ODT_BYTE0(1), 155 },
+	{ DDRMC_CR158_TWR(6), 158 },
+	{ DDRMC_CR161_ODT_EN(1) | DDRMC_CR161_TODTH_RD(2) |
+		   DDRMC_CR161_TODTH_WR(2), 161 },
+
+	/* end marker */
+	{ 0, -1 }
+}
+
 int dram_init(void)
 {
-	static const struct ddr3_jedec_timings timings = {
-		.tinit           = 5,
-		.trst_pwron      = 80000,
-		.cke_inactive    = 200000,
-		.wrlat           = 5,
-		.caslat_lin      = 12,
-		.trc             = 21,
-		.trrd            = 4,
-		.tccd            = 4,
-		.tfaw            = 20,
-		.trp             = 6,
-		.twtr            = 4,
-		.tras_min        = 15,
-		.tmrd            = 4,
-		.trtp            = 4,
-		.tras_max        = 28080,
-		.tmod            = 12,
-		.tckesr          = 4,
-		.tcke            = 3,
-		.trcd_int        = 6,
-		.tdal            = 12,
-		.tdll            = 512,
-		.trp_ab          = 6,
-		.tref            = 3120,
-		.trfc            = 64,
-		.tpdex           = 3,
-		.txpdll          = 10,
-		.txsnr           = 48,
-		.txsr            = 468,
-		.cksrx           = 5,
-		.cksre           = 5,
-		.zqcl            = 256,
-		.zqinit          = 512,
-		.zqcs            = 64,
-		.ref_per_zq      = 64,
-		.aprebit         = 10,
-		.wlmrd           = 40,
-		.wldqsen         = 25,
-	};
-
-	ddrmc_setup_iomux();
+	/* use driver default IOMUX settings */
+	ddrmc_setup_iomux(NULL, 0);
 
-	ddrmc_ctrl_init_ddr3(&timings, NULL, 1, 2);
+	/* provide own CR setup but use default PHY setup */
+	ddrmc_ctrl_init_ddr3(&colibri_vf_cr_settings, NULL, 1, 2);
 	gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
 
 	return 0;