]> git.sur5r.net Git - u-boot/commitdiff
sunxi: makes an invisible option for H3-like DRAM controllers
authorIcenowy Zheng <icenowy@aosc.xyz>
Sat, 3 Jun 2017 09:10:14 +0000 (17:10 +0800)
committerJagan Teki <jagan@amarulasolutions.com>
Thu, 8 Jun 2017 17:07:55 +0000 (22:37 +0530)
Allwinner SoCs after H3 (e.g. A64, H5, R40, V3s) uses a H3-like
DesignWare DRAM controller, which do not have official free DRAM
initialization code, but can use modified dram_sun8i_h3.c.

Add a invisible option for easier DRAM initialization code reuse.

Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
Tested-by: Jagan Teki <jagan@amarulasolutions.com>
arch/arm/include/asm/arch-sunxi/dram.h
arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h [deleted file]
arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h [new file with mode: 0644]
arch/arm/mach-sunxi/Kconfig
arch/arm/mach-sunxi/Makefile
arch/arm/mach-sunxi/dram_sun8i_h3.c [deleted file]
arch/arm/mach-sunxi/dram_sunxi_dw.c [new file with mode: 0644]

index f452f889f928624cfe99a2e101ec4ba29d7bfbbf..80abac95b8e13e4ab6b1802a3b05f0b5bcd81a38 100644 (file)
 #include <asm/arch/dram_sun8i_a33.h>
 #elif defined(CONFIG_MACH_SUN8I_A83T)
 #include <asm/arch/dram_sun8i_a83t.h>
-#elif defined(CONFIG_MACH_SUNXI_H3_H5) || \
-      defined(CONFIG_MACH_SUN8I_R40) || \
-      defined(CONFIG_MACH_SUN50I)
-#include <asm/arch/dram_sun8i_h3.h>
+#elif defined(CONFIG_SUNXI_DRAM_DW)
+#include <asm/arch/dram_sunxi_dw.h>
 #elif defined(CONFIG_MACH_SUN9I)
 #include <asm/arch/dram_sun9i.h>
 #else
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h
deleted file mode 100644 (file)
index 2770986..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * sun8i H3 platform dram controller register and constant defines
- *
- * (C) Copyright 2007-2015 Allwinner Technology Co.
- *                         Jerry Wang <wangflord@allwinnertech.com>
- * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
- * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
- * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
- */
-
-#ifndef _SUNXI_DRAM_SUN8I_H3_H
-#define _SUNXI_DRAM_SUN8I_H3_H
-
-struct sunxi_mctl_com_reg {
-       u32 cr;                 /* 0x00 control register */
-       u32 cr_r1;              /* 0x04 rank 1 control register (R40 only) */
-       u8 res0[0x4];           /* 0x08 */
-       u32 tmr;                /* 0x0c (unused on H3) */
-       u32 mcr[16][2];         /* 0x10 */
-       u32 bwcr;               /* 0x90 bandwidth control register */
-       u32 maer;               /* 0x94 master enable register */
-       u32 mapr;               /* 0x98 master priority register */
-       u32 mcgcr;              /* 0x9c */
-       u32 cpu_bwcr;           /* 0xa0 */
-       u32 gpu_bwcr;           /* 0xa4 */
-       u32 ve_bwcr;            /* 0xa8 */
-       u32 disp_bwcr;          /* 0xac */
-       u32 other_bwcr;         /* 0xb0 */
-       u32 total_bwcr;         /* 0xb4 */
-       u8 res1[0x8];           /* 0xb8 */
-       u32 swonr;              /* 0xc0 */
-       u32 swoffr;             /* 0xc4 */
-       u8 res2[0x8];           /* 0xc8 */
-       u32 cccr;               /* 0xd0 */
-       u8 res3[0x54];          /* 0xd4 */
-       u32 mdfs_bwlr[3];       /* 0x128 (unused on H3) */
-       u8 res4[0x6cc];         /* 0x134 */
-       u32 protect;            /* 0x800 */
-};
-
-#define MCTL_CR_BL8            (0x4 << 20)
-
-#define MCTL_CR_1T             (0x1 << 19)
-#define MCTL_CR_2T             (0x0 << 19)
-
-#define MCTL_CR_LPDDR3         (0x7 << 16)
-#define MCTL_CR_LPDDR2         (0x6 << 16)
-#define MCTL_CR_DDR3           (0x3 << 16)
-#define MCTL_CR_DDR2           (0x2 << 16)
-
-#define MCTL_CR_SEQUENTIAL     (0x1 << 15)
-#define MCTL_CR_INTERLEAVED    (0x0 << 15)
-
-#define MCTL_CR_32BIT          (0x1 << 12)
-#define MCTL_CR_16BIT          (0x0 << 12)
-#define MCTL_CR_BUS_WIDTH(x)   ((x) == 32 ? MCTL_CR_32BIT : MCTL_CR_16BIT)
-
-#define MCTL_CR_PAGE_SIZE(x)   ((fls(x) - 4) << 8)
-#define MCTL_CR_ROW_BITS(x)    (((x) - 1) << 4)
-#define MCTL_CR_EIGHT_BANKS    (0x1 << 2)
-#define MCTL_CR_FOUR_BANKS     (0x0 << 2)
-#define MCTL_CR_DUAL_RANK      (0x1 << 0)
-#define MCTL_CR_SINGLE_RANK    (0x0 << 0)
-
-/*
- * CR_R1 is a register found in the R40's DRAM controller. It sets various
- * parameters for rank 1. Bits [11:0] have the same meaning as the bits in
- * MCTL_CR, but they apply to rank 1 only. This implies we can have
- * different chips for rank 1 than rank 0.
- *
- * As address line A15 and CS1 chip select for rank 1 are muxed on the same
- * pin, if single rank is used, A15 must be muxed in.
- */
-#define MCTL_CR_R1_MUX_A15     (0x1 << 21)
-
-#define PROTECT_MAGIC          (0x94be6fa3)
-
-struct sunxi_mctl_ctl_reg {
-       u32 pir;                /* 0x00 PHY initialization register */
-       u32 pwrctl;             /* 0x04 */
-       u32 mrctrl;             /* 0x08 */
-       u32 clken;              /* 0x0c */
-       u32 pgsr[2];            /* 0x10 PHY general status registers */
-       u32 statr;              /* 0x18 */
-       u8 res1[0x10];          /* 0x1c */
-       u32 lp3mr11;            /* 0x2c */
-       u32 mr[4];              /* 0x30 mode registers */
-       u32 pllgcr;             /* 0x40 */
-       u32 ptr[5];             /* 0x44 PHY timing registers */
-       u32 dramtmg[9];         /* 0x58 DRAM timing registers */
-       u32 odtcfg;             /* 0x7c */
-       u32 pitmg[2];           /* 0x80 PHY interface timing registers */
-       u8 res2[0x4];           /* 0x88 */
-       u32 rfshctl0;           /* 0x8c */
-       u32 rfshtmg;            /* 0x90 refresh timing */
-       u32 rfshctl1;           /* 0x94 */
-       u32 pwrtmg;             /* 0x98 */
-       u8 res3[0x1c];          /* 0x9c */
-       u32 vtfcr;              /* 0xb8 (unused on H3) */
-       u32 dqsgmr;             /* 0xbc */
-       u32 dtcr;               /* 0xc0 */
-       u32 dtar[4];            /* 0xc4 */
-       u32 dtdr[2];            /* 0xd4 */
-       u32 dtmr[2];            /* 0xdc */
-       u32 dtbmr;              /* 0xe4 */
-       u32 catr[2];            /* 0xe8 */
-       u32 dtedr[2];           /* 0xf0 */
-       u8 res4[0x8];           /* 0xf8 */
-       u32 pgcr[4];            /* 0x100 PHY general configuration registers */
-       u32 iovcr[2];           /* 0x110 */
-       u32 dqsdr;              /* 0x118 */
-       u32 dxccr;              /* 0x11c */
-       u32 odtmap;             /* 0x120 */
-       u32 zqctl[2];           /* 0x124 */
-       u8 res6[0x14];          /* 0x12c */
-       u32 zqcr;               /* 0x140 ZQ control register */
-       u32 zqsr;               /* 0x144 ZQ status register */
-       u32 zqdr[3];            /* 0x148 ZQ data registers */
-       u8 res7[0x6c];          /* 0x154 */
-       u32 sched;              /* 0x1c0 */
-       u32 perfhpr[2];         /* 0x1c4 */
-       u32 perflpr[2];         /* 0x1cc */
-       u32 perfwr[2];          /* 0x1d4 */
-       u8 res8[0x24];          /* 0x1dc */
-       u32 acmdlr;             /* 0x200 AC master delay line register */
-       u32 aclcdlr;            /* 0x204 AC local calibrated delay line register */
-       u32 aciocr;             /* 0x208 AC I/O configuration register */
-       u8 res9[0x4];           /* 0x20c */
-       u32 acbdlr[31];         /* 0x210 AC bit delay line registers */
-       u8 res10[0x74];         /* 0x28c */
-       struct {                /* 0x300 DATX8 modules*/
-               u32 mdlr;               /* 0x00 master delay line register */
-               u32 lcdlr[3];           /* 0x04 local calibrated delay line registers */
-               u32 bdlr[11];           /* 0x10 bit delay line registers */
-               u32 sdlr;               /* 0x3c output enable bit delay registers */
-               u32 gtr;                /* 0x40 general timing register */
-               u32 gcr;                /* 0x44 general configuration register */
-               u32 gsr[3];             /* 0x48 general status registers */
-               u8 res0[0x2c];          /* 0x54 */
-       } dx[4];
-       u8 res11[0x388];        /* 0x500 */
-       u32 upd2;               /* 0x888 */
-};
-
-#define PTR3_TDINIT1(x)                ((x) << 20)
-#define PTR3_TDINIT0(x)                ((x) <<  0)
-
-#define PTR4_TDINIT3(x)                ((x) << 20)
-#define PTR4_TDINIT2(x)                ((x) <<  0)
-
-#define DRAMTMG0_TWTP(x)       ((x) << 24)
-#define DRAMTMG0_TFAW(x)       ((x) << 16)
-#define DRAMTMG0_TRAS_MAX(x)   ((x) <<  8)
-#define DRAMTMG0_TRAS(x)       ((x) <<  0)
-
-#define DRAMTMG1_TXP(x)                ((x) << 16)
-#define DRAMTMG1_TRTP(x)       ((x) <<  8)
-#define DRAMTMG1_TRC(x)                ((x) <<  0)
-
-#define DRAMTMG2_TCWL(x)       ((x) << 24)
-#define DRAMTMG2_TCL(x)                ((x) << 16)
-#define DRAMTMG2_TRD2WR(x)     ((x) <<  8)
-#define DRAMTMG2_TWR2RD(x)     ((x) <<  0)
-
-#define DRAMTMG3_TMRW(x)       ((x) << 16)
-#define DRAMTMG3_TMRD(x)       ((x) << 12)
-#define DRAMTMG3_TMOD(x)       ((x) <<  0)
-
-#define DRAMTMG4_TRCD(x)       ((x) << 24)
-#define DRAMTMG4_TCCD(x)       ((x) << 16)
-#define DRAMTMG4_TRRD(x)       ((x) <<  8)
-#define DRAMTMG4_TRP(x)                ((x) <<  0)
-
-#define DRAMTMG5_TCKSRX(x)     ((x) << 24)
-#define DRAMTMG5_TCKSRE(x)     ((x) << 16)
-#define DRAMTMG5_TCKESR(x)     ((x) <<  8)
-#define DRAMTMG5_TCKE(x)       ((x) <<  0)
-
-#define RFSHTMG_TREFI(x)       ((x) << 16)
-#define RFSHTMG_TRFC(x)                ((x) <<  0)
-
-#define PIR_CLRSR      (0x1 << 27)     /* clear status registers */
-#define PIR_QSGATE     (0x1 << 10)     /* Read DQS gate training */
-#define PIR_DRAMINIT   (0x1 << 8)      /* DRAM initialization */
-#define PIR_DRAMRST    (0x1 << 7)      /* DRAM reset */
-#define PIR_PHYRST     (0x1 << 6)      /* PHY reset */
-#define PIR_DCAL       (0x1 << 5)      /* DDL calibration */
-#define PIR_PLLINIT    (0x1 << 4)      /* PLL initialization */
-#define PIR_ZCAL       (0x1 << 1)      /* ZQ calibration */
-#define PIR_INIT       (0x1 << 0)      /* PHY initialization trigger */
-
-#define PGSR_INIT_DONE (0x1 << 0)      /* PHY init done */
-
-#define ZQCR_PWRDOWN   (1U << 31)      /* ZQ power down */
-
-#define ACBDLR_WRITE_DELAY(x)  ((x) << 8)
-
-#define DXBDLR_DQ(x)   (x)             /* DQ0-7 BDLR index */
-#define DXBDLR_DM      8               /* DM BDLR index */
-#define DXBDLR_DQS     9               /* DQS BDLR index */
-#define DXBDLR_DQSN    10              /* DQSN BDLR index */
-
-#define DXBDLR_WRITE_DELAY(x)  ((x) << 8)
-#define DXBDLR_READ_DELAY(x)   ((x) << 0)
-
-#endif /* _SUNXI_DRAM_SUN8I_H3_H */
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h
new file mode 100644 (file)
index 0000000..2770986
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * sun8i H3 platform dram controller register and constant defines
+ *
+ * (C) Copyright 2007-2015 Allwinner Technology Co.
+ *                         Jerry Wang <wangflord@allwinnertech.com>
+ * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
+ * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN8I_H3_H
+#define _SUNXI_DRAM_SUN8I_H3_H
+
+struct sunxi_mctl_com_reg {
+       u32 cr;                 /* 0x00 control register */
+       u32 cr_r1;              /* 0x04 rank 1 control register (R40 only) */
+       u8 res0[0x4];           /* 0x08 */
+       u32 tmr;                /* 0x0c (unused on H3) */
+       u32 mcr[16][2];         /* 0x10 */
+       u32 bwcr;               /* 0x90 bandwidth control register */
+       u32 maer;               /* 0x94 master enable register */
+       u32 mapr;               /* 0x98 master priority register */
+       u32 mcgcr;              /* 0x9c */
+       u32 cpu_bwcr;           /* 0xa0 */
+       u32 gpu_bwcr;           /* 0xa4 */
+       u32 ve_bwcr;            /* 0xa8 */
+       u32 disp_bwcr;          /* 0xac */
+       u32 other_bwcr;         /* 0xb0 */
+       u32 total_bwcr;         /* 0xb4 */
+       u8 res1[0x8];           /* 0xb8 */
+       u32 swonr;              /* 0xc0 */
+       u32 swoffr;             /* 0xc4 */
+       u8 res2[0x8];           /* 0xc8 */
+       u32 cccr;               /* 0xd0 */
+       u8 res3[0x54];          /* 0xd4 */
+       u32 mdfs_bwlr[3];       /* 0x128 (unused on H3) */
+       u8 res4[0x6cc];         /* 0x134 */
+       u32 protect;            /* 0x800 */
+};
+
+#define MCTL_CR_BL8            (0x4 << 20)
+
+#define MCTL_CR_1T             (0x1 << 19)
+#define MCTL_CR_2T             (0x0 << 19)
+
+#define MCTL_CR_LPDDR3         (0x7 << 16)
+#define MCTL_CR_LPDDR2         (0x6 << 16)
+#define MCTL_CR_DDR3           (0x3 << 16)
+#define MCTL_CR_DDR2           (0x2 << 16)
+
+#define MCTL_CR_SEQUENTIAL     (0x1 << 15)
+#define MCTL_CR_INTERLEAVED    (0x0 << 15)
+
+#define MCTL_CR_32BIT          (0x1 << 12)
+#define MCTL_CR_16BIT          (0x0 << 12)
+#define MCTL_CR_BUS_WIDTH(x)   ((x) == 32 ? MCTL_CR_32BIT : MCTL_CR_16BIT)
+
+#define MCTL_CR_PAGE_SIZE(x)   ((fls(x) - 4) << 8)
+#define MCTL_CR_ROW_BITS(x)    (((x) - 1) << 4)
+#define MCTL_CR_EIGHT_BANKS    (0x1 << 2)
+#define MCTL_CR_FOUR_BANKS     (0x0 << 2)
+#define MCTL_CR_DUAL_RANK      (0x1 << 0)
+#define MCTL_CR_SINGLE_RANK    (0x0 << 0)
+
+/*
+ * CR_R1 is a register found in the R40's DRAM controller. It sets various
+ * parameters for rank 1. Bits [11:0] have the same meaning as the bits in
+ * MCTL_CR, but they apply to rank 1 only. This implies we can have
+ * different chips for rank 1 than rank 0.
+ *
+ * As address line A15 and CS1 chip select for rank 1 are muxed on the same
+ * pin, if single rank is used, A15 must be muxed in.
+ */
+#define MCTL_CR_R1_MUX_A15     (0x1 << 21)
+
+#define PROTECT_MAGIC          (0x94be6fa3)
+
+struct sunxi_mctl_ctl_reg {
+       u32 pir;                /* 0x00 PHY initialization register */
+       u32 pwrctl;             /* 0x04 */
+       u32 mrctrl;             /* 0x08 */
+       u32 clken;              /* 0x0c */
+       u32 pgsr[2];            /* 0x10 PHY general status registers */
+       u32 statr;              /* 0x18 */
+       u8 res1[0x10];          /* 0x1c */
+       u32 lp3mr11;            /* 0x2c */
+       u32 mr[4];              /* 0x30 mode registers */
+       u32 pllgcr;             /* 0x40 */
+       u32 ptr[5];             /* 0x44 PHY timing registers */
+       u32 dramtmg[9];         /* 0x58 DRAM timing registers */
+       u32 odtcfg;             /* 0x7c */
+       u32 pitmg[2];           /* 0x80 PHY interface timing registers */
+       u8 res2[0x4];           /* 0x88 */
+       u32 rfshctl0;           /* 0x8c */
+       u32 rfshtmg;            /* 0x90 refresh timing */
+       u32 rfshctl1;           /* 0x94 */
+       u32 pwrtmg;             /* 0x98 */
+       u8 res3[0x1c];          /* 0x9c */
+       u32 vtfcr;              /* 0xb8 (unused on H3) */
+       u32 dqsgmr;             /* 0xbc */
+       u32 dtcr;               /* 0xc0 */
+       u32 dtar[4];            /* 0xc4 */
+       u32 dtdr[2];            /* 0xd4 */
+       u32 dtmr[2];            /* 0xdc */
+       u32 dtbmr;              /* 0xe4 */
+       u32 catr[2];            /* 0xe8 */
+       u32 dtedr[2];           /* 0xf0 */
+       u8 res4[0x8];           /* 0xf8 */
+       u32 pgcr[4];            /* 0x100 PHY general configuration registers */
+       u32 iovcr[2];           /* 0x110 */
+       u32 dqsdr;              /* 0x118 */
+       u32 dxccr;              /* 0x11c */
+       u32 odtmap;             /* 0x120 */
+       u32 zqctl[2];           /* 0x124 */
+       u8 res6[0x14];          /* 0x12c */
+       u32 zqcr;               /* 0x140 ZQ control register */
+       u32 zqsr;               /* 0x144 ZQ status register */
+       u32 zqdr[3];            /* 0x148 ZQ data registers */
+       u8 res7[0x6c];          /* 0x154 */
+       u32 sched;              /* 0x1c0 */
+       u32 perfhpr[2];         /* 0x1c4 */
+       u32 perflpr[2];         /* 0x1cc */
+       u32 perfwr[2];          /* 0x1d4 */
+       u8 res8[0x24];          /* 0x1dc */
+       u32 acmdlr;             /* 0x200 AC master delay line register */
+       u32 aclcdlr;            /* 0x204 AC local calibrated delay line register */
+       u32 aciocr;             /* 0x208 AC I/O configuration register */
+       u8 res9[0x4];           /* 0x20c */
+       u32 acbdlr[31];         /* 0x210 AC bit delay line registers */
+       u8 res10[0x74];         /* 0x28c */
+       struct {                /* 0x300 DATX8 modules*/
+               u32 mdlr;               /* 0x00 master delay line register */
+               u32 lcdlr[3];           /* 0x04 local calibrated delay line registers */
+               u32 bdlr[11];           /* 0x10 bit delay line registers */
+               u32 sdlr;               /* 0x3c output enable bit delay registers */
+               u32 gtr;                /* 0x40 general timing register */
+               u32 gcr;                /* 0x44 general configuration register */
+               u32 gsr[3];             /* 0x48 general status registers */
+               u8 res0[0x2c];          /* 0x54 */
+       } dx[4];
+       u8 res11[0x388];        /* 0x500 */
+       u32 upd2;               /* 0x888 */
+};
+
+#define PTR3_TDINIT1(x)                ((x) << 20)
+#define PTR3_TDINIT0(x)                ((x) <<  0)
+
+#define PTR4_TDINIT3(x)                ((x) << 20)
+#define PTR4_TDINIT2(x)                ((x) <<  0)
+
+#define DRAMTMG0_TWTP(x)       ((x) << 24)
+#define DRAMTMG0_TFAW(x)       ((x) << 16)
+#define DRAMTMG0_TRAS_MAX(x)   ((x) <<  8)
+#define DRAMTMG0_TRAS(x)       ((x) <<  0)
+
+#define DRAMTMG1_TXP(x)                ((x) << 16)
+#define DRAMTMG1_TRTP(x)       ((x) <<  8)
+#define DRAMTMG1_TRC(x)                ((x) <<  0)
+
+#define DRAMTMG2_TCWL(x)       ((x) << 24)
+#define DRAMTMG2_TCL(x)                ((x) << 16)
+#define DRAMTMG2_TRD2WR(x)     ((x) <<  8)
+#define DRAMTMG2_TWR2RD(x)     ((x) <<  0)
+
+#define DRAMTMG3_TMRW(x)       ((x) << 16)
+#define DRAMTMG3_TMRD(x)       ((x) << 12)
+#define DRAMTMG3_TMOD(x)       ((x) <<  0)
+
+#define DRAMTMG4_TRCD(x)       ((x) << 24)
+#define DRAMTMG4_TCCD(x)       ((x) << 16)
+#define DRAMTMG4_TRRD(x)       ((x) <<  8)
+#define DRAMTMG4_TRP(x)                ((x) <<  0)
+
+#define DRAMTMG5_TCKSRX(x)     ((x) << 24)
+#define DRAMTMG5_TCKSRE(x)     ((x) << 16)
+#define DRAMTMG5_TCKESR(x)     ((x) <<  8)
+#define DRAMTMG5_TCKE(x)       ((x) <<  0)
+
+#define RFSHTMG_TREFI(x)       ((x) << 16)
+#define RFSHTMG_TRFC(x)                ((x) <<  0)
+
+#define PIR_CLRSR      (0x1 << 27)     /* clear status registers */
+#define PIR_QSGATE     (0x1 << 10)     /* Read DQS gate training */
+#define PIR_DRAMINIT   (0x1 << 8)      /* DRAM initialization */
+#define PIR_DRAMRST    (0x1 << 7)      /* DRAM reset */
+#define PIR_PHYRST     (0x1 << 6)      /* PHY reset */
+#define PIR_DCAL       (0x1 << 5)      /* DDL calibration */
+#define PIR_PLLINIT    (0x1 << 4)      /* PLL initialization */
+#define PIR_ZCAL       (0x1 << 1)      /* ZQ calibration */
+#define PIR_INIT       (0x1 << 0)      /* PHY initialization trigger */
+
+#define PGSR_INIT_DONE (0x1 << 0)      /* PHY init done */
+
+#define ZQCR_PWRDOWN   (1U << 31)      /* ZQ power down */
+
+#define ACBDLR_WRITE_DELAY(x)  ((x) << 8)
+
+#define DXBDLR_DQ(x)   (x)             /* DQ0-7 BDLR index */
+#define DXBDLR_DM      8               /* DM BDLR index */
+#define DXBDLR_DQS     9               /* DQS BDLR index */
+#define DXBDLR_DQSN    10              /* DQSN BDLR index */
+
+#define DXBDLR_WRITE_DELAY(x)  ((x) << 8)
+#define DXBDLR_READ_DELAY(x)   ((x) << 0)
+
+#endif /* _SUNXI_DRAM_SUN8I_H3_H */
index 7ced838d6a7027cc48371760dd3f021dd1ea96a0..11da1ab738c9929eb65b8599b3fa624d87cc825f 100644 (file)
@@ -29,11 +29,19 @@ config SUNXI_GEN_SUN6I
        separate ahb reset control registers, custom pmic bus, new style
        watchdog, etc.
 
+config SUNXI_DRAM_DW
+       bool
+       ---help---
+       Select this for sunxi SoCs which uses a DRAM controller like the
+       DesignWare controller used in H3, mainly SoCs after H3, which do
+       not have official open-source DRAM initialization code, but can
+       use modified H3 DRAM initialization code.
 
 config MACH_SUNXI_H3_H5
        bool
        select DM_I2C
        select SUNXI_DE2
+       select SUNXI_DRAM_DW
        select SUNXI_GEN_SUN6I
        select SUPPORT_SPL
 
@@ -118,6 +126,7 @@ config MACH_SUN8I_R40
        select ARCH_SUPPORT_PSCI
        select SUNXI_GEN_SUN6I
        select SUPPORT_SPL
+       select SUNXI_DRAM_DW
 
 config MACH_SUN8I_V3S
        bool "sun8i (Allwinner V3s)"
@@ -143,6 +152,7 @@ config MACH_SUN50I
        select SUNXI_GEN_SUN6I
        select SUNXI_HIGH_SRAM
        select SUPPORT_SPL
+       select SUNXI_DRAM_DW
        select FIT
        select SPL_LOAD_FIT
 
index 5510aa54353f5653ed803a2d6cf00f9099ec59dd..41cee267655f870622dce2a1d40d9df0c8134885 100644 (file)
@@ -48,8 +48,6 @@ obj-$(CONFIG_MACH_SUN7I)      += dram_sun4i.o
 obj-$(CONFIG_MACH_SUN8I_A23)   += dram_sun8i_a23.o
 obj-$(CONFIG_MACH_SUN8I_A33)   += dram_sun8i_a33.o
 obj-$(CONFIG_MACH_SUN8I_A83T)  += dram_sun8i_a83t.o
-obj-$(CONFIG_MACH_SUNXI_H3_H5) += dram_sun8i_h3.o
-obj-$(CONFIG_MACH_SUN8I_R40)   += dram_sun8i_h3.o
+obj-$(CONFIG_SUNXI_DRAM_DW)    += dram_sunxi_dw.o
 obj-$(CONFIG_MACH_SUN9I)       += dram_sun9i.o
-obj-$(CONFIG_MACH_SUN50I)      += dram_sun8i_h3.o
 endif
diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c
deleted file mode 100644 (file)
index 2d12661..0000000
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * sun8i H3 platform dram controller init
- *
- * (C) Copyright 2007-2015 Allwinner Technology Co.
- *                         Jerry Wang <wangflord@allwinnertech.com>
- * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
- * (C) Copyright 2015      Hans de Goede <hdegoede@redhat.com>
- * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
- */
-#include <common.h>
-#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/dram.h>
-#include <asm/arch/cpu.h>
-#include <linux/kconfig.h>
-
-/*
- * The delay parameters below allow to allegedly specify delay times of some
- * unknown unit for each individual bit trace in each of the four data bytes
- * the 32-bit wide access consists of. Also three control signals can be
- * adjusted individually.
- */
-#define BITS_PER_BYTE          8
-#define NR_OF_BYTE_LANES       (32 / BITS_PER_BYTE)
-/* The eight data lines (DQn) plus DM, DQS and DQSN */
-#define LINES_PER_BYTE_LANE    (BITS_PER_BYTE + 3)
-struct dram_para {
-       u16 page_size;
-       u8 bus_width;
-       u8 dual_rank;
-       u8 row_bits;
-       const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
-       const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
-       const u8 ac_delays[31];
-};
-
-static inline int ns_to_t(int nanoseconds)
-{
-       const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
-
-       return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
-}
-
-static void mctl_phy_init(u32 val)
-{
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-
-       writel(val | PIR_INIT, &mctl_ctl->pir);
-       mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
-}
-
-static void mctl_set_bit_delays(struct dram_para *para)
-{
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-       int i, j;
-
-       clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
-
-       for (i = 0; i < NR_OF_BYTE_LANES; i++)
-               for (j = 0; j < LINES_PER_BYTE_LANE; j++)
-                       writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
-                              DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
-                              &mctl_ctl->dx[i].bdlr[j]);
-
-       for (i = 0; i < 31; i++)
-               writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
-                      &mctl_ctl->acbdlr[i]);
-
-#ifdef CONFIG_MACH_SUN8I_R40
-       /* DQSn, DMn, DQn output enable bit delay */
-       for (i = 0; i < 4; i++)
-               writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
-#endif
-
-       setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
-}
-
-enum {
-       MBUS_PORT_CPU           = 0,
-       MBUS_PORT_GPU           = 1,
-       MBUS_PORT_UNUSED        = 2,
-       MBUS_PORT_DMA           = 3,
-       MBUS_PORT_VE            = 4,
-       MBUS_PORT_CSI           = 5,
-       MBUS_PORT_NAND          = 6,
-       MBUS_PORT_SS            = 7,
-       MBUS_PORT_TS            = 8,
-       MBUS_PORT_DI            = 9,
-       MBUS_PORT_DE            = 10,
-       MBUS_PORT_DE_CFD        = 11,
-       MBUS_PORT_UNKNOWN1      = 12,
-       MBUS_PORT_UNKNOWN2      = 13,
-       MBUS_PORT_UNKNOWN3      = 14,
-};
-
-enum {
-       MBUS_QOS_LOWEST = 0,
-       MBUS_QOS_LOW,
-       MBUS_QOS_HIGH,
-       MBUS_QOS_HIGHEST
-};
-
-inline void mbus_configure_port(u8 port,
-                               bool bwlimit,
-                               bool priority,
-                               u8 qos,         /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
-                               u8 waittime,    /* 0 .. 0xf */
-                               u8 acs,         /* 0 .. 0xff */
-                               u16 bwl0,       /* 0 .. 0xffff, bandwidth limit in MB/s */
-                               u16 bwl1,
-                               u16 bwl2)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-
-       const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
-                          | (priority ? (1 << 1) : 0)
-                          | ((qos & 0x3) << 2)
-                          | ((waittime & 0xf) << 4)
-                          | ((acs & 0xff) << 8)
-                          | (bwl0 << 16) );
-       const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
-
-       debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
-       writel(cfg0, &mctl_com->mcr[port][0]);
-       writel(cfg1, &mctl_com->mcr[port][1]);
-}
-
-#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)   \
-       mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
-                           MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
-
-static void mctl_set_master_priority_h3(void)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-
-       /* enable bandwidth limit windows and set windows size 1us */
-       writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
-
-       /* set cpu high priority */
-       writel(0x00000001, &mctl_com->mapr);
-
-       MBUS_CONF(   CPU,  true, HIGHEST, 0,  512,  256,  128);
-       MBUS_CONF(   GPU,  true,    HIGH, 0, 1536, 1024,  256);
-       MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
-       MBUS_CONF(   DMA,  true, HIGHEST, 0,  256,  128,   32);
-       MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
-       MBUS_CONF(   CSI,  true, HIGHEST, 0,  256,  128,   32);
-       MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
-       MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
-       MBUS_CONF(    DE,  true, HIGHEST, 3, 8192, 6120, 1024);
-       MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1024,  288,   64);
-}
-
-static void mctl_set_master_priority_a64(void)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-
-       /* enable bandwidth limit windows and set windows size 1us */
-       writel(399, &mctl_com->tmr);
-       writel((1 << 16), &mctl_com->bwcr);
-
-       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
-        * initialise it */
-       MBUS_CONF(   CPU,  true, HIGHEST, 0,  160,  100,   80);
-       MBUS_CONF(   GPU, false,    HIGH, 0, 1536, 1400,  256);
-       MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
-       MBUS_CONF(   DMA,  true,    HIGH, 0,  256,   80,  100);
-       MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
-       MBUS_CONF(   CSI,  true,    HIGH, 0,  256,  128,    0);
-       MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
-       MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
-       MBUS_CONF(    DE,  true,    HIGH, 2, 8192, 6144, 2048);
-       MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1280,  144,   64);
-
-       writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
-}
-
-static void mctl_set_master_priority_h5(void)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-
-       /* enable bandwidth limit windows and set windows size 1us */
-       writel(399, &mctl_com->tmr);
-       writel((1 << 16), &mctl_com->bwcr);
-
-       /* set cpu high priority */
-       writel(0x00000001, &mctl_com->mapr);
-
-       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
-        * they initialise it */
-       MBUS_CONF(   CPU, true, HIGHEST, 0,  300,  260,  150);
-       MBUS_CONF(   GPU, true, HIGHEST, 0,  600,  400,  200);
-       MBUS_CONF(UNUSED, true, HIGHEST, 0,  512,  256,   96);
-       MBUS_CONF(   DMA, true, HIGHEST, 0,  256,  128,   32);
-       MBUS_CONF(    VE, true, HIGHEST, 0, 1900, 1500, 1000);
-       MBUS_CONF(   CSI, true, HIGHEST, 0,  150,  120,  100);
-       MBUS_CONF(  NAND, true,    HIGH, 0,  256,  128,   64);
-       MBUS_CONF(    SS, true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(    TS, true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(    DI, true,    HIGH, 0, 1024,  256,   64);
-       MBUS_CONF(    DE, true, HIGHEST, 3, 3400, 2400, 1024);
-       MBUS_CONF(DE_CFD, true, HIGHEST, 0,  600,  400,  200);
-}
-
-static void mctl_set_master_priority_r40(void)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-
-       /* enable bandwidth limit windows and set windows size 1us */
-       writel(399, &mctl_com->tmr);
-       writel((1 << 16), &mctl_com->bwcr);
-
-       /* set cpu high priority */
-       writel(0x00000001, &mctl_com->mapr);
-
-       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
-        * they initialise it */
-       MBUS_CONF(     CPU, true, HIGHEST, 0,  300,  260,  150);
-       MBUS_CONF(     GPU, true, HIGHEST, 0,  600,  400,  200);
-       MBUS_CONF(  UNUSED, true, HIGHEST, 0,  512,  256,   96);
-       MBUS_CONF(     DMA, true, HIGHEST, 0,  256,  128,   32);
-       MBUS_CONF(      VE, true, HIGHEST, 0, 1900, 1500, 1000);
-       MBUS_CONF(     CSI, true, HIGHEST, 0,  150,  120,  100);
-       MBUS_CONF(    NAND, true,    HIGH, 0,  256,  128,   64);
-       MBUS_CONF(      SS, true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(      TS, true, HIGHEST, 0,  256,  128,   64);
-       MBUS_CONF(      DI, true,    HIGH, 0, 1024,  256,   64);
-
-       /*
-        * The port names are probably wrong, but no correct sources
-        * are available.
-        */
-       MBUS_CONF(      DE, true,    HIGH, 0,  128,   48,    0);
-       MBUS_CONF(  DE_CFD, true,    HIGH, 0,  384,  256,    0);
-       MBUS_CONF(UNKNOWN1, true, HIGHEST, 0,  512,  384,  256);
-       MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
-       MBUS_CONF(UNKNOWN3, true,    HIGH, 0, 1280,  144,   64);
-}
-
-static void mctl_set_master_priority(uint16_t socid)
-{
-       switch (socid) {
-       case SOCID_H3:
-               mctl_set_master_priority_h3();
-               return;
-       case SOCID_A64:
-               mctl_set_master_priority_a64();
-               return;
-       case SOCID_H5:
-               mctl_set_master_priority_h5();
-               return;
-       case SOCID_R40:
-               mctl_set_master_priority_r40();
-               return;
-       }
-}
-
-static void mctl_set_timing_params(uint16_t socid, struct dram_para *para)
-{
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-
-       u8 tccd         = 2;
-       u8 tfaw         = ns_to_t(50);
-       u8 trrd         = max(ns_to_t(10), 4);
-       u8 trcd         = ns_to_t(15);
-       u8 trc          = ns_to_t(53);
-       u8 txp          = max(ns_to_t(8), 3);
-       u8 twtr         = max(ns_to_t(8), 4);
-       u8 trtp         = max(ns_to_t(8), 4);
-       u8 twr          = max(ns_to_t(15), 3);
-       u8 trp          = ns_to_t(15);
-       u8 tras         = ns_to_t(38);
-       u16 trefi       = ns_to_t(7800) / 32;
-       u16 trfc        = ns_to_t(350);
-
-       u8 tmrw         = 0;
-       u8 tmrd         = 4;
-       u8 tmod         = 12;
-       u8 tcke         = 3;
-       u8 tcksrx       = 5;
-       u8 tcksre       = 5;
-       u8 tckesr       = 4;
-       u8 trasmax      = 24;
-
-       u8 tcl          = 6; /* CL 12 */
-       u8 tcwl         = 4; /* CWL 8 */
-       u8 t_rdata_en   = 4;
-       u8 wr_latency   = 2;
-
-       u32 tdinit0     = (500 * CONFIG_DRAM_CLK) + 1;          /* 500us */
-       u32 tdinit1     = (360 * CONFIG_DRAM_CLK) / 1000 + 1;   /* 360ns */
-       u32 tdinit2     = (200 * CONFIG_DRAM_CLK) + 1;          /* 200us */
-       u32 tdinit3     = (1 * CONFIG_DRAM_CLK) + 1;            /* 1us */
-
-       u8 twtp         = tcwl + 2 + twr;       /* WL + BL / 2 + tWR */
-       u8 twr2rd       = tcwl + 2 + twtr;      /* WL + BL / 2 + tWTR */
-       u8 trd2wr       = tcl + 2 + 1 - tcwl;   /* RL + BL / 2 + 2 - WL */
-
-       /* set mode register */
-       writel(0x1c70, &mctl_ctl->mr[0]);       /* CL=11, WR=12 */
-       writel(0x40, &mctl_ctl->mr[1]);
-       writel(0x18, &mctl_ctl->mr[2]);         /* CWL=8 */
-       writel(0x0, &mctl_ctl->mr[3]);
-
-       if (socid == SOCID_R40)
-               writel(0x3, &mctl_ctl->lp3mr11);        /* odt_en[7:4] */
-
-       /* set DRAM timing */
-       writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) |
-              DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras),
-              &mctl_ctl->dramtmg[0]);
-       writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc),
-              &mctl_ctl->dramtmg[1]);
-       writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) |
-              DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd),
-              &mctl_ctl->dramtmg[2]);
-       writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod),
-              &mctl_ctl->dramtmg[3]);
-       writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) |
-              DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]);
-       writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) |
-              DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke),
-              &mctl_ctl->dramtmg[5]);
-
-       /* set two rank timing */
-       clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xff << 8) | (0xff << 0),
-                       ((socid == SOCID_H5 ? 0x33 : 0x66) << 8) | (0x10 << 0));
-
-       /* set PHY interface timing, write latency and read latency configure */
-       writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) |
-              (wr_latency << 0), &mctl_ctl->pitmg[0]);
-
-       /* set PHY timing, PTR0-2 use default */
-       writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]);
-       writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]);
-
-       /* set refresh timing */
-       writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg);
-}
-
-static u32 bin_to_mgray(int val)
-{
-       static const u8 lookup_table[32] = {
-               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
-               0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
-               0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
-               0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
-       };
-
-       return lookup_table[clamp(val, 0, 31)];
-}
-
-static int mgray_to_bin(u32 val)
-{
-       static const u8 lookup_table[32] = {
-               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
-               0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
-               0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
-               0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
-       };
-
-       return lookup_table[val & 0x1f];
-}
-
-static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
-{
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-
-       if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
-           (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
-               u32 reg_val;
-
-               clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
-                               CONFIG_DRAM_ZQ & 0xffff);
-
-               writel(PIR_CLRSR, &mctl_ctl->pir);
-               mctl_phy_init(PIR_ZCAL);
-
-               reg_val = readl(&mctl_ctl->zqdr[0]);
-               reg_val &= (0x1f << 16) | (0x1f << 0);
-               reg_val |= reg_val << 8;
-               writel(reg_val, &mctl_ctl->zqdr[0]);
-
-               reg_val = readl(&mctl_ctl->zqdr[1]);
-               reg_val &= (0x1f << 16) | (0x1f << 0);
-               reg_val |= reg_val << 8;
-               writel(reg_val, &mctl_ctl->zqdr[1]);
-               writel(reg_val, &mctl_ctl->zqdr[2]);
-       } else {
-               int i;
-               u16 zq_val[6];
-               u8 val;
-
-               writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
-
-               for (i = 0; i < 6; i++) {
-                       u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
-
-                       writel((zq << 20) | (zq << 16) | (zq << 12) |
-                                       (zq << 8) | (zq << 4) | (zq << 0),
-                                       &mctl_ctl->zqcr);
-
-                       writel(PIR_CLRSR, &mctl_ctl->pir);
-                       mctl_phy_init(PIR_ZCAL);
-
-                       zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
-                       writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
-
-                       writel(PIR_CLRSR, &mctl_ctl->pir);
-                       mctl_phy_init(PIR_ZCAL);
-
-                       val = readl(&mctl_ctl->zqdr[0]) >> 24;
-                       zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
-               }
-
-               writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
-               writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
-               writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]);
-       }
-}
-
-static void mctl_set_cr(uint16_t socid, struct dram_para *para)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-
-       writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED |
-              MCTL_CR_EIGHT_BANKS | MCTL_CR_BUS_WIDTH(para->bus_width) |
-              (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
-              MCTL_CR_PAGE_SIZE(para->page_size) |
-              MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
-
-       if (socid == SOCID_R40) {
-               if (para->dual_rank)
-                       panic("Dual rank memory not supported\n");
-
-               /* Mux pin to A15 address line for single rank memory. */
-               setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
-       }
-}
-
-static void mctl_sys_init(uint16_t socid, struct dram_para *para)
-{
-       struct sunxi_ccm_reg * const ccm =
-                       (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-
-       clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
-       clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
-       clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
-       clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
-       clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
-       if (socid == SOCID_A64 || socid == SOCID_R40)
-               clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
-       udelay(10);
-
-       clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
-       udelay(1000);
-
-       if (socid == SOCID_A64 || socid == SOCID_R40) {
-               clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
-               clrsetbits_le32(&ccm->dram_clk_cfg,
-                               CCM_DRAMCLK_CFG_DIV_MASK |
-                               CCM_DRAMCLK_CFG_SRC_MASK,
-                               CCM_DRAMCLK_CFG_DIV(1) |
-                               CCM_DRAMCLK_CFG_SRC_PLL11 |
-                               CCM_DRAMCLK_CFG_UPD);
-       } else if (socid == SOCID_H3 || socid == SOCID_H5) {
-               clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
-               clrsetbits_le32(&ccm->dram_clk_cfg,
-                               CCM_DRAMCLK_CFG_DIV_MASK |
-                               CCM_DRAMCLK_CFG_SRC_MASK,
-                               CCM_DRAMCLK_CFG_DIV(1) |
-                               CCM_DRAMCLK_CFG_SRC_PLL5 |
-                               CCM_DRAMCLK_CFG_UPD);
-       }
-       mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
-
-       setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
-       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
-       setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
-       setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
-
-       setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
-       udelay(10);
-
-       writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
-       udelay(500);
-}
-
-/* These are more guessed based on some Allwinner code. */
-#define DX_GCR_ODT_DYNAMIC     (0x0 << 4)
-#define DX_GCR_ODT_ALWAYS_ON   (0x1 << 4)
-#define DX_GCR_ODT_OFF         (0x2 << 4)
-
-static int mctl_channel_init(uint16_t socid, struct dram_para *para)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-
-       unsigned int i;
-
-       mctl_set_cr(socid, para);
-       mctl_set_timing_params(socid, para);
-       mctl_set_master_priority(socid);
-
-       /* setting VTC, default disable all VT */
-       clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
-       if (socid == SOCID_H5)
-               setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
-       else
-               clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
-
-       /* increase DFI_PHY_UPD clock */
-       writel(PROTECT_MAGIC, &mctl_com->protect);
-       udelay(100);
-       clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
-       writel(0x0, &mctl_com->protect);
-       udelay(100);
-
-       /* set dramc odt */
-       for (i = 0; i < 4; i++) {
-               u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
-                               (0x3 << 12) | (0x3 << 14);
-               u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
-                               DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
-
-               if (socid == SOCID_H5) {
-                       clearmask |= 0x2 << 8;
-                       setmask |= 0x4 << 8;
-               }
-               clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
-       }
-
-       /* AC PDR should always ON */
-       clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
-                       0x1 << 1);
-
-       /* set DQS auto gating PD mode */
-       setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
-
-       if (socid == SOCID_H3) {
-               /* dx ddr_clk & hdr_clk dynamic mode */
-               clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
-
-               /* dphy & aphy phase select 270 degree */
-               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
-                               (0x1 << 10) | (0x2 << 8));
-       } else if (socid == SOCID_A64 || socid == SOCID_H5) {
-               /* dphy & aphy phase select ? */
-               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
-                               (0x0 << 10) | (0x3 << 8));
-       } else if (socid == SOCID_R40) {
-               /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
-               clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
-
-               /* dphy & aphy phase select ? */
-               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
-                               (0x0 << 10) | (0x3 << 8));
-       }
-
-       /* set half DQ */
-       if (para->bus_width != 32) {
-               writel(0x0, &mctl_ctl->dx[2].gcr);
-               writel(0x0, &mctl_ctl->dx[3].gcr);
-       }
-
-       /* data training configuration */
-       clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
-                       (para->dual_rank ? 0x3 : 0x1) << 24);
-
-       mctl_set_bit_delays(para);
-       udelay(50);
-
-       if (socid == SOCID_H3) {
-               mctl_h3_zq_calibration_quirk(para);
-
-               mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
-                             PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
-       } else if (socid == SOCID_A64 || socid == SOCID_H5) {
-               clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
-
-               mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
-                             PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
-               /* no PIR_QSGATE for H5 ???? */
-       } else if (socid == SOCID_R40) {
-               clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
-
-               mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
-                             PIR_DRAMRST | PIR_DRAMINIT);
-       }
-
-       /* detect ranks and bus width */
-       if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
-               /* only one rank */
-               if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) ||
-                   ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)) {
-                       clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
-                       para->dual_rank = 0;
-               }
-
-               /* only half DQ width */
-               if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
-                   ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
-                       writel(0x0, &mctl_ctl->dx[2].gcr);
-                       writel(0x0, &mctl_ctl->dx[3].gcr);
-                       para->bus_width = 16;
-               }
-
-               mctl_set_cr(socid, para);
-               udelay(20);
-
-               /* re-train */
-               mctl_phy_init(PIR_QSGATE);
-               if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
-                       return 1;
-       }
-
-       /* check the dramc status */
-       mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
-
-       /* liuke added for refresh debug */
-       setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
-       udelay(10);
-       clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
-       udelay(10);
-
-       /* set PGCR3, CKE polarity */
-       if (socid == SOCID_H3)
-               writel(0x00aa0060, &mctl_ctl->pgcr[3]);
-       else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
-               writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
-
-       /* power down zq calibration module for power save */
-       setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
-
-       /* enable master access */
-       writel(0xffffffff, &mctl_com->maer);
-
-       return 0;
-}
-
-static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
-{
-       /* detect row address bits */
-       para->page_size = 512;
-       para->row_bits = 16;
-       mctl_set_cr(socid, para);
-
-       for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
-               if (mctl_mem_matches((1 << (para->row_bits + 3)) * para->page_size))
-                       break;
-
-       /* detect page size */
-       para->page_size = 8192;
-       mctl_set_cr(socid, para);
-
-       for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
-               if (mctl_mem_matches(para->page_size))
-                       break;
-}
-
-/*
- * The actual values used here are taken from Allwinner provided boot0
- * binaries, though they are probably board specific, so would likely benefit
- * from invidual tuning for each board. Apparently a lot of boards copy from
- * some Allwinner reference design, so we go with those generic values for now
- * in the hope that they are reasonable for most (all?) boards.
- */
-#define SUN8I_H3_DX_READ_DELAYS                                        \
-       {{ 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },        \
-        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
-        { 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },        \
-        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 }}
-#define SUN8I_H3_DX_WRITE_DELAYS                               \
-       {{  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },        \
-        {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },        \
-        {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },        \
-        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  6 }}
-#define SUN8I_H3_AC_DELAYS                                     \
-       {  0,  0,  0,  0,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  0,  0,  0      }
-
-#define SUN8I_R40_DX_READ_DELAYS                               \
-       {{ 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
-        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
-        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
-        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 } }
-#define SUN8I_R40_DX_WRITE_DELAYS                              \
-       {{  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },        \
-        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },        \
-        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },        \
-        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 } }
-#define SUN8I_R40_AC_DELAYS                                    \
-       {  0,  0,  3,  0,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  0,  0,  0      }
-
-#define SUN50I_A64_DX_READ_DELAYS                              \
-       {{ 16, 16, 16, 16, 17, 16, 16, 17, 16,  1,  0 },        \
-        { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 },        \
-        { 16, 17, 17, 16, 16, 16, 16, 16, 16,  0,  0 },        \
-        { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 }}
-#define SUN50I_A64_DX_WRITE_DELAYS                             \
-       {{  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15 },        \
-        {  0,  0,  0,  0,  1,  1,  1,  1,  0, 10, 10 },        \
-        {  1,  0,  1,  1,  1,  1,  1,  1,  0, 11, 11 },        \
-        {  1,  0,  0,  1,  1,  1,  1,  1,  0, 12, 12 }}
-#define SUN50I_A64_AC_DELAYS                                   \
-       {  5,  5, 13, 10,  2,  5,  3,  3,                       \
-          0,  3,  3,  3,  1,  0,  0,  0,                       \
-          3,  4,  0,  3,  4,  1,  4,  0,                       \
-          1,  1,  0,  1, 13,  5,  4      }
-
-#define SUN8I_H5_DX_READ_DELAYS                                        \
-       {{ 14, 15, 17, 17, 17, 17, 17, 18, 17,  3,  3 },        \
-        { 21, 21, 12, 22, 21, 21, 21, 21, 21,  3,  3 },        \
-        { 16, 19, 19, 17, 22, 22, 21, 22, 19,  3,  3 },        \
-        { 21, 21, 22, 22, 20, 21, 19, 19, 19,  3,  3 } }
-#define SUN8I_H5_DX_WRITE_DELAYS                               \
-       {{  1,  2,  3,  4,  3,  4,  4,  4,  6,  6,  6 },        \
-        {  6,  6,  6,  5,  5,  5,  5,  5,  6,  6,  6 },        \
-        {  0,  2,  4,  2,  6,  5,  5,  5,  6,  6,  6 },        \
-        {  3,  3,  3,  2,  2,  1,  1,  1,  4,  4,  4 } }
-#define SUN8I_H5_AC_DELAYS                                     \
-       {  0,  0,  5,  5,  0,  0,  0,  0,                       \
-          0,  0,  0,  0,  3,  3,  3,  3,                       \
-          3,  3,  3,  3,  3,  3,  3,  3,                       \
-          3,  3,  3,  3,  2,  0,  0      }
-
-unsigned long sunxi_dram_init(void)
-{
-       struct sunxi_mctl_com_reg * const mctl_com =
-                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
-       struct sunxi_mctl_ctl_reg * const mctl_ctl =
-                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-
-       struct dram_para para = {
-               .dual_rank = 0,
-               .bus_width = 32,
-               .row_bits = 15,
-               .page_size = 4096,
-
-#if defined(CONFIG_MACH_SUN8I_H3)
-               .dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
-               .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
-               .ac_delays       = SUN8I_H3_AC_DELAYS,
-#elif defined(CONFIG_MACH_SUN8I_R40)
-               .dx_read_delays  = SUN8I_R40_DX_READ_DELAYS,
-               .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
-               .ac_delays       = SUN8I_R40_AC_DELAYS,
-#elif defined(CONFIG_MACH_SUN50I)
-               .dx_read_delays  = SUN50I_A64_DX_READ_DELAYS,
-               .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
-               .ac_delays       = SUN50I_A64_AC_DELAYS,
-#elif defined(CONFIG_MACH_SUN50I_H5)
-               .dx_read_delays  = SUN8I_H5_DX_READ_DELAYS,
-               .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
-               .ac_delays       = SUN8I_H5_AC_DELAYS,
-#endif
-       };
-/*
- * Let the compiler optimize alternatives away by passing this value into
- * the static functions. This saves us #ifdefs, but still keeps the binary
- * small.
- */
-#if defined(CONFIG_MACH_SUN8I_H3)
-       uint16_t socid = SOCID_H3;
-#elif defined(CONFIG_MACH_SUN8I_R40)
-       uint16_t socid = SOCID_R40;
-#elif defined(CONFIG_MACH_SUN50I)
-       uint16_t socid = SOCID_A64;
-#elif defined(CONFIG_MACH_SUN50I_H5)
-       uint16_t socid = SOCID_H5;
-#endif
-
-       mctl_sys_init(socid, &para);
-       if (mctl_channel_init(socid, &para))
-               return 0;
-
-       if (para.dual_rank)
-               writel(0x00000303, &mctl_ctl->odtmap);
-       else
-               writel(0x00000201, &mctl_ctl->odtmap);
-       udelay(1);
-
-       /* odt delay */
-       if (socid == SOCID_H3)
-               writel(0x0c000400, &mctl_ctl->odtcfg);
-
-       if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
-               /* VTF enable (tpr13[8] == 1) */
-               setbits_le32(&mctl_ctl->vtfcr,
-                            (socid != SOCID_A64 ? 3 : 2) << 8);
-               /* DQ hold disable (tpr13[26] == 1) */
-               clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
-       }
-
-       /* clear credit value */
-       setbits_le32(&mctl_com->cccr, 1 << 31);
-       udelay(10);
-
-       mctl_auto_detect_dram_size(socid, &para);
-       mctl_set_cr(socid, &para);
-
-       return (1UL << (para.row_bits + 3)) * para.page_size *
-                                               (para.dual_rank ? 2 : 1);
-}
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c
new file mode 100644 (file)
index 0000000..2d12661
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * sun8i H3 platform dram controller init
+ *
+ * (C) Copyright 2007-2015 Allwinner Technology Co.
+ *                         Jerry Wang <wangflord@allwinnertech.com>
+ * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
+ * (C) Copyright 2015      Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
+#include <linux/kconfig.h>
+
+/*
+ * The delay parameters below allow to allegedly specify delay times of some
+ * unknown unit for each individual bit trace in each of the four data bytes
+ * the 32-bit wide access consists of. Also three control signals can be
+ * adjusted individually.
+ */
+#define BITS_PER_BYTE          8
+#define NR_OF_BYTE_LANES       (32 / BITS_PER_BYTE)
+/* The eight data lines (DQn) plus DM, DQS and DQSN */
+#define LINES_PER_BYTE_LANE    (BITS_PER_BYTE + 3)
+struct dram_para {
+       u16 page_size;
+       u8 bus_width;
+       u8 dual_rank;
+       u8 row_bits;
+       const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
+       const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
+       const u8 ac_delays[31];
+};
+
+static inline int ns_to_t(int nanoseconds)
+{
+       const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
+
+       return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
+}
+
+static void mctl_phy_init(u32 val)
+{
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+       writel(val | PIR_INIT, &mctl_ctl->pir);
+       mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
+}
+
+static void mctl_set_bit_delays(struct dram_para *para)
+{
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+       int i, j;
+
+       clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
+
+       for (i = 0; i < NR_OF_BYTE_LANES; i++)
+               for (j = 0; j < LINES_PER_BYTE_LANE; j++)
+                       writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
+                              DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
+                              &mctl_ctl->dx[i].bdlr[j]);
+
+       for (i = 0; i < 31; i++)
+               writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
+                      &mctl_ctl->acbdlr[i]);
+
+#ifdef CONFIG_MACH_SUN8I_R40
+       /* DQSn, DMn, DQn output enable bit delay */
+       for (i = 0; i < 4; i++)
+               writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
+#endif
+
+       setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
+}
+
+enum {
+       MBUS_PORT_CPU           = 0,
+       MBUS_PORT_GPU           = 1,
+       MBUS_PORT_UNUSED        = 2,
+       MBUS_PORT_DMA           = 3,
+       MBUS_PORT_VE            = 4,
+       MBUS_PORT_CSI           = 5,
+       MBUS_PORT_NAND          = 6,
+       MBUS_PORT_SS            = 7,
+       MBUS_PORT_TS            = 8,
+       MBUS_PORT_DI            = 9,
+       MBUS_PORT_DE            = 10,
+       MBUS_PORT_DE_CFD        = 11,
+       MBUS_PORT_UNKNOWN1      = 12,
+       MBUS_PORT_UNKNOWN2      = 13,
+       MBUS_PORT_UNKNOWN3      = 14,
+};
+
+enum {
+       MBUS_QOS_LOWEST = 0,
+       MBUS_QOS_LOW,
+       MBUS_QOS_HIGH,
+       MBUS_QOS_HIGHEST
+};
+
+inline void mbus_configure_port(u8 port,
+                               bool bwlimit,
+                               bool priority,
+                               u8 qos,         /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
+                               u8 waittime,    /* 0 .. 0xf */
+                               u8 acs,         /* 0 .. 0xff */
+                               u16 bwl0,       /* 0 .. 0xffff, bandwidth limit in MB/s */
+                               u16 bwl1,
+                               u16 bwl2)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
+                          | (priority ? (1 << 1) : 0)
+                          | ((qos & 0x3) << 2)
+                          | ((waittime & 0xf) << 4)
+                          | ((acs & 0xff) << 8)
+                          | (bwl0 << 16) );
+       const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
+
+       debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
+       writel(cfg0, &mctl_com->mcr[port][0]);
+       writel(cfg1, &mctl_com->mcr[port][1]);
+}
+
+#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)   \
+       mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
+                           MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
+
+static void mctl_set_master_priority_h3(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       /* enable bandwidth limit windows and set windows size 1us */
+       writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
+
+       /* set cpu high priority */
+       writel(0x00000001, &mctl_com->mapr);
+
+       MBUS_CONF(   CPU,  true, HIGHEST, 0,  512,  256,  128);
+       MBUS_CONF(   GPU,  true,    HIGH, 0, 1536, 1024,  256);
+       MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
+       MBUS_CONF(   DMA,  true, HIGHEST, 0,  256,  128,   32);
+       MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
+       MBUS_CONF(   CSI,  true, HIGHEST, 0,  256,  128,   32);
+       MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
+       MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
+       MBUS_CONF(    DE,  true, HIGHEST, 3, 8192, 6120, 1024);
+       MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1024,  288,   64);
+}
+
+static void mctl_set_master_priority_a64(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       /* enable bandwidth limit windows and set windows size 1us */
+       writel(399, &mctl_com->tmr);
+       writel((1 << 16), &mctl_com->bwcr);
+
+       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
+        * initialise it */
+       MBUS_CONF(   CPU,  true, HIGHEST, 0,  160,  100,   80);
+       MBUS_CONF(   GPU, false,    HIGH, 0, 1536, 1400,  256);
+       MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
+       MBUS_CONF(   DMA,  true,    HIGH, 0,  256,   80,  100);
+       MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
+       MBUS_CONF(   CSI,  true,    HIGH, 0,  256,  128,    0);
+       MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
+       MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
+       MBUS_CONF(    DE,  true,    HIGH, 2, 8192, 6144, 2048);
+       MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1280,  144,   64);
+
+       writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
+}
+
+static void mctl_set_master_priority_h5(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       /* enable bandwidth limit windows and set windows size 1us */
+       writel(399, &mctl_com->tmr);
+       writel((1 << 16), &mctl_com->bwcr);
+
+       /* set cpu high priority */
+       writel(0x00000001, &mctl_com->mapr);
+
+       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
+        * they initialise it */
+       MBUS_CONF(   CPU, true, HIGHEST, 0,  300,  260,  150);
+       MBUS_CONF(   GPU, true, HIGHEST, 0,  600,  400,  200);
+       MBUS_CONF(UNUSED, true, HIGHEST, 0,  512,  256,   96);
+       MBUS_CONF(   DMA, true, HIGHEST, 0,  256,  128,   32);
+       MBUS_CONF(    VE, true, HIGHEST, 0, 1900, 1500, 1000);
+       MBUS_CONF(   CSI, true, HIGHEST, 0,  150,  120,  100);
+       MBUS_CONF(  NAND, true,    HIGH, 0,  256,  128,   64);
+       MBUS_CONF(    SS, true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    TS, true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    DI, true,    HIGH, 0, 1024,  256,   64);
+       MBUS_CONF(    DE, true, HIGHEST, 3, 3400, 2400, 1024);
+       MBUS_CONF(DE_CFD, true, HIGHEST, 0,  600,  400,  200);
+}
+
+static void mctl_set_master_priority_r40(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       /* enable bandwidth limit windows and set windows size 1us */
+       writel(399, &mctl_com->tmr);
+       writel((1 << 16), &mctl_com->bwcr);
+
+       /* set cpu high priority */
+       writel(0x00000001, &mctl_com->mapr);
+
+       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
+        * they initialise it */
+       MBUS_CONF(     CPU, true, HIGHEST, 0,  300,  260,  150);
+       MBUS_CONF(     GPU, true, HIGHEST, 0,  600,  400,  200);
+       MBUS_CONF(  UNUSED, true, HIGHEST, 0,  512,  256,   96);
+       MBUS_CONF(     DMA, true, HIGHEST, 0,  256,  128,   32);
+       MBUS_CONF(      VE, true, HIGHEST, 0, 1900, 1500, 1000);
+       MBUS_CONF(     CSI, true, HIGHEST, 0,  150,  120,  100);
+       MBUS_CONF(    NAND, true,    HIGH, 0,  256,  128,   64);
+       MBUS_CONF(      SS, true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(      TS, true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(      DI, true,    HIGH, 0, 1024,  256,   64);
+
+       /*
+        * The port names are probably wrong, but no correct sources
+        * are available.
+        */
+       MBUS_CONF(      DE, true,    HIGH, 0,  128,   48,    0);
+       MBUS_CONF(  DE_CFD, true,    HIGH, 0,  384,  256,    0);
+       MBUS_CONF(UNKNOWN1, true, HIGHEST, 0,  512,  384,  256);
+       MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
+       MBUS_CONF(UNKNOWN3, true,    HIGH, 0, 1280,  144,   64);
+}
+
+static void mctl_set_master_priority(uint16_t socid)
+{
+       switch (socid) {
+       case SOCID_H3:
+               mctl_set_master_priority_h3();
+               return;
+       case SOCID_A64:
+               mctl_set_master_priority_a64();
+               return;
+       case SOCID_H5:
+               mctl_set_master_priority_h5();
+               return;
+       case SOCID_R40:
+               mctl_set_master_priority_r40();
+               return;
+       }
+}
+
+static void mctl_set_timing_params(uint16_t socid, struct dram_para *para)
+{
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+       u8 tccd         = 2;
+       u8 tfaw         = ns_to_t(50);
+       u8 trrd         = max(ns_to_t(10), 4);
+       u8 trcd         = ns_to_t(15);
+       u8 trc          = ns_to_t(53);
+       u8 txp          = max(ns_to_t(8), 3);
+       u8 twtr         = max(ns_to_t(8), 4);
+       u8 trtp         = max(ns_to_t(8), 4);
+       u8 twr          = max(ns_to_t(15), 3);
+       u8 trp          = ns_to_t(15);
+       u8 tras         = ns_to_t(38);
+       u16 trefi       = ns_to_t(7800) / 32;
+       u16 trfc        = ns_to_t(350);
+
+       u8 tmrw         = 0;
+       u8 tmrd         = 4;
+       u8 tmod         = 12;
+       u8 tcke         = 3;
+       u8 tcksrx       = 5;
+       u8 tcksre       = 5;
+       u8 tckesr       = 4;
+       u8 trasmax      = 24;
+
+       u8 tcl          = 6; /* CL 12 */
+       u8 tcwl         = 4; /* CWL 8 */
+       u8 t_rdata_en   = 4;
+       u8 wr_latency   = 2;
+
+       u32 tdinit0     = (500 * CONFIG_DRAM_CLK) + 1;          /* 500us */
+       u32 tdinit1     = (360 * CONFIG_DRAM_CLK) / 1000 + 1;   /* 360ns */
+       u32 tdinit2     = (200 * CONFIG_DRAM_CLK) + 1;          /* 200us */
+       u32 tdinit3     = (1 * CONFIG_DRAM_CLK) + 1;            /* 1us */
+
+       u8 twtp         = tcwl + 2 + twr;       /* WL + BL / 2 + tWR */
+       u8 twr2rd       = tcwl + 2 + twtr;      /* WL + BL / 2 + tWTR */
+       u8 trd2wr       = tcl + 2 + 1 - tcwl;   /* RL + BL / 2 + 2 - WL */
+
+       /* set mode register */
+       writel(0x1c70, &mctl_ctl->mr[0]);       /* CL=11, WR=12 */
+       writel(0x40, &mctl_ctl->mr[1]);
+       writel(0x18, &mctl_ctl->mr[2]);         /* CWL=8 */
+       writel(0x0, &mctl_ctl->mr[3]);
+
+       if (socid == SOCID_R40)
+               writel(0x3, &mctl_ctl->lp3mr11);        /* odt_en[7:4] */
+
+       /* set DRAM timing */
+       writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) |
+              DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras),
+              &mctl_ctl->dramtmg[0]);
+       writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc),
+              &mctl_ctl->dramtmg[1]);
+       writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) |
+              DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd),
+              &mctl_ctl->dramtmg[2]);
+       writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod),
+              &mctl_ctl->dramtmg[3]);
+       writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) |
+              DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]);
+       writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) |
+              DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke),
+              &mctl_ctl->dramtmg[5]);
+
+       /* set two rank timing */
+       clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xff << 8) | (0xff << 0),
+                       ((socid == SOCID_H5 ? 0x33 : 0x66) << 8) | (0x10 << 0));
+
+       /* set PHY interface timing, write latency and read latency configure */
+       writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) |
+              (wr_latency << 0), &mctl_ctl->pitmg[0]);
+
+       /* set PHY timing, PTR0-2 use default */
+       writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]);
+       writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]);
+
+       /* set refresh timing */
+       writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg);
+}
+
+static u32 bin_to_mgray(int val)
+{
+       static const u8 lookup_table[32] = {
+               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
+               0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
+               0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
+               0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
+       };
+
+       return lookup_table[clamp(val, 0, 31)];
+}
+
+static int mgray_to_bin(u32 val)
+{
+       static const u8 lookup_table[32] = {
+               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
+               0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
+               0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
+               0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
+       };
+
+       return lookup_table[val & 0x1f];
+}
+
+static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
+{
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+       if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
+           (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
+               u32 reg_val;
+
+               clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
+                               CONFIG_DRAM_ZQ & 0xffff);
+
+               writel(PIR_CLRSR, &mctl_ctl->pir);
+               mctl_phy_init(PIR_ZCAL);
+
+               reg_val = readl(&mctl_ctl->zqdr[0]);
+               reg_val &= (0x1f << 16) | (0x1f << 0);
+               reg_val |= reg_val << 8;
+               writel(reg_val, &mctl_ctl->zqdr[0]);
+
+               reg_val = readl(&mctl_ctl->zqdr[1]);
+               reg_val &= (0x1f << 16) | (0x1f << 0);
+               reg_val |= reg_val << 8;
+               writel(reg_val, &mctl_ctl->zqdr[1]);
+               writel(reg_val, &mctl_ctl->zqdr[2]);
+       } else {
+               int i;
+               u16 zq_val[6];
+               u8 val;
+
+               writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
+
+               for (i = 0; i < 6; i++) {
+                       u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
+
+                       writel((zq << 20) | (zq << 16) | (zq << 12) |
+                                       (zq << 8) | (zq << 4) | (zq << 0),
+                                       &mctl_ctl->zqcr);
+
+                       writel(PIR_CLRSR, &mctl_ctl->pir);
+                       mctl_phy_init(PIR_ZCAL);
+
+                       zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
+                       writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
+
+                       writel(PIR_CLRSR, &mctl_ctl->pir);
+                       mctl_phy_init(PIR_ZCAL);
+
+                       val = readl(&mctl_ctl->zqdr[0]) >> 24;
+                       zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
+               }
+
+               writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
+               writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
+               writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]);
+       }
+}
+
+static void mctl_set_cr(uint16_t socid, struct dram_para *para)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED |
+              MCTL_CR_EIGHT_BANKS | MCTL_CR_BUS_WIDTH(para->bus_width) |
+              (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
+              MCTL_CR_PAGE_SIZE(para->page_size) |
+              MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
+
+       if (socid == SOCID_R40) {
+               if (para->dual_rank)
+                       panic("Dual rank memory not supported\n");
+
+               /* Mux pin to A15 address line for single rank memory. */
+               setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
+       }
+}
+
+static void mctl_sys_init(uint16_t socid, struct dram_para *para)
+{
+       struct sunxi_ccm_reg * const ccm =
+                       (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+       clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
+       clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
+       clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
+       clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
+       clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
+       if (socid == SOCID_A64 || socid == SOCID_R40)
+               clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
+       udelay(10);
+
+       clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
+       udelay(1000);
+
+       if (socid == SOCID_A64 || socid == SOCID_R40) {
+               clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
+               clrsetbits_le32(&ccm->dram_clk_cfg,
+                               CCM_DRAMCLK_CFG_DIV_MASK |
+                               CCM_DRAMCLK_CFG_SRC_MASK,
+                               CCM_DRAMCLK_CFG_DIV(1) |
+                               CCM_DRAMCLK_CFG_SRC_PLL11 |
+                               CCM_DRAMCLK_CFG_UPD);
+       } else if (socid == SOCID_H3 || socid == SOCID_H5) {
+               clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
+               clrsetbits_le32(&ccm->dram_clk_cfg,
+                               CCM_DRAMCLK_CFG_DIV_MASK |
+                               CCM_DRAMCLK_CFG_SRC_MASK,
+                               CCM_DRAMCLK_CFG_DIV(1) |
+                               CCM_DRAMCLK_CFG_SRC_PLL5 |
+                               CCM_DRAMCLK_CFG_UPD);
+       }
+       mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
+
+       setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
+       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
+       setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
+       setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
+
+       setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
+       udelay(10);
+
+       writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
+       udelay(500);
+}
+
+/* These are more guessed based on some Allwinner code. */
+#define DX_GCR_ODT_DYNAMIC     (0x0 << 4)
+#define DX_GCR_ODT_ALWAYS_ON   (0x1 << 4)
+#define DX_GCR_ODT_OFF         (0x2 << 4)
+
+static int mctl_channel_init(uint16_t socid, struct dram_para *para)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+       unsigned int i;
+
+       mctl_set_cr(socid, para);
+       mctl_set_timing_params(socid, para);
+       mctl_set_master_priority(socid);
+
+       /* setting VTC, default disable all VT */
+       clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
+       if (socid == SOCID_H5)
+               setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
+       else
+               clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
+
+       /* increase DFI_PHY_UPD clock */
+       writel(PROTECT_MAGIC, &mctl_com->protect);
+       udelay(100);
+       clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
+       writel(0x0, &mctl_com->protect);
+       udelay(100);
+
+       /* set dramc odt */
+       for (i = 0; i < 4; i++) {
+               u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
+                               (0x3 << 12) | (0x3 << 14);
+               u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
+                               DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
+
+               if (socid == SOCID_H5) {
+                       clearmask |= 0x2 << 8;
+                       setmask |= 0x4 << 8;
+               }
+               clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
+       }
+
+       /* AC PDR should always ON */
+       clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
+                       0x1 << 1);
+
+       /* set DQS auto gating PD mode */
+       setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
+
+       if (socid == SOCID_H3) {
+               /* dx ddr_clk & hdr_clk dynamic mode */
+               clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
+
+               /* dphy & aphy phase select 270 degree */
+               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
+                               (0x1 << 10) | (0x2 << 8));
+       } else if (socid == SOCID_A64 || socid == SOCID_H5) {
+               /* dphy & aphy phase select ? */
+               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
+                               (0x0 << 10) | (0x3 << 8));
+       } else if (socid == SOCID_R40) {
+               /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
+               clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
+
+               /* dphy & aphy phase select ? */
+               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
+                               (0x0 << 10) | (0x3 << 8));
+       }
+
+       /* set half DQ */
+       if (para->bus_width != 32) {
+               writel(0x0, &mctl_ctl->dx[2].gcr);
+               writel(0x0, &mctl_ctl->dx[3].gcr);
+       }
+
+       /* data training configuration */
+       clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
+                       (para->dual_rank ? 0x3 : 0x1) << 24);
+
+       mctl_set_bit_delays(para);
+       udelay(50);
+
+       if (socid == SOCID_H3) {
+               mctl_h3_zq_calibration_quirk(para);
+
+               mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
+                             PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
+       } else if (socid == SOCID_A64 || socid == SOCID_H5) {
+               clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
+
+               mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
+                             PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
+               /* no PIR_QSGATE for H5 ???? */
+       } else if (socid == SOCID_R40) {
+               clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
+
+               mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
+                             PIR_DRAMRST | PIR_DRAMINIT);
+       }
+
+       /* detect ranks and bus width */
+       if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
+               /* only one rank */
+               if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) ||
+                   ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)) {
+                       clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
+                       para->dual_rank = 0;
+               }
+
+               /* only half DQ width */
+               if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
+                   ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
+                       writel(0x0, &mctl_ctl->dx[2].gcr);
+                       writel(0x0, &mctl_ctl->dx[3].gcr);
+                       para->bus_width = 16;
+               }
+
+               mctl_set_cr(socid, para);
+               udelay(20);
+
+               /* re-train */
+               mctl_phy_init(PIR_QSGATE);
+               if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
+                       return 1;
+       }
+
+       /* check the dramc status */
+       mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
+
+       /* liuke added for refresh debug */
+       setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
+       udelay(10);
+       clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
+       udelay(10);
+
+       /* set PGCR3, CKE polarity */
+       if (socid == SOCID_H3)
+               writel(0x00aa0060, &mctl_ctl->pgcr[3]);
+       else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
+               writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
+
+       /* power down zq calibration module for power save */
+       setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
+
+       /* enable master access */
+       writel(0xffffffff, &mctl_com->maer);
+
+       return 0;
+}
+
+static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
+{
+       /* detect row address bits */
+       para->page_size = 512;
+       para->row_bits = 16;
+       mctl_set_cr(socid, para);
+
+       for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
+               if (mctl_mem_matches((1 << (para->row_bits + 3)) * para->page_size))
+                       break;
+
+       /* detect page size */
+       para->page_size = 8192;
+       mctl_set_cr(socid, para);
+
+       for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
+               if (mctl_mem_matches(para->page_size))
+                       break;
+}
+
+/*
+ * The actual values used here are taken from Allwinner provided boot0
+ * binaries, though they are probably board specific, so would likely benefit
+ * from invidual tuning for each board. Apparently a lot of boards copy from
+ * some Allwinner reference design, so we go with those generic values for now
+ * in the hope that they are reasonable for most (all?) boards.
+ */
+#define SUN8I_H3_DX_READ_DELAYS                                        \
+       {{ 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },        \
+        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
+        { 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },        \
+        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 }}
+#define SUN8I_H3_DX_WRITE_DELAYS                               \
+       {{  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },        \
+        {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },        \
+        {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },        \
+        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  6 }}
+#define SUN8I_H3_AC_DELAYS                                     \
+       {  0,  0,  0,  0,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  0,  0,  0      }
+
+#define SUN8I_R40_DX_READ_DELAYS                               \
+       {{ 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
+        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
+        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },        \
+        { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 } }
+#define SUN8I_R40_DX_WRITE_DELAYS                              \
+       {{  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },        \
+        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },        \
+        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },        \
+        {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 } }
+#define SUN8I_R40_AC_DELAYS                                    \
+       {  0,  0,  3,  0,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  0,  0,  0      }
+
+#define SUN50I_A64_DX_READ_DELAYS                              \
+       {{ 16, 16, 16, 16, 17, 16, 16, 17, 16,  1,  0 },        \
+        { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 },        \
+        { 16, 17, 17, 16, 16, 16, 16, 16, 16,  0,  0 },        \
+        { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 }}
+#define SUN50I_A64_DX_WRITE_DELAYS                             \
+       {{  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15 },        \
+        {  0,  0,  0,  0,  1,  1,  1,  1,  0, 10, 10 },        \
+        {  1,  0,  1,  1,  1,  1,  1,  1,  0, 11, 11 },        \
+        {  1,  0,  0,  1,  1,  1,  1,  1,  0, 12, 12 }}
+#define SUN50I_A64_AC_DELAYS                                   \
+       {  5,  5, 13, 10,  2,  5,  3,  3,                       \
+          0,  3,  3,  3,  1,  0,  0,  0,                       \
+          3,  4,  0,  3,  4,  1,  4,  0,                       \
+          1,  1,  0,  1, 13,  5,  4      }
+
+#define SUN8I_H5_DX_READ_DELAYS                                        \
+       {{ 14, 15, 17, 17, 17, 17, 17, 18, 17,  3,  3 },        \
+        { 21, 21, 12, 22, 21, 21, 21, 21, 21,  3,  3 },        \
+        { 16, 19, 19, 17, 22, 22, 21, 22, 19,  3,  3 },        \
+        { 21, 21, 22, 22, 20, 21, 19, 19, 19,  3,  3 } }
+#define SUN8I_H5_DX_WRITE_DELAYS                               \
+       {{  1,  2,  3,  4,  3,  4,  4,  4,  6,  6,  6 },        \
+        {  6,  6,  6,  5,  5,  5,  5,  5,  6,  6,  6 },        \
+        {  0,  2,  4,  2,  6,  5,  5,  5,  6,  6,  6 },        \
+        {  3,  3,  3,  2,  2,  1,  1,  1,  4,  4,  4 } }
+#define SUN8I_H5_AC_DELAYS                                     \
+       {  0,  0,  5,  5,  0,  0,  0,  0,                       \
+          0,  0,  0,  0,  3,  3,  3,  3,                       \
+          3,  3,  3,  3,  3,  3,  3,  3,                       \
+          3,  3,  3,  3,  2,  0,  0      }
+
+unsigned long sunxi_dram_init(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+       struct sunxi_mctl_ctl_reg * const mctl_ctl =
+                       (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+       struct dram_para para = {
+               .dual_rank = 0,
+               .bus_width = 32,
+               .row_bits = 15,
+               .page_size = 4096,
+
+#if defined(CONFIG_MACH_SUN8I_H3)
+               .dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
+               .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
+               .ac_delays       = SUN8I_H3_AC_DELAYS,
+#elif defined(CONFIG_MACH_SUN8I_R40)
+               .dx_read_delays  = SUN8I_R40_DX_READ_DELAYS,
+               .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
+               .ac_delays       = SUN8I_R40_AC_DELAYS,
+#elif defined(CONFIG_MACH_SUN50I)
+               .dx_read_delays  = SUN50I_A64_DX_READ_DELAYS,
+               .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
+               .ac_delays       = SUN50I_A64_AC_DELAYS,
+#elif defined(CONFIG_MACH_SUN50I_H5)
+               .dx_read_delays  = SUN8I_H5_DX_READ_DELAYS,
+               .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
+               .ac_delays       = SUN8I_H5_AC_DELAYS,
+#endif
+       };
+/*
+ * Let the compiler optimize alternatives away by passing this value into
+ * the static functions. This saves us #ifdefs, but still keeps the binary
+ * small.
+ */
+#if defined(CONFIG_MACH_SUN8I_H3)
+       uint16_t socid = SOCID_H3;
+#elif defined(CONFIG_MACH_SUN8I_R40)
+       uint16_t socid = SOCID_R40;
+#elif defined(CONFIG_MACH_SUN50I)
+       uint16_t socid = SOCID_A64;
+#elif defined(CONFIG_MACH_SUN50I_H5)
+       uint16_t socid = SOCID_H5;
+#endif
+
+       mctl_sys_init(socid, &para);
+       if (mctl_channel_init(socid, &para))
+               return 0;
+
+       if (para.dual_rank)
+               writel(0x00000303, &mctl_ctl->odtmap);
+       else
+               writel(0x00000201, &mctl_ctl->odtmap);
+       udelay(1);
+
+       /* odt delay */
+       if (socid == SOCID_H3)
+               writel(0x0c000400, &mctl_ctl->odtcfg);
+
+       if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
+               /* VTF enable (tpr13[8] == 1) */
+               setbits_le32(&mctl_ctl->vtfcr,
+                            (socid != SOCID_A64 ? 3 : 2) << 8);
+               /* DQ hold disable (tpr13[26] == 1) */
+               clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
+       }
+
+       /* clear credit value */
+       setbits_le32(&mctl_com->cccr, 1 << 31);
+       udelay(10);
+
+       mctl_auto_detect_dram_size(socid, &para);
+       mctl_set_cr(socid, &para);
+
+       return (1UL << (para.row_bits + 3)) * para.page_size *
+                                               (para.dual_rank ? 2 : 1);
+}