diff mbox

[U-Boot,13/14] sun8i: Add dram initialization support

Message ID 1418761900-14035-13-git-send-email-hdegoede@redhat.com
State Superseded
Delegated to: Ian Campbell
Headers show

Commit Message

Hans de Goede Dec. 16, 2014, 8:31 p.m. UTC
Based on the register / dram_para headers from the Allwinner u-boot / linux
sources + the init sequences from boot0.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
 arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
 arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
 arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
 arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
 board/sunxi/Kconfig                           |   3 +-
 configs/Ippo_q8h_v5_defconfig                 |  17 +-
 include/configs/sun8i.h                       |   2 +
 9 files changed, 631 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h

Comments

Chen-Yu Tsai Dec. 18, 2014, 11:12 a.m. UTC | #1
On Wed, Dec 17, 2014 at 4:31 AM, Hans de Goede <hdegoede@redhat.com> wrote:
> Based on the register / dram_para headers from the Allwinner u-boot / linux
> sources + the init sequences from boot0.
>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
>  arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
>  arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
>  arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
>  arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
>  board/sunxi/Kconfig                           |   3 +-
>  configs/Ippo_q8h_v5_defconfig                 |  17 +-
>  include/configs/sun8i.h                       |   2 +
>  9 files changed, 631 insertions(+), 7 deletions(-)
>  create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
>  create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h
>
> diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
> index 3e8975a..1e89937 100644
> --- a/arch/arm/cpu/armv7/sunxi/Makefile
> +++ b/arch/arm/cpu/armv7/sunxi/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)      += dram_sun4i.o
>  obj-$(CONFIG_MACH_SUN5I)       += dram_sun4i.o
>  obj-$(CONFIG_MACH_SUN6I)       += dram_sun6i.o
>  obj-$(CONFIG_MACH_SUN7I)       += dram_sun4i.o
> +obj-$(CONFIG_MACH_SUN8I)       += dram_sun8i.o
>  ifdef CONFIG_SPL_FEL
>  obj-y  += start.o
>  endif
> diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
> index 9b3e80c..bc98c56 100644
> --- a/arch/arm/cpu/armv7/sunxi/board.c
> +++ b/arch/arm/cpu/armv7/sunxi/board.c
> @@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
>  /* do some early init */
>  void s_init(void)
>  {
> -#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
> +#if defined CONFIG_SPL_BUILD && \
> +               (defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
>         /* Magic (undocmented) value taken from boot0, without this DRAM
>          * access gets messed up (seems cache related) */
>         setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
> diff --git a/arch/arm/cpu/armv7/sunxi/dram_sun8i.c b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
> new file mode 100644
> index 0000000..3736fd1
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
> @@ -0,0 +1,340 @@
> +/*
> + * Sun8i platform dram controller init.
> + *
> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +/*
> + * Note this code uses a lot of magic hex values, that is because this code
> + * simply replays the init sequence as done by the Allwinner boot0 code, so
> + * we do not know what these values mean. There are no symbolic constants for
> + * these magic values, since we do not know how to name them and making up
> + * names for them is not useful.
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <asm/io.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/dram.h>
> +#include <asm/arch/prcm.h>
> +
> +static const struct dram_para dram_para = {
> +       .clock = CONFIG_DRAM_CLK,
> +       .type = 3,
> +       .zq = CONFIG_DRAM_ZQ,
> +       .odt_en = 1,
> +       .para1 = 0, /* not used (only used when tpr13 bit 31 is set */
> +       .para2 = 0, /* not used (only used when tpr13 bit 31 is set */
> +       .mr0 = 6736,
> +       .mr1 = 4,
> +       .mr2 = 16,
> +       .mr3 = 0,
> +       /* tpr0 - 10 contain timing constants or-ed together in u32 vals */
> +       .tpr0 = 0x2ab83def,
> +       .tpr1 = 0x18082356,
> +       .tpr2 = 0x00034156,
> +       .tpr3 = 0x448c5533,
> +       .tpr4 = 0x08010d00,
> +       .tpr5 = 0x0340b20f,
> +       .tpr6 = 0x20d118cc,
> +       .tpr7 = 0x14062485,
> +       .tpr8 = 0x220d1d52,
> +       .tpr9 = 0x1e078c22,
> +       .tpr10 = 0x3c,
> +       .tpr11 = 0, /* not used */
> +       .tpr12 = 0, /* not used */
> +       .tpr13 = 0x30000,
> +};
> +
> +static void mctl_sys_init(void)
> +{
> +       struct sunxi_ccm_reg * const ccm =
> +               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +
> +       /* enable pll5, note the divide by 2 is deliberate! */
> +       clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
> +                      dram_para.tpr13 & 0x40000);
> +
> +       /* deassert ahb mctl reset */
> +       setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
> +
> +       /* enable ahb mctl clock */
> +       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
> +}
> +
> +static void mctl_apply_odt_correction(u32 *reg, int correction)
> +{
> +       int val;
> +
> +       val = (readl(reg) >> 8) & 0xff;
> +       val += correction;
> +
> +       /* clamp */
> +       if (val < 0)
> +               val = 0;
> +       else if (val > 255)
> +               val = 255;
> +
> +       clrsetbits_le32(reg, 0xff00, val << 8);
> +}
> +
> +static void mctl_init(u32 *bus_width)
> +{
> +       struct sunxi_ccm_reg * const ccm =
> +               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +       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 sunxi_mctl_phy_reg * const mctl_phy =
> +               (struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +       int correction;
> +
> +       if (dram_para.tpr13 & 0x20)
> +               writel(0x40b, &mctl_phy->dcr);
> +       else
> +               writel(0x1000040b, &mctl_phy->dcr);
> +
> +       if (dram_para.clock >= 480)
> +               writel(0x5c000, &mctl_phy->dllgcr);
> +       else
> +               writel(0xdc000, &mctl_phy->dllgcr);
> +
> +       writel(0x0a003e3f, &mctl_phy->pgcr0);
> +       writel(0x03008421, &mctl_phy->pgcr1);
> +
> +       writel(dram_para.mr0, &mctl_phy->mr0);
> +       writel(dram_para.mr1, &mctl_phy->mr1);
> +       writel(dram_para.mr2, &mctl_phy->mr2);
> +       writel(dram_para.mr3, &mctl_phy->mr3);
> +
> +       if (!(dram_para.tpr13 & 0x10000)) {
> +               clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
> +               clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
> +       }
> +
> +       /*
> +        * All the masking and shifting below converts what I assume are DDR
> +        * timing constants from Allwinner dram_para tpr format to the actual
> +        * timing registers format.
> +        */
> +
> +       writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
> +       writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
> +       writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
> +              (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
> +
> +       writel(dram_para.tpr3, &mctl_phy->dtpr0);
> +       writel(dram_para.tpr4, &mctl_phy->dtpr2);
> +
> +       writel(0x01000081, &mctl_phy->dtcr);
> +
> +       if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
> +               clrbits_le32(&mctl_phy->dx0gcr, 0x600);
> +               clrbits_le32(&mctl_phy->dx1gcr, 0x600);
> +       }
> +       if (dram_para.clock <= 240) {
> +               writel(0, &mctl_phy->odtcr);
> +               writel(0, &mctl_ctl->odtmap);
> +       }
> +
> +       writel(((dram_para.tpr5 & 0x0f00) << 12) |
> +              ((dram_para.tpr5 & 0x00f8) <<  9) |
> +              ((dram_para.tpr5 & 0x0007) <<  8),
> +              &mctl_ctl->rfshctl0);
> +
> +       writel(((dram_para.tpr5 & 0x0003f000) << 12) |
> +              ((dram_para.tpr5 & 0x00fc0000) >>  2) |
> +              ((dram_para.tpr5 & 0x3f000000) >> 16) |
> +              ((dram_para.tpr6 & 0x0000003f) >>  0),
> +              &mctl_ctl->dramtmg0);
> +
> +       writel(((dram_para.tpr6 & 0x000007c0) << 10) |
> +              ((dram_para.tpr6 & 0x0000f800) >> 3) |
> +              ((dram_para.tpr6 & 0x003f0000) >> 16),
> +              &mctl_ctl->dramtmg1);
> +
> +       writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
> +              ((dram_para.tpr7 & 0x0000001f) << 16) |
> +              ((dram_para.tpr7 & 0x000003e0) << 3) |
> +              ((dram_para.tpr7 & 0x0000fc00) >> 10),
> +              &mctl_ctl->dramtmg2);
> +
> +       writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
> +              ((dram_para.tpr6 & 0xf0000000) >> 16),
> +              &mctl_ctl->dramtmg3);
> +
> +       writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
> +              ((dram_para.tpr8 & 0x00000007) << 16) |
> +              ((dram_para.tpr8 & 0x00000038) << 5) |
> +              ((dram_para.tpr8 & 0x000003c0) >> 6),
> +              &mctl_ctl->dramtmg4);
> +
> +       writel(((dram_para.tpr8 & 0x00003c00) << 14) |
> +              ((dram_para.tpr8 & 0x0003c000) <<  2) |
> +              ((dram_para.tpr8 & 0x00fc0000) >> 10) |
> +              ((dram_para.tpr8 & 0x0f000000) >> 24),
> +              &mctl_ctl->dramtmg5);
> +
> +       writel(0x00000008, &mctl_ctl->dramtmg8);
> +
> +       writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
> +              ((dram_para.tpr9 & 0x00007c00) << 6) |
> +              ((dram_para.tpr9 & 0x000003e0) << 3) |
> +              ((dram_para.tpr9 & 0x0000001f) >> 0),
> +              &mctl_ctl->pitmg0);
> +
> +       setbits_le32(&mctl_ctl->pitmg1, 0x80000);
> +
> +       writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
> +              &mctl_ctl->sched);
> +
> +       writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
> +       writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
> +
> +       writel(0x00000000, &mctl_ctl->pimisc);
> +       writel(0x80000000, &mctl_ctl->upd0);
> +
> +       writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
> +              ((dram_para.tpr10 & 0x00000fff) << 16),
> +              &mctl_ctl->rfshtmg);
> +
> +       if (dram_para.tpr13 & 0x20)
> +               writel(0x01040001, &mctl_ctl->mstr);
> +       else
> +               writel(0x01040401, &mctl_ctl->mstr);
> +
> +       if (!(dram_para.tpr13 & 0x20000)) {
> +               writel(0x00000002, &mctl_ctl->pwrctl);
> +               writel(0x00008001, &mctl_ctl->pwrtmg);
> +       }
> +
> +       writel(0x00000001, &mctl_ctl->rfshctl3);
> +       writel(0x00000001, &mctl_ctl->pimisc);
> +
> +       /* deassert dram_clk_cfg reset */
> +       setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
> +
> +       setbits_le32(&mctl_com->ccr, 0x80000);
> +
> +       /* zq stuff */
> +       writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);
> +
> +       writel(0x00000003, &mctl_phy->pir);
> +       udelay(10);
> +       mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);
> +
> +       writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
> +       writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
> +
> +       /* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
> +       writel(0x000005f3, &mctl_phy->pir);
> +       udelay(10);
> +       mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
> +
> +       if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
> +               *bus_width = 8;
> +               writel(0, &mctl_phy->dx1gcr);
> +               writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
> +               writel(0x5f3, &mctl_phy->pir);
> +               udelay(10000);
> +               setbits_le32(&mctl_ctl->mstr, 0x1000);
> +       } else
> +               *bus_width = 16;
> +
> +       correction = (dram_para.odt_en >> 8) & 0xff;
> +       if (correction) {
> +               if (dram_para.odt_en & 0x80000000)
> +                       correction = -correction;
> +
> +               mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
> +               mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
> +       }
> +
> +       mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
> +
> +       writel(0x08003e3f, &mctl_phy->pgcr0);
> +       writel(0x00000000, &mctl_ctl->rfshctl3);
> +}
> +
> +unsigned long sunxi_dram_init(void)
> +{
> +       struct sunxi_mctl_com_reg * const mctl_com =
> +               (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +       const u32 columns = 13;
> +       u32 bus, bus_width, offset, page_size, rows;
> +
> +       mctl_sys_init();
> +       mctl_init(&bus_width);
> +
> +       if (bus_width == 16) {
> +               page_size = 8;
> +               bus = 1;
> +       } else {
> +               page_size = 7;
> +               bus = 0;
> +       }
> +
> +       if (!(dram_para.tpr13 & 0x80000000)) {
> +               /* Detect and set rows */
> +               writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
> +                      &mctl_com->cr);
> +               setbits_le32(&mctl_com->swonr, 0x0003ffff);
> +               mctl_mem_fill();
> +               for (rows = 11; rows < 16; rows++) {
> +                       offset = 1 << (rows + columns + bus);
> +                       if (mctl_mem_matches(offset))
> +                               break;
> +               }
> +               clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
> +                               MCTL_CR_ROW(rows));
> +       } else {
> +               rows = (dram_para.para1 >> 16) & 0xff;
> +               writel(((dram_para.para2 & 0x000000f0) << 11) |
> +                      ((rows - 1) << 4) |
> +                      ((dram_para.para1 & 0x0f000000) >> 22) |
> +                      0x31000 | MCTL_CR_PAGE_SIZE(page_size),
> +                      &mctl_com->cr);
> +               setbits_le32(&mctl_com->swonr, 0x0003ffff);
> +       }
> +
> +       /* Setup DRAM master priority? If this is left out things still work */
> +       writel(0x00000008, &mctl_com->mcr0_0);
> +       writel(0x0001000d, &mctl_com->mcr1_0);
> +       writel(0x00000004, &mctl_com->mcr0_1);
> +       writel(0x00000080, &mctl_com->mcr1_1);
> +       writel(0x00000004, &mctl_com->mcr0_2);
> +       writel(0x00000019, &mctl_com->mcr1_2);
> +       writel(0x00000004, &mctl_com->mcr0_3);
> +       writel(0x00000080, &mctl_com->mcr1_3);
> +       writel(0x00000004, &mctl_com->mcr0_4);
> +       writel(0x01010040, &mctl_com->mcr1_4);
> +       writel(0x00000004, &mctl_com->mcr0_5);
> +       writel(0x0001002f, &mctl_com->mcr1_5);
> +       writel(0x00000004, &mctl_com->mcr0_6);
> +       writel(0x00010020, &mctl_com->mcr1_6);
> +       writel(0x00000004, &mctl_com->mcr0_7);
> +       writel(0x00010020, &mctl_com->mcr1_7);
> +       writel(0x00000008, &mctl_com->mcr0_8);
> +       writel(0x00000001, &mctl_com->mcr1_8);
> +       writel(0x00000008, &mctl_com->mcr0_9);
> +       writel(0x00000005, &mctl_com->mcr1_9);
> +       writel(0x00000008, &mctl_com->mcr0_10);
> +       writel(0x00000003, &mctl_com->mcr1_10);
> +       writel(0x00000008, &mctl_com->mcr0_11);
> +       writel(0x00000005, &mctl_com->mcr1_11);
> +       writel(0x00000008, &mctl_com->mcr0_12);
> +       writel(0x00000003, &mctl_com->mcr1_12);
> +       writel(0x00000008, &mctl_com->mcr0_13);
> +       writel(0x00000004, &mctl_com->mcr1_13);
> +       writel(0x00000008, &mctl_com->mcr0_14);
> +       writel(0x00000002, &mctl_com->mcr1_14);
> +       writel(0x00000008, &mctl_com->mcr0_15);
> +       writel(0x00000003, &mctl_com->mcr1_15);
> +       writel(0x00010138, &mctl_com->bwcr);
> +
> +       return 1 << (rows + columns + bus);
> +}
> diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
> index 7d61216..45a199c 100644
> --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
> +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
> @@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
>  #define CCM_HDMI_CTRL_DDC_GATE         (0x1 << 30)
>  #define CCM_HDMI_CTRL_GATE             (0x1 << 31)
>
> +#ifndef CONFIG_MACH_SUN8I
>  #define MBUS_CLK_DEFAULT               0x81000001 /* PLL6 / 2 */
> +#else
> +#define MBUS_CLK_DEFAULT               0x81000003 /* PLL6 / 4 */
> +#endif
>
>  #define CCM_PLL5_PATTERN               0xd1303333
>
> diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
> index a8a37d5..8d78029 100644
> --- a/arch/arm/include/asm/arch-sunxi/dram.h
> +++ b/arch/arm/include/asm/arch-sunxi/dram.h
> @@ -18,6 +18,8 @@
>  /* dram regs definition */
>  #if defined(CONFIG_MACH_SUN6I)
>  #include <asm/arch/dram_sun6i.h>
> +#elif defined(CONFIG_MACH_SUN8I)
> +#include <asm/arch/dram_sun8i.h>
>  #else
>  #include <asm/arch/dram_sun4i.h>
>  #endif
> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
> new file mode 100644
> index 0000000..425cf37
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
> @@ -0,0 +1,266 @@
> +/*
> + * Sun8i platform dram controller register and constant defines
> + *
> + * (C) Copyright 2007-2013
> + * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
> + * CPL <cplanxy@allwinnertech.com>
> + * Jerry Wang <wangflord@allwinnertech.com>
> + *
> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef _SUNXI_DRAM_SUN8I_H
> +#define _SUNXI_DRAM_SUN8I_H
> +
> +struct dram_para {
> +       u32 clock;
> +       u32 type;
> +       u32 zq;
> +       u32 odt_en;
> +       u32 para1;
> +       u32 para2;
> +       u32 mr0;
> +       u32 mr1;
> +       u32 mr2;
> +       u32 mr3;
> +       u32 tpr0;
> +       u32 tpr1;
> +       u32 tpr2;
> +       u32 tpr3;
> +       u32 tpr4;
> +       u32 tpr5;
> +       u32 tpr6;
> +       u32 tpr7;
> +       u32 tpr8;
> +       u32 tpr9;
> +       u32 tpr10;
> +       u32 tpr11;
> +       u32 tpr12;
> +       u32 tpr13;
> +};
> +
> +struct sunxi_mctl_com_reg {
> +       u32 cr;                 /* 0x00 */
> +       u32 ccr;                /* 0x04 controller configuration register */
> +       u32 dbgcr;              /* 0x08 */
> +       u8 res0[0x4];           /* 0x0c */
> +       u32 mcr0_0;             /* 0x10 */
> +       u32 mcr1_0;             /* 0x14 */
> +       u32 mcr0_1;             /* 0x18 */
> +       u32 mcr1_1;             /* 0x1c */
> +       u32 mcr0_2;             /* 0x20 */
> +       u32 mcr1_2;             /* 0x24 */
> +       u32 mcr0_3;             /* 0x28 */
> +       u32 mcr1_3;             /* 0x2c */
> +       u32 mcr0_4;             /* 0x30 */
> +       u32 mcr1_4;             /* 0x34 */
> +       u32 mcr0_5;             /* 0x38 */
> +       u32 mcr1_5;             /* 0x3c */
> +       u32 mcr0_6;             /* 0x40 */
> +       u32 mcr1_6;             /* 0x44 */
> +       u32 mcr0_7;             /* 0x48 */
> +       u32 mcr1_7;             /* 0x4c */
> +       u32 mcr0_8;             /* 0x50 */
> +       u32 mcr1_8;             /* 0x54 */
> +       u32 mcr0_9;             /* 0x58 */
> +       u32 mcr1_9;             /* 0x5c */
> +       u32 mcr0_10;            /* 0x60 */
> +       u32 mcr1_10;            /* 0x64 */
> +       u32 mcr0_11;            /* 0x68 */
> +       u32 mcr1_11;            /* 0x6c */
> +       u32 mcr0_12;            /* 0x70 */
> +       u32 mcr1_12;            /* 0x74 */
> +       u32 mcr0_13;            /* 0x78 */
> +       u32 mcr1_13;            /* 0x7c */
> +       u32 mcr0_14;            /* 0x80 */
> +       u32 mcr1_14;            /* 0x84 */
> +       u32 mcr0_15;            /* 0x88 */
> +       u32 mcr1_15;            /* 0x8c */
> +       u32 bwcr;               /* 0x90 */
> +       u32 maer;               /* 0x94 */
> +       u8 res1[0x4];           /* 0x98 */
> +       u32 mcgcr;              /* 0x9c */
> +       u32 bwctr;              /* 0xa0 */
> +       u8 res2[0x4];           /* 0xa4 */
> +       u32 swonr;              /* 0xa8 */
> +       u32 swoffr;             /* 0xac */
> +};
> +
> +struct sunxi_mctl_ctl_reg {
> +       u32 mstr;               /* 0x00 */
> +       u32 statr;              /* 0x04 */
> +       u8 res0[0x08];          /* 0x08 */
> +       u32 mrctrl0;            /* 0x10 */
> +       u32 mrctrl1;            /* 0x14 */
> +       u32 mrstatr;            /* 0x18 */
> +       u8 res1[0x04];          /* 0x1c */
> +       u32 derateen;           /* 0x20 */
> +       u32 deratenint;         /* 0x24 */
> +       u8 res2[0x08];          /* 0x28 */
> +       u32 pwrctl;             /* 0x30 */
> +       u32 pwrtmg;             /* 0x34 */
> +       u8 res3[0x18];          /* 0x38 */
> +       u32 rfshctl0;           /* 0x50 */
> +       u32 rfshctl1;           /* 0x54 */
> +       u8 res4[0x8];           /* 0x58 */
> +       u32 rfshctl3;           /* 0x60 */
> +       u32 rfshtmg;            /* 0x64 */
> +       u8 res6[0x68];          /* 0x68 */
> +       u32 init0;              /* 0xd0 */
> +       u32 init1;              /* 0xd4 */
> +       u32 init2;              /* 0xd8 */
> +       u32 init3;              /* 0xdc */
> +       u32 init4;              /* 0xe0 */
> +       u32 init5;              /* 0xe4 */
> +       u8 res7[0x0c];          /* 0xe8 */
> +       u32 rankctl;            /* 0xf4 */
> +       u8 res8[0x08];          /* 0xf8 */
> +       u32 dramtmg0;           /* 0x100 */
> +       u32 dramtmg1;           /* 0x104 */
> +       u32 dramtmg2;           /* 0x108 */
> +       u32 dramtmg3;           /* 0x10c */
> +       u32 dramtmg4;           /* 0x110 */
> +       u32 dramtmg5;           /* 0x114 */
> +       u32 dramtmg6;           /* 0x118 */
> +       u32 dramtmg7;           /* 0x11c */
> +       u32 dramtmg8;           /* 0x120 */
> +       u8 res9[0x5c];          /* 0x124 */
> +       u32 zqctl0;             /* 0x180 */
> +       u32 zqctl1;             /* 0x184 */
> +       u32 zqctl2;             /* 0x188 */
> +       u32 zqstat;             /* 0x18c */
> +       u32 pitmg0;             /* 0x190 */
> +       u32 pitmg1;             /* 0x194 */
> +       u32 plpcfg0;            /* 0x198 */
> +       u8 res10[0x04];         /* 0x19c */
> +       u32 upd0;               /* 0x1a0 */
> +       u32 upd1;               /* 0x1a4 */
> +       u32 upd2;               /* 0x1a8 */
> +       u32 upd3;               /* 0x1ac */
> +       u32 pimisc;             /* 0x1b0 */
> +       u8 res11[0x1c];         /* 0x1b4 */
> +       u32 trainctl0;          /* 0x1d0 */
> +       u32 trainctl1;          /* 0x1d4 */
> +       u32 trainctl2;          /* 0x1d8 */
> +       u32 trainstat;          /* 0x1dc */
> +       u8 res12[0x60];         /* 0x1e0 */
> +       u32 odtcfg;             /* 0x240 */
> +       u32 odtmap;             /* 0x244 */
> +       u8 res13[0x08];         /* 0x248 */
> +       u32 sched;              /* 0x250 */
> +       u8 res14[0x04];         /* 0x254 */
> +       u32 perfshpr0;          /* 0x258 */
> +       u32 perfshpr1;          /* 0x25c */
> +       u32 perflpr0;           /* 0x260 */
> +       u32 perflpr1;           /* 0x264 */
> +       u32 perfwr0;            /* 0x268 */
> +       u32 perfwr1;            /* 0x26c */
> +};
> +
> +struct sunxi_mctl_phy_reg {
> +       u8 res0[0x04];          /* 0x00 */
> +       u32 pir;                /* 0x04 */
> +       u32 pgcr0;              /* 0x08 phy general configuration register */
> +       u32 pgcr1;              /* 0x0c phy general configuration register */
> +       u32 pgsr0;              /* 0x10 */
> +       u32 pgsr1;              /* 0x14 */
> +       u32 dllgcr;             /* 0x18 */
> +       u32 ptr0;               /* 0x1c */
> +       u32 ptr1;               /* 0x20 */
> +       u32 ptr2;               /* 0x24 */
> +       u32 ptr3;               /* 0x28 */
> +       u32 ptr4;               /* 0x2c */
> +       u32 acmdlr;             /* 0x30 */
> +       u32 acbdlr;             /* 0x34 */
> +       u32 aciocr;             /* 0x38 */
> +       u32 dxccr;              /* 0x3c DATX8 common configuration register */
> +       u32 dsgcr;              /* 0x40 dram system general config register */
> +       u32 dcr;                /* 0x44 */
> +       u32 dtpr0;              /* 0x48 dram timing parameters register 0 */
> +       u32 dtpr1;              /* 0x4c dram timing parameters register 1 */
> +       u32 dtpr2;              /* 0x50 dram timing parameters register 2 */
> +       u32 mr0;                /* 0x54 mode register 0 */
> +       u32 mr1;                /* 0x58 mode register 1 */
> +       u32 mr2;                /* 0x5c mode register 2 */
> +       u32 mr3;                /* 0x60 mode register 3 */
> +       u32 odtcr;              /* 0x64 */
> +       u32 dtcr;               /* 0x68 */
> +       u32 dtar0;              /* 0x6c data training address register 0 */
> +       u32 dtar1;              /* 0x70 data training address register 1 */
> +       u32 dtar2;              /* 0x74 data training address register 2 */
> +       u32 dtar3;              /* 0x78 data training address register 3 */
> +       u32 dtdr0;              /* 0x7c */
> +       u32 dtdr1;              /* 0x80 */
> +       u32 dtedr0;             /* 0x84 */
> +       u32 dtedr1;             /* 0x88 */
> +       u32 pgcr2;              /* 0x8c */
> +       u8 res1[0x70];          /* 0x90 */
> +       u32 bistrr;             /* 0x100 */
> +       u32 bistwcr;            /* 0x104 */
> +       u32 bistmskr0;          /* 0x108 */
> +       u32 bistmskr1;          /* 0x10c */
> +       u32 bistmskr2;          /* 0x110 */
> +       u32 bistlsr;            /* 0x114 */
> +       u32 bistar0;            /* 0x118 */
> +       u32 bistar1;            /* 0x11c */
> +       u32 bistar2;            /* 0x120 */
> +       u32 bistupdr;           /* 0x124 */
> +       u32 bistgsr;            /* 0x128 */
> +       u32 bistwer;            /* 0x12c */
> +       u32 bistber0;           /* 0x130 */
> +       u32 bistber1;           /* 0x134 */
> +       u32 bistber2;           /* 0x138 */
> +       u32 bistber3;           /* 0x13c */
> +       u32 bistwcsr;           /* 0x140 */
> +       u32 bistfwr0;           /* 0x144 */
> +       u32 bistfwr1;           /* 0x148 */
> +       u32 bistfwr2;           /* 0x14c */
> +       u8 res2[0x30];          /* 0x150 */
> +       u32 zqcr0;              /* 0x180 zq control register 0 */
> +       u32 zqcr1;              /* 0x184 zq control register 1 */
> +       u32 zqsr0;              /* 0x188 zq status register 0 */
> +       u32 zqsr1;              /* 0x18c zq status register 1 */
> +       u32 zqcr2;              /* 0x190 zq control register 2 */
> +       u8 res3[0x2c];          /* 0x194 */
> +       u32 dx0gcr;             /* 0x1c0 */
> +       u32 dx0gsr0;            /* 0x1c4 */
> +       u32 dx0gsr1;            /* 0x1c8 */
> +       u32 dx0bdlr0;           /* 0x1cc */
> +       u32 dx0bdlr1;           /* 0x1d0 */
> +       u32 dx0bdlr2;           /* 0x1d4 */
> +       u32 dx0bdlr3;           /* 0x1d8 */
> +       u32 dx0bdlr4;           /* 0x1dc */
> +       u32 dx0lcdlr0;          /* 0x1e0 */
> +       u32 dx0lcdlr1;          /* 0x1e4 */
> +       u32 dx0lcdlr2;          /* 0x1e8 */
> +       u32 dx0mdlr;            /* 0x1ec */
> +       u32 dx0gtr;             /* 0x1f0 */
> +       u32 dx0gsr2;            /* 0x1f4 */
> +       u8 res4[0x08];          /* 0x1f8 */
> +       u32 dx1gcr;             /* 0x200 */
> +       u32 dx1gsr0;            /* 0x204 */
> +       u32 dx1gsr1;            /* 0x208 */
> +       u32 dx1bdlr0;           /* 0x20c */
> +       u32 dx1bdlr1;           /* 0x210 */
> +       u32 dx1bdlr2;           /* 0x214 */
> +       u32 dx1bdlr3;           /* 0x218 */
> +       u32 dx1bdlr4;           /* 0x21c */
> +       u32 dx1lcdlr0;          /* 0x220 */
> +       u32 dx1lcdlr1;          /* 0x224 */
> +       u32 dx1lcdlr2;          /* 0x228 */
> +       u32 dx1mdlr;            /* 0x22c */
> +       u32 dx1gtr;             /* 0x230 */
> +       u32 dx1gsr2;            /* 0x234 */
> +};
> +
> +/*
> + * DRAM common (sunxi_mctl_com_reg) register constants.
> + */
> +#define MCTL_CR_ROW_MASK               (0xf << 4)
> +#define MCTL_CR_ROW(x)                 (((x) - 1) << 4)
> +#define MCTL_CR_PAGE_SIZE_MASK         (0xf << 8)
> +#define MCTL_CR_PAGE_SIZE(x)           ((x) << 8)
> +
> +#endif /* _SUNXI_DRAM_SUN8I_H */
> diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
> index 5bb2f58..5a88ba0 100644
> --- a/board/sunxi/Kconfig
> +++ b/board/sunxi/Kconfig
> @@ -29,10 +29,11 @@ config MACH_SUN7I
>  config MACH_SUN8I
>         bool "sun8i (Allwinner A23)"
>         select CPU_V7
> +       select SUPPORT_SPL
>
>  endchoice
>
> -if MACH_SUN6I
> +if MACH_SUN6I || MACH_SUN8I
>
>  config DRAM_CLK
>         int "sun6i dram clock speed"
> diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
> index 50c2f93..37aa46d 100644
> --- a/configs/Ippo_q8h_v5_defconfig
> +++ b/configs/Ippo_q8h_v5_defconfig
> @@ -1,8 +1,15 @@
> +CONFIG_SPL=y
>  CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
> -CONFIG_ARM=y
> -CONFIG_ARCH_SUNXI=y
> -CONFIG_MACH_SUN8I=y
> -CONFIG_TARGET_IPPO_Q8H_V5=y
> -CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
> +CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
>  CONFIG_VIDEO=n
>  CONFIG_USB_KEYBOARD=n
> ++S:CONFIG_ARM=y
> ++S:CONFIG_ARCH_SUNXI=y
> ++S:CONFIG_MACH_SUN8I=y
> ++S:CONFIG_DRAM_CLK=480
> +# zq = 0xf777
> ++S:CONFIG_DRAM_ZQ=63351
> +# Wifi power
> ++S:CONFIG_AXP221_DLDO1_VOLT=3300
> +# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
> ++S:CONFIG_AXP221_ALDO1_VOLT=3000
> diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h
> index 6f1fc48..792422d 100644
> --- a/include/configs/sun8i.h
> +++ b/include/configs/sun8i.h
> @@ -12,6 +12,8 @@
>  /*
>   * A23 specific configuration
>   */
> +#define CONFIG_CLK_FULL_SPEED  1008000000
> +
>  #define CONFIG_SYS_PROMPT      "sun8i# "
>
>  /*
> --
> 2.1.0

git am reports:

Applying patch #422080 using 'git am'
Description: [U-Boot,13/14] sun8i: Add dram initialization support
Applying: sun8i: Add dram initialization support
/home/wens/sunxi/u-boot/.git/rebase-apply/patch:201: trailing whitespace.
        writel(((dram_para.tpr6 & 0x000007c0) << 10) |
/home/wens/sunxi/u-boot/.git/rebase-apply/patch:455: space before tab in indent.
        u32 tpr6;
warning: 2 lines add whitespace errors.

---

I forgot to send out this one. Anyway, I've tested the series on
my A23 tablet and it's working fine. Something in linux-next broke
my system though.


ChenYu
Ian Campbell Dec. 18, 2014, 7:17 p.m. UTC | #2
On Tue, 2014-12-16 at 21:31 +0100, Hans de Goede wrote:
> Based on the register / dram_para headers from the Allwinner u-boot / linux
> sources + the init sequences from boot0.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> +/*
> + * Note this code uses a lot of magic hex values, that is because this code
> + * simply replays the init sequence as done by the Allwinner boot0 code, so
> + * we do not know what these values mean. There are no symbolic constants for
> + * these magic values, since we do not know how to name them and making up
> + * names for them is not useful.

On that basis I've only really given this a quick glance. I've no
problem with it.

Couple of queries about the defconfig changes:

> diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
> index 50c2f93..37aa46d 100644
> --- a/configs/Ippo_q8h_v5_defconfig
> +++ b/configs/Ippo_q8h_v5_defconfig
> @@ -1,8 +1,15 @@
> +CONFIG_SPL=y
>  CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
> -CONFIG_ARM=y
> -CONFIG_ARCH_SUNXI=y
> -CONFIG_MACH_SUN8I=y
> -CONFIG_TARGET_IPPO_Q8H_V5=y

Not replaced with a S: variant? I know you want CONFIG_TARGET to go, but
I don't think that was part of what you intended in this patch.

> -CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
> +CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"

The switch from CONFIG_DEFAULT_DEVICE_TREE to CONFIG_FDTFILE conversion
seems a little out of place too.

Ian.
Siarhei Siamashka Dec. 19, 2014, 10:20 a.m. UTC | #3
On Tue, 16 Dec 2014 21:31:38 +0100
Hans de Goede <hdegoede@redhat.com> wrote:

> Based on the register / dram_para headers from the Allwinner u-boot / linux
> sources + the init sequences from boot0.

Can the commit message have more detailed information about the precise
location of the original Allwinner code, which was used as the
reference?

> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
>  arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
>  arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
>  arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
>  arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
>  board/sunxi/Kconfig                           |   3 +-
>  configs/Ippo_q8h_v5_defconfig                 |  17 +-
>  include/configs/sun8i.h                       |   2 +
>  9 files changed, 631 insertions(+), 7 deletions(-)
>  create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
>  create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h
> 
> diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
> index 3e8975a..1e89937 100644
> --- a/arch/arm/cpu/armv7/sunxi/Makefile
> +++ b/arch/arm/cpu/armv7/sunxi/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i.o
>  obj-$(CONFIG_MACH_SUN5I)	+= dram_sun4i.o
>  obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
>  obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
> +obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
>  ifdef CONFIG_SPL_FEL
>  obj-y	+= start.o
>  endif
> diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
> index 9b3e80c..bc98c56 100644
> --- a/arch/arm/cpu/armv7/sunxi/board.c
> +++ b/arch/arm/cpu/armv7/sunxi/board.c
> @@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
>  /* do some early init */
>  void s_init(void)
>  {
> -#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
> +#if defined CONFIG_SPL_BUILD && \
> +		(defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
>  	/* Magic (undocmented) value taken from boot0, without this DRAM
>  	 * access gets messed up (seems cache related) */
>  	setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
> diff --git a/arch/arm/cpu/armv7/sunxi/dram_sun8i.c b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
> new file mode 100644
> index 0000000..3736fd1
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
> @@ -0,0 +1,340 @@
> +/*
> + * Sun8i platform dram controller init.
> + *
> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>

Is Allwinner copyright really not necessary here?

> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +/*
> + * Note this code uses a lot of magic hex values, that is because this code
> + * simply replays the init sequence as done by the Allwinner boot0 code, so
> + * we do not know what these values mean. There are no symbolic constants for
> + * these magic values, since we do not know how to name them and making up
> + * names for them is not useful.
> + */

You are well aware of this documentation since a long time ago, right?
   http://www.ti.com/lit/ug/spruhn7a/spruhn7a.pdf

Please open it and find "Table4-2 DDR3 PHY Registers". Then have a
look at the "sunxi_mctl_phy_reg" struct from your patch. Compare
the register names and their offsets. Looks like we are reasonably
lucky again.

Just as an example, I have commented about a few hardware registers
at different locations in the code.

> +#include <common.h>
> +#include <errno.h>
> +#include <asm/io.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/dram.h>
> +#include <asm/arch/prcm.h>
> +
> +static const struct dram_para dram_para = {
> +	.clock = CONFIG_DRAM_CLK,
> +	.type = 3,
> +	.zq = CONFIG_DRAM_ZQ,
> +	.odt_en = 1,
> +	.para1 = 0, /* not used (only used when tpr13 bit 31 is set */
> +	.para2 = 0, /* not used (only used when tpr13 bit 31 is set */
> +	.mr0 = 6736,
> +	.mr1 = 4,
> +	.mr2 = 16,
> +	.mr3 = 0,
> +	/* tpr0 - 10 contain timing constants or-ed together in u32 vals */
> +	.tpr0 = 0x2ab83def,
> +	.tpr1 = 0x18082356,
> +	.tpr2 = 0x00034156,
> +	.tpr3 = 0x448c5533,
> +	.tpr4 = 0x08010d00,
> +	.tpr5 = 0x0340b20f,
> +	.tpr6 = 0x20d118cc,
> +	.tpr7 = 0x14062485,
> +	.tpr8 = 0x220d1d52,
> +	.tpr9 = 0x1e078c22,
> +	.tpr10 = 0x3c,
> +	.tpr11 = 0, /* not used */
> +	.tpr12 = 0, /* not used */
> +	.tpr13 = 0x30000,
> +};
> +
> +static void mctl_sys_init(void)
> +{
> +	struct sunxi_ccm_reg * const ccm =
> +		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +
> +	/* enable pll5, note the divide by 2 is deliberate! */
> +	clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
> +		       dram_para.tpr13 & 0x40000);

Is it really necessary to have the PLL5 setup so complicated and full
of magic?

> +
> +	/* deassert ahb mctl reset */
> +	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
> +
> +	/* enable ahb mctl clock */
> +	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
> +}
> +
> +static void mctl_apply_odt_correction(u32 *reg, int correction)
> +{
> +	int val;
> +
> +	val = (readl(reg) >> 8) & 0xff;
> +	val += correction;
> +
> +	/* clamp */
> +	if (val < 0)
> +		val = 0;
> +	else if (val > 255)
> +		val = 255;
> +
> +	clrsetbits_le32(reg, 0xff00, val << 8);
> +}
> +
> +static void mctl_init(u32 *bus_width)
> +{
> +	struct sunxi_ccm_reg * const ccm =
> +		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +	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 sunxi_mctl_phy_reg * const mctl_phy =
> +		(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +	int correction;
> +
> +	if (dram_para.tpr13 & 0x20)
> +		writel(0x40b, &mctl_phy->dcr);

The bits 2-0 are DDRMR (DDR Mode), and the value 3 means DDR3.
And 0x40b is actually the default reset value of this register
according to the TI Keystone2 documentation.

> +	else
> +		writel(0x1000040b, &mctl_phy->dcr);

The bit 28 is marked as reserved and "Reads return zeros" in the
TI Keystone2 documentation. It's a nice chance to test whether
this write has any effect and whether it does modify the register.

> +
> +	if (dram_para.clock >= 480)
> +		writel(0x5c000, &mctl_phy->dllgcr);

0x5c000 = (1 << 18) | (0xE << 13)

> +	else
> +		writel(0xdc000, &mctl_phy->dllgcr);

0xdc000 = (3 << 18) | (0xE << 13)

The 'dllgcr' has the same offset as "4.40 PLL Control Register (PLLCR)"
in the TI Keystone2 documentation.

Bits 16-13 are CPPC (Charge Pump Proportional Current Control) with the
default value 0xE, which matches what we see here.

Bits 19-18 are FRQSEL:
 01 = PLL reference clock (ctl_clk/REF_CLK) ranges from 225MHz to 385MHz
 11 = PLL reference clock (ctl_clk/REF_CLK) ranges from 166MHz to 275MHz

> +
> +	writel(0x0a003e3f, &mctl_phy->pgcr0);
> +	writel(0x03008421, &mctl_phy->pgcr1);
> +
> +	writel(dram_para.mr0, &mctl_phy->mr0);
> +	writel(dram_para.mr1, &mctl_phy->mr1);
> +	writel(dram_para.mr2, &mctl_phy->mr2);
> +	writel(dram_para.mr3, &mctl_phy->mr3);
> +
> +	if (!(dram_para.tpr13 & 0x10000)) {
> +		clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
> +		clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
> +	}
> +
> +	/*
> +	 * All the masking and shifting below converts what I assume are DDR
> +	 * timing constants from Allwinner dram_para tpr format to the actual
> +	 * timing registers format.
> +	 */
> +
> +	writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
> +	writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
> +	writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
> +	       (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
> +
> +	writel(dram_para.tpr3, &mctl_phy->dtpr0);
> +	writel(dram_para.tpr4, &mctl_phy->dtpr2);
> +
> +	writel(0x01000081, &mctl_phy->dtcr);
> +
> +	if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
> +		clrbits_le32(&mctl_phy->dx0gcr, 0x600);
> +		clrbits_le32(&mctl_phy->dx1gcr, 0x600);
> +	}
> +	if (dram_para.clock <= 240) {
> +		writel(0, &mctl_phy->odtcr);
> +		writel(0, &mctl_ctl->odtmap);
> +	}
> +
> +	writel(((dram_para.tpr5 & 0x0f00) << 12) |
> +	       ((dram_para.tpr5 & 0x00f8) <<  9) |
> +	       ((dram_para.tpr5 & 0x0007) <<  8),
> +	       &mctl_ctl->rfshctl0);
> +
> +	writel(((dram_para.tpr5 & 0x0003f000) << 12) |
> +	       ((dram_para.tpr5 & 0x00fc0000) >>  2) |
> +	       ((dram_para.tpr5 & 0x3f000000) >> 16) |
> +	       ((dram_para.tpr6 & 0x0000003f) >>  0),
> +	       &mctl_ctl->dramtmg0);
> +
> +	writel(((dram_para.tpr6 & 0x000007c0) << 10) | 
> +	       ((dram_para.tpr6 & 0x0000f800) >> 3) |
> +	       ((dram_para.tpr6 & 0x003f0000) >> 16),
> +	       &mctl_ctl->dramtmg1);
> +
> +	writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
> +	       ((dram_para.tpr7 & 0x0000001f) << 16) |
> +	       ((dram_para.tpr7 & 0x000003e0) << 3) |
> +	       ((dram_para.tpr7 & 0x0000fc00) >> 10),
> +	       &mctl_ctl->dramtmg2);
> +
> +	writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
> +	       ((dram_para.tpr6 & 0xf0000000) >> 16),
> +	       &mctl_ctl->dramtmg3);
> +
> +	writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
> +	       ((dram_para.tpr8 & 0x00000007) << 16) |
> +	       ((dram_para.tpr8 & 0x00000038) << 5) |
> +	       ((dram_para.tpr8 & 0x000003c0) >> 6),
> +	       &mctl_ctl->dramtmg4);
> +
> +	writel(((dram_para.tpr8 & 0x00003c00) << 14) |
> +	       ((dram_para.tpr8 & 0x0003c000) <<  2) |
> +	       ((dram_para.tpr8 & 0x00fc0000) >> 10) |
> +	       ((dram_para.tpr8 & 0x0f000000) >> 24),
> +	       &mctl_ctl->dramtmg5);
> +
> +	writel(0x00000008, &mctl_ctl->dramtmg8);
> +
> +	writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
> +	       ((dram_para.tpr9 & 0x00007c00) << 6) |
> +	       ((dram_para.tpr9 & 0x000003e0) << 3) |
> +	       ((dram_para.tpr9 & 0x0000001f) >> 0),
> +	       &mctl_ctl->pitmg0);

Could there be any purpose for this other than obfuscation? Looks
really strange.

> +
> +	setbits_le32(&mctl_ctl->pitmg1, 0x80000);
> +
> +	writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
> +	       &mctl_ctl->sched);
> +
> +	writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
> +	writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
> +
> +	writel(0x00000000, &mctl_ctl->pimisc);
> +	writel(0x80000000, &mctl_ctl->upd0);
> +
> +	writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
> +	       ((dram_para.tpr10 & 0x00000fff) << 16),
> +	       &mctl_ctl->rfshtmg);
> +
> +	if (dram_para.tpr13 & 0x20)
> +		writel(0x01040001, &mctl_ctl->mstr);
> +	else
> +		writel(0x01040401, &mctl_ctl->mstr);
> +
> +	if (!(dram_para.tpr13 & 0x20000)) {
> +		writel(0x00000002, &mctl_ctl->pwrctl);
> +		writel(0x00008001, &mctl_ctl->pwrtmg);
> +	}
> +
> +	writel(0x00000001, &mctl_ctl->rfshctl3);
> +	writel(0x00000001, &mctl_ctl->pimisc);
> +
> +	/* deassert dram_clk_cfg reset */
> +	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
> +
> +	setbits_le32(&mctl_com->ccr, 0x80000);
> +
> +	/* zq stuff */
> +	writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);

4.59 Impedance Control Register 1 (ZQnCR1)

Bits 7-0 - ZPROG (Impedance Divide Ratio), reset value 0x7B

> +	writel(0x00000003, &mctl_phy->pir);

4.34 PHY Initialization Register (PIR)

Bit 0 - INIT
Bit 1 - ZCAL

> +	udelay(10);
> +	mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);

4.38 PHY General Status Register 0 (PGSR0)

Bit 0 - IDONE (Initialization Done)
Bit 3 - ZCDONE (Impedance Calibration Done)

> +	writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
> +	writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);

Overwriting ZPROG again? Is it doing something reasonable?
Or might it be an attempt to hide data from the tools like
a10-meminfo (which can dump the DRAM setting via /dev/mem)?

> +	/* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
> +	writel(0x000005f3, &mctl_phy->pir);
> +	udelay(10);
> +	mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
> +
> +	if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
> +		*bus_width = 8;
> +		writel(0, &mctl_phy->dx1gcr);
> +		writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
> +		writel(0x5f3, &mctl_phy->pir);
> +		udelay(10000);
> +		setbits_le32(&mctl_ctl->mstr, 0x1000);
> +	} else
> +		*bus_width = 16;
> +
> +	correction = (dram_para.odt_en >> 8) & 0xff;
> +	if (correction) {
> +		if (dram_para.odt_en & 0x80000000)
> +			correction = -correction;
> +
> +		mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
> +		mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
> +	}
> +
> +	mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
> +
> +	writel(0x08003e3f, &mctl_phy->pgcr0);
> +	writel(0x00000000, &mctl_ctl->rfshctl3);
> +}
> +
> +unsigned long sunxi_dram_init(void)
> +{
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +		(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +	const u32 columns = 13;
> +	u32 bus, bus_width, offset, page_size, rows;
> +
> +	mctl_sys_init();
> +	mctl_init(&bus_width);
> +
> +	if (bus_width == 16) {
> +		page_size = 8;
> +		bus = 1;
> +	} else {
> +		page_size = 7;
> +		bus = 0;
> +	}
> +
> +	if (!(dram_para.tpr13 & 0x80000000)) {
> +		/* Detect and set rows */
> +		writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
> +		       &mctl_com->cr);
> +		setbits_le32(&mctl_com->swonr, 0x0003ffff);
> +		mctl_mem_fill();
> +		for (rows = 11; rows < 16; rows++) {
> +			offset = 1 << (rows + columns + bus);
> +			if (mctl_mem_matches(offset))
> +				break;
> +		}
> +		clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
> +				MCTL_CR_ROW(rows));
> +	} else {
> +		rows = (dram_para.para1 >> 16) & 0xff;
> +		writel(((dram_para.para2 & 0x000000f0) << 11) |
> +		       ((rows - 1) << 4) |
> +		       ((dram_para.para1 & 0x0f000000) >> 22) |
> +		       0x31000 | MCTL_CR_PAGE_SIZE(page_size),
> +		       &mctl_com->cr);
> +		setbits_le32(&mctl_com->swonr, 0x0003ffff);
> +	}
> +
> +	/* Setup DRAM master priority? If this is left out things still work */
> +	writel(0x00000008, &mctl_com->mcr0_0);
> +	writel(0x0001000d, &mctl_com->mcr1_0);
> +	writel(0x00000004, &mctl_com->mcr0_1);
> +	writel(0x00000080, &mctl_com->mcr1_1);
> +	writel(0x00000004, &mctl_com->mcr0_2);
> +	writel(0x00000019, &mctl_com->mcr1_2);
> +	writel(0x00000004, &mctl_com->mcr0_3);
> +	writel(0x00000080, &mctl_com->mcr1_3);
> +	writel(0x00000004, &mctl_com->mcr0_4);
> +	writel(0x01010040, &mctl_com->mcr1_4);
> +	writel(0x00000004, &mctl_com->mcr0_5);
> +	writel(0x0001002f, &mctl_com->mcr1_5);
> +	writel(0x00000004, &mctl_com->mcr0_6);
> +	writel(0x00010020, &mctl_com->mcr1_6);
> +	writel(0x00000004, &mctl_com->mcr0_7);
> +	writel(0x00010020, &mctl_com->mcr1_7);
> +	writel(0x00000008, &mctl_com->mcr0_8);
> +	writel(0x00000001, &mctl_com->mcr1_8);
> +	writel(0x00000008, &mctl_com->mcr0_9);
> +	writel(0x00000005, &mctl_com->mcr1_9);
> +	writel(0x00000008, &mctl_com->mcr0_10);
> +	writel(0x00000003, &mctl_com->mcr1_10);
> +	writel(0x00000008, &mctl_com->mcr0_11);
> +	writel(0x00000005, &mctl_com->mcr1_11);
> +	writel(0x00000008, &mctl_com->mcr0_12);
> +	writel(0x00000003, &mctl_com->mcr1_12);
> +	writel(0x00000008, &mctl_com->mcr0_13);
> +	writel(0x00000004, &mctl_com->mcr1_13);
> +	writel(0x00000008, &mctl_com->mcr0_14);
> +	writel(0x00000002, &mctl_com->mcr1_14);
> +	writel(0x00000008, &mctl_com->mcr0_15);
> +	writel(0x00000003, &mctl_com->mcr1_15);
> +	writel(0x00010138, &mctl_com->bwcr);
> +
> +	return 1 << (rows + columns + bus);
> +}
> diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
> index 7d61216..45a199c 100644
> --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
> +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
> @@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
>  #define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
>  #define CCM_HDMI_CTRL_GATE		(0x1 << 31)
>  
> +#ifndef CONFIG_MACH_SUN8I
>  #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
> +#else
> +#define MBUS_CLK_DEFAULT		0x81000003 /* PLL6 / 4 */
> +#endif
>  
>  #define CCM_PLL5_PATTERN		0xd1303333
>  
> diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
> index a8a37d5..8d78029 100644
> --- a/arch/arm/include/asm/arch-sunxi/dram.h
> +++ b/arch/arm/include/asm/arch-sunxi/dram.h
> @@ -18,6 +18,8 @@
>  /* dram regs definition */
>  #if defined(CONFIG_MACH_SUN6I)
>  #include <asm/arch/dram_sun6i.h>
> +#elif defined(CONFIG_MACH_SUN8I)
> +#include <asm/arch/dram_sun8i.h>
>  #else
>  #include <asm/arch/dram_sun4i.h>
>  #endif
> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
> new file mode 100644
> index 0000000..425cf37
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
> @@ -0,0 +1,266 @@
> +/*
> + * Sun8i platform dram controller register and constant defines
> + *
> + * (C) Copyright 2007-2013
> + * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
> + * CPL <cplanxy@allwinnertech.com>
> + * Jerry Wang <wangflord@allwinnertech.com>
> + *
> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _SUNXI_DRAM_SUN8I_H
> +#define _SUNXI_DRAM_SUN8I_H
> +
> +struct dram_para {
> +	u32 clock;
> +	u32 type;
> +	u32 zq;
> +	u32 odt_en;
> +	u32 para1;
> +	u32 para2;
> +	u32 mr0;
> +	u32 mr1;
> +	u32 mr2;
> +	u32 mr3;
> +	u32 tpr0;
> +	u32 tpr1;
> +	u32 tpr2;
> +	u32 tpr3;
> +	u32 tpr4;
> +	u32 tpr5;
> +   	u32 tpr6;
> +	u32 tpr7;
> +	u32 tpr8;
> +	u32 tpr9;
> +	u32 tpr10;
> +	u32 tpr11;
> +	u32 tpr12;
> +	u32 tpr13;
> +};
> +
> +struct sunxi_mctl_com_reg {
> +	u32 cr;			/* 0x00 */
> +	u32 ccr;		/* 0x04 controller configuration register */
> +	u32 dbgcr;		/* 0x08 */
> +	u8 res0[0x4];		/* 0x0c */
> +	u32 mcr0_0;		/* 0x10 */
> +	u32 mcr1_0;		/* 0x14 */
> +	u32 mcr0_1;		/* 0x18 */
> +	u32 mcr1_1;		/* 0x1c */
> +	u32 mcr0_2;		/* 0x20 */
> +	u32 mcr1_2;		/* 0x24 */
> +	u32 mcr0_3;		/* 0x28 */
> +	u32 mcr1_3;		/* 0x2c */
> +	u32 mcr0_4;		/* 0x30 */
> +	u32 mcr1_4;		/* 0x34 */
> +	u32 mcr0_5;		/* 0x38 */
> +	u32 mcr1_5;		/* 0x3c */
> +	u32 mcr0_6;		/* 0x40 */
> +	u32 mcr1_6;		/* 0x44 */
> +	u32 mcr0_7;		/* 0x48 */
> +	u32 mcr1_7;		/* 0x4c */
> +	u32 mcr0_8;		/* 0x50 */
> +	u32 mcr1_8;		/* 0x54 */
> +	u32 mcr0_9;		/* 0x58 */
> +	u32 mcr1_9;		/* 0x5c */
> +	u32 mcr0_10;		/* 0x60 */
> +	u32 mcr1_10;		/* 0x64 */
> +	u32 mcr0_11;		/* 0x68 */
> +	u32 mcr1_11;		/* 0x6c */
> +	u32 mcr0_12;		/* 0x70 */
> +	u32 mcr1_12;		/* 0x74 */
> +	u32 mcr0_13;		/* 0x78 */
> +	u32 mcr1_13;		/* 0x7c */
> +	u32 mcr0_14;		/* 0x80 */
> +	u32 mcr1_14;		/* 0x84 */
> +	u32 mcr0_15;		/* 0x88 */
> +	u32 mcr1_15;		/* 0x8c */
> +	u32 bwcr;		/* 0x90 */
> +	u32 maer;		/* 0x94 */
> +	u8 res1[0x4];		/* 0x98 */
> +	u32 mcgcr;		/* 0x9c */
> +	u32 bwctr;		/* 0xa0 */
> +	u8 res2[0x4];		/* 0xa4 */
> +	u32 swonr;		/* 0xa8 */
> +	u32 swoffr;		/* 0xac */
> +};
> +
> +struct sunxi_mctl_ctl_reg {
> +	u32 mstr;		/* 0x00 */
> +	u32 statr;		/* 0x04 */
> +	u8 res0[0x08];		/* 0x08 */
> +	u32 mrctrl0;		/* 0x10 */
> +	u32 mrctrl1;		/* 0x14 */
> +	u32 mrstatr;		/* 0x18 */
> +	u8 res1[0x04];		/* 0x1c */
> +	u32 derateen;		/* 0x20 */
> +	u32 deratenint;		/* 0x24 */
> +	u8 res2[0x08];		/* 0x28 */
> +	u32 pwrctl;		/* 0x30 */
> +	u32 pwrtmg;		/* 0x34 */
> +	u8 res3[0x18];		/* 0x38 */
> +	u32 rfshctl0;		/* 0x50 */
> +	u32 rfshctl1;		/* 0x54 */
> +	u8 res4[0x8];		/* 0x58 */
> +	u32 rfshctl3;		/* 0x60 */
> +	u32 rfshtmg;		/* 0x64 */
> +	u8 res6[0x68];		/* 0x68 */
> +	u32 init0;		/* 0xd0 */
> +	u32 init1;		/* 0xd4 */
> +	u32 init2;		/* 0xd8 */
> +	u32 init3;		/* 0xdc */
> +	u32 init4;		/* 0xe0 */
> +	u32 init5;		/* 0xe4 */
> +	u8 res7[0x0c];		/* 0xe8 */
> +	u32 rankctl;		/* 0xf4 */
> +	u8 res8[0x08];		/* 0xf8 */
> +	u32 dramtmg0;		/* 0x100 */
> +	u32 dramtmg1;		/* 0x104 */
> +	u32 dramtmg2;		/* 0x108 */
> +	u32 dramtmg3;		/* 0x10c */
> +	u32 dramtmg4;		/* 0x110 */
> +	u32 dramtmg5;		/* 0x114 */
> +	u32 dramtmg6;		/* 0x118 */
> +	u32 dramtmg7;		/* 0x11c */
> +	u32 dramtmg8;		/* 0x120 */
> +	u8 res9[0x5c];		/* 0x124 */
> +	u32 zqctl0;		/* 0x180 */
> +	u32 zqctl1;		/* 0x184 */
> +	u32 zqctl2;		/* 0x188 */
> +	u32 zqstat;		/* 0x18c */
> +	u32 pitmg0;		/* 0x190 */
> +	u32 pitmg1;		/* 0x194 */
> +	u32 plpcfg0;		/* 0x198 */
> +	u8 res10[0x04];		/* 0x19c */
> +	u32 upd0;		/* 0x1a0 */
> +	u32 upd1;		/* 0x1a4 */
> +	u32 upd2;		/* 0x1a8 */
> +	u32 upd3;		/* 0x1ac */
> +	u32 pimisc;		/* 0x1b0 */
> +	u8 res11[0x1c];		/* 0x1b4 */
> +	u32 trainctl0;		/* 0x1d0 */
> +	u32 trainctl1;		/* 0x1d4 */
> +	u32 trainctl2;		/* 0x1d8 */
> +	u32 trainstat;		/* 0x1dc */
> +	u8 res12[0x60];		/* 0x1e0 */
> +	u32 odtcfg;		/* 0x240 */
> +	u32 odtmap;		/* 0x244 */
> +	u8 res13[0x08];		/* 0x248 */
> +	u32 sched;		/* 0x250 */
> +	u8 res14[0x04];		/* 0x254 */
> +	u32 perfshpr0;		/* 0x258 */
> +	u32 perfshpr1;		/* 0x25c */
> +	u32 perflpr0;		/* 0x260 */
> +	u32 perflpr1;		/* 0x264 */
> +	u32 perfwr0;		/* 0x268 */
> +	u32 perfwr1;		/* 0x26c */
> +};
> +
> +struct sunxi_mctl_phy_reg {
> +	u8 res0[0x04];		/* 0x00 */
> +	u32 pir;		/* 0x04 */
> +	u32 pgcr0;		/* 0x08 phy general configuration register */
> +	u32 pgcr1;		/* 0x0c phy general configuration register */
> +	u32 pgsr0;		/* 0x10 */
> +	u32 pgsr1;		/* 0x14 */
> +	u32 dllgcr;		/* 0x18 */
> +	u32 ptr0;		/* 0x1c */
> +	u32 ptr1;		/* 0x20 */
> +	u32 ptr2;		/* 0x24 */
> +	u32 ptr3;		/* 0x28 */
> +	u32 ptr4;		/* 0x2c */
> +	u32 acmdlr;		/* 0x30 */
> +	u32 acbdlr;		/* 0x34 */
> +	u32 aciocr;		/* 0x38 */
> +	u32 dxccr;		/* 0x3c DATX8 common configuration register */
> +	u32 dsgcr;		/* 0x40 dram system general config register */
> +	u32 dcr;		/* 0x44 */
> +	u32 dtpr0;		/* 0x48 dram timing parameters register 0 */
> +	u32 dtpr1;		/* 0x4c dram timing parameters register 1 */
> +	u32 dtpr2;		/* 0x50 dram timing parameters register 2 */
> +	u32 mr0;		/* 0x54 mode register 0 */
> +	u32 mr1;		/* 0x58 mode register 1 */
> +	u32 mr2;		/* 0x5c mode register 2 */
> +	u32 mr3;		/* 0x60 mode register 3 */
> +	u32 odtcr;		/* 0x64 */
> +	u32 dtcr;		/* 0x68 */
> +	u32 dtar0;		/* 0x6c data training address register 0 */
> +	u32 dtar1;		/* 0x70 data training address register 1 */
> +	u32 dtar2;		/* 0x74 data training address register 2 */
> +	u32 dtar3;		/* 0x78 data training address register 3 */
> +	u32 dtdr0;		/* 0x7c */
> +	u32 dtdr1;		/* 0x80 */
> +	u32 dtedr0;		/* 0x84 */
> +	u32 dtedr1;		/* 0x88 */
> +	u32 pgcr2;		/* 0x8c */
> +	u8 res1[0x70];		/* 0x90 */
> +	u32 bistrr;		/* 0x100 */
> +	u32 bistwcr;		/* 0x104 */
> +	u32 bistmskr0;		/* 0x108 */
> +	u32 bistmskr1;		/* 0x10c */
> +	u32 bistmskr2;		/* 0x110 */
> +	u32 bistlsr;		/* 0x114 */
> +	u32 bistar0;		/* 0x118 */
> +	u32 bistar1;		/* 0x11c */
> +	u32 bistar2;		/* 0x120 */
> +	u32 bistupdr;		/* 0x124 */
> +	u32 bistgsr;		/* 0x128 */
> +	u32 bistwer;		/* 0x12c */
> +	u32 bistber0;		/* 0x130 */
> +	u32 bistber1;		/* 0x134 */
> +	u32 bistber2;		/* 0x138 */
> +	u32 bistber3;		/* 0x13c */
> +	u32 bistwcsr;		/* 0x140 */
> +	u32 bistfwr0;		/* 0x144 */
> +	u32 bistfwr1;		/* 0x148 */
> +	u32 bistfwr2;		/* 0x14c */
> +	u8 res2[0x30];		/* 0x150 */
> +	u32 zqcr0;		/* 0x180 zq control register 0 */
> +	u32 zqcr1;		/* 0x184 zq control register 1 */
> +	u32 zqsr0;		/* 0x188 zq status register 0 */
> +	u32 zqsr1;		/* 0x18c zq status register 1 */
> +	u32 zqcr2;		/* 0x190 zq control register 2 */
> +	u8 res3[0x2c];		/* 0x194 */
> +	u32 dx0gcr;		/* 0x1c0 */
> +	u32 dx0gsr0;		/* 0x1c4 */
> +	u32 dx0gsr1;		/* 0x1c8 */
> +	u32 dx0bdlr0;		/* 0x1cc */
> +	u32 dx0bdlr1;		/* 0x1d0 */
> +	u32 dx0bdlr2;		/* 0x1d4 */
> +	u32 dx0bdlr3;		/* 0x1d8 */
> +	u32 dx0bdlr4;		/* 0x1dc */
> +	u32 dx0lcdlr0;		/* 0x1e0 */
> +	u32 dx0lcdlr1;		/* 0x1e4 */
> +	u32 dx0lcdlr2;		/* 0x1e8 */
> +	u32 dx0mdlr;		/* 0x1ec */
> +	u32 dx0gtr;		/* 0x1f0 */
> +	u32 dx0gsr2;		/* 0x1f4 */
> +	u8 res4[0x08];		/* 0x1f8 */
> +	u32 dx1gcr;		/* 0x200 */
> +	u32 dx1gsr0;		/* 0x204 */
> +	u32 dx1gsr1;		/* 0x208 */
> +	u32 dx1bdlr0;		/* 0x20c */
> +	u32 dx1bdlr1;		/* 0x210 */
> +	u32 dx1bdlr2;		/* 0x214 */
> +	u32 dx1bdlr3;		/* 0x218 */
> +	u32 dx1bdlr4;		/* 0x21c */
> +	u32 dx1lcdlr0;		/* 0x220 */
> +	u32 dx1lcdlr1;		/* 0x224 */
> +	u32 dx1lcdlr2;		/* 0x228 */
> +	u32 dx1mdlr;		/* 0x22c */
> +	u32 dx1gtr;		/* 0x230 */
> +	u32 dx1gsr2;		/* 0x234 */
> +};
> +
> +/*
> + * DRAM common (sunxi_mctl_com_reg) register constants.
> + */
> +#define MCTL_CR_ROW_MASK		(0xf << 4)
> +#define MCTL_CR_ROW(x)			(((x) - 1) << 4)
> +#define MCTL_CR_PAGE_SIZE_MASK		(0xf << 8)
> +#define MCTL_CR_PAGE_SIZE(x)		((x) << 8)
> +
> +#endif /* _SUNXI_DRAM_SUN8I_H */
> diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
> index 5bb2f58..5a88ba0 100644
> --- a/board/sunxi/Kconfig
> +++ b/board/sunxi/Kconfig
> @@ -29,10 +29,11 @@ config MACH_SUN7I
>  config MACH_SUN8I
>  	bool "sun8i (Allwinner A23)"
>  	select CPU_V7
> +	select SUPPORT_SPL
>  
>  endchoice
>  
> -if MACH_SUN6I
> +if MACH_SUN6I || MACH_SUN8I
>  
>  config DRAM_CLK
>  	int "sun6i dram clock speed"
> diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
> index 50c2f93..37aa46d 100644
> --- a/configs/Ippo_q8h_v5_defconfig
> +++ b/configs/Ippo_q8h_v5_defconfig
> @@ -1,8 +1,15 @@
> +CONFIG_SPL=y
>  CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
> -CONFIG_ARM=y
> -CONFIG_ARCH_SUNXI=y
> -CONFIG_MACH_SUN8I=y
> -CONFIG_TARGET_IPPO_Q8H_V5=y
> -CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
> +CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
>  CONFIG_VIDEO=n
>  CONFIG_USB_KEYBOARD=n
> ++S:CONFIG_ARM=y
> ++S:CONFIG_ARCH_SUNXI=y
> ++S:CONFIG_MACH_SUN8I=y
> ++S:CONFIG_DRAM_CLK=480
> +# zq = 0xf777
> ++S:CONFIG_DRAM_ZQ=63351
> +# Wifi power
> ++S:CONFIG_AXP221_DLDO1_VOLT=3300
> +# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
> ++S:CONFIG_AXP221_ALDO1_VOLT=3000
> diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h
> index 6f1fc48..792422d 100644
> --- a/include/configs/sun8i.h
> +++ b/include/configs/sun8i.h
> @@ -12,6 +12,8 @@
>  /*
>   * A23 specific configuration
>   */
> +#define CONFIG_CLK_FULL_SPEED	1008000000
> +
>  #define CONFIG_SYS_PROMPT	"sun8i# "
>  
>  /*
Hans de Goede Dec. 19, 2014, 4:51 p.m. UTC | #4
Hi,

On 18-12-14 20:17, Ian Campbell wrote:
> On Tue, 2014-12-16 at 21:31 +0100, Hans de Goede wrote:
>> Based on the register / dram_para headers from the Allwinner u-boot / linux
>> sources + the init sequences from boot0.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> +/*
>> + * Note this code uses a lot of magic hex values, that is because this code
>> + * simply replays the init sequence as done by the Allwinner boot0 code, so
>> + * we do not know what these values mean. There are no symbolic constants for
>> + * these magic values, since we do not know how to name them and making up
>> + * names for them is not useful.
>
> On that basis I've only really given this a quick glance. I've no
> problem with it.
>
> Couple of queries about the defconfig changes:
>
>> diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
>> index 50c2f93..37aa46d 100644
>> --- a/configs/Ippo_q8h_v5_defconfig
>> +++ b/configs/Ippo_q8h_v5_defconfig
>> @@ -1,8 +1,15 @@
>> +CONFIG_SPL=y
>>   CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
>> -CONFIG_ARM=y
>> -CONFIG_ARCH_SUNXI=y
>> -CONFIG_MACH_SUN8I=y
>> -CONFIG_TARGET_IPPO_Q8H_V5=y
>
> Not replaced with a S: variant? I know you want CONFIG_TARGET to go, but
> I don't think that was part of what you intended in this patch.

Right, I'll add that back.

>
>> -CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
>> +CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
>
> The switch from CONFIG_DEFAULT_DEVICE_TREE to CONFIG_FDTFILE conversion
> seems a little out of place too.

That was deliberate, the CONFIG_DEFAULT_DEVICE_TREE is the wrong CONFIG
define to use to set the dtb for the kernel. I'll split the Ippo_q8h_v5_defconfig
changes out into a separate patch and mention this in the commit message.

Regards,

Hans
Hans de Goede Dec. 19, 2014, 5:05 p.m. UTC | #5
Hi,

On 19-12-14 11:20, Siarhei Siamashka wrote:
> On Tue, 16 Dec 2014 21:31:38 +0100
> Hans de Goede <hdegoede@redhat.com> wrote:
>
>> Based on the register / dram_para headers from the Allwinner u-boot / linux
>> sources + the init sequences from boot0.
>
> Can the commit message have more detailed information about the precise
> location of the original Allwinner code, which was used as the
> reference?

No, it cannot because no code was referenced, I traced the boot0 binary to
figure out what was needed to get dram going on the A23.


>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>>   arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
>>   arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
>>   arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
>>   arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
>>   arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
>>   arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
>>   board/sunxi/Kconfig                           |   3 +-
>>   configs/Ippo_q8h_v5_defconfig                 |  17 +-
>>   include/configs/sun8i.h                       |   2 +
>>   9 files changed, 631 insertions(+), 7 deletions(-)
>>   create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
>>   create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h
>>
>> diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
>> index 3e8975a..1e89937 100644
>> --- a/arch/arm/cpu/armv7/sunxi/Makefile
>> +++ b/arch/arm/cpu/armv7/sunxi/Makefile
>> @@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i.o
>>   obj-$(CONFIG_MACH_SUN5I)	+= dram_sun4i.o
>>   obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
>>   obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
>> +obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
>>   ifdef CONFIG_SPL_FEL
>>   obj-y	+= start.o
>>   endif
>> diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
>> index 9b3e80c..bc98c56 100644
>> --- a/arch/arm/cpu/armv7/sunxi/board.c
>> +++ b/arch/arm/cpu/armv7/sunxi/board.c
>> @@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
>>   /* do some early init */
>>   void s_init(void)
>>   {
>> -#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
>> +#if defined CONFIG_SPL_BUILD && \
>> +		(defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
>>   	/* Magic (undocmented) value taken from boot0, without this DRAM
>>   	 * access gets messed up (seems cache related) */
>>   	setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
>> diff --git a/arch/arm/cpu/armv7/sunxi/dram_sun8i.c b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
>> new file mode 100644
>> index 0000000..3736fd1
>> --- /dev/null
>> +++ b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
>> @@ -0,0 +1,340 @@
>> +/*
>> + * Sun8i platform dram controller init.
>> + *
>> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
>
> Is Allwinner copyright really not necessary here?
>
>> + * SPDX-License-Identifier:	GPL-2.0+
>> + */
>> +
>> +/*
>> + * Note this code uses a lot of magic hex values, that is because this code
>> + * simply replays the init sequence as done by the Allwinner boot0 code, so
>> + * we do not know what these values mean. There are no symbolic constants for
>> + * these magic values, since we do not know how to name them and making up
>> + * names for them is not useful.
>> + */
>
> You are well aware of this documentation since a long time ago, right?
>     http://www.ti.com/lit/ug/spruhn7a/spruhn7a.pdf

I'm aware you've used various sources to figure out more about the A10
dram controller, since this DRAM controller seems significantly different
I assumed your sources would not apply, it is good to hear that they do.

I'll add a comment to the next version of this patch referencing that
document.

>
> Please open it and find "Table4-2 DDR3 PHY Registers". Then have a
> look at the "sunxi_mctl_phy_reg" struct from your patch. Compare
> the register names and their offsets. Looks like we are reasonably
> lucky again.
>
> Just as an example, I have commented about a few hardware registers
> at different locations in the code.
>
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <asm/io.h>
>> +#include <asm/arch/clock.h>
>> +#include <asm/arch/dram.h>
>> +#include <asm/arch/prcm.h>
>> +
>> +static const struct dram_para dram_para = {
>> +	.clock = CONFIG_DRAM_CLK,
>> +	.type = 3,
>> +	.zq = CONFIG_DRAM_ZQ,
>> +	.odt_en = 1,
>> +	.para1 = 0, /* not used (only used when tpr13 bit 31 is set */
>> +	.para2 = 0, /* not used (only used when tpr13 bit 31 is set */
>> +	.mr0 = 6736,
>> +	.mr1 = 4,
>> +	.mr2 = 16,
>> +	.mr3 = 0,
>> +	/* tpr0 - 10 contain timing constants or-ed together in u32 vals */
>> +	.tpr0 = 0x2ab83def,
>> +	.tpr1 = 0x18082356,
>> +	.tpr2 = 0x00034156,
>> +	.tpr3 = 0x448c5533,
>> +	.tpr4 = 0x08010d00,
>> +	.tpr5 = 0x0340b20f,
>> +	.tpr6 = 0x20d118cc,
>> +	.tpr7 = 0x14062485,
>> +	.tpr8 = 0x220d1d52,
>> +	.tpr9 = 0x1e078c22,
>> +	.tpr10 = 0x3c,
>> +	.tpr11 = 0, /* not used */
>> +	.tpr12 = 0, /* not used */
>> +	.tpr13 = 0x30000,
>> +};
>> +
>> +static void mctl_sys_init(void)
>> +{
>> +	struct sunxi_ccm_reg * const ccm =
>> +		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
>> +
>> +	/* enable pll5, note the divide by 2 is deliberate! */
>> +	clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
>> +		       dram_para.tpr13 & 0x40000);
>
> Is it really necessary to have the PLL5 setup so complicated and full
> of magic?
>
>> +
>> +	/* deassert ahb mctl reset */
>> +	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
>> +
>> +	/* enable ahb mctl clock */
>> +	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
>> +}
>> +
>> +static void mctl_apply_odt_correction(u32 *reg, int correction)
>> +{
>> +	int val;
>> +
>> +	val = (readl(reg) >> 8) & 0xff;
>> +	val += correction;
>> +
>> +	/* clamp */
>> +	if (val < 0)
>> +		val = 0;
>> +	else if (val > 255)
>> +		val = 255;
>> +
>> +	clrsetbits_le32(reg, 0xff00, val << 8);
>> +}
>> +
>> +static void mctl_init(u32 *bus_width)
>> +{
>> +	struct sunxi_ccm_reg * const ccm =
>> +		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
>> +	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 sunxi_mctl_phy_reg * const mctl_phy =
>> +		(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
>> +	int correction;
>> +
>> +	if (dram_para.tpr13 & 0x20)
>> +		writel(0x40b, &mctl_phy->dcr);
>
> The bits 2-0 are DDRMR (DDR Mode), and the value 3 means DDR3.
> And 0x40b is actually the default reset value of this register
> according to the TI Keystone2 documentation.
>
>> +	else
>> +		writel(0x1000040b, &mctl_phy->dcr);
>
> The bit 28 is marked as reserved and "Reads return zeros" in the
> TI Keystone2 documentation. It's a nice chance to test whether
> this write has any effect and whether it does modify the register.

It modifies the register, so that means that at least that bit does
not match the TI Keystone2 documentation.

>
>> +
>> +	if (dram_para.clock >= 480)
>> +		writel(0x5c000, &mctl_phy->dllgcr);
>
> 0x5c000 = (1 << 18) | (0xE << 13)
>
>> +	else
>> +		writel(0xdc000, &mctl_phy->dllgcr);
>
> 0xdc000 = (3 << 18) | (0xE << 13)
>
> The 'dllgcr' has the same offset as "4.40 PLL Control Register (PLLCR)"
> in the TI Keystone2 documentation.
>
> Bits 16-13 are CPPC (Charge Pump Proportional Current Control) with the
> default value 0xE, which matches what we see here.
>
> Bits 19-18 are FRQSEL:
>   01 = PLL reference clock (ctl_clk/REF_CLK) ranges from 225MHz to 385MHz
>   11 = PLL reference clock (ctl_clk/REF_CLK) ranges from 166MHz to 275MHz

That seems to match nicely, as said pll5 is set to dram_clk / 2. which
puts the cut over point at 240 MHz

>
>> +
>> +	writel(0x0a003e3f, &mctl_phy->pgcr0);
>> +	writel(0x03008421, &mctl_phy->pgcr1);
>> +
>> +	writel(dram_para.mr0, &mctl_phy->mr0);
>> +	writel(dram_para.mr1, &mctl_phy->mr1);
>> +	writel(dram_para.mr2, &mctl_phy->mr2);
>> +	writel(dram_para.mr3, &mctl_phy->mr3);
>> +
>> +	if (!(dram_para.tpr13 & 0x10000)) {
>> +		clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
>> +		clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
>> +	}
>> +
>> +	/*
>> +	 * All the masking and shifting below converts what I assume are DDR
>> +	 * timing constants from Allwinner dram_para tpr format to the actual
>> +	 * timing registers format.
>> +	 */
>> +
>> +	writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
>> +	writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
>> +	writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
>> +	       (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
>> +
>> +	writel(dram_para.tpr3, &mctl_phy->dtpr0);
>> +	writel(dram_para.tpr4, &mctl_phy->dtpr2);
>> +
>> +	writel(0x01000081, &mctl_phy->dtcr);
>> +
>> +	if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
>> +		clrbits_le32(&mctl_phy->dx0gcr, 0x600);
>> +		clrbits_le32(&mctl_phy->dx1gcr, 0x600);
>> +	}
>> +	if (dram_para.clock <= 240) {
>> +		writel(0, &mctl_phy->odtcr);
>> +		writel(0, &mctl_ctl->odtmap);
>> +	}
>> +
>> +	writel(((dram_para.tpr5 & 0x0f00) << 12) |
>> +	       ((dram_para.tpr5 & 0x00f8) <<  9) |
>> +	       ((dram_para.tpr5 & 0x0007) <<  8),
>> +	       &mctl_ctl->rfshctl0);
>> +
>> +	writel(((dram_para.tpr5 & 0x0003f000) << 12) |
>> +	       ((dram_para.tpr5 & 0x00fc0000) >>  2) |
>> +	       ((dram_para.tpr5 & 0x3f000000) >> 16) |
>> +	       ((dram_para.tpr6 & 0x0000003f) >>  0),
>> +	       &mctl_ctl->dramtmg0);
>> +
>> +	writel(((dram_para.tpr6 & 0x000007c0) << 10) |
>> +	       ((dram_para.tpr6 & 0x0000f800) >> 3) |
>> +	       ((dram_para.tpr6 & 0x003f0000) >> 16),
>> +	       &mctl_ctl->dramtmg1);
>> +
>> +	writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
>> +	       ((dram_para.tpr7 & 0x0000001f) << 16) |
>> +	       ((dram_para.tpr7 & 0x000003e0) << 3) |
>> +	       ((dram_para.tpr7 & 0x0000fc00) >> 10),
>> +	       &mctl_ctl->dramtmg2);
>> +
>> +	writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
>> +	       ((dram_para.tpr6 & 0xf0000000) >> 16),
>> +	       &mctl_ctl->dramtmg3);
>> +
>> +	writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
>> +	       ((dram_para.tpr8 & 0x00000007) << 16) |
>> +	       ((dram_para.tpr8 & 0x00000038) << 5) |
>> +	       ((dram_para.tpr8 & 0x000003c0) >> 6),
>> +	       &mctl_ctl->dramtmg4);
>> +
>> +	writel(((dram_para.tpr8 & 0x00003c00) << 14) |
>> +	       ((dram_para.tpr8 & 0x0003c000) <<  2) |
>> +	       ((dram_para.tpr8 & 0x00fc0000) >> 10) |
>> +	       ((dram_para.tpr8 & 0x0f000000) >> 24),
>> +	       &mctl_ctl->dramtmg5);
>> +
>> +	writel(0x00000008, &mctl_ctl->dramtmg8);
>> +
>> +	writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
>> +	       ((dram_para.tpr9 & 0x00007c00) << 6) |
>> +	       ((dram_para.tpr9 & 0x000003e0) << 3) |
>> +	       ((dram_para.tpr9 & 0x0000001f) >> 0),
>> +	       &mctl_ctl->pitmg0);
>
> Could there be any purpose for this other than obfuscation? Looks
> really strange.

I think the purpose is to keep the dram_para.tpr? values the same
as with sun6i, so that they can be copy pasted between designs ...


>
>> +
>> +	setbits_le32(&mctl_ctl->pitmg1, 0x80000);
>> +
>> +	writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
>> +	       &mctl_ctl->sched);
>> +
>> +	writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
>> +	writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
>> +
>> +	writel(0x00000000, &mctl_ctl->pimisc);
>> +	writel(0x80000000, &mctl_ctl->upd0);
>> +
>> +	writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
>> +	       ((dram_para.tpr10 & 0x00000fff) << 16),
>> +	       &mctl_ctl->rfshtmg);
>> +
>> +	if (dram_para.tpr13 & 0x20)
>> +		writel(0x01040001, &mctl_ctl->mstr);
>> +	else
>> +		writel(0x01040401, &mctl_ctl->mstr);
>> +
>> +	if (!(dram_para.tpr13 & 0x20000)) {
>> +		writel(0x00000002, &mctl_ctl->pwrctl);
>> +		writel(0x00008001, &mctl_ctl->pwrtmg);
>> +	}
>> +
>> +	writel(0x00000001, &mctl_ctl->rfshctl3);
>> +	writel(0x00000001, &mctl_ctl->pimisc);
>> +
>> +	/* deassert dram_clk_cfg reset */
>> +	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
>> +
>> +	setbits_le32(&mctl_com->ccr, 0x80000);
>> +
>> +	/* zq stuff */
>> +	writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);
>
> 4.59 Impedance Control Register 1 (ZQnCR1)
>
> Bits 7-0 - ZPROG (Impedance Divide Ratio), reset value 0x7B
>
>> +	writel(0x00000003, &mctl_phy->pir);
>
> 4.34 PHY Initialization Register (PIR)
>
> Bit 0 - INIT
> Bit 1 - ZCAL
>
>> +	udelay(10);
>> +	mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);
>
> 4.38 PHY General Status Register 0 (PGSR0)
>
> Bit 0 - IDONE (Initialization Done)
> Bit 3 - ZCDONE (Impedance Calibration Done)
>
>> +	writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
>> +	writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
>
> Overwriting ZPROG again? Is it doing something reasonable?
> Or might it be an attempt to hide data from the tools like
> a10-meminfo (which can dump the DRAM setting via /dev/mem)?

I've no clue.

Regards,

Hans



>
>> +	/* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
>> +	writel(0x000005f3, &mctl_phy->pir);
>> +	udelay(10);
>> +	mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
>> +
>> +	if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
>> +		*bus_width = 8;
>> +		writel(0, &mctl_phy->dx1gcr);
>> +		writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
>> +		writel(0x5f3, &mctl_phy->pir);
>> +		udelay(10000);
>> +		setbits_le32(&mctl_ctl->mstr, 0x1000);
>> +	} else
>> +		*bus_width = 16;
>> +
>> +	correction = (dram_para.odt_en >> 8) & 0xff;
>> +	if (correction) {
>> +		if (dram_para.odt_en & 0x80000000)
>> +			correction = -correction;
>> +
>> +		mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
>> +		mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
>> +	}
>> +
>> +	mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
>> +
>> +	writel(0x08003e3f, &mctl_phy->pgcr0);
>> +	writel(0x00000000, &mctl_ctl->rfshctl3);
>> +}
>> +
>> +unsigned long sunxi_dram_init(void)
>> +{
>> +	struct sunxi_mctl_com_reg * const mctl_com =
>> +		(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
>> +	const u32 columns = 13;
>> +	u32 bus, bus_width, offset, page_size, rows;
>> +
>> +	mctl_sys_init();
>> +	mctl_init(&bus_width);
>> +
>> +	if (bus_width == 16) {
>> +		page_size = 8;
>> +		bus = 1;
>> +	} else {
>> +		page_size = 7;
>> +		bus = 0;
>> +	}
>> +
>> +	if (!(dram_para.tpr13 & 0x80000000)) {
>> +		/* Detect and set rows */
>> +		writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
>> +		       &mctl_com->cr);
>> +		setbits_le32(&mctl_com->swonr, 0x0003ffff);
>> +		mctl_mem_fill();
>> +		for (rows = 11; rows < 16; rows++) {
>> +			offset = 1 << (rows + columns + bus);
>> +			if (mctl_mem_matches(offset))
>> +				break;
>> +		}
>> +		clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
>> +				MCTL_CR_ROW(rows));
>> +	} else {
>> +		rows = (dram_para.para1 >> 16) & 0xff;
>> +		writel(((dram_para.para2 & 0x000000f0) << 11) |
>> +		       ((rows - 1) << 4) |
>> +		       ((dram_para.para1 & 0x0f000000) >> 22) |
>> +		       0x31000 | MCTL_CR_PAGE_SIZE(page_size),
>> +		       &mctl_com->cr);
>> +		setbits_le32(&mctl_com->swonr, 0x0003ffff);
>> +	}
>> +
>> +	/* Setup DRAM master priority? If this is left out things still work */
>> +	writel(0x00000008, &mctl_com->mcr0_0);
>> +	writel(0x0001000d, &mctl_com->mcr1_0);
>> +	writel(0x00000004, &mctl_com->mcr0_1);
>> +	writel(0x00000080, &mctl_com->mcr1_1);
>> +	writel(0x00000004, &mctl_com->mcr0_2);
>> +	writel(0x00000019, &mctl_com->mcr1_2);
>> +	writel(0x00000004, &mctl_com->mcr0_3);
>> +	writel(0x00000080, &mctl_com->mcr1_3);
>> +	writel(0x00000004, &mctl_com->mcr0_4);
>> +	writel(0x01010040, &mctl_com->mcr1_4);
>> +	writel(0x00000004, &mctl_com->mcr0_5);
>> +	writel(0x0001002f, &mctl_com->mcr1_5);
>> +	writel(0x00000004, &mctl_com->mcr0_6);
>> +	writel(0x00010020, &mctl_com->mcr1_6);
>> +	writel(0x00000004, &mctl_com->mcr0_7);
>> +	writel(0x00010020, &mctl_com->mcr1_7);
>> +	writel(0x00000008, &mctl_com->mcr0_8);
>> +	writel(0x00000001, &mctl_com->mcr1_8);
>> +	writel(0x00000008, &mctl_com->mcr0_9);
>> +	writel(0x00000005, &mctl_com->mcr1_9);
>> +	writel(0x00000008, &mctl_com->mcr0_10);
>> +	writel(0x00000003, &mctl_com->mcr1_10);
>> +	writel(0x00000008, &mctl_com->mcr0_11);
>> +	writel(0x00000005, &mctl_com->mcr1_11);
>> +	writel(0x00000008, &mctl_com->mcr0_12);
>> +	writel(0x00000003, &mctl_com->mcr1_12);
>> +	writel(0x00000008, &mctl_com->mcr0_13);
>> +	writel(0x00000004, &mctl_com->mcr1_13);
>> +	writel(0x00000008, &mctl_com->mcr0_14);
>> +	writel(0x00000002, &mctl_com->mcr1_14);
>> +	writel(0x00000008, &mctl_com->mcr0_15);
>> +	writel(0x00000003, &mctl_com->mcr1_15);
>> +	writel(0x00010138, &mctl_com->bwcr);
>> +
>> +	return 1 << (rows + columns + bus);
>> +}
>> diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
>> index 7d61216..45a199c 100644
>> --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
>> +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
>> @@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
>>   #define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
>>   #define CCM_HDMI_CTRL_GATE		(0x1 << 31)
>>
>> +#ifndef CONFIG_MACH_SUN8I
>>   #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
>> +#else
>> +#define MBUS_CLK_DEFAULT		0x81000003 /* PLL6 / 4 */
>> +#endif
>>
>>   #define CCM_PLL5_PATTERN		0xd1303333
>>
>> diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
>> index a8a37d5..8d78029 100644
>> --- a/arch/arm/include/asm/arch-sunxi/dram.h
>> +++ b/arch/arm/include/asm/arch-sunxi/dram.h
>> @@ -18,6 +18,8 @@
>>   /* dram regs definition */
>>   #if defined(CONFIG_MACH_SUN6I)
>>   #include <asm/arch/dram_sun6i.h>
>> +#elif defined(CONFIG_MACH_SUN8I)
>> +#include <asm/arch/dram_sun8i.h>
>>   #else
>>   #include <asm/arch/dram_sun4i.h>
>>   #endif
>> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
>> new file mode 100644
>> index 0000000..425cf37
>> --- /dev/null
>> +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
>> @@ -0,0 +1,266 @@
>> +/*
>> + * Sun8i platform dram controller register and constant defines
>> + *
>> + * (C) Copyright 2007-2013
>> + * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
>> + * CPL <cplanxy@allwinnertech.com>
>> + * Jerry Wang <wangflord@allwinnertech.com>
>> + *
>> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
>> + *
>> + * SPDX-License-Identifier:	GPL-2.0+
>> + */
>> +
>> +#ifndef _SUNXI_DRAM_SUN8I_H
>> +#define _SUNXI_DRAM_SUN8I_H
>> +
>> +struct dram_para {
>> +	u32 clock;
>> +	u32 type;
>> +	u32 zq;
>> +	u32 odt_en;
>> +	u32 para1;
>> +	u32 para2;
>> +	u32 mr0;
>> +	u32 mr1;
>> +	u32 mr2;
>> +	u32 mr3;
>> +	u32 tpr0;
>> +	u32 tpr1;
>> +	u32 tpr2;
>> +	u32 tpr3;
>> +	u32 tpr4;
>> +	u32 tpr5;
>> +   	u32 tpr6;
>> +	u32 tpr7;
>> +	u32 tpr8;
>> +	u32 tpr9;
>> +	u32 tpr10;
>> +	u32 tpr11;
>> +	u32 tpr12;
>> +	u32 tpr13;
>> +};
>> +
>> +struct sunxi_mctl_com_reg {
>> +	u32 cr;			/* 0x00 */
>> +	u32 ccr;		/* 0x04 controller configuration register */
>> +	u32 dbgcr;		/* 0x08 */
>> +	u8 res0[0x4];		/* 0x0c */
>> +	u32 mcr0_0;		/* 0x10 */
>> +	u32 mcr1_0;		/* 0x14 */
>> +	u32 mcr0_1;		/* 0x18 */
>> +	u32 mcr1_1;		/* 0x1c */
>> +	u32 mcr0_2;		/* 0x20 */
>> +	u32 mcr1_2;		/* 0x24 */
>> +	u32 mcr0_3;		/* 0x28 */
>> +	u32 mcr1_3;		/* 0x2c */
>> +	u32 mcr0_4;		/* 0x30 */
>> +	u32 mcr1_4;		/* 0x34 */
>> +	u32 mcr0_5;		/* 0x38 */
>> +	u32 mcr1_5;		/* 0x3c */
>> +	u32 mcr0_6;		/* 0x40 */
>> +	u32 mcr1_6;		/* 0x44 */
>> +	u32 mcr0_7;		/* 0x48 */
>> +	u32 mcr1_7;		/* 0x4c */
>> +	u32 mcr0_8;		/* 0x50 */
>> +	u32 mcr1_8;		/* 0x54 */
>> +	u32 mcr0_9;		/* 0x58 */
>> +	u32 mcr1_9;		/* 0x5c */
>> +	u32 mcr0_10;		/* 0x60 */
>> +	u32 mcr1_10;		/* 0x64 */
>> +	u32 mcr0_11;		/* 0x68 */
>> +	u32 mcr1_11;		/* 0x6c */
>> +	u32 mcr0_12;		/* 0x70 */
>> +	u32 mcr1_12;		/* 0x74 */
>> +	u32 mcr0_13;		/* 0x78 */
>> +	u32 mcr1_13;		/* 0x7c */
>> +	u32 mcr0_14;		/* 0x80 */
>> +	u32 mcr1_14;		/* 0x84 */
>> +	u32 mcr0_15;		/* 0x88 */
>> +	u32 mcr1_15;		/* 0x8c */
>> +	u32 bwcr;		/* 0x90 */
>> +	u32 maer;		/* 0x94 */
>> +	u8 res1[0x4];		/* 0x98 */
>> +	u32 mcgcr;		/* 0x9c */
>> +	u32 bwctr;		/* 0xa0 */
>> +	u8 res2[0x4];		/* 0xa4 */
>> +	u32 swonr;		/* 0xa8 */
>> +	u32 swoffr;		/* 0xac */
>> +};
>> +
>> +struct sunxi_mctl_ctl_reg {
>> +	u32 mstr;		/* 0x00 */
>> +	u32 statr;		/* 0x04 */
>> +	u8 res0[0x08];		/* 0x08 */
>> +	u32 mrctrl0;		/* 0x10 */
>> +	u32 mrctrl1;		/* 0x14 */
>> +	u32 mrstatr;		/* 0x18 */
>> +	u8 res1[0x04];		/* 0x1c */
>> +	u32 derateen;		/* 0x20 */
>> +	u32 deratenint;		/* 0x24 */
>> +	u8 res2[0x08];		/* 0x28 */
>> +	u32 pwrctl;		/* 0x30 */
>> +	u32 pwrtmg;		/* 0x34 */
>> +	u8 res3[0x18];		/* 0x38 */
>> +	u32 rfshctl0;		/* 0x50 */
>> +	u32 rfshctl1;		/* 0x54 */
>> +	u8 res4[0x8];		/* 0x58 */
>> +	u32 rfshctl3;		/* 0x60 */
>> +	u32 rfshtmg;		/* 0x64 */
>> +	u8 res6[0x68];		/* 0x68 */
>> +	u32 init0;		/* 0xd0 */
>> +	u32 init1;		/* 0xd4 */
>> +	u32 init2;		/* 0xd8 */
>> +	u32 init3;		/* 0xdc */
>> +	u32 init4;		/* 0xe0 */
>> +	u32 init5;		/* 0xe4 */
>> +	u8 res7[0x0c];		/* 0xe8 */
>> +	u32 rankctl;		/* 0xf4 */
>> +	u8 res8[0x08];		/* 0xf8 */
>> +	u32 dramtmg0;		/* 0x100 */
>> +	u32 dramtmg1;		/* 0x104 */
>> +	u32 dramtmg2;		/* 0x108 */
>> +	u32 dramtmg3;		/* 0x10c */
>> +	u32 dramtmg4;		/* 0x110 */
>> +	u32 dramtmg5;		/* 0x114 */
>> +	u32 dramtmg6;		/* 0x118 */
>> +	u32 dramtmg7;		/* 0x11c */
>> +	u32 dramtmg8;		/* 0x120 */
>> +	u8 res9[0x5c];		/* 0x124 */
>> +	u32 zqctl0;		/* 0x180 */
>> +	u32 zqctl1;		/* 0x184 */
>> +	u32 zqctl2;		/* 0x188 */
>> +	u32 zqstat;		/* 0x18c */
>> +	u32 pitmg0;		/* 0x190 */
>> +	u32 pitmg1;		/* 0x194 */
>> +	u32 plpcfg0;		/* 0x198 */
>> +	u8 res10[0x04];		/* 0x19c */
>> +	u32 upd0;		/* 0x1a0 */
>> +	u32 upd1;		/* 0x1a4 */
>> +	u32 upd2;		/* 0x1a8 */
>> +	u32 upd3;		/* 0x1ac */
>> +	u32 pimisc;		/* 0x1b0 */
>> +	u8 res11[0x1c];		/* 0x1b4 */
>> +	u32 trainctl0;		/* 0x1d0 */
>> +	u32 trainctl1;		/* 0x1d4 */
>> +	u32 trainctl2;		/* 0x1d8 */
>> +	u32 trainstat;		/* 0x1dc */
>> +	u8 res12[0x60];		/* 0x1e0 */
>> +	u32 odtcfg;		/* 0x240 */
>> +	u32 odtmap;		/* 0x244 */
>> +	u8 res13[0x08];		/* 0x248 */
>> +	u32 sched;		/* 0x250 */
>> +	u8 res14[0x04];		/* 0x254 */
>> +	u32 perfshpr0;		/* 0x258 */
>> +	u32 perfshpr1;		/* 0x25c */
>> +	u32 perflpr0;		/* 0x260 */
>> +	u32 perflpr1;		/* 0x264 */
>> +	u32 perfwr0;		/* 0x268 */
>> +	u32 perfwr1;		/* 0x26c */
>> +};
>> +
>> +struct sunxi_mctl_phy_reg {
>> +	u8 res0[0x04];		/* 0x00 */
>> +	u32 pir;		/* 0x04 */
>> +	u32 pgcr0;		/* 0x08 phy general configuration register */
>> +	u32 pgcr1;		/* 0x0c phy general configuration register */
>> +	u32 pgsr0;		/* 0x10 */
>> +	u32 pgsr1;		/* 0x14 */
>> +	u32 dllgcr;		/* 0x18 */
>> +	u32 ptr0;		/* 0x1c */
>> +	u32 ptr1;		/* 0x20 */
>> +	u32 ptr2;		/* 0x24 */
>> +	u32 ptr3;		/* 0x28 */
>> +	u32 ptr4;		/* 0x2c */
>> +	u32 acmdlr;		/* 0x30 */
>> +	u32 acbdlr;		/* 0x34 */
>> +	u32 aciocr;		/* 0x38 */
>> +	u32 dxccr;		/* 0x3c DATX8 common configuration register */
>> +	u32 dsgcr;		/* 0x40 dram system general config register */
>> +	u32 dcr;		/* 0x44 */
>> +	u32 dtpr0;		/* 0x48 dram timing parameters register 0 */
>> +	u32 dtpr1;		/* 0x4c dram timing parameters register 1 */
>> +	u32 dtpr2;		/* 0x50 dram timing parameters register 2 */
>> +	u32 mr0;		/* 0x54 mode register 0 */
>> +	u32 mr1;		/* 0x58 mode register 1 */
>> +	u32 mr2;		/* 0x5c mode register 2 */
>> +	u32 mr3;		/* 0x60 mode register 3 */
>> +	u32 odtcr;		/* 0x64 */
>> +	u32 dtcr;		/* 0x68 */
>> +	u32 dtar0;		/* 0x6c data training address register 0 */
>> +	u32 dtar1;		/* 0x70 data training address register 1 */
>> +	u32 dtar2;		/* 0x74 data training address register 2 */
>> +	u32 dtar3;		/* 0x78 data training address register 3 */
>> +	u32 dtdr0;		/* 0x7c */
>> +	u32 dtdr1;		/* 0x80 */
>> +	u32 dtedr0;		/* 0x84 */
>> +	u32 dtedr1;		/* 0x88 */
>> +	u32 pgcr2;		/* 0x8c */
>> +	u8 res1[0x70];		/* 0x90 */
>> +	u32 bistrr;		/* 0x100 */
>> +	u32 bistwcr;		/* 0x104 */
>> +	u32 bistmskr0;		/* 0x108 */
>> +	u32 bistmskr1;		/* 0x10c */
>> +	u32 bistmskr2;		/* 0x110 */
>> +	u32 bistlsr;		/* 0x114 */
>> +	u32 bistar0;		/* 0x118 */
>> +	u32 bistar1;		/* 0x11c */
>> +	u32 bistar2;		/* 0x120 */
>> +	u32 bistupdr;		/* 0x124 */
>> +	u32 bistgsr;		/* 0x128 */
>> +	u32 bistwer;		/* 0x12c */
>> +	u32 bistber0;		/* 0x130 */
>> +	u32 bistber1;		/* 0x134 */
>> +	u32 bistber2;		/* 0x138 */
>> +	u32 bistber3;		/* 0x13c */
>> +	u32 bistwcsr;		/* 0x140 */
>> +	u32 bistfwr0;		/* 0x144 */
>> +	u32 bistfwr1;		/* 0x148 */
>> +	u32 bistfwr2;		/* 0x14c */
>> +	u8 res2[0x30];		/* 0x150 */
>> +	u32 zqcr0;		/* 0x180 zq control register 0 */
>> +	u32 zqcr1;		/* 0x184 zq control register 1 */
>> +	u32 zqsr0;		/* 0x188 zq status register 0 */
>> +	u32 zqsr1;		/* 0x18c zq status register 1 */
>> +	u32 zqcr2;		/* 0x190 zq control register 2 */
>> +	u8 res3[0x2c];		/* 0x194 */
>> +	u32 dx0gcr;		/* 0x1c0 */
>> +	u32 dx0gsr0;		/* 0x1c4 */
>> +	u32 dx0gsr1;		/* 0x1c8 */
>> +	u32 dx0bdlr0;		/* 0x1cc */
>> +	u32 dx0bdlr1;		/* 0x1d0 */
>> +	u32 dx0bdlr2;		/* 0x1d4 */
>> +	u32 dx0bdlr3;		/* 0x1d8 */
>> +	u32 dx0bdlr4;		/* 0x1dc */
>> +	u32 dx0lcdlr0;		/* 0x1e0 */
>> +	u32 dx0lcdlr1;		/* 0x1e4 */
>> +	u32 dx0lcdlr2;		/* 0x1e8 */
>> +	u32 dx0mdlr;		/* 0x1ec */
>> +	u32 dx0gtr;		/* 0x1f0 */
>> +	u32 dx0gsr2;		/* 0x1f4 */
>> +	u8 res4[0x08];		/* 0x1f8 */
>> +	u32 dx1gcr;		/* 0x200 */
>> +	u32 dx1gsr0;		/* 0x204 */
>> +	u32 dx1gsr1;		/* 0x208 */
>> +	u32 dx1bdlr0;		/* 0x20c */
>> +	u32 dx1bdlr1;		/* 0x210 */
>> +	u32 dx1bdlr2;		/* 0x214 */
>> +	u32 dx1bdlr3;		/* 0x218 */
>> +	u32 dx1bdlr4;		/* 0x21c */
>> +	u32 dx1lcdlr0;		/* 0x220 */
>> +	u32 dx1lcdlr1;		/* 0x224 */
>> +	u32 dx1lcdlr2;		/* 0x228 */
>> +	u32 dx1mdlr;		/* 0x22c */
>> +	u32 dx1gtr;		/* 0x230 */
>> +	u32 dx1gsr2;		/* 0x234 */
>> +};
>> +
>> +/*
>> + * DRAM common (sunxi_mctl_com_reg) register constants.
>> + */
>> +#define MCTL_CR_ROW_MASK		(0xf << 4)
>> +#define MCTL_CR_ROW(x)			(((x) - 1) << 4)
>> +#define MCTL_CR_PAGE_SIZE_MASK		(0xf << 8)
>> +#define MCTL_CR_PAGE_SIZE(x)		((x) << 8)
>> +
>> +#endif /* _SUNXI_DRAM_SUN8I_H */
>> diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
>> index 5bb2f58..5a88ba0 100644
>> --- a/board/sunxi/Kconfig
>> +++ b/board/sunxi/Kconfig
>> @@ -29,10 +29,11 @@ config MACH_SUN7I
>>   config MACH_SUN8I
>>   	bool "sun8i (Allwinner A23)"
>>   	select CPU_V7
>> +	select SUPPORT_SPL
>>
>>   endchoice
>>
>> -if MACH_SUN6I
>> +if MACH_SUN6I || MACH_SUN8I
>>
>>   config DRAM_CLK
>>   	int "sun6i dram clock speed"
>> diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
>> index 50c2f93..37aa46d 100644
>> --- a/configs/Ippo_q8h_v5_defconfig
>> +++ b/configs/Ippo_q8h_v5_defconfig
>> @@ -1,8 +1,15 @@
>> +CONFIG_SPL=y
>>   CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
>> -CONFIG_ARM=y
>> -CONFIG_ARCH_SUNXI=y
>> -CONFIG_MACH_SUN8I=y
>> -CONFIG_TARGET_IPPO_Q8H_V5=y
>> -CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
>> +CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
>>   CONFIG_VIDEO=n
>>   CONFIG_USB_KEYBOARD=n
>> ++S:CONFIG_ARM=y
>> ++S:CONFIG_ARCH_SUNXI=y
>> ++S:CONFIG_MACH_SUN8I=y
>> ++S:CONFIG_DRAM_CLK=480
>> +# zq = 0xf777
>> ++S:CONFIG_DRAM_ZQ=63351
>> +# Wifi power
>> ++S:CONFIG_AXP221_DLDO1_VOLT=3300
>> +# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
>> ++S:CONFIG_AXP221_ALDO1_VOLT=3000
>> diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h
>> index 6f1fc48..792422d 100644
>> --- a/include/configs/sun8i.h
>> +++ b/include/configs/sun8i.h
>> @@ -12,6 +12,8 @@
>>   /*
>>    * A23 specific configuration
>>    */
>> +#define CONFIG_CLK_FULL_SPEED	1008000000
>> +
>>   #define CONFIG_SYS_PROMPT	"sun8i# "
>>
>>   /*
>
>
>
Siarhei Siamashka Dec. 22, 2014, 7:43 a.m. UTC | #6
On Fri, 19 Dec 2014 18:05:49 +0100
Hans de Goede <hdegoede@redhat.com> wrote:

> Hi,
> 
> On 19-12-14 11:20, Siarhei Siamashka wrote:
> > On Tue, 16 Dec 2014 21:31:38 +0100
> > Hans de Goede <hdegoede@redhat.com> wrote:
> >
> >> Based on the register / dram_para headers from the Allwinner u-boot / linux
> >> sources + the init sequences from boot0.
> >
> > Can the commit message have more detailed information about the precise
> > location of the original Allwinner code, which was used as the
> > reference?
> 
> No, it cannot because no code was referenced, I traced the boot0 binary to
> figure out what was needed to get dram going on the A23.

Thanks for explaining. And good job extracting all the information
from there.

In this case, can we have a clear reference to this binary in the
commit message? It might be useful to have a look at objdump logs
when reviewing your patch.

[...]

> >> +++ b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
> >> @@ -0,0 +1,340 @@
> >> +/*
> >> + * Sun8i platform dram controller init.
> >> + *
> >> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
> >
> > Is Allwinner copyright really not necessary here?
> >
> >> + * SPDX-License-Identifier:	GPL-2.0+
> >> + */
> >> +
> >> +/*
> >> + * Note this code uses a lot of magic hex values, that is because this code
> >> + * simply replays the init sequence as done by the Allwinner boot0 code, so
> >> + * we do not know what these values mean. There are no symbolic constants for
> >> + * these magic values, since we do not know how to name them and making up
> >> + * names for them is not useful.
> >> + */
> >
> > You are well aware of this documentation since a long time ago, right?
> >     http://www.ti.com/lit/ug/spruhn7a/spruhn7a.pdf
> 
> I'm aware you've used various sources to figure out more about the A10
> dram controller, since this DRAM controller seems significantly different
> I assumed your sources would not apply, it is good to hear that they do.

I wonder how could you have ended up with this strange assumption?
When I clearly told you that "It looks like the Allwinner A31 DRAM
controller registers are very similar to what is used in RK3288" and
provided the links to the relevant sources and documentation back
in September:
    http://lists.denx.de/pipermail/u-boot/2014-September/189199.html

Then reminded yet again about this RK3288 similarity and used the
mctl_phy->ptr0 register as an example:
    http://lists.denx.de/pipermail/u-boot/2014-December/198582.html

When we were discussing the A31 DRAM controller, of course you should
have expected the information about A31.

Yes, A23 was not a part of the picture at that time. However comparing
its registers with the information from spruhn7a.pdf and various
Rockchip source code drops is a very natural thing to try.

So far the best matching pairs (almost 100% identical PHY) are:
   Allwinner A10 (sun4i) - RK29xx
   Allwinner A31 (sun6i) - RK3288
   Allwinner A23 (sun8i) - TI Keystone2

It's all the same family of DRAM controllers, very likely just
different revisions/generations from the same supplier. I don't
expect A80 or other Allwinner chips to be any different.

[...]

> >> +	else
> >> +		writel(0x1000040b, &mctl_phy->dcr);
> >
> > The bit 28 is marked as reserved and "Reads return zeros" in the
> > TI Keystone2 documentation. It's a nice chance to test whether
> > this write has any effect and whether it does modify the register.
> 
> It modifies the register, so that means that at least that bit does
> not match the TI Keystone2 documentation.

OK.
diff mbox

Patch

diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
index 3e8975a..1e89937 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -33,6 +33,7 @@  obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN5I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
 obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
+obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
 ifdef CONFIG_SPL_FEL
 obj-y	+= start.o
 endif
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
index 9b3e80c..bc98c56 100644
--- a/arch/arm/cpu/armv7/sunxi/board.c
+++ b/arch/arm/cpu/armv7/sunxi/board.c
@@ -114,7 +114,8 @@  void reset_cpu(ulong addr)
 /* do some early init */
 void s_init(void)
 {
-#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
+#if defined CONFIG_SPL_BUILD && \
+		(defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
 	/* Magic (undocmented) value taken from boot0, without this DRAM
 	 * access gets messed up (seems cache related) */
 	setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
diff --git a/arch/arm/cpu/armv7/sunxi/dram_sun8i.c b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
new file mode 100644
index 0000000..3736fd1
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c
@@ -0,0 +1,340 @@ 
+/*
+ * Sun8i platform dram controller init.
+ *
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/prcm.h>
+
+static const struct dram_para dram_para = {
+	.clock = CONFIG_DRAM_CLK,
+	.type = 3,
+	.zq = CONFIG_DRAM_ZQ,
+	.odt_en = 1,
+	.para1 = 0, /* not used (only used when tpr13 bit 31 is set */
+	.para2 = 0, /* not used (only used when tpr13 bit 31 is set */
+	.mr0 = 6736,
+	.mr1 = 4,
+	.mr2 = 16,
+	.mr3 = 0,
+	/* tpr0 - 10 contain timing constants or-ed together in u32 vals */
+	.tpr0 = 0x2ab83def,
+	.tpr1 = 0x18082356,
+	.tpr2 = 0x00034156,
+	.tpr3 = 0x448c5533,
+	.tpr4 = 0x08010d00,
+	.tpr5 = 0x0340b20f,
+	.tpr6 = 0x20d118cc,
+	.tpr7 = 0x14062485,
+	.tpr8 = 0x220d1d52,
+	.tpr9 = 0x1e078c22,
+	.tpr10 = 0x3c,
+	.tpr11 = 0, /* not used */
+	.tpr12 = 0, /* not used */
+	.tpr13 = 0x30000,
+};
+
+static void mctl_sys_init(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* enable pll5, note the divide by 2 is deliberate! */
+	clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
+		       dram_para.tpr13 & 0x40000);
+
+	/* deassert ahb mctl reset */
+	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
+
+	/* enable ahb mctl clock */
+	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
+}
+
+static void mctl_apply_odt_correction(u32 *reg, int correction)
+{
+	int val;
+
+	val = (readl(reg) >> 8) & 0xff;
+	val += correction;
+
+	/* clamp */
+	if (val < 0)
+		val = 0;
+	else if (val > 255)
+		val = 255;
+
+	clrsetbits_le32(reg, 0xff00, val << 8);
+}
+
+static void mctl_init(u32 *bus_width)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	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 sunxi_mctl_phy_reg * const mctl_phy =
+		(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	int correction;
+
+	if (dram_para.tpr13 & 0x20)
+		writel(0x40b, &mctl_phy->dcr);
+	else
+		writel(0x1000040b, &mctl_phy->dcr);
+
+	if (dram_para.clock >= 480)
+		writel(0x5c000, &mctl_phy->dllgcr);
+	else
+		writel(0xdc000, &mctl_phy->dllgcr);
+
+	writel(0x0a003e3f, &mctl_phy->pgcr0);
+	writel(0x03008421, &mctl_phy->pgcr1);
+
+	writel(dram_para.mr0, &mctl_phy->mr0);
+	writel(dram_para.mr1, &mctl_phy->mr1);
+	writel(dram_para.mr2, &mctl_phy->mr2);
+	writel(dram_para.mr3, &mctl_phy->mr3);
+
+	if (!(dram_para.tpr13 & 0x10000)) {
+		clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
+		clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
+	}
+
+	/*
+	 * All the masking and shifting below converts what I assume are DDR
+	 * timing constants from Allwinner dram_para tpr format to the actual
+	 * timing registers format.
+	 */
+
+	writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
+	writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
+	writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
+	       (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
+
+	writel(dram_para.tpr3, &mctl_phy->dtpr0);
+	writel(dram_para.tpr4, &mctl_phy->dtpr2);
+
+	writel(0x01000081, &mctl_phy->dtcr);
+
+	if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
+		clrbits_le32(&mctl_phy->dx0gcr, 0x600);
+		clrbits_le32(&mctl_phy->dx1gcr, 0x600);
+	}
+	if (dram_para.clock <= 240) {
+		writel(0, &mctl_phy->odtcr);
+		writel(0, &mctl_ctl->odtmap);
+	}
+
+	writel(((dram_para.tpr5 & 0x0f00) << 12) |
+	       ((dram_para.tpr5 & 0x00f8) <<  9) |
+	       ((dram_para.tpr5 & 0x0007) <<  8),
+	       &mctl_ctl->rfshctl0);
+
+	writel(((dram_para.tpr5 & 0x0003f000) << 12) |
+	       ((dram_para.tpr5 & 0x00fc0000) >>  2) |
+	       ((dram_para.tpr5 & 0x3f000000) >> 16) |
+	       ((dram_para.tpr6 & 0x0000003f) >>  0),
+	       &mctl_ctl->dramtmg0);
+
+	writel(((dram_para.tpr6 & 0x000007c0) << 10) | 
+	       ((dram_para.tpr6 & 0x0000f800) >> 3) |
+	       ((dram_para.tpr6 & 0x003f0000) >> 16),
+	       &mctl_ctl->dramtmg1);
+
+	writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
+	       ((dram_para.tpr7 & 0x0000001f) << 16) |
+	       ((dram_para.tpr7 & 0x000003e0) << 3) |
+	       ((dram_para.tpr7 & 0x0000fc00) >> 10),
+	       &mctl_ctl->dramtmg2);
+
+	writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
+	       ((dram_para.tpr6 & 0xf0000000) >> 16),
+	       &mctl_ctl->dramtmg3);
+
+	writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
+	       ((dram_para.tpr8 & 0x00000007) << 16) |
+	       ((dram_para.tpr8 & 0x00000038) << 5) |
+	       ((dram_para.tpr8 & 0x000003c0) >> 6),
+	       &mctl_ctl->dramtmg4);
+
+	writel(((dram_para.tpr8 & 0x00003c00) << 14) |
+	       ((dram_para.tpr8 & 0x0003c000) <<  2) |
+	       ((dram_para.tpr8 & 0x00fc0000) >> 10) |
+	       ((dram_para.tpr8 & 0x0f000000) >> 24),
+	       &mctl_ctl->dramtmg5);
+
+	writel(0x00000008, &mctl_ctl->dramtmg8);
+
+	writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
+	       ((dram_para.tpr9 & 0x00007c00) << 6) |
+	       ((dram_para.tpr9 & 0x000003e0) << 3) |
+	       ((dram_para.tpr9 & 0x0000001f) >> 0),
+	       &mctl_ctl->pitmg0);
+
+	setbits_le32(&mctl_ctl->pitmg1, 0x80000);
+
+	writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
+	       &mctl_ctl->sched);
+
+	writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
+	writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
+
+	writel(0x00000000, &mctl_ctl->pimisc);
+	writel(0x80000000, &mctl_ctl->upd0);
+
+	writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
+	       ((dram_para.tpr10 & 0x00000fff) << 16),
+	       &mctl_ctl->rfshtmg);
+
+	if (dram_para.tpr13 & 0x20)
+		writel(0x01040001, &mctl_ctl->mstr);
+	else
+		writel(0x01040401, &mctl_ctl->mstr);
+
+	if (!(dram_para.tpr13 & 0x20000)) {
+		writel(0x00000002, &mctl_ctl->pwrctl);
+		writel(0x00008001, &mctl_ctl->pwrtmg);
+	}
+
+	writel(0x00000001, &mctl_ctl->rfshctl3);
+	writel(0x00000001, &mctl_ctl->pimisc);
+
+	/* deassert dram_clk_cfg reset */
+	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
+
+	setbits_le32(&mctl_com->ccr, 0x80000);
+
+	/* zq stuff */
+	writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);
+
+	writel(0x00000003, &mctl_phy->pir);
+	udelay(10);
+	mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);
+
+	writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
+	writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
+
+	/* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
+	writel(0x000005f3, &mctl_phy->pir);
+	udelay(10);
+	mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
+
+	if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
+		*bus_width = 8;
+		writel(0, &mctl_phy->dx1gcr);
+		writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
+		writel(0x5f3, &mctl_phy->pir);
+		udelay(10000);
+		setbits_le32(&mctl_ctl->mstr, 0x1000);
+	} else
+		*bus_width = 16;
+
+	correction = (dram_para.odt_en >> 8) & 0xff;
+	if (correction) {
+		if (dram_para.odt_en & 0x80000000)
+			correction = -correction;
+
+		mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
+		mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
+	}
+
+	mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
+
+	writel(0x08003e3f, &mctl_phy->pgcr0);
+	writel(0x00000000, &mctl_ctl->rfshctl3);
+}
+
+unsigned long sunxi_dram_init(void)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+		(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	const u32 columns = 13;
+	u32 bus, bus_width, offset, page_size, rows;
+
+	mctl_sys_init();
+	mctl_init(&bus_width);
+
+	if (bus_width == 16) {
+		page_size = 8;
+		bus = 1;
+	} else {
+		page_size = 7;
+		bus = 0;
+	}
+
+	if (!(dram_para.tpr13 & 0x80000000)) {
+		/* Detect and set rows */
+		writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
+		       &mctl_com->cr);
+		setbits_le32(&mctl_com->swonr, 0x0003ffff);
+		mctl_mem_fill();
+		for (rows = 11; rows < 16; rows++) {
+			offset = 1 << (rows + columns + bus);
+			if (mctl_mem_matches(offset))
+				break;
+		}
+		clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
+				MCTL_CR_ROW(rows));
+	} else {
+		rows = (dram_para.para1 >> 16) & 0xff;
+		writel(((dram_para.para2 & 0x000000f0) << 11) |
+		       ((rows - 1) << 4) |
+		       ((dram_para.para1 & 0x0f000000) >> 22) |
+		       0x31000 | MCTL_CR_PAGE_SIZE(page_size),
+		       &mctl_com->cr);
+		setbits_le32(&mctl_com->swonr, 0x0003ffff);
+	}
+
+	/* Setup DRAM master priority? If this is left out things still work */
+	writel(0x00000008, &mctl_com->mcr0_0);
+	writel(0x0001000d, &mctl_com->mcr1_0);
+	writel(0x00000004, &mctl_com->mcr0_1);
+	writel(0x00000080, &mctl_com->mcr1_1);
+	writel(0x00000004, &mctl_com->mcr0_2);
+	writel(0x00000019, &mctl_com->mcr1_2);
+	writel(0x00000004, &mctl_com->mcr0_3);
+	writel(0x00000080, &mctl_com->mcr1_3);
+	writel(0x00000004, &mctl_com->mcr0_4);
+	writel(0x01010040, &mctl_com->mcr1_4);
+	writel(0x00000004, &mctl_com->mcr0_5);
+	writel(0x0001002f, &mctl_com->mcr1_5);
+	writel(0x00000004, &mctl_com->mcr0_6);
+	writel(0x00010020, &mctl_com->mcr1_6);
+	writel(0x00000004, &mctl_com->mcr0_7);
+	writel(0x00010020, &mctl_com->mcr1_7);
+	writel(0x00000008, &mctl_com->mcr0_8);
+	writel(0x00000001, &mctl_com->mcr1_8);
+	writel(0x00000008, &mctl_com->mcr0_9);
+	writel(0x00000005, &mctl_com->mcr1_9);
+	writel(0x00000008, &mctl_com->mcr0_10);
+	writel(0x00000003, &mctl_com->mcr1_10);
+	writel(0x00000008, &mctl_com->mcr0_11);
+	writel(0x00000005, &mctl_com->mcr1_11);
+	writel(0x00000008, &mctl_com->mcr0_12);
+	writel(0x00000003, &mctl_com->mcr1_12);
+	writel(0x00000008, &mctl_com->mcr0_13);
+	writel(0x00000004, &mctl_com->mcr1_13);
+	writel(0x00000008, &mctl_com->mcr0_14);
+	writel(0x00000002, &mctl_com->mcr1_14);
+	writel(0x00000008, &mctl_com->mcr0_15);
+	writel(0x00000003, &mctl_com->mcr1_15);
+	writel(0x00010138, &mctl_com->bwcr);
+
+	return 1 << (rows + columns + bus);
+}
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index 7d61216..45a199c 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -273,7 +273,11 @@  struct sunxi_ccm_reg {
 #define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
 #define CCM_HDMI_CTRL_GATE		(0x1 << 31)
 
+#ifndef CONFIG_MACH_SUN8I
 #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
+#else
+#define MBUS_CLK_DEFAULT		0x81000003 /* PLL6 / 4 */
+#endif
 
 #define CCM_PLL5_PATTERN		0xd1303333
 
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
index a8a37d5..8d78029 100644
--- a/arch/arm/include/asm/arch-sunxi/dram.h
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -18,6 +18,8 @@ 
 /* dram regs definition */
 #if defined(CONFIG_MACH_SUN6I)
 #include <asm/arch/dram_sun6i.h>
+#elif defined(CONFIG_MACH_SUN8I)
+#include <asm/arch/dram_sun8i.h>
 #else
 #include <asm/arch/dram_sun4i.h>
 #endif
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
new file mode 100644
index 0000000..425cf37
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i.h
@@ -0,0 +1,266 @@ 
+/*
+ * Sun8i platform dram controller register and constant defines
+ *
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * CPL <cplanxy@allwinnertech.com>
+ * Jerry Wang <wangflord@allwinnertech.com>
+ *
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN8I_H
+#define _SUNXI_DRAM_SUN8I_H
+
+struct dram_para {
+	u32 clock;
+	u32 type;
+	u32 zq;
+	u32 odt_en;
+	u32 para1;
+	u32 para2;
+	u32 mr0;
+	u32 mr1;
+	u32 mr2;
+	u32 mr3;
+	u32 tpr0;
+	u32 tpr1;
+	u32 tpr2;
+	u32 tpr3;
+	u32 tpr4;
+	u32 tpr5;
+   	u32 tpr6;
+	u32 tpr7;
+	u32 tpr8;
+	u32 tpr9;
+	u32 tpr10;
+	u32 tpr11;
+	u32 tpr12;
+	u32 tpr13;
+};
+
+struct sunxi_mctl_com_reg {
+	u32 cr;			/* 0x00 */
+	u32 ccr;		/* 0x04 controller configuration register */
+	u32 dbgcr;		/* 0x08 */
+	u8 res0[0x4];		/* 0x0c */
+	u32 mcr0_0;		/* 0x10 */
+	u32 mcr1_0;		/* 0x14 */
+	u32 mcr0_1;		/* 0x18 */
+	u32 mcr1_1;		/* 0x1c */
+	u32 mcr0_2;		/* 0x20 */
+	u32 mcr1_2;		/* 0x24 */
+	u32 mcr0_3;		/* 0x28 */
+	u32 mcr1_3;		/* 0x2c */
+	u32 mcr0_4;		/* 0x30 */
+	u32 mcr1_4;		/* 0x34 */
+	u32 mcr0_5;		/* 0x38 */
+	u32 mcr1_5;		/* 0x3c */
+	u32 mcr0_6;		/* 0x40 */
+	u32 mcr1_6;		/* 0x44 */
+	u32 mcr0_7;		/* 0x48 */
+	u32 mcr1_7;		/* 0x4c */
+	u32 mcr0_8;		/* 0x50 */
+	u32 mcr1_8;		/* 0x54 */
+	u32 mcr0_9;		/* 0x58 */
+	u32 mcr1_9;		/* 0x5c */
+	u32 mcr0_10;		/* 0x60 */
+	u32 mcr1_10;		/* 0x64 */
+	u32 mcr0_11;		/* 0x68 */
+	u32 mcr1_11;		/* 0x6c */
+	u32 mcr0_12;		/* 0x70 */
+	u32 mcr1_12;		/* 0x74 */
+	u32 mcr0_13;		/* 0x78 */
+	u32 mcr1_13;		/* 0x7c */
+	u32 mcr0_14;		/* 0x80 */
+	u32 mcr1_14;		/* 0x84 */
+	u32 mcr0_15;		/* 0x88 */
+	u32 mcr1_15;		/* 0x8c */
+	u32 bwcr;		/* 0x90 */
+	u32 maer;		/* 0x94 */
+	u8 res1[0x4];		/* 0x98 */
+	u32 mcgcr;		/* 0x9c */
+	u32 bwctr;		/* 0xa0 */
+	u8 res2[0x4];		/* 0xa4 */
+	u32 swonr;		/* 0xa8 */
+	u32 swoffr;		/* 0xac */
+};
+
+struct sunxi_mctl_ctl_reg {
+	u32 mstr;		/* 0x00 */
+	u32 statr;		/* 0x04 */
+	u8 res0[0x08];		/* 0x08 */
+	u32 mrctrl0;		/* 0x10 */
+	u32 mrctrl1;		/* 0x14 */
+	u32 mrstatr;		/* 0x18 */
+	u8 res1[0x04];		/* 0x1c */
+	u32 derateen;		/* 0x20 */
+	u32 deratenint;		/* 0x24 */
+	u8 res2[0x08];		/* 0x28 */
+	u32 pwrctl;		/* 0x30 */
+	u32 pwrtmg;		/* 0x34 */
+	u8 res3[0x18];		/* 0x38 */
+	u32 rfshctl0;		/* 0x50 */
+	u32 rfshctl1;		/* 0x54 */
+	u8 res4[0x8];		/* 0x58 */
+	u32 rfshctl3;		/* 0x60 */
+	u32 rfshtmg;		/* 0x64 */
+	u8 res6[0x68];		/* 0x68 */
+	u32 init0;		/* 0xd0 */
+	u32 init1;		/* 0xd4 */
+	u32 init2;		/* 0xd8 */
+	u32 init3;		/* 0xdc */
+	u32 init4;		/* 0xe0 */
+	u32 init5;		/* 0xe4 */
+	u8 res7[0x0c];		/* 0xe8 */
+	u32 rankctl;		/* 0xf4 */
+	u8 res8[0x08];		/* 0xf8 */
+	u32 dramtmg0;		/* 0x100 */
+	u32 dramtmg1;		/* 0x104 */
+	u32 dramtmg2;		/* 0x108 */
+	u32 dramtmg3;		/* 0x10c */
+	u32 dramtmg4;		/* 0x110 */
+	u32 dramtmg5;		/* 0x114 */
+	u32 dramtmg6;		/* 0x118 */
+	u32 dramtmg7;		/* 0x11c */
+	u32 dramtmg8;		/* 0x120 */
+	u8 res9[0x5c];		/* 0x124 */
+	u32 zqctl0;		/* 0x180 */
+	u32 zqctl1;		/* 0x184 */
+	u32 zqctl2;		/* 0x188 */
+	u32 zqstat;		/* 0x18c */
+	u32 pitmg0;		/* 0x190 */
+	u32 pitmg1;		/* 0x194 */
+	u32 plpcfg0;		/* 0x198 */
+	u8 res10[0x04];		/* 0x19c */
+	u32 upd0;		/* 0x1a0 */
+	u32 upd1;		/* 0x1a4 */
+	u32 upd2;		/* 0x1a8 */
+	u32 upd3;		/* 0x1ac */
+	u32 pimisc;		/* 0x1b0 */
+	u8 res11[0x1c];		/* 0x1b4 */
+	u32 trainctl0;		/* 0x1d0 */
+	u32 trainctl1;		/* 0x1d4 */
+	u32 trainctl2;		/* 0x1d8 */
+	u32 trainstat;		/* 0x1dc */
+	u8 res12[0x60];		/* 0x1e0 */
+	u32 odtcfg;		/* 0x240 */
+	u32 odtmap;		/* 0x244 */
+	u8 res13[0x08];		/* 0x248 */
+	u32 sched;		/* 0x250 */
+	u8 res14[0x04];		/* 0x254 */
+	u32 perfshpr0;		/* 0x258 */
+	u32 perfshpr1;		/* 0x25c */
+	u32 perflpr0;		/* 0x260 */
+	u32 perflpr1;		/* 0x264 */
+	u32 perfwr0;		/* 0x268 */
+	u32 perfwr1;		/* 0x26c */
+};
+
+struct sunxi_mctl_phy_reg {
+	u8 res0[0x04];		/* 0x00 */
+	u32 pir;		/* 0x04 */
+	u32 pgcr0;		/* 0x08 phy general configuration register */
+	u32 pgcr1;		/* 0x0c phy general configuration register */
+	u32 pgsr0;		/* 0x10 */
+	u32 pgsr1;		/* 0x14 */
+	u32 dllgcr;		/* 0x18 */
+	u32 ptr0;		/* 0x1c */
+	u32 ptr1;		/* 0x20 */
+	u32 ptr2;		/* 0x24 */
+	u32 ptr3;		/* 0x28 */
+	u32 ptr4;		/* 0x2c */
+	u32 acmdlr;		/* 0x30 */
+	u32 acbdlr;		/* 0x34 */
+	u32 aciocr;		/* 0x38 */
+	u32 dxccr;		/* 0x3c DATX8 common configuration register */
+	u32 dsgcr;		/* 0x40 dram system general config register */
+	u32 dcr;		/* 0x44 */
+	u32 dtpr0;		/* 0x48 dram timing parameters register 0 */
+	u32 dtpr1;		/* 0x4c dram timing parameters register 1 */
+	u32 dtpr2;		/* 0x50 dram timing parameters register 2 */
+	u32 mr0;		/* 0x54 mode register 0 */
+	u32 mr1;		/* 0x58 mode register 1 */
+	u32 mr2;		/* 0x5c mode register 2 */
+	u32 mr3;		/* 0x60 mode register 3 */
+	u32 odtcr;		/* 0x64 */
+	u32 dtcr;		/* 0x68 */
+	u32 dtar0;		/* 0x6c data training address register 0 */
+	u32 dtar1;		/* 0x70 data training address register 1 */
+	u32 dtar2;		/* 0x74 data training address register 2 */
+	u32 dtar3;		/* 0x78 data training address register 3 */
+	u32 dtdr0;		/* 0x7c */
+	u32 dtdr1;		/* 0x80 */
+	u32 dtedr0;		/* 0x84 */
+	u32 dtedr1;		/* 0x88 */
+	u32 pgcr2;		/* 0x8c */
+	u8 res1[0x70];		/* 0x90 */
+	u32 bistrr;		/* 0x100 */
+	u32 bistwcr;		/* 0x104 */
+	u32 bistmskr0;		/* 0x108 */
+	u32 bistmskr1;		/* 0x10c */
+	u32 bistmskr2;		/* 0x110 */
+	u32 bistlsr;		/* 0x114 */
+	u32 bistar0;		/* 0x118 */
+	u32 bistar1;		/* 0x11c */
+	u32 bistar2;		/* 0x120 */
+	u32 bistupdr;		/* 0x124 */
+	u32 bistgsr;		/* 0x128 */
+	u32 bistwer;		/* 0x12c */
+	u32 bistber0;		/* 0x130 */
+	u32 bistber1;		/* 0x134 */
+	u32 bistber2;		/* 0x138 */
+	u32 bistber3;		/* 0x13c */
+	u32 bistwcsr;		/* 0x140 */
+	u32 bistfwr0;		/* 0x144 */
+	u32 bistfwr1;		/* 0x148 */
+	u32 bistfwr2;		/* 0x14c */
+	u8 res2[0x30];		/* 0x150 */
+	u32 zqcr0;		/* 0x180 zq control register 0 */
+	u32 zqcr1;		/* 0x184 zq control register 1 */
+	u32 zqsr0;		/* 0x188 zq status register 0 */
+	u32 zqsr1;		/* 0x18c zq status register 1 */
+	u32 zqcr2;		/* 0x190 zq control register 2 */
+	u8 res3[0x2c];		/* 0x194 */
+	u32 dx0gcr;		/* 0x1c0 */
+	u32 dx0gsr0;		/* 0x1c4 */
+	u32 dx0gsr1;		/* 0x1c8 */
+	u32 dx0bdlr0;		/* 0x1cc */
+	u32 dx0bdlr1;		/* 0x1d0 */
+	u32 dx0bdlr2;		/* 0x1d4 */
+	u32 dx0bdlr3;		/* 0x1d8 */
+	u32 dx0bdlr4;		/* 0x1dc */
+	u32 dx0lcdlr0;		/* 0x1e0 */
+	u32 dx0lcdlr1;		/* 0x1e4 */
+	u32 dx0lcdlr2;		/* 0x1e8 */
+	u32 dx0mdlr;		/* 0x1ec */
+	u32 dx0gtr;		/* 0x1f0 */
+	u32 dx0gsr2;		/* 0x1f4 */
+	u8 res4[0x08];		/* 0x1f8 */
+	u32 dx1gcr;		/* 0x200 */
+	u32 dx1gsr0;		/* 0x204 */
+	u32 dx1gsr1;		/* 0x208 */
+	u32 dx1bdlr0;		/* 0x20c */
+	u32 dx1bdlr1;		/* 0x210 */
+	u32 dx1bdlr2;		/* 0x214 */
+	u32 dx1bdlr3;		/* 0x218 */
+	u32 dx1bdlr4;		/* 0x21c */
+	u32 dx1lcdlr0;		/* 0x220 */
+	u32 dx1lcdlr1;		/* 0x224 */
+	u32 dx1lcdlr2;		/* 0x228 */
+	u32 dx1mdlr;		/* 0x22c */
+	u32 dx1gtr;		/* 0x230 */
+	u32 dx1gsr2;		/* 0x234 */
+};
+
+/*
+ * DRAM common (sunxi_mctl_com_reg) register constants.
+ */
+#define MCTL_CR_ROW_MASK		(0xf << 4)
+#define MCTL_CR_ROW(x)			(((x) - 1) << 4)
+#define MCTL_CR_PAGE_SIZE_MASK		(0xf << 8)
+#define MCTL_CR_PAGE_SIZE(x)		((x) << 8)
+
+#endif /* _SUNXI_DRAM_SUN8I_H */
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
index 5bb2f58..5a88ba0 100644
--- a/board/sunxi/Kconfig
+++ b/board/sunxi/Kconfig
@@ -29,10 +29,11 @@  config MACH_SUN7I
 config MACH_SUN8I
 	bool "sun8i (Allwinner A23)"
 	select CPU_V7
+	select SUPPORT_SPL
 
 endchoice
 
-if MACH_SUN6I
+if MACH_SUN6I || MACH_SUN8I
 
 config DRAM_CLK
 	int "sun6i dram clock speed"
diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
index 50c2f93..37aa46d 100644
--- a/configs/Ippo_q8h_v5_defconfig
+++ b/configs/Ippo_q8h_v5_defconfig
@@ -1,8 +1,15 @@ 
+CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
 CONFIG_VIDEO=n
 CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y
++S:CONFIG_DRAM_CLK=480
+# zq = 0xf777
++S:CONFIG_DRAM_ZQ=63351
+# Wifi power
++S:CONFIG_AXP221_DLDO1_VOLT=3300
+# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
++S:CONFIG_AXP221_ALDO1_VOLT=3000
diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h
index 6f1fc48..792422d 100644
--- a/include/configs/sun8i.h
+++ b/include/configs/sun8i.h
@@ -12,6 +12,8 @@ 
 /*
  * A23 specific configuration
  */
+#define CONFIG_CLK_FULL_SPEED	1008000000
+
 #define CONFIG_SYS_PROMPT	"sun8i# "
 
 /*