Dne nedelja, 23. marec 2025 ob 12:35:40 Srednjeevropski standardni čas je Andre 
Przywara napisal(a):
> From: Jernej Skrabec <jernej.skra...@gmail.com>
> 
> DRAM init code, as per reverse engineering and matching against
> previous SoCs.
> Supports LPDDR4 for now only.
> ---
>  arch/arm/include/asm/arch-sunxi/dram.h        |    2 +
>  .../include/asm/arch-sunxi/dram_sun55i_a523.h |  183 ++
>  arch/arm/mach-sunxi/Kconfig                   |   31 +-
>  arch/arm/mach-sunxi/Makefile                  |    2 +
>  arch/arm/mach-sunxi/dram_sun55i_a523.c        | 1468 +++++++++++++++++
>  arch/arm/mach-sunxi/dram_timings/Makefile     |    1 +
>  .../arm/mach-sunxi/dram_timings/a523_lpddr4.c |  119 ++
>  7 files changed, 1804 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h
>  create mode 100644 arch/arm/mach-sunxi/dram_sun55i_a523.c
>  create mode 100644 arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/dram.h 
> b/arch/arm/include/asm/arch-sunxi/dram.h
> index 9d21b492418..9676c747442 100644
> --- a/arch/arm/include/asm/arch-sunxi/dram.h
> +++ b/arch/arm/include/asm/arch-sunxi/dram.h
> @@ -33,6 +33,8 @@
>  #include <asm/arch/dram_sun50i_h616.h>
>  #elif defined(CONFIG_MACH_SUNIV)
>  #include <asm/arch/dram_suniv.h>
> +#elif defined(CONFIG_MACH_SUN55I_A523)
> +#include <asm/arch/dram_sun55i_a523.h>
>  #else
>  #include <asm/arch/dram_sun4i.h>
>  #endif
> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h 
> b/arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h
> new file mode 100644
> index 00000000000..24e487b6880
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h
> @@ -0,0 +1,183 @@
> +/*
> + * t527 dram controller register and constant defines
> + *
> + * (C) Copyright 2024  Jernej Skrabec <jernej.skra...@gmail.com>
> + *
> + * SPDX-License-Identifier:  GPL-2.0+
> + */
> +
> +#ifndef _SUNXI_DRAM_SUN55I_A523_H
> +#define _SUNXI_DRAM_SUN55I_A523_H
> +
> +#include <stdbool.h>
> +#ifndef __ASSEMBLY__
> +#include <linux/bitops.h>
> +#endif
> +
> +enum sunxi_dram_type {
> +     SUNXI_DRAM_TYPE_DDR3 = 3,
> +     SUNXI_DRAM_TYPE_DDR4,
> +     SUNXI_DRAM_TYPE_LPDDR3 = 7,
> +     SUNXI_DRAM_TYPE_LPDDR4
> +};
> +
> +/* MBUS part is largely the same as in H6, except for one special register */
> +struct sunxi_mctl_com_reg {
> +     u32 cr;                 /* 0x000 control register */
> +     u8 reserved_0x004[4];   /* 0x004 */
> +     u32 unk_0x008;          /* 0x008 */
> +     u32 tmr;                /* 0x00c timer register */
> +     u8 reserved_0x010[4];   /* 0x010 */
> +     u32 unk_0x014;          /* 0x014 */
> +     u8 reserved_0x018[8];   /* 0x018 */
> +     u32 unk_0x020;          /* 0x020 */
> +     u32 unk_0x024;          /* 0x024 */
> +     u32 unk_0x028;          /* 0x028 */
> +     u8 reserved_0x02c[468]; /* 0x02c */
> +     u32 bwcr;               /* 0x200 bandwidth control register */
> +     u8 reserved_0x204[12];  /* 0x204 */
> +     /*
> +      * The last master configured by BSP libdram is at 0x49x, so the
> +      * size of this struct array is set to 41 (0x29) now.
> +      */
> +     struct {
> +             u32 cfg0;               /* 0x0 */
> +             u32 cfg1;               /* 0x4 */
> +             u8 reserved_0x8[8];     /* 0x8 */
> +     } master[41];           /* 0x210 + index * 0x10 */
> +     u8 reserved_0x4a0[96];  /* 0x4a0 */
> +     u32 unk_0x500;          /* 0x500 */
> +};
> +check_member(sunxi_mctl_com_reg, unk_0x500, 0x500);

This struct doesn't make much sense. It's copy & paste from H616, only a few
registers are used and their names are not known. I would vote for it to be
redesigned as macros.

> +
> +/*
> + * Controller registers seems to be the same or at least very similar
> + * to those in H6.
> + */
> +struct sunxi_mctl_ctl_reg {
> +     u32 mstr;               /* 0x000 */
> +     u32 statr;              /* 0x004 unused */
> +     u32 mstr1;              /* 0x008 unused */
> +     u32 clken;              /* 0x00c */
> +     u32 mrctrl0;            /* 0x010 unused */
> +     u32 mrctrl1;            /* 0x014 unused */
> +     u32 mrstatr;            /* 0x018 unused */
> +     u32 mrctrl2;            /* 0x01c unused */
> +     u32 derateen;           /* 0x020 unused */
> +     u32 derateint;          /* 0x024 unused */
> +     u8 reserved_0x028[8];   /* 0x028 */
> +     u32 pwrctl;             /* 0x030 */
> +     u32 pwrtmg;             /* 0x034 unused */
> +     u32 hwlpctl;            /* 0x038 */
> +     u8 reserved_0x03c[20];  /* 0x03c */
> +     u32 rfshctl0;           /* 0x050 unused */
> +     u32 rfshctl1;           /* 0x054 unused */
> +     u8 reserved_0x058[8];   /* 0x05c */
> +     u32 rfshctl3;           /* 0x060 */
> +     u32 rfshtmg;            /* 0x064 */
> +     u8 reserved_0x068[104]; /* 0x068 */
> +     u32 init[8];            /* 0x0d0 */
> +     u32 dimmctl;            /* 0x0f0 unused */
> +     u32 rankctl;            /* 0x0f4 */
> +     u8 reserved_0x0f8[8];   /* 0x0f8 */
> +     u32 dramtmg[17];        /* 0x100 */
> +     u8 reserved_0x144[60];  /* 0x144 */
> +     u32 zqctl[3];           /* 0x180 */
> +     u32 zqstat;             /* 0x18c unused */
> +     u32 dfitmg0;            /* 0x190 */
> +     u32 dfitmg1;            /* 0x194 */
> +     u32 dfilpcfg[2];        /* 0x198 unused */
> +     u32 dfiupd[3];          /* 0x1a0 */
> +     u32 reserved_0x1ac;     /* 0x1ac */
> +     u32 dfimisc;            /* 0x1b0 */
> +     u32 dfitmg2;            /* 0x1b4 unused */
> +     u32 dfitmg3;            /* 0x1b8 unused */
> +     u32 dfistat;            /* 0x1bc */
> +     u32 dbictl;             /* 0x1c0 */
> +     u8 reserved_0x1c4[60];  /* 0x1c4 */
> +     u32 addrmap[12];        /* 0x200 */
> +     u8 reserved_0x230[16];  /* 0x230 */
> +     u32 odtcfg;             /* 0x240 */
> +     u32 odtmap;             /* 0x244 */
> +     u8 reserved_0x248[8];   /* 0x248 */
> +     u32 sched[2];           /* 0x250 */
> +     u8 reserved_0x258[12];  /* 0x258 */
> +     u32 unk_0x264;          /* 0x264 */
> +     u8 reserved_0x268[8];   /* 0x268 */
> +     u32 unk_0x270;          /* 0x270 */
> +     u8 reserved_0x274[152]; /* 0x274 */
> +     u32 dbgcmd;             /* 0x30c unused */
> +     u32 dbgstat;            /* 0x310 unused */
> +     u8 reserved_0x314[12];  /* 0x314 */
> +     u32 swctl;              /* 0x320 */
> +     u32 swstat;             /* 0x324 */
> +     u8 reserved_0x328[7768];/* 0x328 */
> +     u32 unk_0x2180;         /* 0x2180 */
> +     u8 reserved_0x2184[188];/* 0x2184 */
> +     u32 unk_0x2240;         /* 0x2240 */
> +     u8 reserved_0x2244[3900];/* 0x2244 */
> +     u32 unk_0x3180;         /* 0x3180 */
> +     u8 reserved_0x3184[188];/* 0x3184 */
> +     u32 unk_0x3240;         /* 0x3240 */
> +     u8 reserved_0x3244[3900];/* 0x3244 */
> +     u32 unk_0x4180;         /* 0x4180 */
> +     u8 reserved_0x4184[188];/* 0x4184 */
> +     u32 unk_0x4240;         /* 0x4240 */
> +};
> +check_member(sunxi_mctl_ctl_reg, swstat, 0x324);
> +check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240);

While this struct is much more useful and properly named, I would still
change it to macros, which could even be shared with H6 and H616, since
controller didn't change much between generations.

Fun fact: Those unk_0x2180, unk_0x3180, etc. registers are actually same as
the ones on offset 0x180. In short, there are four backs of same registers.
Seemingly, this is needed for DDR4.

> +
> +#define MSTR_DEVICETYPE_DDR3 BIT(0)
> +#define MSTR_DEVICETYPE_LPDDR2       BIT(2)
> +#define MSTR_DEVICETYPE_LPDDR3       BIT(3)
> +#define MSTR_DEVICETYPE_DDR4 BIT(4)
> +#define MSTR_DEVICETYPE_LPDDR4       BIT(5)
> +#define MSTR_DEVICETYPE_MASK GENMASK(5, 0)
> +#define MSTR_2TMODE          BIT(10)
> +#define MSTR_BUSWIDTH_FULL   (0 << 12)
> +#define MSTR_BUSWIDTH_HALF   (1 << 12)
> +#define MSTR_ACTIVE_RANKS(x) (((x == 2) ? 3 : 1) << 24)
> +#define MSTR_BURST_LENGTH(x) (((x) >> 1) << 16)
> +
> +#define TPR10_CA_BIT_DELAY   0xffff0000
> +#define TPR10_DX_BIT_DELAY0  BIT(17)
> +#define TPR10_DX_BIT_DELAY1  BIT(18)
> +#define TPR10_WRITE_LEVELING BIT(20)
> +#define TPR10_READ_CALIBRATION       BIT(21)
> +#define TPR10_READ_TRAINING  BIT(22)
> +#define TPR10_WRITE_TRAINING BIT(23)
> +
> +struct dram_para {
> +     enum sunxi_dram_type type;
> +     u32 dx_odt;
> +     u32 dx_dri;
> +     u32 ca_dri;
> +     u32 tpr0;
> +     u32 tpr1;
> +     u32 tpr2;
> +     u32 tpr6;
> +     u32 tpr10;
> +};
> +
> +struct dram_config {
> +     u8 cols;
> +     u8 rows;
> +     u8 ranks;
> +     u8 bus_full_width;
> +     u32 clk;
> +     u32 odt_en;
> +     u32 tpr11;
> +     u32 tpr12;
> +     u32 tpr14;
> +};
> +
> +static inline int ns_to_t(int nanoseconds, u32 clk)
> +{
> +     const unsigned int ctrl_freq = clk / 2;
> +
> +     return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
> +}
> +
> +void mctl_set_timing_params(u32 clk);
> +
> +#endif /* _SUNXI_DRAM_SUN55I_T527_H */
> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
> index ab432390d3c..aeab2b3f6dd 100644
> --- a/arch/arm/mach-sunxi/Kconfig
> +++ b/arch/arm/mach-sunxi/Kconfig
> @@ -51,7 +51,12 @@ config DRAM_SUN50I_H616
>         Select this dram controller driver for some sun50i platforms,
>         like H616.
>  
> -if DRAM_SUN50I_H616
> +config DRAM_SUN55I_A523
> +     bool
> +     help
> +       Select this DRAM controller driver for A523/T527 SoCs.
> +
> +if DRAM_SUN50I_H616 || DRAM_SUN55I_A523
>  config DRAM_SUNXI_DX_ODT
>       hex "DRAM DX ODT parameter"
>       help
> @@ -79,6 +84,12 @@ config DRAM_SUNXI_TPR0
>       help
>         TPR0 value from vendor DRAM settings.
>  
> +config DRAM_SUNXI_TPR1
> +     hex "DRAM TPR1 parameter"
> +     default 0x0
> +     help
> +       TPR1 value from vendor DRAM settings.
> +
>  config DRAM_SUNXI_TPR2
>       hex "DRAM TPR2 parameter"
>       default 0x0
> @@ -109,6 +120,13 @@ config DRAM_SUNXI_TPR12
>       help
>         TPR12 value from vendor DRAM settings.
>  
> +config DRAM_SUNXI_TPR14
> +     hex "DRAM TPR14 parameter"
> +     depends on MACH_SUN55I_A523
> +     default 0x48484848
> +     help
> +       TPR14 value from vendor DRAM settings.
> +
>  choice
>       prompt "DRAM PHY pin mapping selection"
>       default DRAM_SUNXI_PHY_ADDR_MAP_0
> @@ -497,7 +515,7 @@ config ARM_BOOT_HOOK_RMR
>       This allows both the SPL and the U-Boot proper to be entered in
>       either mode and switch to AArch64 if needed.
>  
> -if SUNXI_DRAM_DW || DRAM_SUN50I_H6 || DRAM_SUN50I_H616
> +if SUNXI_DRAM_DW || DRAM_SUN50I_H6 || DRAM_SUN50I_H616 || DRAM_SUN55I_A523
>  config SUNXI_DRAM_DDR3
>       bool
>  
> @@ -512,6 +530,7 @@ config SUNXI_DRAM_LPDDR4
>  
>  choice
>       prompt "DRAM Type and Timing"
> +     default SUNXI_DRAM_A523_LPDDR4 if MACH_SUN55I_A523
>       default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S
>       default SUNXI_DRAM_DDR2_V3S if MACH_SUN8I_V3S
>  
> @@ -577,6 +596,13 @@ config SUNXI_DRAM_DDR2_V3S
>       This option is only for the DDR2 memory chip which is co-packaged in
>       Allwinner V3s SoC.
>  
> +config SUNXI_DRAM_A523_LPDDR4
> +     bool "LPDDR4 DRAM chips on the A523/T527 DRAM controller"
> +     select SUNXI_DRAM_LPDDR4
> +     depends on DRAM_SUN55I_A523
> +     help
> +       This option is the LPDDR4 timing used by the stock boot0 by
> +       Allwinner.
>  endchoice
>  endif
>  
> @@ -597,6 +623,7 @@ config DRAM_CLK
>       default 672 if MACH_SUN50I
>       default 744 if MACH_SUN50I_H6
>       default 720 if MACH_SUN50I_H616
> +     default 1200 if MACH_SUN55I_A523
>       ---help---
>       Set the dram clock speed, valid range 240 - 480 (prior to sun9i),
>       must be a multiple of 24. For the sun9i (A80), the tested values
> diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
> index eb6a49119a1..3521335dbbf 100644
> --- a/arch/arm/mach-sunxi/Makefile
> +++ b/arch/arm/mach-sunxi/Makefile
> @@ -45,4 +45,6 @@ obj-$(CONFIG_DRAM_SUN50I_H6)        += dram_sun50i_h6.o
>  obj-$(CONFIG_DRAM_SUN50I_H6) += dram_timings/
>  obj-$(CONFIG_DRAM_SUN50I_H616)       += dram_sun50i_h616.o
>  obj-$(CONFIG_DRAM_SUN50I_H616)       += dram_timings/
> +obj-$(CONFIG_MACH_SUN55I_A523)       += dram_sun55i_a523.o
> +obj-$(CONFIG_DRAM_SUN55I_A523)       += dram_timings/
>  endif
> diff --git a/arch/arm/mach-sunxi/dram_sun55i_a523.c 
> b/arch/arm/mach-sunxi/dram_sun55i_a523.c
> new file mode 100644
> index 00000000000..fae02062547
> --- /dev/null
> +++ b/arch/arm/mach-sunxi/dram_sun55i_a523.c
> @@ -0,0 +1,1468 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * sun55i A523/A527/T527/H728 platform DRAM controller driver
> + *
> + * This driver supports DDR3 and LPDDR4 memory.
> + *
> + * (C) Copyright 2024 Jernej Skrabec <jernej.skra...@gmail.com>
> + *
> + */
> +#include <init.h>
> +#include <log.h>
> +#include <asm/io.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/dram.h>
> +#include <asm/arch/cpu.h>
> +#include <asm/arch/prcm.h>
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +
> +static void mctl_sys_init(u32 clk_rate)
> +{
> +     void * const ccm = (void *)SUNXI_CCM_BASE;
> +
> +     /* Put all DRAM-related blocks to reset state */
> +     clrbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_ENABLE);
> +     clrbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_RESET);
> +     setbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_UPDATE);
> +     clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(GATE_SHIFT));
> +     udelay(5);
> +     clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(RESET_SHIFT));
> +     clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL_CTRL_EN);
> +     clrsetbits_le32(ccm + CCU_H6_DRAM_CLK_CFG,
> +                     DRAM_CLK_ENABLE, DRAM_CLK_UPDATE);
> +
> +     udelay(5);
> +
> +     /* Set PLL5 rate to doubled DRAM clock rate */
> +     writel(CCM_PLL_CTRL_EN | CCM_PLL_LDO_EN | CCM_PLL_LOCK_EN |
> +            CCM_PLL_OUT_EN | CCM_PLL5_CTRL_N(clk_rate * 2 / 24),
> +            ccm + CCU_H6_PLL5_CFG);
> +     mctl_await_completion(ccm + CCU_H6_PLL5_CFG,
> +                           CCM_PLL_LOCK, CCM_PLL_LOCK);
> +
> +     /* Configure DRAM mod clock */
> +     writel(DRAM_CLK_SRC_PLL5, ccm + CCU_H6_DRAM_CLK_CFG);
> +     writel(BIT(RESET_SHIFT), ccm + CCU_H6_DRAM_GATE_RESET);
> +     udelay(5);
> +     setbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(GATE_SHIFT));
> +
> +     /* Configure MBUS and enable DRAM clock */
> +     setbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_RESET | MBUS_UPDATE);
> +     setbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_ENABLE | MBUS_UPDATE);
> +
> +     clrsetbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, DRAM_CLK_M_MASK,
> +                     DRAM_CLK_ENABLE | DRAM_CLK_UPDATE | DRAM_CLK_M(4));
> +     udelay(5);
> +}
> +
> +static void mctl_set_addrmap(const struct dram_config *config)
> +{
> +     struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +                     (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +     u8 cols = config->cols;
> +     u8 rows = config->rows;
> +     u8 ranks = config->ranks;
> +
> +     if (!config->bus_full_width)
> +             cols -= 1;
> +
> +     /* Ranks */
> +     if (ranks == 2)
> +             mctl_ctl->addrmap[0] = 0x1F00 | (rows + cols - 3);
> +     else
> +             mctl_ctl->addrmap[0] = 0x1F1F;
> +
> +     /* Banks, hardcoded to 8 banks now */
> +     mctl_ctl->addrmap[1] = (cols - 2) | (cols - 2) << 8 | (cols - 2) << 16;
> +
> +     /* Columns */
> +     mctl_ctl->addrmap[2] = 0;
> +     switch (cols) {
> +     case 7:
> +             mctl_ctl->addrmap[3] = 0x1F1F1F00;
> +             mctl_ctl->addrmap[4] = 0x1F1F;
> +             break;
> +     case 8:
> +             mctl_ctl->addrmap[3] = 0x1F1F0000;
> +             mctl_ctl->addrmap[4] = 0x1F1F;
> +             break;
> +     case 9:
> +             mctl_ctl->addrmap[3] = 0x1F000000;
> +             mctl_ctl->addrmap[4] = 0x1F1F;
> +             break;
> +     case 10:
> +             mctl_ctl->addrmap[3] = 0;
> +             mctl_ctl->addrmap[4] = 0x1F1F;
> +             break;
> +     case 11:
> +             mctl_ctl->addrmap[3] = 0;
> +             mctl_ctl->addrmap[4] = 0x1F00;
> +             break;
> +     case 12:
> +             mctl_ctl->addrmap[3] = 0;
> +             mctl_ctl->addrmap[4] = 0;
> +             break;
> +     default:
> +             panic("Unsupported DRAM configuration: column number 
> invalid\n");
> +     }
> +
> +     /* Rows */
> +     mctl_ctl->addrmap[5] = (cols - 3) | ((cols - 3) << 8) |
> +                            ((cols - 3) << 16) | ((cols - 3) << 24);
> +     switch (rows) {
> +     case 13:
> +             mctl_ctl->addrmap[6] = (cols - 3) | 0x0F0F0F00;
> +             mctl_ctl->addrmap[7] = 0x0F0F;
> +             break;
> +     case 14:
> +             mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) |
> +                                    0x0F0F0000;
> +             mctl_ctl->addrmap[7] = 0x0F0F;
> +             break;
> +     case 15:
> +             mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) |
> +                                    ((cols - 3) << 16) | 0x0F000000;
> +             mctl_ctl->addrmap[7] = 0x0F0F;
> +             break;
> +     case 16:
> +             mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) |
> +                                    ((cols - 3) << 16) | ((cols - 3) << 24);
> +             mctl_ctl->addrmap[7] = 0x0F0F;
> +             break;
> +     case 17:
> +             mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) |
> +                                    ((cols - 3) << 16) | ((cols - 3) << 24);
> +             mctl_ctl->addrmap[7] = (cols - 3) | 0x0F00;
> +             break;
> +     case 18:
> +             mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) |
> +                                    ((cols - 3) << 16) | ((cols - 3) << 24);
> +             mctl_ctl->addrmap[7] = (cols - 3) | ((cols - 3) << 8);
> +             break;
> +     default:
> +             panic("Unsupported DRAM configuration: row number invalid\n");
> +     }
> +
> +     /* Bank groups, DDR4 only */
> +     mctl_ctl->addrmap[8] = 0x3F3F;
> +}
> +
> +#define MASK_BYTE(reg, nr) (((reg) >> ((nr) * 8)) & 0x1f)
> +static void mctl_phy_configure_odt(const struct dram_para *para)
> +{
> +     u32 val_lo, val_hi;
> +
> +     val_hi = para->dx_dri;
> +     val_lo = (para->type != SUNXI_DRAM_TYPE_LPDDR4) ? para->dx_dri :
> +              (para->tpr1 & 0x1f1f1f1f) ? para->tpr1 : 0x04040404;
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x304, 0x1f1f0000,
> +                     (MASK_BYTE(val_hi, 0) << 24) |
> +                     (MASK_BYTE(val_lo, 0) << 16));
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x484, 0x1f1f0000,
> +                     (MASK_BYTE(val_hi, 1) << 24) |
> +                     (MASK_BYTE(val_lo, 1) << 16));
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x604, 0x1f1f0000,
> +                     (MASK_BYTE(val_hi, 2) << 24) |
> +                     (MASK_BYTE(val_lo, 2) << 16));
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x784, 0x1f1f0000,
> +                     (MASK_BYTE(val_hi, 3) << 24) |
> +                     (MASK_BYTE(val_lo, 3) << 16));
> +
> +     val_lo = para->ca_dri;
> +     val_hi = para->ca_dri;
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xf4, 0x1f1f1f1f,
> +                     (MASK_BYTE(val_hi, 0) << 24) |
> +                     (MASK_BYTE(val_lo, 0) << 16) |
> +                     (MASK_BYTE(val_hi, 1) << 8) |
> +                     (MASK_BYTE(val_lo, 1)));
> +
> +     val_hi = para->dx_odt;
> +     val_lo = (para->type == SUNXI_DRAM_TYPE_LPDDR4) ? 0 : para->dx_odt;
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x304, 0x00001f1f,
> +                     (MASK_BYTE(val_hi, 0) << 8) | MASK_BYTE(val_lo, 0));
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x484, 0x00001f1f,
> +                     (MASK_BYTE(val_hi, 1) << 8) | MASK_BYTE(val_lo, 1));
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x604, 0x00001f1f,
> +                     (MASK_BYTE(val_hi, 2) << 8) | MASK_BYTE(val_lo, 2));
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x784, 0x00001f1f,
> +                     (MASK_BYTE(val_hi, 3) << 8) | MASK_BYTE(val_lo, 3));
> +}
> +
> +static bool mctl_phy_write_leveling(const struct dram_para *para,
> +                                 const struct dram_config *config)
> +{
> +     u32 mr2, low, high, val = 0;
> +     bool result = true;
> +

This one is untested, I guess warning would be nice?

> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0xf00, 0xe00);
> +
> +     if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
> +             if (config->clk <= 936)
> +                     mr2 = 0x1b;
> +             else if (config->clk <= 1200)
> +                     mr2 = 0x2d;
> +             else
> +                     mr2 = 0x36;
> +             writeb(mr2, SUNXI_DRAM_PHY0_BASE + 3);
> +     }
> +
> +     low = readw(SUNXI_DRAM_PHY0_BASE + 2) | 4;
> +     high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +     writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +     writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +
> +     if (config->bus_full_width)
> +             val = 0xf;
> +     else
> +             val = 3;
> +
> +     mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x62), val, val);
> +
> +     low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xfffb;
> +     high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +     writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +     writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +
> +     val = readl(SUNXI_DRAM_PHY0_BASE + 0x96);
> +     if (val == 0 || val == 0x3f)
> +             result = false;
> +     val = readl(SUNXI_DRAM_PHY0_BASE + 0x97); //TODO: ???
> +     if (val == 0 || val == 0x3f)
> +             result = false;
> +     val = readl(SUNXI_DRAM_PHY0_BASE + 0xc6);
> +     if (val == 0 || val == 0x3f)
> +             result = false;
> +     val = readl(SUNXI_DRAM_PHY0_BASE + 0xc7); //TODO: ???
> +     if (val == 0 || val == 0x3f)
> +             result = false;
> +
> +     low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xff3f;
> +     high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +     writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +     writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +
> +     if (config->ranks == 2) {
> +             low = (readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xff3f) | 0x40;
> +             high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +             writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +             writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +
> +             low = readw(SUNXI_DRAM_PHY0_BASE + 2) | 4;
> +             high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +             writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +             writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +
> +             if (config->bus_full_width)
> +                     val = 0xf;
> +             else
> +                     val = 3;
> +
> +             mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x62), 
> val, val);
> +
> +             low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xfffb;
> +             high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +             writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +             writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +     }
> +
> +     low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xff3f;
> +     high = readw(SUNXI_DRAM_PHY0_BASE + 4);
> +     writew(low, SUNXI_DRAM_PHY0_BASE + 2);
> +     writew(high, SUNXI_DRAM_PHY0_BASE + 4);
> +
> +     return result;
> +}
> +
> +static bool mctl_phy_read_calibration(const struct dram_para *para,
> +                                   const struct dram_config *config)
> +{
> +     bool result = true;
> +     u32 val;

This one works.

> +
> +     if (para->type == SUNXI_DRAM_TYPE_LPDDR4)
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, 0x20000000);
> +
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c, 0x38);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1);
> +
> +     if (config->bus_full_width)
> +             val = 0xf;
> +     else
> +             val = 3;
> +
> +     while ((readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & val) != val) {
> +             if (readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & 0x20) {
> +                     result = false;
> +                     break;
> +             }
> +     }
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c);
> +
> +     if (config->ranks == 2) {
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c, 0x34);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1);
> +
> +             while ((readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & val) != val) {
> +                     if (readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & 0x20) {
> +                             result = false;
> +                             break;
> +                     }
> +             }
> +
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1);
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c);
> +     }
> +
> +     return result;
> +}
> +
> +static bool mctl_phy_read_training(const struct dram_para *para,
> +                                const struct dram_config *config)
> +{
> +     u32 val1, val2, *ptr1, *ptr2;
> +     bool result = true;
> +     int i;

This one is untested too.

> +
> +     if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
> +             writel(0, SUNXI_DRAM_PHY0_BASE + 0x200);
> +             writeb(0, SUNXI_DRAM_PHY0_BASE + 0x207);
> +             writeb(0, SUNXI_DRAM_PHY0_BASE + 0x208);
> +             writeb(0, SUNXI_DRAM_PHY0_BASE + 0x209);
> +             writeb(0, SUNXI_DRAM_PHY0_BASE + 0x20a);
> +     }
> +
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x804, 0x3f, 0xf);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x808, 0x3f, 0xf);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa04, 0x3f, 0xf);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa08, 0x3f, 0xf);
> +
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1);
> +
> +     mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc);
> +     if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3)
> +             result = false;
> +
> +     if (config->bus_full_width) {
> +             mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 
> 0xc, 0xc);
> +             if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3)
> +                     result = false;
> +     }
> +
> +     ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x898);
> +     ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x850);
> +     for (i = 0; i < 9; i++) {
> +             val1 = readl(&ptr1[i]);
> +             val2 = readl(&ptr2[i]);
> +             if (val1 - val2 <= 6)
> +                     result = false;
> +     }
> +     ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8bc);
> +     ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x874);
> +     for (i = 0; i < 9; i++) {
> +             val1 = readl(&ptr1[i]);
> +             val2 = readl(&ptr2[i]);
> +             if (val1 - val2 <= 6)
> +                     result = false;
> +     }
> +
> +     if (config->bus_full_width) {
> +             ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa98);
> +             ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa50);
> +             for (i = 0; i < 9; i++) {
> +                     val1 = readl(&ptr1[i]);
> +                     val2 = readl(&ptr2[i]);
> +                     if (val1 - val2 <= 6)
> +                             result = false;
> +             }
> +
> +             ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xabc);
> +             ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa74);
> +             for (i = 0; i < 9; i++) {
> +                     val1 = readl(&ptr1[i]);
> +                     val2 = readl(&ptr2[i]);
> +                     if (val1 - val2 <= 6)
> +                             result = false;
> +             }
> +     }
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3);
> +
> +     if (config->ranks == 2) {
> +             /* maybe last parameter should be 1? */
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2);
> +
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1);
> +
> +             mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 
> 0xc, 0xc);
> +             if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3)
> +                     result = false;
> +
> +             if (config->bus_full_width) {
> +                     mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 
> 0xa40), 0xc, 0xc);
> +                     if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3)
> +                             result = false;
> +             }
> +
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3);
> +     }
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3);
> +
> +     return result;
> +}
> +
> +static bool mctl_phy_write_training(const struct dram_config *config)
> +{
> +     u32 val1, val2, *ptr1, *ptr2;
> +     bool result = true;
> +     int i;

This one is simply wrong. I guess empty function with panic would be in order.

> +
> +     writel(0, SUNXI_DRAM_PHY0_BASE + 0x134);
> +     writel(0, SUNXI_DRAM_PHY0_BASE + 0x138);
> +     writel(0, SUNXI_DRAM_PHY0_BASE + 0x19c);
> +     writel(0, SUNXI_DRAM_PHY0_BASE + 0x1a0);
> +
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 8);
> +
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20);
> +
> +     mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3);
> +     if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc)
> +             result = false;
> +
> +     if (config->bus_full_width) {
> +             mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 
> 3);
> +             if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc)
> +                     result = false;
> +     }
> +
> +     ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x938);
> +     ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8f0);
> +     for (i = 0; i < 9; i++) {
> +             val1 = readl(&ptr1[i]);
> +             val2 = readl(&ptr2[i]);
> +             if (val1 - val2 <= 6)
> +                     result = false;
> +     }
> +     ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x95c);
> +     ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x914);
> +     for (i = 0; i < 9; i++) {
> +             val1 = readl(&ptr1[i]);
> +             val2 = readl(&ptr2[i]);
> +             if (val1 - val2 <= 6)
> +                     result = false;
> +     }
> +
> +     if (config->bus_full_width) {
> +             ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb38);
> +             ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xaf0);
> +             for (i = 0; i < 9; i++) {
> +                     val1 = readl(&ptr1[i]);
> +                     val2 = readl(&ptr2[i]);
> +                     if (val1 - val2 <= 6)
> +                             result = false;
> +             }
> +             ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb5c);
> +             ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb14);
> +             for (i = 0; i < 9; i++) {
> +                     val1 = readl(&ptr1[i]);
> +                     val2 = readl(&ptr2[i]);
> +                     if (val1 - val2 <= 6)
> +                             result = false;
> +             }
> +     }
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60);
> +
> +     if (config->ranks == 2) {
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 4);
> +
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20);
> +
> +             mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 
> 3);
> +             if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc)
> +                     result = false;
> +
> +             if (config->bus_full_width) {
> +                     mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 
> 0xae0), 3, 3);
> +                     if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc)
> +                             result = false;
> +             }
> +
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60);
> +     }
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc);
> +
> +     return result;
> +}
> +
> +static void mctl_phy_bit_delay_compensation(const struct dram_para *para,
> +                                         const struct dram_config *config)
> +{
> +     u8 array0[32], array1[32];
> +     u32 tmp;
> +     int i;
> +
> +     for (i = 0; i < 32; i++) {
> +             array0[i] = (config->tpr11 >> (i & 0xf8)) & 0xff;
> +             array1[i] = (config->tpr12 >> (i & 0xf8)) & 0x7f;
> +     }
> +
> +     if (para->tpr10 & TPR10_DX_BIT_DELAY1) {
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa0, 3);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x80);
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, BIT(28));
> +
> +             writel(array0[0], SUNXI_DRAM_PHY0_BASE + 0x320);
> +             writel((array0[0] << 24) | (array0[1] << 16) |
> +                    (array0[2] << 8) |
> +                    array0[3], SUNXI_DRAM_PHY0_BASE + 0x324);
> +             writel((array0[4] << 24) | (array0[5] << 16) |
> +                    (array0[6] << 8) |
> +                    array0[7], SUNXI_DRAM_PHY0_BASE + 0x328);
> +
> +             writel(array0[0], SUNXI_DRAM_PHY0_BASE + 0x340);
> +             writel((array0[0] << 24) | (array0[1] << 16) |
> +                    (array0[2] << 8) |
> +                    array0[3], SUNXI_DRAM_PHY0_BASE + 0x344);
> +             writel((array0[4] << 24) | (array0[5] << 16) |
> +                    (array0[6] << 8) |
> +                    array0[7], SUNXI_DRAM_PHY0_BASE + 0x348);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x40c, 0xff00,
> +                             array0[0] << 8);
> +             writel((array0[0] << 24) | (array0[1] << 16) |
> +                    (array0[2] << 8) | array0[3],
> +                    SUNXI_DRAM_PHY0_BASE + 0x400);
> +             writel((array0[4] << 24) | (array0[5] << 16) |
> +                    (array0[6] << 8) | array0[7],
> +                    SUNXI_DRAM_PHY0_BASE + 0x404);
> +
> +             writel(array0[0], SUNXI_DRAM_PHY0_BASE + 0x41c);
> +             writel((array0[0] << 24) | (array0[1] << 16) |
> +                    (array0[2] << 8) | array0[3],
> +                    SUNXI_DRAM_PHY0_BASE + 0x420);
> +             writel((array0[4] << 24) | (array0[5] << 16) |
> +                    (array0[6] << 8) | array0[7],
> +                    SUNXI_DRAM_PHY0_BASE + 0x424);
> +
> +             tmp = config->odt_en & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x32c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x34c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x408);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x428);
> +
> +             writel(array0[8], SUNXI_DRAM_PHY0_BASE + 0x4a0);
> +             writel((array0[8] << 24) | (array0[9] << 16) |
> +                    (array0[10] << 8) | array0[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4a4);
> +             writel((array0[12] << 24) | (array0[13] << 16) |
> +                    (array0[14] << 8) | array0[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4a8);
> +
> +             writel(array0[8], SUNXI_DRAM_PHY0_BASE + 0x4c0);
> +             writel((array0[8] << 24) | (array0[9] << 16) |
> +                    (array0[10] << 8) | array0[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4c4);
> +             writel((array0[12] << 24) | (array0[13] << 16) |
> +                    (array0[14] << 8) | array0[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4c8);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x58c, 0xff00,
> +                             array0[8] << 8);
> +             writel((array0[8] << 24) | (array0[9] << 16) |
> +                    (array0[10] << 8) | array0[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x580);
> +             writel((array0[12] << 24) | (array0[13] << 16) |
> +                    (array0[14] << 8) | array0[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x584);
> +
> +             writel(array0[8], SUNXI_DRAM_PHY0_BASE + 0x59c);
> +             writel((array0[8] << 24) | (array0[9] << 16) |
> +                    (array0[10] << 8) | array0[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x5a0);
> +             writel((array0[12] << 24) | (array0[13] << 16) |
> +                    (array0[14] << 8) | array0[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x5a4);
> +
> +             tmp = (config->odt_en >> 8) & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4ac);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4cc);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x588);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x5a8);
> +
> +             writel(array0[16], SUNXI_DRAM_PHY0_BASE + 0x620);
> +             writel((array0[16] << 24) | (array0[17] << 16) |
> +                    (array0[18] << 8) | array0[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x624);
> +             writel((array0[20] << 24) | (array0[21] << 16) |
> +                    (array0[22] << 8) | array0[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x628);
> +
> +             writel(array0[16], SUNXI_DRAM_PHY0_BASE + 0x640);
> +             writel((array0[16] << 24) | (array0[17] << 16) |
> +                    (array0[18] << 8) | array0[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x644);
> +             writel((array0[20] << 24) | (array0[21] << 16) |
> +                    (array0[22] << 8) | array0[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x648);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x70c,
> +                             0xff00, array0[16] << 8);
> +             writel((array0[16] << 24) | (array0[17] << 16) |
> +                    (array0[18] << 8) | array0[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x700);
> +             writel((array0[20] << 24) | (array0[21] << 16) |
> +                    (array0[22] << 8) | array0[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x704);
> +
> +             writel(array0[16], SUNXI_DRAM_PHY0_BASE + 0x71c);
> +             writel((array0[16] << 24) | (array0[17] << 16) |
> +                    (array0[18] << 8) | array0[19],
> +                   SUNXI_DRAM_PHY0_BASE + 0x720);
> +             writel((array0[20] << 24) | (array0[21] << 16) |
> +                    (array0[22] << 8) | array0[23], SUNXI_DRAM_PHY0_BASE + 
> 0x724);
> +
> +             tmp = (config->odt_en >> 16) & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x62c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x64c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x708);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x728);
> +
> +             writel(array0[24], SUNXI_DRAM_PHY0_BASE + 0x7a0);
> +             writel((array0[24] << 24) | (array0[25] << 16) |
> +                    (array0[26] << 8) | array0[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7a4);
> +             writel((array0[28] << 24) | (array0[29] << 16) |
> +                    (array0[30] << 8) | array0[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7a8);
> +
> +             writel(array0[24], SUNXI_DRAM_PHY0_BASE + 0x7c0);
> +             writel((array0[24] << 24) | (array0[25] << 16) |
> +                    (array0[26] << 8) | array0[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7c4);
> +             writel((array0[28] << 24) | (array0[29] << 16) |
> +                    (array0[30] << 8) | array0[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7c8);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x88c, 0xff00,
> +                             array0[24] << 8);
> +             writel((array0[24] << 24) | (array0[25] << 16) |
> +                    (array0[26] << 8) | array0[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x880);
> +             writel((array0[28] << 24) | (array0[29] << 16) |
> +                    (array0[30] << 8) | array0[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x884);
> +
> +             writel(array0[24], SUNXI_DRAM_PHY0_BASE + 0x89c);
> +             writel((array0[24] << 24) | (array0[25] << 16) |
> +                    (array0[26] << 8) | array0[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x8a0);
> +             writel((array0[28] << 24) | (array0[29] << 16) |
> +                    (array0[30] << 8) | array0[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x8a4);
> +
> +             tmp = (config->odt_en >> 24) & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7ac);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7cc);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x888);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x8a8);
> +
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, BIT(28));
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, BIT(28));
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +     }
> +
> +     if (para->tpr10 & TPR10_DX_BIT_DELAY0) {
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +
> +             writel(array1[0] << 8, SUNXI_DRAM_PHY0_BASE + 0x330);
> +             writel((array1[0] << 24) | (array1[1] << 16) |
> +                    (array1[2] << 8) | array1[3],
> +                    SUNXI_DRAM_PHY0_BASE + 0x334);
> +             writel((array1[4] << 24) | (array1[5] << 16) |
> +                    (array1[6] << 8) | array1[7],
> +                    SUNXI_DRAM_PHY0_BASE + 0x338);
> +
> +             writel(array1[0] << 8, SUNXI_DRAM_PHY0_BASE + 0x350);
> +             writel((array1[0] << 24) | (array1[1] << 16) |
> +                    (array1[2] << 8) | array1[3],
> +                    SUNXI_DRAM_PHY0_BASE + 0x354);
> +             writel((array1[4] << 24) | (array1[5] << 16) |
> +                    (array1[6] << 8) | array1[7],
> +                    SUNXI_DRAM_PHY0_BASE + 0x358);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x40c, 0xff, array1[0]);
> +             writel((array1[0] << 24) | (array1[1] << 16) |
> +                    (array1[2] << 8) | array1[3],
> +                    SUNXI_DRAM_PHY0_BASE + 0x410);
> +             writel((array1[4] << 24) | (array1[5] << 16) |
> +                    (array1[6] << 8) | array1[7],
> +                    SUNXI_DRAM_PHY0_BASE + 0x414);
> +
> +             writel(array1[0] << 8, SUNXI_DRAM_PHY0_BASE + 0x42c);
> +             writel((array1[0] << 24) | (array1[1] << 16) |
> +                    (array1[2] << 8) | array1[3],
> +                    SUNXI_DRAM_PHY0_BASE + 0x430);
> +             writel((array1[4] << 24) | (array1[5] << 16) |
> +                    (array1[6] << 8) | array1[7],
> +                    SUNXI_DRAM_PHY0_BASE + 0x434);
> +
> +             tmp = config->tpr14 & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x33c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x35c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x418);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x438);
> +
> +             writel(array1[8] << 8, SUNXI_DRAM_PHY0_BASE + 0x4b0);
> +             writel((array1[8] << 24) | (array1[9] << 16) |
> +                    (array1[10] << 8) | array1[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4b4);
> +             writel((array1[12] << 24) | (array1[13] << 16) |
> +                    (array1[14] << 8) | array1[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4b8);
> +
> +             writel(array1[8] << 8, SUNXI_DRAM_PHY0_BASE + 0x4d0);
> +             writel((array1[8] << 24) | (array1[9] << 16) |
> +                    (array1[10] << 8) | array1[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4d4);
> +             writel((array1[12] << 24) | (array1[13] << 16) |
> +                    (array1[14] << 8) | array1[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x4d8);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x58c, 0xff, array1[8]);
> +             writel((array1[8] << 24) | (array1[9] << 16) |
> +                    (array1[10] << 8) | array1[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x590);
> +             writel((array1[12] << 24) | (array1[13] << 16) |
> +                    (array1[14] << 8) | array1[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x594);
> +
> +             writel(array1[8] << 8, SUNXI_DRAM_PHY0_BASE + 0x5ac);
> +             writel((array1[8] << 24) | (array1[9] << 16) |
> +                    (array1[10] << 8) | array1[11],
> +                    SUNXI_DRAM_PHY0_BASE + 0x5b0);
> +             writel((array1[12] << 24) | (array1[13] << 16) |
> +                    (array1[14] << 8) | array1[15],
> +                    SUNXI_DRAM_PHY0_BASE + 0x5b4);
> +
> +             tmp = (config->tpr14 >> 8) & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4bc);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4dc);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x598);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x5b8);
> +
> +             writel(array1[16] << 8, SUNXI_DRAM_PHY0_BASE + 0x630);
> +             writel((array1[16] << 24) | (array1[17] << 16) |
> +                    (array1[18] << 8) | array1[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x634);
> +             writel((array1[20] << 24) | (array1[21] << 16) |
> +                    (array1[22] << 8) | array1[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x638);
> +
> +             writel(array1[16] << 8, SUNXI_DRAM_PHY0_BASE + 0x650);
> +             writel((array1[16] << 24) | (array1[17] << 16) |
> +                    (array1[18] << 8) | array1[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x654);
> +             writel((array1[20] << 24) | (array1[21] << 16) |
> +                    (array1[22] << 8) | array1[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x658);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x70c, 0xff, array1[16]);
> +             writel((array1[16] << 24) | (array1[17] << 16) |
> +                    (array1[18] << 8) | array1[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x710);
> +             writel((array1[20] << 24) | (array1[21] << 16) |
> +                    (array1[22] << 8) | array1[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x714);
> +
> +             writel(array1[16] << 8, SUNXI_DRAM_PHY0_BASE + 0x72c);
> +             writel((array1[16] << 24) | (array1[17] << 16) |
> +                    (array1[18] << 8) | array1[19],
> +                    SUNXI_DRAM_PHY0_BASE + 0x730);
> +             writel((array1[20] << 24) | (array1[21] << 16) |
> +                    (array1[22] << 8) | array1[23],
> +                    SUNXI_DRAM_PHY0_BASE + 0x734);
> +
> +             tmp = (config->tpr14 >> 16) & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x63c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x65c);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x718);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x738);
> +
> +             writel(array1[24] << 8, SUNXI_DRAM_PHY0_BASE + 0x7b0);
> +             writel((array1[24] << 24) | (array1[25] << 16) |
> +                    (array1[26] << 8) | array1[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7b4);
> +             writel((array1[28] << 24) | (array1[29] << 16) |
> +                    (array1[30] << 8) | array1[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7b8);
> +
> +             writel(array1[24] << 8, SUNXI_DRAM_PHY0_BASE + 0x7d0);
> +             writel((array1[24] << 24) | (array1[25] << 16) |
> +                    (array1[26] << 8) | array1[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7d4);
> +             writel((array1[28] << 24) | (array1[29] << 16) |
> +                    (array1[30] << 8) | array1[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x7d8);
> +
> +             clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x88c, 0xff, array1[24]);
> +             writel((array1[24] << 24) | (array1[25] << 16) |
> +                    (array1[26] << 8) | array1[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x890);
> +             writel((array1[28] << 24) | (array1[29] << 16) |
> +                    (array1[30] << 8) | array1[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x894);
> +
> +             writel(array1[24] << 8, SUNXI_DRAM_PHY0_BASE + 0x8ac);
> +             writel((array1[24] << 24) | (array1[25] << 16) |
> +                    (array1[26] << 8) | array1[27],
> +                    SUNXI_DRAM_PHY0_BASE + 0x8b0);
> +             writel((array1[28] << 24) | (array1[29] << 16) |
> +                    (array1[30] << 8) | array1[31],
> +                    SUNXI_DRAM_PHY0_BASE + 0x8b4);
> +
> +             tmp = (config->tpr14 >> 24) & 0xff;
> +             tmp = (tmp << 24) | (tmp << 8);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7bc);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7dc);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x898);
> +             writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x8b8);
> +
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 4);
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 4);
> +             clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +     }
> +}
> +
> +static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para,
> +                                            const struct dram_config *config)
> +{
> +     u32 val, low, high;
> +
> +     if (para->tpr10 & BIT(31)) {
> +             val = para->tpr0;
> +     } else {
> +             val = ((para->tpr10 & 0xf0) << 5) | ((para->tpr10 & 0xf) << 1);
> +             if (para->tpr10 >> 29)
> +                     val <<= 1;
> +     }
> +
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0xac, 0x1000);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x48, 0xc0000000);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             low = val & 0xff;
> +             high = (val >> 8) & 0xff;
> +
> +             val = (high << 24) | (high << 16) | (high << 8) | high;
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x104);
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x108);
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x10c);
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x114);
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x118);
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x11c);
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x120);
> +
> +             val = (high << 24) | (high << 16) | (low << 8) | low;
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x110);
> +
> +             val = (low << 24) | (high << 16) | (low << 8) | high;
> +             writel(val, SUNXI_DRAM_PHY0_BASE + 0x11c);
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x38, 1);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x38, 1);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +}
> +
> +static bool mctl_phy_init(const struct dram_para *para,
> +                       const struct dram_config *config)
> +{
> +     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;
> +     void *const prcm = (void *)SUNXI_PRCM_BASE;
> +     u32 val, val2, mr1, mr2;
> +     int i;
> +
> +     clrbits_le32(prcm + CCU_PRCM_SYS_PWROFF_GATING, 1);
> +     udelay(1);
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000);
> +
> +     if (config->bus_full_width)
> +             val = 0xf00;
> +     else
> +             val = 0x300;
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, 0xf00, val);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             if (config->clk <= 936) {
> +                     val = 10;
> +                     val2 = 20;
> +             } else if (config->clk <= 1200) {
> +                     val = 14;
> +                     val2 = 28;
> +             } else {
> +                     val = 16;
> +                     val2 = 32;
> +             }
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +
> +     writel((val << 24) | (val << 16) | (val << 8) | val, 
> SUNXI_DRAM_PHY0_BASE + 0x10);
> +     writel((val2 << 24) | (val2 << 16) | (val2 << 8) | val2, 
> SUNXI_DRAM_PHY0_BASE + 0x0c);
> +     writel(0, SUNXI_DRAM_PHY0_BASE + 0x08);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             writel(0x00010203, SUNXI_DRAM_PHY0_BASE + 0x54);
> +             writel(0x04050607, SUNXI_DRAM_PHY0_BASE + 0x58);
> +             writel(0x08090a0b, SUNXI_DRAM_PHY0_BASE + 0x5c);
> +             writel(0x0c0d0e0f, SUNXI_DRAM_PHY0_BASE + 0x60);
> +             writel(0x10111213, SUNXI_DRAM_PHY0_BASE + 0x64);
> +             writel(0x14151617, SUNXI_DRAM_PHY0_BASE + 0x68);
> +             writel(0x18191a1b, SUNXI_DRAM_PHY0_BASE + 0x6c);
> +             writel(0x1c1d1e00, SUNXI_DRAM_PHY0_BASE + 0x70);
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +
> +     mctl_phy_configure_odt(para);
> +
> +     if (para->tpr10 & TPR10_CA_BIT_DELAY)
> +             mctl_phy_ca_bit_delay_compensation(para, config);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             val = 0x18fd6300;
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa8, 0xffffff00, val);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, 0x70);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             val = 0x50;
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, val);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, 0x80);
> +
> +     // TODO: fix intervals
> +     if (config->clk - 251 < 250) {
> +             val = 0x18000000;
> +             val2 = 0x18181818;
> +     } else if (config->clk - 126 < 125) {
> +             val = 0x28000000;
> +             val2 = 0x28282828;
> +     } else if (config->clk < 126) {
> +             val = 0x38000000;
> +             val2 = 0x38383838;
> +     } else {
> +             val = 0x18000000;
> +             val2 = 0;
> +     }
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xc0, 0x78000000, val);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xd0, 0x78787878, val2);
> +
> +     clrbits_le32(&mctl_com->unk_0x008, 0x200);
> +     udelay(10);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             val = para->tpr6 >> 24 & 0xff;
> +             if (val)
> +                     val <<= 1;
> +             else
> +                     val = 0x33;
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +     val <<= 23;
> +
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x300, 0xff800060, val | 0x40);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x600, 0xff800060, val | 0x40);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x480, 0xff800060, val | 0x40);
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x780, 0xff800060, val | 0x40);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x8000000);
> +     setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 0x80);
> +     udelay(10);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 0x80);
> +     udelay(10);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x8000000);
> +
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x308, 0x200);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x488, 0x200);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x608, 0x200);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x788, 0x200);
> +     clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x908, 0x200);
> +     if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x308, 0x200);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x488, 0x200);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x608, 0x200);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x788, 0x200);
> +             setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x908, 0x200);
> +     }
> +
> +     if (config->clk < 936)
> +             val = 0x1b000000;
> +     else
> +             val = 0xc000000;
> +     clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x14, 0x1f000000, val);
> +
> +     setbits_le32(&mctl_com->unk_0x020, 0x100);
> +
> +     /* start DFI init */
> +     writel(0, &mctl_ctl->swctl);
> +     setbits_le32(&mctl_ctl->dfimisc, 1);
> +     setbits_le32(&mctl_ctl->dfimisc, 0x20);
> +     writel(1, &mctl_ctl->swctl);
> +     mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> +     mctl_await_completion(&mctl_ctl->dfistat, 1, 1);
> +
> +     udelay(500);
> +     setbits_le32(prcm + CCU_PRCM_SYS_PWROFF_GATING, 1);
> +     udelay(1);
> +
> +     writel(0, &mctl_ctl->swctl);
> +     clrbits_le32(&mctl_ctl->dfimisc, 0x20);
> +     writel(1, &mctl_ctl->swctl);
> +     mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> +
> +     writel(0, &mctl_ctl->swctl);
> +     clrbits_le32(&mctl_ctl->pwrctl, 0x20);
> +     writel(1, &mctl_ctl->swctl);
> +     mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> +     mctl_await_completion(&mctl_ctl->statr, 3, 1);
> +
> +     udelay(500);
> +
> +     writel(0, &mctl_ctl->swctl);
> +     clrbits_le32(&mctl_ctl->dfimisc, 1);
> +     writel(1, &mctl_ctl->swctl);
> +     mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             if (config->clk <= 936) {
> +                     mr1 = 0x34;
> +                     mr2 = 0x1b;
> +             } else if (config->clk <= 1200) {
> +                     mr1 = 0x54;
> +                     mr2 = 0x2d;
> +             } else {
> +                     mr1 = 0x64;
> +                     mr2 = 0x36;
> +             }
> +
> +             writel(0x0, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0x100 | mr1, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0x200 | mr2, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0x333, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0x403, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0xb04, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0xc72, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0xd00, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0xe08, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +
> +             writel(0x1626, &mctl_ctl->mrctrl1);
> +             writel(0x800000f0, &mctl_ctl->mrctrl0);
> +             mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +
> +     writel(0, &mctl_ctl->swctl);
> +     clrbits_le32(&mctl_ctl->rfshctl3, 1);
> +     writel(1, &mctl_ctl->swctl);
> +
> +     if (para->tpr10 & TPR10_WRITE_LEVELING) {
> +             for (i = 0; i < 5; i++)
> +                     if (mctl_phy_write_leveling(para, config))
> +                             break;
> +             if (i == 5) {
> +                     debug("write leveling failed!\n");
> +                     return false;
> +             }
> +     }
> +
> +     if (para->tpr10 & TPR10_READ_CALIBRATION) {
> +             for (i = 0; i < 5; i++)
> +                     if (mctl_phy_read_calibration(para, config))
> +                             break;
> +             if (i == 5) {
> +                     debug("read calibration failed!\n");
> +                     return false;
> +             }
> +     }
> +
> +     if (para->tpr10 & TPR10_READ_TRAINING) {
> +             for (i = 0; i < 5; i++)
> +                     if (mctl_phy_read_training(para, config))
> +                             break;
> +             if (i == 5) {
> +                     debug("read training failed!\n");
> +                     return false;
> +             }
> +     }
> +
> +     if (para->tpr10 & TPR10_WRITE_TRAINING) {
> +             for (i = 0; i < 5; i++)
> +                     if (mctl_phy_write_training(config))
> +                             break;
> +             if (i == 5) {
> +                     debug("write training failed!\n");
> +                     return false;
> +             }
> +     }
> +
> +     mctl_phy_bit_delay_compensation(para, config);
> +
> +     return true;
> +}
> +
> +static bool mctl_ctrl_init(const struct dram_para *para,
> +                        const struct dram_config *config)
> +{
> +     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;
> +     u32 reg_val;
> +
> +     clrsetbits_le32(&mctl_com->unk_0x008, BIT(24), 0x2000200);
> +     setbits_le32(&mctl_com->unk_0x020, 0x8200);
> +
> +     if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
> +             setbits_le32(0x02023ea8, 1); // NSI
> +             setbits_le32(0x02071008, 1); // NSI_CPU
> +     }
> +
> +     clrsetbits_le32(&mctl_ctl->sched[0], 0xff08, 0x3000);
> +     clrsetbits_le32(&mctl_ctl->sched[1], 0x77000000, 0x33000000);
> +     clrsetbits_le32(&mctl_ctl->unk_0x270, 0xffff, 0x808);
> +     clrsetbits_le32(&mctl_ctl->unk_0x264, 0xff00ffff, 0x1f000030);
> +
> +     writel(0, &mctl_ctl->hwlpctl);
> +
> +     reg_val = MSTR_ACTIVE_RANKS(config->ranks);
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             reg_val |= MSTR_BURST_LENGTH(16) | MSTR_DEVICETYPE_LPDDR4;
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +     if (config->bus_full_width)
> +             reg_val |= MSTR_BUSWIDTH_FULL;
> +     else
> +             reg_val |= MSTR_BUSWIDTH_HALF;
> +     writel(BIT(31) | BIT(30) | reg_val, &mctl_ctl->mstr);
> +
> +     if (config->ranks == 2)
> +             writel(0x0303, &mctl_ctl->odtmap);
> +     else
> +             writel(0x0201, &mctl_ctl->odtmap);
> +
> +     switch (para->type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             reg_val = 0x04000400;
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +     writel(reg_val, &mctl_ctl->odtcfg);
> +     writel(reg_val, &mctl_ctl->unk_0x2240);
> +     writel(reg_val, &mctl_ctl->unk_0x3240);
> +     writel(reg_val, &mctl_ctl->unk_0x4240);
> +
> +     mctl_set_addrmap(config);
> +
> +     mctl_set_timing_params(config->clk);
> +
> +     writel(0, &mctl_ctl->pwrctl);
> +
> +     setbits_le32(&mctl_ctl->dfiupd[0], BIT(31) | BIT(30));
> +     setbits_le32(&mctl_ctl->zqctl[0], BIT(31) | BIT(30));
> +     setbits_le32(&mctl_ctl->unk_0x2180, BIT(31) | BIT(30));
> +     setbits_le32(&mctl_ctl->unk_0x3180, BIT(31) | BIT(30));
> +     setbits_le32(&mctl_ctl->unk_0x4180, BIT(31) | BIT(30));
> +
> +     if (para->type == SUNXI_DRAM_TYPE_LPDDR4)
> +             setbits_le32(&mctl_ctl->dbictl, 0x1);
> +
> +     setbits_le32(&mctl_ctl->rfshctl3, BIT(0));
> +     clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
> +
> +     writel(0x20, &mctl_ctl->pwrctl);
> +     setbits_le32(&mctl_ctl->clken, BIT(8));
> +
> +     clrsetbits_le32(&mctl_com->unk_0x008, BIT(24), 0x200);
> +     udelay(1);
> +     /* this write seems to enable PHY MMIO region */
> +     setbits_le32(&mctl_com->unk_0x008, BIT(24));
> +
> +     if (!mctl_phy_init(para, config))
> +             return false;
> +
> +     writel(0, &mctl_ctl->swctl);
> +     clrbits_le32(&mctl_ctl->rfshctl3, BIT(0));
> +     writel(1, &mctl_ctl->swctl);
> +     mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> +
> +     return true;
> +}
> +
> +static bool mctl_core_init(const struct dram_para *para,
> +                        const struct dram_config *config)
> +{
> +     mctl_sys_init(config->clk);
> +
> +     return mctl_ctrl_init(para, config);
> +}
> +
> +static void mctl_auto_detect_rank_width(const struct dram_para *para,
> +                                     struct dram_config *config)
> +{
> +     /* this is minimum size that it's supported */
> +     config->cols = 8;
> +     config->rows = 13;
> +
> +     /*
> +      * Strategy here is to test most demanding combination first and least
> +      * demanding last, otherwise HW might not be fully utilized. For
> +      * example, half bus width and rank = 1 combination would also work
> +      * on HW with full bus width and rank = 2, but only 1/4 RAM would be
> +      * visible.
> +      */
> +
> +     debug("testing 32-bit width, rank = 2\n");
> +     config->bus_full_width = 1;
> +     config->ranks = 2;
> +     if (mctl_core_init(para, config))
> +             return;
> +
> +     debug("testing 32-bit width, rank = 1\n");
> +     config->bus_full_width = 1;
> +     config->ranks = 1;
> +     if (mctl_core_init(para, config))
> +             return;
> +
> +     debug("testing 16-bit width, rank = 2\n");
> +     config->bus_full_width = 0;
> +     config->ranks = 2;
> +     if (mctl_core_init(para, config))
> +             return;
> +
> +     debug("testing 16-bit width, rank = 1\n");
> +     config->bus_full_width = 0;
> +     config->ranks = 1;
> +     if (mctl_core_init(para, config))
> +             return;
> +
> +     panic("This DRAM setup is currently not supported.\n");
> +}
> +
> +static void mctl_auto_detect_dram_size(const struct dram_para *para,
> +                                    struct dram_config *config)
> +{
> +     /* detect row address bits */
> +     config->cols = 8;
> +     config->rows = 16;
> +     mctl_core_init(para, config);
> +
> +     for (config->rows = 13; config->rows < 16; config->rows++) {
> +             /* 8 banks, 8 bit per byte and 16/32 bit width */
> +             if (mctl_mem_matches((1 << (config->rows + config->cols +
> +                                         4 + config->bus_full_width))))
> +                     break;
> +     }
> +
> +     /* detect column address bits */
> +     config->cols = 11;
> +     mctl_core_init(para, config);
> +
> +     for (config->cols = 8; config->cols < 11; config->cols++) {
> +             /* 8 bits per byte and 16/32 bit width */
> +             if (mctl_mem_matches(1 << (config->cols + 1 +
> +                                        config->bus_full_width)))
> +                     break;
> +     }
> +}
> +
> +static unsigned long long mctl_calc_size(const struct dram_config *config)
> +{
> +     u8 width = config->bus_full_width ? 4 : 2;
> +
> +     /* 8 banks */
> +     return (1ULL << (config->cols + config->rows + 3)) * width * 
> config->ranks;
> +}

As soon as H616 DRAM size fixup is merged, above functions should be replaced.

> +
> +static const struct dram_para para = {
> +     .type = SUNXI_DRAM_TYPE_LPDDR4,
> +     .dx_odt = CONFIG_DRAM_SUNXI_DX_ODT,
> +     .dx_dri = CONFIG_DRAM_SUNXI_DX_DRI,
> +     .ca_dri = CONFIG_DRAM_SUNXI_CA_DRI,
> +     .tpr0 = CONFIG_DRAM_SUNXI_TPR0,
> +     .tpr1 = CONFIG_DRAM_SUNXI_TPR1,
> +     .tpr2 = CONFIG_DRAM_SUNXI_TPR2,
> +     .tpr6 = CONFIG_DRAM_SUNXI_TPR6,
> +     .tpr10 = CONFIG_DRAM_SUNXI_TPR10,
> +};
> +
> +static void sunxi_nsi_init(void)

This replaces old mctl_set_master_priority(), but it needs to be expanded
to include all channels.

> +{
> +     /* IOMMU prio 3 */
> +     writel(0x1, 0x02021418);
> +     writel(0xf, 0x02021414);
> +     /* DE prio 2 */
> +     writel(0x1, 0x02021a18);
> +     writel(0xa, 0x02021a14);
> +     /* VE R prio 2 */
> +     writel(0x1, 0x02021618);
> +     writel(0xa, 0x02021614);
> +     /* VE RW prio 2 */
> +     writel(0x1, 0x02021818);
> +     writel(0xa, 0x02021814);
> +     /* ISP prio 2 */
> +     writel(0x1, 0x02020c18);
> +     writel(0xa, 0x02020c14);
> +     /* CSI prio 2 */
> +     writel(0x1, 0x02021c18);
> +     writel(0xa, 0x02021c14);
> +     /* NPU prio 2 */
> +     writel(0x1, 0x02020a18);
> +     writel(0xa, 0x02020a14);
> +
> +     /* close ra0 autogating */
> +     writel(0x0, 0x02023c00);
> +     /* close ta autogating */
> +     writel(0x0, 0x02023e00);
> +     /* close pcie autogating */
> +     writel(0x0, 0x02020600);
> +}
> +
> +static void init_something(void)

This function should be removed.

Best regards,
Jernej

> +
> +{
> +     u32 *ptr = (u32 *)0x02000804;
> +
> +     do {
> +             *ptr++ = 0xffffffff;
> +     } while (ptr != (u32 *)0x20008e4);
> +
> +     writel(0, 0x07002400);
> +     writel(0, 0x07002404);
> +     writel(0, 0x07002408);
> +
> +     writel(0xffffffff, 0x07002004);
> +     writel(0xffffffff, 0x07002014);
> +     writel(0xffffffff, 0x07002024);
> +     setbits_le32(0x07010290, 7);
> +
> +     writel(7, 0x02001f00);
> +     writel(0xffff, 0x03002020);
> +     writel(3, 0x020008e0);
> +     writel(7, 0x07102008);
> +}
> +
> +unsigned long sunxi_dram_init(void)
> +{
> +     struct dram_config config;
> +     unsigned long size;
> +
> +     config.clk = 360;
> +     switch (para.type) {
> +     case SUNXI_DRAM_TYPE_LPDDR4:
> +             config.odt_en = 0x84848484;
> +             config.tpr11 = 0x9a9a9a9a;
> +             config.tpr12 = 0x0e0f070a;
> +             config.tpr14 = 0x48484848;
> +             break;
> +     default:
> +             panic("This DRAM setup is currently not supported.\n");
> +     };
> +
> +     setbits_le32(0x03000160, BIT(8));
> +     clrbits_le32(0x03000168, 0x3f);
> +
> +     mctl_auto_detect_rank_width(&para, &config);
> +     mctl_auto_detect_dram_size(&para, &config);
> +
> +     config.clk = CONFIG_DRAM_CLK;
> +     config.odt_en = CONFIG_DRAM_SUNXI_ODT_EN;
> +     config.tpr11 = CONFIG_DRAM_SUNXI_TPR11;
> +     config.tpr12 = CONFIG_DRAM_SUNXI_TPR12;
> +     config.tpr14 = CONFIG_DRAM_SUNXI_TPR14;
> +
> +     mctl_core_init(&para, &config);
> +
> +     size = mctl_calc_size(&config);
> +
> +     sunxi_nsi_init();
> +     init_something();
> +
> +     return size;
> +};
> diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile 
> b/arch/arm/mach-sunxi/dram_timings/Makefile
> index 5f203419240..7bcda180d0a 100644
> --- a/arch/arm/mach-sunxi/dram_timings/Makefile
> +++ b/arch/arm/mach-sunxi/dram_timings/Makefile
> @@ -6,3 +6,4 @@ obj-$(CONFIG_SUNXI_DRAM_H6_DDR3_1333) += h6_ddr3_1333.o
>  obj-$(CONFIG_SUNXI_DRAM_H616_DDR3_1333)      += h616_ddr3_1333.o
>  obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR3) += h616_lpddr3.o
>  obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR4) += h616_lpddr4_2133.o
> +obj-$(CONFIG_SUNXI_DRAM_A523_LPDDR4) += a523_lpddr4.o
> diff --git a/arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c 
> b/arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c
> new file mode 100644
> index 00000000000..64a28e14c4e
> --- /dev/null
> +++ b/arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c
> @@ -0,0 +1,119 @@
> +// SPDX-License-Identifier:  GPL-2.0+
> +/*
> + * sun55i A523 LPDDR4-2133 timings, as programmed by Allwinner's boot0
> + *
> + * (C) Copyright 2024 Jernej Skrabec <jernej.skra...@gmail.com>
> + * (C) Copyright 2023 Mikhail Kalashnikov <iunc...@gmail.com>
> + *
> + */
> +
> +#include <asm/arch/dram.h>
> +#include <asm/arch/cpu.h>
> +
> +void mctl_set_timing_params(u32 clk)
> +{
> +     struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +                     (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +     u8 tcl, tcwl, t_rdata_en, trtp, twr, tphy_wrlat;
> +     unsigned int mr1, mr2;
> +
> +     u8 tccd         = 4;
> +     u8 tfaw         = ns_to_t(40, clk);
> +     u8 trrd         = max(ns_to_t(10, clk), 2);
> +     u8 twtr         = max(ns_to_t(10, clk), 4);
> +     u8 trcd         = max(ns_to_t(18, clk), 2);
> +     u8 trc          = ns_to_t(65, clk);
> +     u8 txp          = max(ns_to_t(8, clk), 2);
> +     u8 trp          = ns_to_t(21, clk);
> +     u8 tras         = ns_to_t(42, clk);
> +     u16 trefi       = ns_to_t(3904, clk) / 32;
> +     u16 trfc        = ns_to_t(280, clk);
> +     u16 txsr        = ns_to_t(290, clk);
> +
> +     u8 tmrw         = max(ns_to_t(14, clk), 5);
> +     u8 tmod         = 12;
> +     u8 tcke         = max(ns_to_t(15, clk), 2);
> +     u8 tcksrx       = max(ns_to_t(2, clk), 2);
> +     u8 tcksre       = max(ns_to_t(5, clk), 2);
> +     u8 trasmax      = (trefi * 9) / 32;
> +
> +     if (clk <= 936) {
> +             mr1 = 0x34;
> +             mr2 = 0x1b;
> +             tcl = 10;
> +             tcwl = 5;
> +             t_rdata_en = 17;
> +             trtp = 4;
> +             tphy_wrlat = 5;
> +             twr = 10;
> +     } else if (clk <= 1200) {
> +             mr1 = 0x54;
> +             mr2 = 0x2d;
> +             tcl = 14;
> +             tcwl = 7;
> +             t_rdata_en = 25;
> +             trtp = 6;
> +             tphy_wrlat = 9;
> +             twr = 15;
> +     } else {
> +             mr1 = 0x64;
> +             mr2 = 0x36;
> +             tcl = 16;
> +             tcwl = 8;
> +             t_rdata_en = 29;
> +             trtp = 7;
> +             tphy_wrlat = 11;
> +             twr = 17;
> +     }
> +
> +     u8 tmrd         = tmrw;
> +     u8 tckesr       = tcke;
> +     u8 twtp         = twr + 9 + tcwl;
> +     u8 twr2rd       = twtr + 9 + tcwl;
> +     u8 trd2wr       = ns_to_t(4, clk) + 7 - ns_to_t(1, clk) + tcl;
> +     u8 txs          = 4;
> +     u8 txsdll       = 16;
> +     u8 txsabort     = 4;
> +     u8 txsfast      = 4;
> +
> +     /* set DRAM timing */
> +     writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras,
> +            &mctl_ctl->dramtmg[0]);
> +     writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]);
> +     writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd,
> +            &mctl_ctl->dramtmg[2]);
> +     writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]);
> +     writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp,
> +            &mctl_ctl->dramtmg[4]);
> +     writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke,
> +            &mctl_ctl->dramtmg[5]);
> +     /* Value suggested by ZynqMP manual and used by libdram */
> +     writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]);
> +     writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs,
> +            &mctl_ctl->dramtmg[8]);
> +     writel(0x00020208, &mctl_ctl->dramtmg[9]);
> +     writel(0xE0C05, &mctl_ctl->dramtmg[10]);
> +     writel(0x440C021C, &mctl_ctl->dramtmg[11]);
> +     writel(8, &mctl_ctl->dramtmg[12]);
> +     writel(0xA100002, &mctl_ctl->dramtmg[13]);
> +     writel(txsr, &mctl_ctl->dramtmg[14]);
> +
> +     clrsetbits_le32(&mctl_ctl->init[0], 0xC0000FFF, 0x558);
> +     writel(0x01f20000, &mctl_ctl->init[1]);
> +     writel(0x00001705, &mctl_ctl->init[2]);
> +     writel(0, &mctl_ctl->dfimisc);
> +     writel((mr1 << 16) | mr2, &mctl_ctl->init[3]);
> +     writel(0x00330000, &mctl_ctl->init[4]);
> +     writel(0x00040072, &mctl_ctl->init[6]);
> +     writel(0x00260008, &mctl_ctl->init[7]);
> +
> +     clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
> +
> +     /* Configure DFI timing */
> +     writel(tphy_wrlat | 0x2000000 | (t_rdata_en << 16) | 0x808000,
> +            &mctl_ctl->dfitmg0);
> +     writel(0x100202, &mctl_ctl->dfitmg1);
> +
> +     /* set refresh timing */
> +     writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
> +}
> 




Reply via email to