diff mbox

[U-Boot,RFC,2/3] arm64: rk3399: add ddr controller driver

Message ID 1483007152-675-3-git-send-email-kever.yang@rock-chips.com
State RFC
Delegated to: Simon Glass
Headers show

Commit Message

Kever Yang Dec. 29, 2016, 10:25 a.m. UTC
RK3399 support DDR3, LPDDR3, DDR4 sdram, this patch is porting from
coreboot, support 4GB lpddr3 in this version.

Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
---

 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h  |  188 +++
 arch/arm/mach-rockchip/rk3399/Makefile             |    1 +
 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc | 1565 ++++++++++++++++++++
 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c       | 1121 ++++++++++++++
 4 files changed, 2875 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
 create mode 100644 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
 create mode 100644 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c

Comments

Simon Glass Jan. 13, 2017, 2:18 a.m. UTC | #1
Hi Kever,

On 29 December 2016 at 03:25, Kever Yang <kever.yang@rock-chips.com> wrote:
> RK3399 support DDR3, LPDDR3, DDR4 sdram, this patch is porting from
> coreboot, support 4GB lpddr3 in this version.
>
> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
> ---
>
>  arch/arm/include/asm/arch-rockchip/sdram_rk3399.h  |  188 +++
>  arch/arm/mach-rockchip/rk3399/Makefile             |    1 +
>  arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc | 1565 ++++++++++++++++++++
>  arch/arm/mach-rockchip/rk3399/sdram_rk3399.c       | 1121 ++++++++++++++
>  4 files changed, 2875 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
>  create mode 100644 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
>  create mode 100644 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
>
> diff --git a/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
> new file mode 100644
> index 0000000..fab0faf
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
> @@ -0,0 +1,188 @@
> +/*
> + * Copyright (C) 2015 Rockchip Electronics Co., Ltd
> + *
> + * SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#ifndef __SOC_ROCKCHIP_RK3399_SDRAM_H__
> +#define __SOC_ROCKCHIP_RK3399_SDRAM_H__

Please use the same format as other headers (i.e. no SOC).

> +
> +#include <stddef.h>

What is this for?

> +
> +enum {
> +       DDR3 = 3,
> +       LPDDR2 = 5,
> +       LPDDR3 = 6,
> +       LPDDR4 = 7,
> +       UNUSED = 0xFF

Please can you use lower-case hex?

> +};
> +
> +struct rk3399_ddr_pctl_regs {
> +       u32 denali_ctl[332];
> +};
> +
> +struct rk3399_ddr_publ_regs {
> +       u32 denali_phy[959];
> +};
> +
> +struct rk3399_ddr_pi_regs {
> +       u32 denali_pi[200];
> +};
> +union noc_ddrtiminga0 {
> +       u32 d32;
> +       struct {
> +               unsigned acttoact : 6;
> +               unsigned reserved0 : 2;
> +               unsigned rdtomiss : 6;
> +               unsigned reserved1 : 2;
> +               unsigned wrtomiss : 6;
> +               unsigned reserved2 : 2;
> +               unsigned readlatency : 8;
> +       } b;

Can we use a simple value here, and drop the bitfields?

> +};
> +
> +union noc_ddrtimingb0 {
> +       u32 d32;
> +       struct {
> +               unsigned rdtowr : 5;
> +               unsigned reserved0 : 3;
> +               unsigned wrtord : 5;
> +               unsigned reserved1 : 3;
> +               unsigned rrd : 4;
> +               unsigned reserved2 : 4;
> +               unsigned faw : 6;
> +               unsigned reserved3 : 2;
> +       } b;
> +};
> +
> +union noc_ddrtimingc0 {
> +       u32 d32;
> +       struct {
> +               unsigned burstpenalty : 4;
> +               unsigned reserved0 : 4;
> +               unsigned wrtomwr : 6;
> +               unsigned reserved1 : 18;
> +       } b;
> +};
> +
> +union noc_devtodev0 {
> +       u32 d32;
> +       struct {
> +               unsigned busrdtord : 3;
> +               unsigned reserved0 : 1;
> +               unsigned busrdtowr : 3;
> +               unsigned reserved1 : 1;
> +               unsigned buswrtord : 3;
> +               unsigned reserved2 : 1;
> +               unsigned buswrtowr : 3;
> +               unsigned reserved3 : 17;
> +       } b;
> +};
> +
> +union noc_ddrmode {
> +       u32 d32;
> +       struct {
> +               unsigned autoprecharge : 1;
> +               unsigned bypassfiltering : 1;
> +               unsigned fawbank : 1;
> +               unsigned burstsize : 2;
> +               unsigned mwrsize : 2;
> +               unsigned reserved2 : 1;
> +               unsigned forceorder : 8;
> +               unsigned forceorderstate : 8;
> +               unsigned reserved3 : 8;
> +       } b;
> +};
> +
> +struct rk3399_msch_regs {
> +       u32 coreid;
> +       u32 revisionid;
> +       u32 ddrconf;
> +       u32 ddrsize;
> +       union noc_ddrtiminga0 ddrtiminga0;
> +       union noc_ddrtimingb0 ddrtimingb0;
> +       union noc_ddrtimingc0 ddrtimingc0;
> +       union noc_devtodev0 devtodev0;
> +       u32 reserved0[(0x110-0x20)/4];

Please add spaces around operators:

      u32 reserved0[(0x110 - 0x20) / 4];


> +       union noc_ddrmode ddrmode;
> +       u32 reserved1[(0x1000-0x114)/4];
> +       u32 agingx0;
> +};
> +
> +struct rk3399_msch_timings {

These structures and members should have comments.

> +       union noc_ddrtiminga0 ddrtiminga0;
> +       union noc_ddrtimingb0 ddrtimingb0;
> +       union noc_ddrtimingc0 ddrtimingc0;
> +       union noc_devtodev0 devtodev0;
> +       union noc_ddrmode ddrmode;
> +       u32 agingx0;
> +};
> +
> +struct rk3399_ddr_cic_regs {
> +       u32 cic_ctrl0;
> +       u32 cic_ctrl1;
> +       u32 cic_idle_th;
> +       u32 cic_cg_wait_th;
> +       u32 cic_status0;
> +       u32 cic_status1;
> +       u32 cic_ctrl2;
> +       u32 cic_ctrl3;
> +       u32 cic_ctrl4;
> +};
> +
> +/* DENALI_CTL_00 */
> +#define START          (1)

Drop brackets around simple constants

> +
> +/* DENALI_CTL_68 */
> +#define PWRUP_SREFRESH_EXIT    (1 << 16)
> +
> +/* DENALI_CTL_274 */
> +#define MEM_RST_VALID  (1)
> +
> +struct rk3399_sdram_channel {
> +       unsigned char rank;
> +       /* col = 0, means this channel is invalid */

But what is col? Please can you expand these comments a bit?

> +       unsigned char col;
> +       /* 3:8bank, 2:4bank */
> +       unsigned char bk;
> +       /* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
> +       unsigned char bw;
> +       /* die buswidth, 2:32bit, 1:16bit, 0:8bit */
> +       unsigned char dbw;
> +       /* row_3_4 = 1: 6Gb or 12Gb die

Multi-line comment style:

/*
 * ...
 * ...
 */

> +        * row_3_4 = 0: normal die, power of 2
> +        */
> +       unsigned char row_3_4;
> +       unsigned char cs0_row;
> +       unsigned char cs1_row;
> +       unsigned int ddrconfig;
> +       struct rk3399_msch_timings noc_timings;
> +};
> +
> +struct rk3399_sdram_params {
> +       struct rk3399_sdram_channel ch[2];
> +       unsigned int ddr_freq;
> +       unsigned char dramtype;
> +       unsigned char num_channels;
> +       unsigned char stride;
> +       unsigned char odt;
> +       /* align 8 byte */
> +       struct rk3399_ddr_pctl_regs pctl_regs;
> +       /* align 8 byte */
> +       struct rk3399_ddr_pi_regs pi_regs;
> +       /* align 8 byte */
> +       struct rk3399_ddr_publ_regs phy_regs;
> +       /* used for align 8byte for next struct */
> +       unsigned int align_8;
> +};
> +
> +#define PI_CA_TRAINING (1 << 0)
> +#define PI_WRITE_LEVELING      (1 << 1)
> +#define PI_READ_GATE_TRAINING  (1 << 2)
> +#define PI_READ_LEVELING       (1 << 3)
> +#define PI_WDQ_LEVELING        (1 << 4)
> +#define PI_FULL_TRAINING       (0xff)
> +
> +size_t sdram_size_mb(void);

Function comment

> +
> +#endif
> diff --git a/arch/arm/mach-rockchip/rk3399/Makefile b/arch/arm/mach-rockchip/rk3399/Makefile
> index 98ebeac..437d851 100644
> --- a/arch/arm/mach-rockchip/rk3399/Makefile
> +++ b/arch/arm/mach-rockchip/rk3399/Makefile
> @@ -7,3 +7,4 @@
>  obj-y += clk_rk3399.o
>  obj-y += rk3399.o
>  obj-y += syscon_rk3399.o
> +obj-y += sdram_rk3399.o
> diff --git a/arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc b/arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
> new file mode 100644
> index 0000000..2b29bdf
> --- /dev/null
> +++ b/arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc

Can you put this into the device tree as is done for rk3288?

> @@ -0,0 +1,1565 @@
> +/*
> + * This file is part of the coreboot project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +
[...]

> diff --git a/arch/arm/mach-rockchip/rk3399/sdram_rk3399.c b/arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
> new file mode 100644
> index 0000000..67a92cc
> --- /dev/null
> +++ b/arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
> @@ -0,0 +1,1121 @@
> +/*
> + * (C) Copyright 2016 Rockchip Inc.
> + *
> + * SPDX-License-Identifier:     GPL-2.0
> + *
> + * Adapted from coreboot.
> + */
> +#include <common.h>
> +#include <dm.h>
> +#include <asm/io.h>
> +#include <clk.h>

clk.h should go after common.h

> +#include <asm/arch/sdram_rk3399.h>
> +#include <asm/arch/cru_rk3399.h>
> +#include <asm/arch/grf_rk3399.h>
> +#include <asm/arch/hardware.h>
> +#include <linux/err.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define DDRC0_BASE_ADDR         0xffa80000
> +#define SERVER_MSCH0_BASE_ADDR  0xffa84000
> +#define DDRC1_BASE_ADDR         0xffa88000
> +#define SERVER_MSCH1_BASE_ADDR  0xffa8c000
> +
> +#define DDR_PI_OFFSET                  0x800
> +#define DDR_PHY_OFFSET                 0x2000
> +#define DDRC0_PI_BASE_ADDR             (DDRC0_BASE_ADDR + DDR_PI_OFFSET)
> +#define DDRC0_PHY_BASE_ADDR            (DDRC0_BASE_ADDR + DDR_PHY_OFFSET)
> +#define DDRC1_PI_BASE_ADDR             (DDRC1_BASE_ADDR + DDR_PI_OFFSET)
> +#define DDRC1_PHY_BASE_ADDR            (DDRC1_BASE_ADDR + DDR_PHY_OFFSET)
> +
> +#define PMUCRU_BASE             0xff750000
> +#define CRU_BASE                0xff760000
> +#define PMUGRF_BASE             0xff320000
> +#define PMUSGRF_BASE            0xff330000
> +#define CIC_BASE_ADDR          0xff620000
> +
> +static struct rk3399_pmucru * const pmucru_ptr = (void *)PMUCRU_BASE;
> +static struct rk3399_cru * const cru_ptr = (void *)CRU_BASE;
> +static struct rk3399_pmugrf_regs * const rk3399_pmugrf = (void *)PMUGRF_BASE;
> +static struct rk3399_pmusgrf_regs * const rk3399_pmusgrf = (void *)PMUSGRF_BASE;
> +
> +static struct rk3399_ddr_pctl_regs * const rk3399_ddr_pctl[2] = {
> +       (void *)DDRC0_BASE_ADDR, (void *)DDRC1_BASE_ADDR };
> +static struct rk3399_ddr_pi_regs * const rk3399_ddr_pi[2] = {
> +       (void *)DDRC0_PI_BASE_ADDR, (void *)DDRC1_PI_BASE_ADDR };
> +static struct rk3399_ddr_publ_regs * const rk3399_ddr_publ[2] = {
> +       (void *)DDRC0_PHY_BASE_ADDR, (void *)DDRC1_PHY_BASE_ADDR };
> +static struct rk3399_msch_regs * const rk3399_msch[2] = {
> +       (void *)SERVER_MSCH0_BASE_ADDR, (void *)SERVER_MSCH1_BASE_ADDR };
> +static struct rk3399_ddr_cic_regs *const rk3399_ddr_cic = (void *)CIC_BASE_ADDR;

These should all come from the device tree, right?

> +
> +/*
> + * sys_reg bitfield struct
> + * [31]                row_3_4_ch1
> + * [30]                row_3_4_ch0
> + * [29:28]     chinfo
> + * [27]                rank_ch1
> + * [26:25]     col_ch1
> + * [24]                bk_ch1
> + * [23:22]     cs0_row_ch1
> + * [21:20]     cs1_row_ch1
> + * [19:18]     bw_ch1
> + * [17:16]     dbw_ch1;
> + * [15:13]     ddrtype
> + * [12]                channelnum
> + * [11]                rank_ch0
> + * [10:9]      col_ch0
> + * [8]         bk_ch0
> + * [7:6]       cs0_row_ch0
> + * [5:4]       cs1_row_ch0
> + * [3:2]       bw_ch0
> + * [1:0]       dbw_ch0
> +*/
> +#define SYS_REG_ENC_ROW_3_4(n, ch)     ((n) << (30 + (ch)))
> +#define SYS_REG_DEC_ROW_3_4(n, ch)     ((n >> (30 + ch)) & 0x1)
> +#define SYS_REG_ENC_CHINFO(ch)         (1 << (28 + (ch)))
> +#define SYS_REG_ENC_DDRTYPE(n)         ((n) << 13)
> +#define SYS_REG_ENC_NUM_CH(n)          (((n) - 1) << 12)
> +#define SYS_REG_DEC_NUM_CH(n)          (1 + ((n >> 12) & 0x1))
> +#define SYS_REG_ENC_RANK(n, ch)                (((n) - 1) << (11 + ((ch) * 16)))
> +#define SYS_REG_DEC_RANK(n, ch)                (1 + ((n >> (11 + 16 * ch)) & 0x1))
> +#define SYS_REG_ENC_COL(n, ch)         (((n) - 9) << (9 + ((ch) * 16)))
> +#define SYS_REG_DEC_COL(n, ch)         (9 + ((n >> (9 + 16 * ch)) & 0x3))
> +#define SYS_REG_ENC_BK(n, ch)          (((n) == 3 ? 0 : 1) \
> +                                               << (8 + ((ch) * 16)))
> +#define SYS_REG_DEC_BK(n, ch)          (3 - ((n >> (8 + 16 * ch)) & 0x1))
> +#define SYS_REG_ENC_CS0_ROW(n, ch)     (((n) - 13) << (6 + ((ch) * 16)))
> +#define SYS_REG_DEC_CS0_ROW(n, ch)     (13 + ((n >> (6 + 16 * ch)) & 0x3))
> +#define SYS_REG_ENC_CS1_ROW(n, ch)     (((n) - 13) << (4 + ((ch) * 16)))
> +#define SYS_REG_DEC_CS1_ROW(n, ch)     (13 + ((n >> (4 + 16 * ch)) & 0x3))
> +#define SYS_REG_ENC_BW(n, ch)          ((2 >> (n)) << (2 + ((ch) * 16)))
> +#define SYS_REG_DEC_BW(n, ch)          (2 >> ((n >> (2 + 16 * ch)) & 0x3))
> +#define SYS_REG_ENC_DBW(n, ch)         ((2 >> (n)) << (0 + ((ch) * 16)))
> +#define SYS_REG_DEC_DBW(n, ch)         (2 >> ((n >> (0 + 16 * ch)) & 0x3))
> +
> +#define DDR_STRIDE(n)          writel((0x1F << (10 + 16)) | (n << 10), \
> +                                       &rk3399_pmusgrf->soc_con4)
> +
> +#define PRESET_SGRF_HOLD(n)    ((0x1 << (6+16)) | ((n) << 6))
> +#define PRESET_GPIO0_HOLD(n)   ((0x1 << (7+16)) | ((n) << 7))
> +#define PRESET_GPIO1_HOLD(n)   ((0x1 << (8+16)) | ((n) << 8))

Can we please have the shift/mask values defined, and use explicit
shift/mask in the code, instead of these macros?

> +
> +#define PHY_DRV_ODT_Hi_Z       (0x0)
> +#define PHY_DRV_ODT_240                (0x1)
> +#define PHY_DRV_ODT_120                (0x8)
> +#define PHY_DRV_ODT_80         (0x9)
> +#define PHY_DRV_ODT_60         (0xc)
> +#define PHY_DRV_ODT_48         (0xd)
> +#define PHY_DRV_ODT_40         (0xe)
> +#define PHY_DRV_ODT_34_3       (0xf)

Drop brackets

> +
> +#ifdef CONFIG_SPL_BUILD
> +static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
> +{
> +       int i;
> +
> +       for (i = 0; i < n / sizeof(u32); i++) {
> +               writel(*src, dest);
> +               src++;
> +               dest++;
> +       }
> +}
> +
> +static void phy_dll_bypass_set(u32 channel,
> +       struct rk3399_ddr_publ_regs *ddr_publ_regs, u32 freq)

Can you check patman/checkpatch for this? The alignment seems wrong.

> +{
> +       u32 *denali_phy = ddr_publ_regs->denali_phy;
> +       if (freq <= 125*MHz) {
> +               /* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
> +               setbits_le32(&denali_phy[86], (0x3 << 2) << 8);
> +               setbits_le32(&denali_phy[214], (0x3 << 2) << 8);
> +               setbits_le32(&denali_phy[342], (0x3 << 2) << 8);
> +               setbits_le32(&denali_phy[470], (0x3 << 2) << 8);

These should really be defined as SHIFT and MASK values.

> +
> +               /* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
> +               setbits_le32(&denali_phy[547], (0x3 << 2) << 16);
> +               setbits_le32(&denali_phy[675], (0x3 << 2) << 16);
> +               setbits_le32(&denali_phy[803], (0x3 << 2) << 16);
> +       } else {
> +               /* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
> +               clrbits_le32(&denali_phy[86], (0x3 << 2) << 8);
> +               clrbits_le32(&denali_phy[214], (0x3 << 2) << 8);
> +               clrbits_le32(&denali_phy[342], (0x3 << 2) << 8);
> +               clrbits_le32(&denali_phy[470], (0x3 << 2) << 8);
> +
> +               /* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
> +               clrbits_le32(&denali_phy[547], (0x3 << 2) << 16);
> +               clrbits_le32(&denali_phy[675], (0x3 << 2) << 16);
> +               clrbits_le32(&denali_phy[803], (0x3 << 2) << 16);
> +       }
> +}
> +
> +static void set_memory_map(u32 channel,
> +                          const struct rk3399_sdram_params *sdram_params)
> +{
> +       const struct rk3399_sdram_channel *sdram_ch =
> +               &sdram_params->ch[channel];
> +       u32 *denali_ctl = rk3399_ddr_pctl[channel]->denali_ctl;
> +       u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
> +       u32 cs_map;
> +       u32 reduc;
> +       u32 row;
> +
> +       if ((sdram_ch->ddrconfig < 2) || (sdram_ch->ddrconfig == 4))

Can you add a comment as to what this code is doing?

> +               row = 16;
> +       else if (sdram_ch->ddrconfig == 3)
> +               row = 14;
> +       else
> +               row = 15;
> +
> +       cs_map = (sdram_ch->rank > 1) ? 3 : 1;
> +       reduc = (sdram_ch->bw == 2) ? 0 : 1;
> +
> +       clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->col));
> +       clrsetbits_le32(&denali_ctl[190], (0x3 << 16) | (0x7 << 24),
> +                       ((3 - sdram_ch->bk) << 16) |
> +                       ((16 - row) << 24));
> +
> +       clrsetbits_le32(&denali_ctl[196], 0x3 | (1 << 16),
> +                       cs_map | (reduc << 16));
> +
> +       /* PI_199 PI_COL_DIFF:RW:0:4 */
> +       clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->col));
> +
> +       /* PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2 */
> +       clrsetbits_le32(&denali_pi[155], (0x3 << 16) | (0x7 << 24),
> +                       ((3 - sdram_ch->bk) << 16) |
> +                       ((16 - row) << 24));
> +       /* PI_41 PI_CS_MAP:RW:24:4 */
> +       clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24);
> +       if ((sdram_ch->rank == 1) && (sdram_params->dramtype == DDR3))
> +               writel(0x2EC7FFFF, &denali_pi[34]);
> +}
> +
> +static void set_ds_odt(u32 channel,
> +                      const struct rk3399_sdram_params *sdram_params)
> +{
> +       u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
> +
> +       u32 tsel_idle_en, tsel_wr_en, tsel_rd_en;
> +       u32 tsel_idle_select_p, tsel_wr_select_p, tsel_rd_select_p;
> +       u32 ca_tsel_wr_select_p, ca_tsel_wr_select_n;
> +       u32 tsel_idle_select_n, tsel_wr_select_n, tsel_rd_select_n;
> +       u32 reg_value;
> +
> +       if (sdram_params->dramtype == LPDDR4) {
> +               tsel_rd_select_p = PHY_DRV_ODT_Hi_Z;
> +               tsel_wr_select_p = PHY_DRV_ODT_40;
> +               ca_tsel_wr_select_p = PHY_DRV_ODT_40;
> +               tsel_idle_select_p = PHY_DRV_ODT_Hi_Z;
> +
> +               tsel_rd_select_n = PHY_DRV_ODT_240;
> +               tsel_wr_select_n = PHY_DRV_ODT_40;
> +               ca_tsel_wr_select_n = PHY_DRV_ODT_40;
> +               tsel_idle_select_n = PHY_DRV_ODT_240;
> +       } else if (sdram_params->dramtype == LPDDR3) {
> +               tsel_rd_select_p = PHY_DRV_ODT_240;
> +               tsel_wr_select_p = PHY_DRV_ODT_34_3;
> +               ca_tsel_wr_select_p = PHY_DRV_ODT_48;
> +               tsel_idle_select_p = PHY_DRV_ODT_240;
> +
> +               tsel_rd_select_n = PHY_DRV_ODT_Hi_Z;
> +               tsel_wr_select_n = PHY_DRV_ODT_34_3;
> +               ca_tsel_wr_select_n = PHY_DRV_ODT_48;
> +               tsel_idle_select_n = PHY_DRV_ODT_Hi_Z;
> +       } else {
> +               tsel_rd_select_p = PHY_DRV_ODT_240;
> +               tsel_wr_select_p = PHY_DRV_ODT_34_3;
> +               ca_tsel_wr_select_p = PHY_DRV_ODT_34_3;
> +               tsel_idle_select_p = PHY_DRV_ODT_240;
> +
> +               tsel_rd_select_n = PHY_DRV_ODT_240;
> +               tsel_wr_select_n = PHY_DRV_ODT_34_3;
> +               ca_tsel_wr_select_n = PHY_DRV_ODT_34_3;
> +               tsel_idle_select_n = PHY_DRV_ODT_240;
> +       }
> +
> +       if (sdram_params->odt == 1)
> +               tsel_rd_en = 1;
> +       else
> +               tsel_rd_en = 0;
> +
> +       tsel_wr_en = 0;
> +       tsel_idle_en = 0;
> +
> +       /*
> +        * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0
> +        * sets termination values for read/idle cycles and drive strength
> +        * for write cycles for DQ/DM
> +        */
> +       reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) |
> +                   (tsel_wr_select_n << 8) | (tsel_wr_select_p << 12) |
> +                   (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20);
> +       clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value);
> +       clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value);
> +       clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value);
> +       clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value);
> +
> +       /*
> +        * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0
> +        * sets termination values for read/idle cycles and drive strength
> +        * for write cycles for DQS
> +        */
> +       clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value);
> +       clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value);
> +       clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value);
> +       clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value);
> +
> +       /* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
> +       reg_value = ca_tsel_wr_select_n | (ca_tsel_wr_select_p << 0x4);
> +       clrsetbits_le32(&denali_phy[544], 0xff, reg_value);
> +       clrsetbits_le32(&denali_phy[672], 0xff, reg_value);
> +       clrsetbits_le32(&denali_phy[800], 0xff, reg_value);
> +
> +       /* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */
> +       clrsetbits_le32(&denali_phy[928], 0xff, reg_value);
> +
> +       /* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */
> +       clrsetbits_le32(&denali_phy[937], 0xff, reg_value);
> +
> +       /* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */
> +       clrsetbits_le32(&denali_phy[935], 0xff, reg_value);
> +
> +       /* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */
> +       clrsetbits_le32(&denali_phy[939], 0xff, reg_value);
> +
> +       /* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */
> +       clrsetbits_le32(&denali_phy[929], 0xff, reg_value);
> +
> +       /* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
> +       clrsetbits_le32(&denali_phy[924], 0xff,
> +                       tsel_wr_select_n | (tsel_wr_select_p << 4));
> +       clrsetbits_le32(&denali_phy[925], 0xff,
> +                       tsel_rd_select_n | (tsel_rd_select_p << 4));
> +
> +       /* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
> +       reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
> +               << 16;
> +       clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value);
> +       clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value);
> +       clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value);
> +       clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value);
> +
> +       /* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */
> +       reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
> +               << 24;
> +       clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value);
> +       clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value);
> +       clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value);
> +       clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value);
> +
> +       /* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */
> +       reg_value = tsel_wr_en << 8;
> +       clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value);
> +       clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value);
> +       clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value);
> +
> +       /* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */
> +       reg_value = tsel_wr_en << 17;
> +       clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value);
> +       /*
> +        * pad_rst/cke/cs/clk_term tsel 1bits
> +        * DENALI_PHY_938/936/940/934 offset_17
> +        */
> +       clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value);
> +       clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value);
> +       clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value);
> +       clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value);
> +
> +       /* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */

These could all use SHIFT/MASK values

> +       clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value);
> +}
> +
> +static void phy_io_config(u32 channel,
> +                         const struct rk3399_sdram_params *sdram_params)
> +{
> +       u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
> +       u32 vref_mode_dq = 0;
> +       u32 vref_value_dq = 0;
> +       u32 vref_mode_ac = 0;
> +       u32 vref_value_ac = 0;
> +       u32 mode_sel = 0;

Don't init here unless you need to.

> +       u32 reg_value;
> +       u32 drv_value, odt_value;
> +       u32 speed;
> +
> +       /* vref setting */
> +       if (sdram_params->dramtype == LPDDR4) {
> +               /* LPDDR4 */
> +               vref_mode_dq = 0x6;
> +               vref_value_dq = 0x1f;
> +               vref_mode_ac = 0x6;
> +               vref_value_ac = 0x1f;
> +       } else if (sdram_params->dramtype == LPDDR3) {
> +               if (sdram_params->odt == 1) {
> +                       vref_mode_dq = 0x5;  /* LPDDR3 ODT */
> +                       drv_value = (readl(&denali_phy[6]) >> 12) & 0xf;
> +                       odt_value = (readl(&denali_phy[6]) >> 4) & 0xf;
> +                       if (drv_value == PHY_DRV_ODT_48) {
> +                               switch (odt_value) {
> +                               case PHY_DRV_ODT_240:
> +                                       vref_value_dq = 0x16;
> +                                       break;
> +                               case PHY_DRV_ODT_120:
> +                                       vref_value_dq = 0x26;
> +                                       break;
> +                               case PHY_DRV_ODT_60:
> +                                       vref_value_dq = 0x36;
> +                                       break;
> +                               default:
> +                                       error("Halting: Invalid ODT value.\n");

Can we return an error and use debug() ?

> +                               }
> +                       } else if (drv_value == PHY_DRV_ODT_40) {
> +                               switch (odt_value) {
> +                               case PHY_DRV_ODT_240:
> +                                       vref_value_dq = 0x19;
> +                                       break;
> +                               case PHY_DRV_ODT_120:
> +                                       vref_value_dq = 0x23;
> +                                       break;
> +                               case PHY_DRV_ODT_60:
> +                                       vref_value_dq = 0x31;
> +                                       break;
> +                               default:
> +                                       error("Halting: Invalid ODT value.\n");
> +                               }
> +                       } else if (drv_value == PHY_DRV_ODT_34_3) {
> +                               switch (odt_value) {
> +                               case PHY_DRV_ODT_240:
> +                                       vref_value_dq = 0x17;
> +                                       break;
> +                               case PHY_DRV_ODT_120:
> +                                       vref_value_dq = 0x20;
> +                                       break;
> +                               case PHY_DRV_ODT_60:
> +                                       vref_value_dq = 0x2e;
> +                                       break;
> +                               default:
> +                                       error("Halting: Invalid ODT value.\n");
> +                               }
> +                       } else {
> +                               error("Halting: Invalid DRV value.\n");
> +                       }
> +               } else {
> +                       vref_mode_dq = 0x2;  /* LPDDR3 */
> +                       vref_value_dq = 0x1f;
> +               }
> +               vref_mode_ac = 0x2;
> +               vref_value_ac = 0x1f;
> +       } else if (sdram_params->dramtype == DDR3) {
> +               /* DDR3L */
> +               vref_mode_dq = 0x1;
> +               vref_value_dq = 0x1f;
> +               vref_mode_ac = 0x1;
> +               vref_value_ac = 0x1f;
> +       }
> +       else
> +               error("Halting: Unknown DRAM type.\n");
> +
> +       reg_value = (vref_mode_dq << 9) | (0x1 << 8) | vref_value_dq;
> +
> +       /* PHY_913 PHY_PAD_VREF_CTRL_DQ_0 12bits offset_8 */
> +       clrsetbits_le32(&denali_phy[913], 0xfff << 8, reg_value << 8);
> +       /* PHY_914 PHY_PAD_VREF_CTRL_DQ_1 12bits offset_0 */
> +       clrsetbits_le32(&denali_phy[914], 0xfff, reg_value);
> +       /* PHY_914 PHY_PAD_VREF_CTRL_DQ_2 12bits offset_16 */
> +       clrsetbits_le32(&denali_phy[914], 0xfff << 16, reg_value << 16);
> +       /* PHY_915 PHY_PAD_VREF_CTRL_DQ_3 12bits offset_0 */
> +       clrsetbits_le32(&denali_phy[915], 0xfff, reg_value);
> +
> +       reg_value = (vref_mode_ac << 9) | (0x1 << 8) | vref_value_ac;
> +
> +       /* PHY_915 PHY_PAD_VREF_CTRL_AC 12bits offset_16 */
> +       clrsetbits_le32(&denali_phy[915], 0xfff << 16, reg_value << 16);
> +
> +       if (sdram_params->dramtype == LPDDR4)
> +               mode_sel = 0x6;
> +       else if (sdram_params->dramtype == LPDDR3)
> +               mode_sel = 0x0;
> +       else if (sdram_params->dramtype == DDR3)
> +               mode_sel = 0x1;
> +
> +       /* PHY_924 PHY_PAD_FDBK_DRIVE */
> +       clrsetbits_le32(&denali_phy[924], 0x7 << 15, mode_sel << 15);
> +       /* PHY_926 PHY_PAD_DATA_DRIVE */
> +       clrsetbits_le32(&denali_phy[926], 0x7 << 6, mode_sel << 6);
> +       /* PHY_927 PHY_PAD_DQS_DRIVE */
> +       clrsetbits_le32(&denali_phy[927], 0x7 << 6, mode_sel << 6);
> +       /* PHY_928 PHY_PAD_ADDR_DRIVE */
> +       clrsetbits_le32(&denali_phy[928], 0x7 << 14, mode_sel << 14);
> +       /* PHY_929 PHY_PAD_CLK_DRIVE */
> +       clrsetbits_le32(&denali_phy[929], 0x7 << 14, mode_sel << 14);
> +       /* PHY_935 PHY_PAD_CKE_DRIVE */
> +       clrsetbits_le32(&denali_phy[935], 0x7 << 14, mode_sel << 14);
> +       /* PHY_937 PHY_PAD_RST_DRIVE */
> +       clrsetbits_le32(&denali_phy[937], 0x7 << 14, mode_sel << 14);
> +       /* PHY_939 PHY_PAD_CS_DRIVE */
> +       clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14);
> +
> +
> +       /* speed setting */
> +       if (sdram_params->ddr_freq < 400*MHz)
> +               speed = 0x0;
> +       else if (sdram_params->ddr_freq < 800*MHz)
> +               speed = 0x1;
> +       else if (sdram_params->ddr_freq < 1200*MHz)
> +               speed = 0x2;
> +       else
> +               speed = 0x3;
> +
> +       /* PHY_924 PHY_PAD_FDBK_DRIVE */
> +       clrsetbits_le32(&denali_phy[924], 0x3 << 21, speed << 21);
> +       /* PHY_926 PHY_PAD_DATA_DRIVE */
> +       clrsetbits_le32(&denali_phy[926], 0x3 << 9, speed << 9);
> +       /* PHY_927 PHY_PAD_DQS_DRIVE */
> +       clrsetbits_le32(&denali_phy[927], 0x3 << 9, speed << 9);
> +       /* PHY_928 PHY_PAD_ADDR_DRIVE */
> +       clrsetbits_le32(&denali_phy[928], 0x3 << 17, speed << 17);
> +       /* PHY_929 PHY_PAD_CLK_DRIVE */
> +       clrsetbits_le32(&denali_phy[929], 0x3 << 17, speed << 17);
> +       /* PHY_935 PHY_PAD_CKE_DRIVE */
> +       clrsetbits_le32(&denali_phy[935], 0x3 << 17, speed << 17);
> +       /* PHY_937 PHY_PAD_RST_DRIVE */
> +       clrsetbits_le32(&denali_phy[937], 0x3 << 17, speed << 17);
> +       /* PHY_939 PHY_PAD_CS_DRIVE */
> +       clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
> +}
> +
> +static int pctl_cfg(u32 channel,
> +                   const struct rk3399_sdram_params *sdram_params)
> +{
> +       u32 *denali_ctl = rk3399_ddr_pctl[channel]->denali_ctl;
> +       u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
> +       u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
> +       const u32 *params_ctl = sdram_params->pctl_regs.denali_ctl;
> +       const u32 *params_phy = sdram_params->phy_regs.denali_phy;

I think all of these should go in a struct, and you can set up the
values by reading from the DT.

> +       u32 tmp, tmp1, tmp2;
> +       u32 pwrup_srefresh_exit;
> +
> +       /*
> +        * work around controller bug:
> +        * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
> +        */
> +       copy_to_reg(&denali_ctl[1], &params_ctl[1],
> +                   sizeof(struct rk3399_ddr_pctl_regs) - 4);
> +       writel(params_ctl[0], &denali_ctl[0]);
> +       copy_to_reg(denali_pi, &sdram_params->pi_regs.denali_pi[0],
> +                   sizeof(struct rk3399_ddr_pi_regs));
> +       /* rank count need to set for init */
> +       set_memory_map(channel, sdram_params);
> +
> +       writel(sdram_params->phy_regs.denali_phy[910], &denali_phy[910]);
> +       writel(sdram_params->phy_regs.denali_phy[911], &denali_phy[911]);
> +       writel(sdram_params->phy_regs.denali_phy[912], &denali_phy[912]);
> +
> +       pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT;
> +       clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
> +
> +       /* PHY_DLL_RST_EN */
> +       clrsetbits_le32(&denali_phy[957], 0x3 << 24, 1 << 24);
> +
> +       setbits_le32(&denali_pi[0], START);
> +       setbits_le32(&denali_ctl[0], START);
> +
> +       while (1) {
> +               tmp = readl(&denali_phy[920]);
> +               tmp1 = readl(&denali_phy[921]);
> +               tmp2 = readl(&denali_phy[922]);
> +               if ((((tmp >> 16) & 0x1) == 0x1) &&
> +                   (((tmp1 >> 16) & 0x1) == 0x1) &&
> +                   (((tmp1 >> 0) & 0x1) == 0x1) &&
> +                   (((tmp2 >> 0) & 0x1) == 0x1))
> +                       break;
> +       }

What is this loop doing? SHIFT/MASK defines might help.

> +
> +       copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
> +       copy_to_reg(&denali_phy[0], &params_phy[0], (90 - 0 + 1) * 4);
> +       copy_to_reg(&denali_phy[128], &params_phy[128], (218 - 128 + 1) * 4);
> +       copy_to_reg(&denali_phy[256], &params_phy[256], (346 - 256 + 1) * 4);
> +       copy_to_reg(&denali_phy[384], &params_phy[384], (474 - 384 + 1) * 4);
> +       copy_to_reg(&denali_phy[512], &params_phy[512], (549 - 512 + 1) * 4);
> +       copy_to_reg(&denali_phy[640], &params_phy[640], (677 - 640 + 1) * 4);
> +       copy_to_reg(&denali_phy[768], &params_phy[768], (805 - 768 + 1) * 4);
> +       set_ds_odt(channel, sdram_params);
> +
> +       /*
> +        * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
> +        * dqs_tsel_wr_end[7:4] add Half cycle
> +        */
> +       tmp = (readl(&denali_phy[84]) >> 8) & 0xff;
> +       clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8);
> +       tmp = (readl(&denali_phy[212]) >> 8) & 0xff;
> +       clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8);
> +       tmp = (readl(&denali_phy[340]) >> 8) & 0xff;
> +       clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8);
> +       tmp = (readl(&denali_phy[468]) >> 8) & 0xff;
> +       clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8);
> +
> +       /*
> +        * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8
> +        * dq_tsel_wr_end[7:4] add Half cycle
> +        */
> +       tmp = (readl(&denali_phy[83]) >> 16) & 0xff;
> +       clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16);
> +       tmp = (readl(&denali_phy[211]) >> 16) & 0xff;
> +       clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16);
> +       tmp = (readl(&denali_phy[339]) >> 16) & 0xff;
> +       clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16);
> +       tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
> +       clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
> +
> +       phy_io_config(channel, sdram_params);
> +
> +       /* PHY_DLL_RST_EN */
> +       clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
> +
> +       /*
> +        * FIXME:

TODO(email):

> +        * need to care ERROR bit,
> +        * if 100ms do not get right status, return err
> +        */
> +       tmp = 0;
> +       while (!(readl(&denali_ctl[203]) & (1 << 3))) {
> +               mdelay(10);
> +               tmp ++;
> +               if (tmp > 10)
> +                       return -1;

-EIO or something else?

> +       }
> +
> +       clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
> +                       pwrup_srefresh_exit);
> +       return 0;
> +}
> +
> +static void select_per_cs_training_index(u32 channel, u32 rank)
> +{
> +       u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
> +
> +       /* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
> +       if ((readl(&denali_phy[84])>>16) & 1) {
> +               /*
> +                * PHY_8/136/264/392
> +                * phy_per_cs_training_index_X 1bit offset_24
> +                */
> +               clrsetbits_le32(&denali_phy[8], 0x1 << 24, rank << 24);
> +               clrsetbits_le32(&denali_phy[136], 0x1 << 24, rank << 24);
> +               clrsetbits_le32(&denali_phy[264], 0x1 << 24, rank << 24);
> +               clrsetbits_le32(&denali_phy[392], 0x1 << 24, rank << 24);
> +       }
> +}
> +
> +static void override_write_leveling_value(u32 channel)
> +{
> +       u32 *denali_ctl = rk3399_ddr_pctl[channel]->denali_ctl;
> +       u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;

Again if you pass in a struct with all these values you can avoid
assigning them here.

> +       u32 byte;
> +
> +       /* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
> +       setbits_le32(&denali_phy[896], 1);
> +
> +       /*
> +        * PHY_8/136/264/392
> +        * phy_per_cs_training_multicast_en_X 1bit offset_16
> +        */
> +       clrsetbits_le32(&denali_phy[8], 0x1 << 16, 1 << 16);
> +       clrsetbits_le32(&denali_phy[136], 0x1 << 16, 1 << 16);
> +       clrsetbits_le32(&denali_phy[264], 0x1 << 16, 1 << 16);
> +       clrsetbits_le32(&denali_phy[392], 0x1 << 16, 1 << 16);
> +
> +       for (byte = 0; byte < 4; byte++)
> +               clrsetbits_le32(&denali_phy[63 + (128 * byte)], 0xffff << 16,
> +                       0x200 << 16);
> +
> +       /* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
> +       clrbits_le32(&denali_phy[896], 1);
> +
> +       /* CTL_200 ctrlupd_req 1bit offset_8 */
> +       clrsetbits_le32(&denali_ctl[200], 0x1 << 8, 0x1 << 8);
> +}
> +
> +static int data_training(u32 channel,
> +                        const struct rk3399_sdram_params *sdram_params,
> +                        u32 training_flag)
> +{
> +       u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
> +       u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
> +       u32 i, tmp;
> +       u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
> +       u32 rank = sdram_params->ch[channel].rank;
> +
> +       /* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
> +       setbits_le32(&denali_phy[927], (1 << 22));
> +
> +       if (training_flag == PI_FULL_TRAINING) {
> +               if (sdram_params->dramtype == LPDDR4) {
> +                       training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
> +                                       PI_READ_GATE_TRAINING |
> +                                       PI_READ_LEVELING | PI_WDQ_LEVELING;
> +               } else if (sdram_params->dramtype == LPDDR3) {
> +                       training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
> +                                       PI_READ_GATE_TRAINING;
> +               } else if (sdram_params->dramtype == DDR3) {
> +                       training_flag = PI_WRITE_LEVELING |
> +                                       PI_READ_GATE_TRAINING |
> +                                       PI_READ_LEVELING;
> +               }
> +       }
> +
> +       /* ca training(LPDDR4,LPDDR3 support) */
> +       if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
> +               for (i = 0; i < rank; i++) {
> +                       select_per_cs_training_index(channel, i);
> +                       /* PI_100 PI_CALVL_EN:RW:8:2 */
> +                       clrsetbits_le32(&denali_pi[100], 0x3 << 8, 0x2 << 8);
> +                       /* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
> +                       clrsetbits_le32(&denali_pi[92],
> +                                       (0x1 << 16) | (0x3 << 24),
> +                                       (0x1 << 16) | (i << 24));
> +
> +                       while (1) {

What is this loop doing? Can you add a comment?

> +                               /* PI_174 PI_INT_STATUS:RD:8:18 */
> +                               tmp = readl(&denali_pi[174]) >> 8;
> +                               /*
> +                                * check status obs
> +                                * PHY_532/660/789 phy_adr_calvl_obs1_:0:32
> +                                */
> +                               obs_0 = readl(&denali_phy[532]);
> +                               obs_1 = readl(&denali_phy[660]);
> +                               obs_2 = readl(&denali_phy[788]);
> +                               if (((obs_0 >> 30) & 0x3) ||
> +                                   ((obs_1 >> 30) & 0x3) ||
> +                                   ((obs_2 >> 30) & 0x3))
> +                                       obs_err = 1;
> +                               if ((((tmp >> 11) & 0x1) == 0x1) &&
> +                                   (((tmp >> 13) & 0x1) == 0x1) &&
> +                                   (((tmp >> 5) & 0x1) == 0x0) &&
> +                                   (obs_err == 0))
> +                                       break;
> +                               else if ((((tmp >> 5) & 0x1) == 0x1) ||
> +                                        (obs_err == 1))
> +                                       return -1;
> +                       }
> +                       /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
> +                       writel(0x00003f7c, (&denali_pi[175]));
> +               }
> +               clrbits_le32(&denali_pi[100], 0x3 << 8);
> +       }
> +
> +       /* write leveling(LPDDR4,LPDDR3,DDR3 support) */
> +       if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
> +               for (i = 0; i < rank; i++) {
> +                       select_per_cs_training_index(channel, i);
> +                       /* PI_60 PI_WRLVL_EN:RW:8:2 */
> +                       clrsetbits_le32(&denali_pi[60], 0x3 << 8, 0x2 << 8);
> +                       /* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
> +                       clrsetbits_le32(&denali_pi[59],
> +                                       (0x1 << 8) | (0x3 << 16),
> +                                       (0x1 << 8) | (i << 16));
> +
> +                       while (1) {
> +                               /* PI_174 PI_INT_STATUS:RD:8:18 */
> +                               tmp = readl(&denali_pi[174]) >> 8;
> +
> +                               /*
> +                                * check status obs, if error maybe can not
> +                                * get leveling done PHY_40/168/296/424
> +                                * phy_wrlvl_status_obs_X:0:13
> +                                */
> +                               obs_0 = readl(&denali_phy[40]);
> +                               obs_1 = readl(&denali_phy[168]);
> +                               obs_2 = readl(&denali_phy[296]);
> +                               obs_3 = readl(&denali_phy[424]);
> +                               if (((obs_0 >> 12) & 0x1) ||
> +                                   ((obs_1 >> 12) & 0x1) ||
> +                                   ((obs_2 >> 12) & 0x1) ||
> +                                   ((obs_3 >> 12) & 0x1))
> +                                       obs_err = 1;
> +                               if ((((tmp >> 10) & 0x1) == 0x1) &&
> +                                   (((tmp >> 13) & 0x1) == 0x1) &&
> +                                   (((tmp >> 4) & 0x1) == 0x0) &&
> +                                   (obs_err == 0))
> +                                       break;
> +                               else if ((((tmp >> 4) & 0x1) == 0x1) ||
> +                                        (obs_err == 1))
> +                                       return -1;
> +                       }
> +                       /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
> +                       writel(0x00003f7c, (&denali_pi[175]));
> +               }
> +
> +               override_write_leveling_value(channel);
> +               clrbits_le32(&denali_pi[60], 0x3 << 8);
> +       }
> +
> +       /* read gate training(LPDDR4,LPDDR3,DDR3 support) */
> +       if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {

This is a very long function. Can you put each stage in a separate function?

if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING)
   ca_training();
if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING)
    read_gate_training();

Or similar...

> +               for (i = 0; i < rank; i++) {
> +                       select_per_cs_training_index(channel, i);
> +                       /* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
> +                       clrsetbits_le32(&denali_pi[80], 0x3 << 24, 0x2 << 24);
> +                       /*
> +                        * PI_74 PI_RDLVL_GATE_REQ:WR:16:1
> +                        * PI_RDLVL_CS:RW:24:2
> +                        */
> +                       clrsetbits_le32(&denali_pi[74],
> +                                       (0x1 << 16) | (0x3 << 24),
> +                                       (0x1 << 16) | (i << 24));
> +
> +                       while (1) {
> +                               /* PI_174 PI_INT_STATUS:RD:8:18 */
> +                               tmp = readl(&denali_pi[174]) >> 8;
> +
> +                               /*
> +                                * check status obs
> +                                * PHY_43/171/299/427
> +                                *     PHY_GTLVL_STATUS_OBS_x:16:8
> +                                */
> +                               obs_0 = readl(&denali_phy[43]);
> +                               obs_1 = readl(&denali_phy[171]);
> +                               obs_2 = readl(&denali_phy[299]);
> +                               obs_3 = readl(&denali_phy[427]);
> +                               if (((obs_0 >> (16 + 6)) & 0x3) ||
> +                                   ((obs_1 >> (16 + 6)) & 0x3) ||
> +                                   ((obs_2 >> (16 + 6)) & 0x3) ||
> +                                   ((obs_3 >> (16 + 6)) & 0x3))
> +                                       obs_err = 1;
> +                               if ((((tmp >> 9) & 0x1) == 0x1) &&
> +                                   (((tmp >> 13) & 0x1) == 0x1) &&
> +                                   (((tmp >> 3) & 0x1) == 0x0) &&
> +                                   (obs_err == 0))
> +                                       break;
> +                               else if ((((tmp >> 3) & 0x1) == 0x1) ||
> +                                        (obs_err == 1))
> +                                       return -1;
> +                       }
> +                       /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
> +                       writel(0x00003f7c, (&denali_pi[175]));
> +               }
> +               clrbits_le32(&denali_pi[80], 0x3 << 24);
> +       }
> +
> +       /* read leveling(LPDDR4,LPDDR3,DDR3 support) */
> +       if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
> +               for (i = 0; i < rank; i++) {
> +                       select_per_cs_training_index(channel, i);
> +                       /* PI_80 PI_RDLVL_EN:RW:16:2 */
> +                       clrsetbits_le32(&denali_pi[80], 0x3 << 16, 0x2 << 16);
> +                       /* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
> +                       clrsetbits_le32(&denali_pi[74],
> +                                       (0x1 << 8) | (0x3 << 24),
> +                                       (0x1 << 8) | (i << 24));
> +
> +                       while (1) {

What is this loop doing? Is there any commonality compared to the
other similar loops? Perhaps a function where you pass in the mask to
check?


> +                               /* PI_174 PI_INT_STATUS:RD:8:18 */
> +                               tmp = readl(&denali_pi[174]) >> 8;
> +
> +                               /*
> +                                * make sure status obs not report error bit
> +                                * PHY_46/174/302/430
> +                                *     phy_rdlvl_status_obs_X:16:8
> +                                */
> +                               if ((((tmp >> 8) & 0x1) == 0x1) &&
> +                                   (((tmp >> 13) & 0x1) == 0x1) &&
> +                                   (((tmp >> 2) & 0x1) == 0x0))
> +                                       break;
> +                               else if (((tmp >> 2) & 0x1) == 0x1)
> +                                       return -1;
> +                       }
> +                       /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
> +                       writel(0x00003f7c, (&denali_pi[175]));
> +               }
> +               clrbits_le32(&denali_pi[80], 0x3 << 16);
> +       }
> +
> +       /* wdq leveling(LPDDR4 support) */
> +       if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
> +               for (i = 0; i < rank; i++) {
> +                       select_per_cs_training_index(channel, i);
> +                       /*
> +                        * disable PI_WDQLVL_VREF_EN before wdq leveling?
> +                        * PI_181 PI_WDQLVL_VREF_EN:RW:8:1
> +                        */
> +                       clrbits_le32(&denali_pi[181], 0x1 << 8);
> +                       /* PI_124 PI_WDQLVL_EN:RW:16:2 */
> +                       clrsetbits_le32(&denali_pi[124], 0x3 << 16, 0x2 << 16);
> +                       /* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
> +                       clrsetbits_le32(&denali_pi[121],
> +                                       (0x1 << 8) | (0x3 << 16),
> +                                       (0x1 << 8) | (i << 16));
> +
> +                       while (1) {
> +                               /* PI_174 PI_INT_STATUS:RD:8:18 */
> +                               tmp = readl(&denali_pi[174]) >> 8;
> +                               if ((((tmp >> 12) & 0x1) == 0x1) &&
> +                                   (((tmp >> 13) & 0x1) == 0x1) &&
> +                                   (((tmp >> 6) & 0x1) == 0x0))
> +                                       break;
> +                               else if (((tmp >> 6) & 0x1) == 0x1)
> +                                       return -1;
> +                       }
> +                       /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
> +                       writel(0x00003f7c, (&denali_pi[175]));
> +               }
> +               clrbits_le32(&denali_pi[124], 0x3 << 16);
> +       }
> +
> +       /* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
> +       clrbits_le32(&denali_phy[927], (1 << 22));
> +
> +       return 0;
> +}
> +
> +static void set_ddrconfig(const struct rk3399_sdram_params *sdram_params,
> +                         unsigned char channel, u32 ddrconfig)
> +{
> +       /* only need to set ddrconfig */
> +       struct rk3399_msch_regs *ddr_msch_regs = rk3399_msch[channel];
> +       unsigned int cs0_cap = 0;
> +       unsigned int cs1_cap = 0;
> +
> +       cs0_cap = (1 << (sdram_params->ch[channel].cs0_row
> +                       + sdram_params->ch[channel].col
> +                       + sdram_params->ch[channel].bk
> +                       + sdram_params->ch[channel].bw - 20));
> +       if (sdram_params->ch[channel].rank > 1)
> +               cs1_cap = cs0_cap >> (sdram_params->ch[channel].cs0_row
> +                               - sdram_params->ch[channel].cs1_row);
> +       if (sdram_params->ch[channel].row_3_4) {
> +               cs0_cap = cs0_cap * 3 / 4;
> +               cs1_cap = cs1_cap * 3 / 4;
> +       }
> +
> +       writel(ddrconfig | (ddrconfig << 8), &ddr_msch_regs->ddrconf);
> +       writel(((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8),
> +               &ddr_msch_regs->ddrsize);
> +}
> +
> +static void dram_all_config(const struct rk3399_sdram_params *sdram_params)
> +{
> +       u32 sys_reg = 0;
> +       unsigned int channel;
> +       unsigned int use;

What is 'use' for? Is 'index' a better name?

> +
> +       sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype);
> +       sys_reg |= SYS_REG_ENC_NUM_CH(sdram_params->num_channels);
> +       for (channel = 0, use = 0;
> +            (use < sdram_params->num_channels) && (channel < 2); channel++) {
> +               const struct rk3399_sdram_channel *info =
> +                       &sdram_params->ch[channel];
> +               struct rk3399_msch_regs *ddr_msch_regs;
> +               const struct rk3399_msch_timings *noc_timing;
> +
> +               if (sdram_params->ch[channel].col == 0)
> +                       continue;
> +               use++;
> +               sys_reg |= SYS_REG_ENC_ROW_3_4(info->row_3_4, channel);
> +               sys_reg |= SYS_REG_ENC_CHINFO(channel);
> +               sys_reg |= SYS_REG_ENC_RANK(info->rank, channel);
> +               sys_reg |= SYS_REG_ENC_COL(info->col, channel);
> +               sys_reg |= SYS_REG_ENC_BK(info->bk, channel);
> +               sys_reg |= SYS_REG_ENC_CS0_ROW(info->cs0_row, channel);
> +               if (sdram_params->ch[channel].rank > 1)
> +                       sys_reg |= SYS_REG_ENC_CS1_ROW(info->cs1_row, channel);
> +               sys_reg |= SYS_REG_ENC_BW(info->bw, channel);
> +               sys_reg |= SYS_REG_ENC_DBW(info->dbw, channel);
> +
> +               ddr_msch_regs = rk3399_msch[channel];
> +               noc_timing = &sdram_params->ch[channel].noc_timings;
> +               writel(noc_timing->ddrtiminga0.d32,
> +                      &ddr_msch_regs->ddrtiminga0.d32);
> +               writel(noc_timing->ddrtimingb0.d32,
> +                       &ddr_msch_regs->ddrtimingb0.d32);
> +               writel(noc_timing->ddrtimingc0.d32,
> +                       &ddr_msch_regs->ddrtimingc0.d32);
> +               writel(noc_timing->devtodev0.d32,
> +                       &ddr_msch_regs->devtodev0.d32);
> +               writel(noc_timing->ddrmode.d32,
> +                       &ddr_msch_regs->ddrmode.d32);
> +
> +               /* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
> +               if (sdram_params->ch[channel].rank == 1)
> +                       setbits_le32(&rk3399_ddr_pctl[channel]->denali_ctl[276],
> +                                    1 << 17);
> +       }
> +
> +       writel(sys_reg, &rk3399_pmugrf->os_reg2);
> +       DDR_STRIDE(sdram_params->stride);
> +
> +       /* reboot hold register set */
> +       writel(PRESET_SGRF_HOLD(0) | PRESET_GPIO0_HOLD(1) |
> +               PRESET_GPIO1_HOLD(1),
> +               &pmucru_ptr->pmucru_rstnhold_con[1]);
> +       clrsetbits_le32(&cru_ptr->glb_rst_con, 0x3, 0x3);
> +}
> +
> +static void switch_to_phy_index1(const struct rk3399_sdram_params *sdram_params)
> +{
> +       u32 channel;
> +       u32 *denali_phy;
> +       u32 ch_count = sdram_params->num_channels;
> +       int i = 0;
> +
> +       writel(RK_CLRSETBITS(0x03 << 4 | 1 << 2 | 1,
> +                             1 << 4 | 1 << 2 | 1),
> +                       &rk3399_ddr_cic->cic_ctrl0);
> +       while (!(readl(&rk3399_ddr_cic->cic_status0) & (1 << 2))) {
> +               mdelay(10);
> +               i++;
> +               if (i > 10) {
> +                       error("index1 frequency change overtime, reset\n");
> +                       hang();

Please have this return an error, so there is just one hang(), at the
top-level caller. Also consider using debug() here.

> +               }
> +       }
> +
> +       i = 0;
> +       writel(RK_CLRSETBITS(1 << 1, 1 << 1), &rk3399_ddr_cic->cic_ctrl0);
> +       while (!(readl(&rk3399_ddr_cic->cic_status0) & (1 << 0))) {
> +               mdelay(10);
> +               if (i>10) {
> +                       error("index1 frequency done overtime, reset\n");
> +                       hang();
> +               }
> +       }
> +
> +       for (channel = 0; channel < ch_count; channel++) {
> +               denali_phy = rk3399_ddr_publ[channel]->denali_phy;
> +               clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8);
> +               if (data_training(channel, sdram_params, PI_FULL_TRAINING)) {
> +                       error("index1 training failed, reset\n");
> +                       hang();
> +               }
> +       }
> +}
> +static struct rk3399_sdram_params sdram_configs[] = {
> +#include "sdram-lpddr3-4GB.inc"
> +};
> +
> +void sdram_init(const struct rk3399_sdram_params *sdram_params)
> +{
> +       unsigned char dramtype = sdram_params->dramtype;
> +       unsigned int ddr_freq = sdram_params->ddr_freq;
> +       int channel;
> +
> +       debug("Starting SDRAM initialization...\n");
> +
> +       if ((dramtype == DDR3 && ddr_freq > 800*MHz) ||
> +           (dramtype == LPDDR3 && ddr_freq > 933*MHz) ||
> +           (dramtype == LPDDR4 && ddr_freq > 800*MHz))
> +               error("SDRAM frequency is to high!");
> +
> +
> +       for (channel = 0; channel < 2; channel++) {
> +               phy_dll_bypass_set(channel, rk3399_ddr_publ[channel], ddr_freq);
> +
> +               if (channel >= sdram_params->num_channels)
> +                       continue;
> +
> +               /*
> +                * TODO: we need to find the root cause why this
> +                * step may fail, before that, we just reset the
> +                * system, and start again.
> +                */
> +               if (pctl_cfg(channel, sdram_params) != 0) {
> +                       printf("pctl_cfg fail, reset\n");
> +                       hang();
> +               }
> +
> +               /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
> +               if (dramtype == LPDDR3)
> +                       udelay(10);
> +
> +               if (data_training(channel, sdram_params, PI_FULL_TRAINING)) {
> +                       printf("SDRAM initialization failed, reset\n");
> +                       hang();
> +               }
> +
> +               set_ddrconfig(sdram_params, channel,
> +                             sdram_params->ch[channel].ddrconfig);
> +       }
> +       dram_all_config(sdram_params);
> +       switch_to_phy_index1(sdram_params);
> +
> +       debug("Finish SDRAM initialization...\n");
> +}
> +#endif
> +
> +size_t sdram_size_mb(void)
> +{
> +       u32 rank, col, bk, cs0_row, cs1_row, bw, row_3_4;
> +       size_t chipsize_mb = 0;
> +       static size_t size_mb = 0;

Do we need this? Perhaps we can just calculate it each time? It will
only be called once or twice I suspect.

> +       u32 ch;
> +
> +       if (!size_mb) {
> +               u32 sys_reg = readl(&rk3399_pmugrf->os_reg2);
> +               u32 ch_num = SYS_REG_DEC_NUM_CH(sys_reg);
> +
> +               for (ch = 0; ch < ch_num; ch++) {
> +                       rank = SYS_REG_DEC_RANK(sys_reg, ch);
> +                       col = SYS_REG_DEC_COL(sys_reg, ch);
> +                       bk = SYS_REG_DEC_BK(sys_reg, ch);
> +                       cs0_row = SYS_REG_DEC_CS0_ROW(sys_reg, ch);
> +                       cs1_row = SYS_REG_DEC_CS1_ROW(sys_reg, ch);
> +                       bw = SYS_REG_DEC_BW(sys_reg, ch);
> +                       row_3_4 = SYS_REG_DEC_ROW_3_4(sys_reg, ch);
> +
> +                       chipsize_mb = (1 << (cs0_row + col + bk + bw - 20));
> +
> +                       if (rank > 1)
> +                               chipsize_mb += chipsize_mb >>
> +                                       (cs0_row - cs1_row);
> +                       if (row_3_4)
> +                               chipsize_mb = chipsize_mb * 3 / 4;
> +                       size_mb += chipsize_mb;
> +               }
> +
> +               /*
> +                * we use the 0x00000000~0xf7ffffff space
> +                * since 0xf8000000~0xffffffff is soc register space
> +                * so we reserve it
> +                */
> +               size_mb = min_t(size_t, size_mb, 0xf8000000/(1<<20));
> +       }
> +
> +       return size_mb;
> +}
> +
> +static int rk3399_dmc_probe(struct udevice *dev)
> +{
> +#ifdef CONFIG_SPL_BUILD
> +       struct rk3399_sdram_params *plat = sdram_configs;
> +       int ret;
> +       struct clk ddr_clk;
> +
> +       ret = clk_get_by_index(dev, 0, &ddr_clk);
> +       if (ret){
> +               debug("%s clk get failed %d\n", __func__, ret);
> +               return ret;
> +       }
> +       ret = clk_set_rate(&ddr_clk, plat->ddr_freq);
> +       if (ret < 0){
> +               debug("%s clk set failed %d\n", __func__, ret);
> +               return ret;
> +       }
> +       sdram_init(plat);

Check return value here.

> +#endif
> +       return 0;
> +}
> +
> +static const struct udevice_id rk3399_dmc_ids[] = {
> +       { .compatible = "rockchip,rk3399-dmc" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(dmc_rk3399) = {
> +       .name = "rockchip_rk3399_dmc",
> +       .id = UCLASS_RAM,
> +       .of_match = rk3399_dmc_ids,
> +       .probe = rk3399_dmc_probe,
> +};
> --
> 1.9.1
>

Regards,
Simon
Kever Yang Jan. 18, 2017, 9:55 a.m. UTC | #2
Hi Simon,

     Thanks for your review, I would like to take all the comments but 
one below,
because I think the change only get a lot of work to do but have no any help
on understand the source code, because each of shift/mask operation has 
comment
for it.

     I have spend a lot of time on make different controller base 
addresses from dts
and gather them into one structure, which we think it does not make any 
helpful on
source code itself but only met some bug on of-platdata for address decode.

     There are hundreds of ctrl/pi/phy register in this dram controller, 
I don't think it's a
good idea to add MASK/SHIFT MACRO definition for all of them since comments
are already there.

     I will send my patch V2 without mask/shift change, but updates by 
your other comments.

Thanks,
- Kever

On 01/13/2017 10:18 AM, Simon Glass wrote:
>> >+{
>> >+       u32 *denali_phy = ddr_publ_regs->denali_phy;
>> >+       if (freq <= 125*MHz) {
>> >+               /* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
>> >+               setbits_le32(&denali_phy[86], (0x3 << 2) << 8);
>> >+               setbits_le32(&denali_phy[214], (0x3 << 2) << 8);
>> >+               setbits_le32(&denali_phy[342], (0x3 << 2) << 8);
>> >+               setbits_le32(&denali_phy[470], (0x3 << 2) << 8);
> These should really be defined as SHIFT and MASK values.
>
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
new file mode 100644
index 0000000..fab0faf
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
@@ -0,0 +1,188 @@ 
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __SOC_ROCKCHIP_RK3399_SDRAM_H__
+#define __SOC_ROCKCHIP_RK3399_SDRAM_H__
+
+#include <stddef.h>
+
+enum {
+	DDR3 = 3,
+	LPDDR2 = 5,
+	LPDDR3 = 6,
+	LPDDR4 = 7,
+	UNUSED = 0xFF
+};
+
+struct rk3399_ddr_pctl_regs {
+	u32 denali_ctl[332];
+};
+
+struct rk3399_ddr_publ_regs {
+	u32 denali_phy[959];
+};
+
+struct rk3399_ddr_pi_regs {
+	u32 denali_pi[200];
+};
+union noc_ddrtiminga0 {
+	u32 d32;
+	struct {
+		unsigned acttoact : 6;
+		unsigned reserved0 : 2;
+		unsigned rdtomiss : 6;
+		unsigned reserved1 : 2;
+		unsigned wrtomiss : 6;
+		unsigned reserved2 : 2;
+		unsigned readlatency : 8;
+	} b;
+};
+
+union noc_ddrtimingb0 {
+	u32 d32;
+	struct {
+		unsigned rdtowr : 5;
+		unsigned reserved0 : 3;
+		unsigned wrtord : 5;
+		unsigned reserved1 : 3;
+		unsigned rrd : 4;
+		unsigned reserved2 : 4;
+		unsigned faw : 6;
+		unsigned reserved3 : 2;
+	} b;
+};
+
+union noc_ddrtimingc0 {
+	u32 d32;
+	struct {
+		unsigned burstpenalty : 4;
+		unsigned reserved0 : 4;
+		unsigned wrtomwr : 6;
+		unsigned reserved1 : 18;
+	} b;
+};
+
+union noc_devtodev0 {
+	u32 d32;
+	struct {
+		unsigned busrdtord : 3;
+		unsigned reserved0 : 1;
+		unsigned busrdtowr : 3;
+		unsigned reserved1 : 1;
+		unsigned buswrtord : 3;
+		unsigned reserved2 : 1;
+		unsigned buswrtowr : 3;
+		unsigned reserved3 : 17;
+	} b;
+};
+
+union noc_ddrmode {
+	u32 d32;
+	struct {
+		unsigned autoprecharge : 1;
+		unsigned bypassfiltering : 1;
+		unsigned fawbank : 1;
+		unsigned burstsize : 2;
+		unsigned mwrsize : 2;
+		unsigned reserved2 : 1;
+		unsigned forceorder : 8;
+		unsigned forceorderstate : 8;
+		unsigned reserved3 : 8;
+	} b;
+};
+
+struct rk3399_msch_regs {
+	u32 coreid;
+	u32 revisionid;
+	u32 ddrconf;
+	u32 ddrsize;
+	union noc_ddrtiminga0 ddrtiminga0;
+	union noc_ddrtimingb0 ddrtimingb0;
+	union noc_ddrtimingc0 ddrtimingc0;
+	union noc_devtodev0 devtodev0;
+	u32 reserved0[(0x110-0x20)/4];
+	union noc_ddrmode ddrmode;
+	u32 reserved1[(0x1000-0x114)/4];
+	u32 agingx0;
+};
+
+struct rk3399_msch_timings {
+	union noc_ddrtiminga0 ddrtiminga0;
+	union noc_ddrtimingb0 ddrtimingb0;
+	union noc_ddrtimingc0 ddrtimingc0;
+	union noc_devtodev0 devtodev0;
+	union noc_ddrmode ddrmode;
+	u32 agingx0;
+};
+
+struct rk3399_ddr_cic_regs {
+	u32 cic_ctrl0;
+	u32 cic_ctrl1;
+	u32 cic_idle_th;
+	u32 cic_cg_wait_th;
+	u32 cic_status0;
+	u32 cic_status1;
+	u32 cic_ctrl2;
+	u32 cic_ctrl3;
+	u32 cic_ctrl4;
+};
+
+/* DENALI_CTL_00 */
+#define START		(1)
+
+/* DENALI_CTL_68 */
+#define PWRUP_SREFRESH_EXIT	(1 << 16)
+
+/* DENALI_CTL_274 */
+#define MEM_RST_VALID	(1)
+
+struct rk3399_sdram_channel {
+	unsigned char rank;
+	/* col = 0, means this channel is invalid */
+	unsigned char col;
+	/* 3:8bank, 2:4bank */
+	unsigned char bk;
+	/* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
+	unsigned char bw;
+	/* die buswidth, 2:32bit, 1:16bit, 0:8bit */
+	unsigned char dbw;
+	/* row_3_4 = 1: 6Gb or 12Gb die
+	 * row_3_4 = 0: normal die, power of 2
+	 */
+	unsigned char row_3_4;
+	unsigned char cs0_row;
+	unsigned char cs1_row;
+	unsigned int ddrconfig;
+	struct rk3399_msch_timings noc_timings;
+};
+
+struct rk3399_sdram_params {
+	struct rk3399_sdram_channel ch[2];
+	unsigned int ddr_freq;
+	unsigned char dramtype;
+	unsigned char num_channels;
+	unsigned char stride;
+	unsigned char odt;
+	/* align 8 byte */
+	struct rk3399_ddr_pctl_regs pctl_regs;
+	/* align 8 byte */
+	struct rk3399_ddr_pi_regs pi_regs;
+	/* align 8 byte */
+	struct rk3399_ddr_publ_regs phy_regs;
+	/* used for align 8byte for next struct */
+	unsigned int align_8;
+};
+
+#define PI_CA_TRAINING	(1 << 0)
+#define PI_WRITE_LEVELING	(1 << 1)
+#define PI_READ_GATE_TRAINING	(1 << 2)
+#define PI_READ_LEVELING	(1 << 3)
+#define PI_WDQ_LEVELING	(1 << 4)
+#define PI_FULL_TRAINING	(0xff)
+
+size_t sdram_size_mb(void);
+
+#endif
diff --git a/arch/arm/mach-rockchip/rk3399/Makefile b/arch/arm/mach-rockchip/rk3399/Makefile
index 98ebeac..437d851 100644
--- a/arch/arm/mach-rockchip/rk3399/Makefile
+++ b/arch/arm/mach-rockchip/rk3399/Makefile
@@ -7,3 +7,4 @@ 
 obj-y += clk_rk3399.o
 obj-y += rk3399.o
 obj-y += syscon_rk3399.o
+obj-y += sdram_rk3399.o
diff --git a/arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc b/arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
new file mode 100644
index 0000000..2b29bdf
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
@@ -0,0 +1,1565 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/* 2 Samsung K4E6E304EB-EGCE chips */
+{
+	{
+		{
+			.rank = 0x2,
+			.col = 0xA,
+			.bk = 0x3,
+			.bw = 0x2,
+			.dbw = 0x2,
+			.row_3_4 = 0x0,
+			.cs0_row = 0xF,
+			.cs1_row = 0xF,
+			.ddrconfig = 1,
+			{
+				{0x801d181e},
+				{0x17050a08},
+				{0x00000002},
+				{0x00006426},
+				{0x0000004c},
+				0x00000000
+			}
+		},
+		{
+			.rank = 0x2,
+			.col = 0xA,
+			.bk = 0x3,
+			.bw = 0x2,
+			.dbw = 0x2,
+			.row_3_4 = 0x0,
+			.cs0_row = 0xF,
+			.cs1_row = 0xF,
+			.ddrconfig = 1,
+			{
+				{0x801d181e},
+				{0x17050a08},
+				{0x00000002},
+				{0x00006426},
+				{0x0000004c},
+				0x00000000
+			}
+		}
+	},
+	.ddr_freq = 933*MHz,
+	.dramtype = LPDDR3,
+	.num_channels = 2,
+	.stride = 13,
+	.odt = 1,
+	{
+		{
+			0x00000700,	/* DENALI_CTL_00_DATA */
+			0x00000000,	/* DENALI_CTL_01_DATA */
+			0x00000000,	/* DENALI_CTL_02_DATA */
+			0x00000000,	/* DENALI_CTL_03_DATA */
+			0x00000000,	/* DENALI_CTL_04_DATA */
+			0x0000005e,	/* DENALI_CTL_05_DATA */
+			0x0002d976,	/* DENALI_CTL_06_DATA */
+			0x000003a6,	/* DENALI_CTL_07_DATA */
+			0x0000247a,	/* DENALI_CTL_08_DATA */
+			0x0000005e,	/* DENALI_CTL_09_DATA */
+			0x0002d976,	/* DENALI_CTL_10_DATA */
+			0x000003a6,	/* DENALI_CTL_11_DATA */
+			0x0000247a,	/* DENALI_CTL_12_DATA */
+			0x0000005e,	/* DENALI_CTL_13_DATA */
+			0x0002d976,	/* DENALI_CTL_14_DATA */
+			0x000003a6,	/* DENALI_CTL_15_DATA */
+			0x0100247a,	/* DENALI_CTL_16_DATA */
+			0x00000000,	/* DENALI_CTL_17_DATA */
+			0x00000101,	/* DENALI_CTL_18_DATA */
+			0x00020100,	/* DENALI_CTL_19_DATA */
+			0x000000bb,	/* DENALI_CTL_20_DATA */
+			0x000001d3,	/* DENALI_CTL_21_DATA */
+			0x00000000,	/* DENALI_CTL_22_DATA */
+			0x081c0000,	/* DENALI_CTL_23_DATA */
+			0x00081c00,	/* DENALI_CTL_24_DATA */
+			0x0400081c,	/* DENALI_CTL_25_DATA */
+			0x3b0a0004,	/* DENALI_CTL_26_DATA */
+			0x2f110828,	/* DENALI_CTL_27_DATA */
+			0x283b0a00,	/* DENALI_CTL_28_DATA */
+			0x002f1108,	/* DENALI_CTL_29_DATA */
+			0x08283b0a,	/* DENALI_CTL_30_DATA */
+			0x08002f11,	/* DENALI_CTL_31_DATA */
+			0x00000a0a,	/* DENALI_CTL_32_DATA */
+			0x0800ff4f,	/* DENALI_CTL_33_DATA */
+			0x0a0a080f,	/* DENALI_CTL_34_DATA */
+			0x0800ff4f,	/* DENALI_CTL_35_DATA */
+			0x0a0a080f,	/* DENALI_CTL_36_DATA */
+			0x0800ff4f,	/* DENALI_CTL_37_DATA */
+			0x0203000f,	/* DENALI_CTL_38_DATA */
+			0x110f1100,	/* DENALI_CTL_39_DATA */
+			0x040f110f,	/* DENALI_CTL_40_DATA */
+			0x14000a0a,	/* DENALI_CTL_41_DATA */
+			0x03030a0a,	/* DENALI_CTL_42_DATA */
+			0x00010003,	/* DENALI_CTL_43_DATA */
+			0x03212121,	/* DENALI_CTL_44_DATA */
+			0x00141414,	/* DENALI_CTL_45_DATA */
+			0x00000000,	/* DENALI_CTL_46_DATA */
+			0x03010000,	/* DENALI_CTL_47_DATA */
+			0x0e3100c5,	/* DENALI_CTL_48_DATA */
+			0x0e3100c5,	/* DENALI_CTL_49_DATA */
+			0x0e3100c5,	/* DENALI_CTL_50_DATA */
+			0x00000000,	/* DENALI_CTL_51_DATA */
+			0x00080008,	/* DENALI_CTL_52_DATA */
+			0x00170008,	/* DENALI_CTL_53_DATA */
+			0x00170017,	/* DENALI_CTL_54_DATA */
+			0x00111111,	/* DENALI_CTL_55_DATA */
+			0x00000000,	/* DENALI_CTL_56_DATA */
+			0x00000000,	/* DENALI_CTL_57_DATA */
+			0x00000000,	/* DENALI_CTL_58_DATA */
+			0x00ce0000,	/* DENALI_CTL_59_DATA */
+			0x00ce00ce,	/* DENALI_CTL_60_DATA */
+			0x00ce00ce,	/* DENALI_CTL_61_DATA */
+			0x000000ce,	/* DENALI_CTL_62_DATA */
+			0x00000000,	/* DENALI_CTL_63_DATA */
+			0x00000000,	/* DENALI_CTL_64_DATA */
+			0x00000000,	/* DENALI_CTL_65_DATA */
+			0x00000000,	/* DENALI_CTL_66_DATA */
+			0x00000000,	/* DENALI_CTL_67_DATA */
+			0x00000000,	/* DENALI_CTL_68_DATA */
+			0x00000301,	/* DENALI_CTL_69_DATA */
+			0x00000001,	/* DENALI_CTL_70_DATA */
+			0x00000000,	/* DENALI_CTL_71_DATA */
+			0x00000000,	/* DENALI_CTL_72_DATA */
+			0x01000000,	/* DENALI_CTL_73_DATA */
+			0x80104002,	/* DENALI_CTL_74_DATA */
+			0x00040003,	/* DENALI_CTL_75_DATA */
+			0x00040005,	/* DENALI_CTL_76_DATA */
+			0x00030000,	/* DENALI_CTL_77_DATA */
+			0x00050004,	/* DENALI_CTL_78_DATA */
+			0x00000004,	/* DENALI_CTL_79_DATA */
+			0x00040003,	/* DENALI_CTL_80_DATA */
+			0x00040005,	/* DENALI_CTL_81_DATA */
+			0x38c40000,	/* DENALI_CTL_82_DATA */
+			0x00001c62,	/* DENALI_CTL_83_DATA */
+			0x1c6238c4,	/* DENALI_CTL_84_DATA */
+			0x38c40000,	/* DENALI_CTL_85_DATA */
+			0x00001c62,	/* DENALI_CTL_86_DATA */
+			0x00000000,	/* DENALI_CTL_87_DATA */
+			0x00000000,	/* DENALI_CTL_88_DATA */
+			0x00000000,	/* DENALI_CTL_89_DATA */
+			0x00000000,	/* DENALI_CTL_90_DATA */
+			0x00000000,	/* DENALI_CTL_91_DATA */
+			0x02020200,	/* DENALI_CTL_92_DATA */
+			0x00020202,	/* DENALI_CTL_93_DATA */
+			0x00030200,	/* DENALI_CTL_94_DATA */
+			0x00040700,	/* DENALI_CTL_95_DATA */
+			0x00000302,	/* DENALI_CTL_96_DATA */
+			0x02000407,	/* DENALI_CTL_97_DATA */
+			0x00000003,	/* DENALI_CTL_98_DATA */
+			0x00030f04,	/* DENALI_CTL_99_DATA */
+			0x00070004,	/* DENALI_CTL_100_DATA */
+			0x00000000,	/* DENALI_CTL_101_DATA */
+			0x00000000,	/* DENALI_CTL_102_DATA */
+			0x00000000,	/* DENALI_CTL_103_DATA */
+			0x00000000,	/* DENALI_CTL_104_DATA */
+			0x00000000,	/* DENALI_CTL_105_DATA */
+			0x00000000,	/* DENALI_CTL_106_DATA */
+			0x00000000,	/* DENALI_CTL_107_DATA */
+			0x00010000,	/* DENALI_CTL_108_DATA */
+			0x20040020,	/* DENALI_CTL_109_DATA */
+			0x00200400,	/* DENALI_CTL_110_DATA */
+			0x01000400,	/* DENALI_CTL_111_DATA */
+			0x00000b80,	/* DENALI_CTL_112_DATA */
+			0x00000000,	/* DENALI_CTL_113_DATA */
+			0x00000001,	/* DENALI_CTL_114_DATA */
+			0x00000002,	/* DENALI_CTL_115_DATA */
+			0x0000000e,	/* DENALI_CTL_116_DATA */
+			0x00000000,	/* DENALI_CTL_117_DATA */
+			0x00000000,	/* DENALI_CTL_118_DATA */
+			0x00000000,	/* DENALI_CTL_119_DATA */
+			0x00000000,	/* DENALI_CTL_120_DATA */
+			0x00000000,	/* DENALI_CTL_121_DATA */
+			0x00bb0000,	/* DENALI_CTL_122_DATA */
+			0x00ea005e,	/* DENALI_CTL_123_DATA */
+			0x00ea0000,	/* DENALI_CTL_124_DATA */
+			0x005e00bb,	/* DENALI_CTL_125_DATA */
+			0x000000ea,	/* DENALI_CTL_126_DATA */
+			0x00bb00ea,	/* DENALI_CTL_127_DATA */
+			0x00ea005e,	/* DENALI_CTL_128_DATA */
+			0x00ea0000,	/* DENALI_CTL_129_DATA */
+			0x00000000,	/* DENALI_CTL_130_DATA */
+			0x00000000,	/* DENALI_CTL_131_DATA */
+			0x00000000,	/* DENALI_CTL_132_DATA */
+			0x00c30000,	/* DENALI_CTL_133_DATA */
+			0x0000001c,	/* DENALI_CTL_134_DATA */
+			0x001c00c3,	/* DENALI_CTL_135_DATA */
+			0x00c30000,	/* DENALI_CTL_136_DATA */
+			0x0000001c,	/* DENALI_CTL_137_DATA */
+			0x00010001,	/* DENALI_CTL_138_DATA */
+			0x06000001,	/* DENALI_CTL_139_DATA */
+			0x00000606,	/* DENALI_CTL_140_DATA */
+			0x00000000,	/* DENALI_CTL_141_DATA */
+			0x00000000,	/* DENALI_CTL_142_DATA */
+			0x00000000,	/* DENALI_CTL_143_DATA */
+			0x00000000,	/* DENALI_CTL_144_DATA */
+			0x00000000,	/* DENALI_CTL_145_DATA */
+			0x00000000,	/* DENALI_CTL_146_DATA */
+			0x00c30000,	/* DENALI_CTL_147_DATA */
+			0x0000001c,	/* DENALI_CTL_148_DATA */
+			0x001c00c3,	/* DENALI_CTL_149_DATA */
+			0x00c30000,	/* DENALI_CTL_150_DATA */
+			0x0000001c,	/* DENALI_CTL_151_DATA */
+			0x00010001,	/* DENALI_CTL_152_DATA */
+			0x06000001,	/* DENALI_CTL_153_DATA */
+			0x00000606,	/* DENALI_CTL_154_DATA */
+			0x00000000,	/* DENALI_CTL_155_DATA */
+			0x00000000,	/* DENALI_CTL_156_DATA */
+			0x00000000,	/* DENALI_CTL_157_DATA */
+			0x00000000,	/* DENALI_CTL_158_DATA */
+			0x00000000,	/* DENALI_CTL_159_DATA */
+			0x00000000,	/* DENALI_CTL_160_DATA */
+			0x01000000,	/* DENALI_CTL_161_DATA */
+			0x00000000,	/* DENALI_CTL_162_DATA */
+			0x00000000,	/* DENALI_CTL_163_DATA */
+			0x18151100,	/* DENALI_CTL_164_DATA */
+			0x0000000c,	/* DENALI_CTL_165_DATA */
+			0x00000000,	/* DENALI_CTL_166_DATA */
+			0x00000000,	/* DENALI_CTL_167_DATA */
+			0x00000000,	/* DENALI_CTL_168_DATA */
+			0x00000000,	/* DENALI_CTL_169_DATA */
+			0x00000000,	/* DENALI_CTL_170_DATA */
+			0x00000000,	/* DENALI_CTL_171_DATA */
+			0x00000000,	/* DENALI_CTL_172_DATA */
+			0x00000000,	/* DENALI_CTL_173_DATA */
+			0x00000000,	/* DENALI_CTL_174_DATA */
+			0x00000000,	/* DENALI_CTL_175_DATA */
+			0x00000000,	/* DENALI_CTL_176_DATA */
+			0x00000000,	/* DENALI_CTL_177_DATA */
+			0x00000000,	/* DENALI_CTL_178_DATA */
+			0x0003a603,	/* DENALI_CTL_179_DATA */
+			0x00550151,	/* DENALI_CTL_180_DATA */
+			0x00000000,	/* DENALI_CTL_181_DATA */
+			0x015103a6,	/* DENALI_CTL_182_DATA */
+			0x00000055,	/* DENALI_CTL_183_DATA */
+			0x0003a600,	/* DENALI_CTL_184_DATA */
+			0x00550151,	/* DENALI_CTL_185_DATA */
+			0x00000000,	/* DENALI_CTL_186_DATA */
+			0x002f0000,	/* DENALI_CTL_187_DATA */
+			0x002f002f,	/* DENALI_CTL_188_DATA */
+			0x01010100,	/* DENALI_CTL_189_DATA */
+			0x01000202,	/* DENALI_CTL_190_DATA */
+			0x0a000002,	/* DENALI_CTL_191_DATA */
+			0x01000f0f,	/* DENALI_CTL_192_DATA */
+			0x00000000,	/* DENALI_CTL_193_DATA */
+			0x00000000,	/* DENALI_CTL_194_DATA */
+			0x00010003,	/* DENALI_CTL_195_DATA */
+			0x00000c03,	/* DENALI_CTL_196_DATA */
+			0x00000100,	/* DENALI_CTL_197_DATA */
+			0x00010000,	/* DENALI_CTL_198_DATA */
+			0x01000000,	/* DENALI_CTL_199_DATA */
+			0x00010000,	/* DENALI_CTL_200_DATA */
+			0x00000001,	/* DENALI_CTL_201_DATA */
+			0x00000000,	/* DENALI_CTL_202_DATA */
+			0x00000000,	/* DENALI_CTL_203_DATA */
+			0x00000000,	/* DENALI_CTL_204_DATA */
+			0x00000000,	/* DENALI_CTL_205_DATA */
+			0x00000000,	/* DENALI_CTL_206_DATA */
+			0x00000000,	/* DENALI_CTL_207_DATA */
+			0x00000000,	/* DENALI_CTL_208_DATA */
+			0x00000000,	/* DENALI_CTL_209_DATA */
+			0x00000000,	/* DENALI_CTL_210_DATA */
+			0x00010000,	/* DENALI_CTL_211_DATA */
+			0x04040401,	/* DENALI_CTL_212_DATA */
+			0x01010808,	/* DENALI_CTL_213_DATA */
+			0x04040001,	/* DENALI_CTL_214_DATA */
+			0x0c0c0c04,	/* DENALI_CTL_215_DATA */
+			0x08080808,	/* DENALI_CTL_216_DATA */
+			0x08050103,	/* DENALI_CTL_217_DATA */
+			0x02050103,	/* DENALI_CTL_218_DATA */
+			0x00050103,	/* DENALI_CTL_219_DATA */
+			0x00020202,	/* DENALI_CTL_220_DATA */
+			0x06030600,	/* DENALI_CTL_221_DATA */
+			0x00030603,	/* DENALI_CTL_222_DATA */
+			0x00000000,	/* DENALI_CTL_223_DATA */
+			0x00000000,	/* DENALI_CTL_224_DATA */
+			0x0d000001,	/* DENALI_CTL_225_DATA */
+			0x00010028,	/* DENALI_CTL_226_DATA */
+			0x00010000,	/* DENALI_CTL_227_DATA */
+			0x00000003,	/* DENALI_CTL_228_DATA */
+			0x00000000,	/* DENALI_CTL_229_DATA */
+			0x00000000,	/* DENALI_CTL_230_DATA */
+			0x00000000,	/* DENALI_CTL_231_DATA */
+			0x00000000,	/* DENALI_CTL_232_DATA */
+			0x00000000,	/* DENALI_CTL_233_DATA */
+			0x00000000,	/* DENALI_CTL_234_DATA */
+			0x00000000,	/* DENALI_CTL_235_DATA */
+			0x00000000,	/* DENALI_CTL_236_DATA */
+			0x00010100,	/* DENALI_CTL_237_DATA */
+			0x01000000,	/* DENALI_CTL_238_DATA */
+			0x00000001,	/* DENALI_CTL_239_DATA */
+			0x00000303,	/* DENALI_CTL_240_DATA */
+			0x00000000,	/* DENALI_CTL_241_DATA */
+			0x00000000,	/* DENALI_CTL_242_DATA */
+			0x00000000,	/* DENALI_CTL_243_DATA */
+			0x00000000,	/* DENALI_CTL_244_DATA */
+			0x00000000,	/* DENALI_CTL_245_DATA */
+			0x00000000,	/* DENALI_CTL_246_DATA */
+			0x00000000,	/* DENALI_CTL_247_DATA */
+			0x00000000,	/* DENALI_CTL_248_DATA */
+			0x00000000,	/* DENALI_CTL_249_DATA */
+			0x00000000,	/* DENALI_CTL_250_DATA */
+			0x00000000,	/* DENALI_CTL_251_DATA */
+			0x00000000,	/* DENALI_CTL_252_DATA */
+			0x00000000,	/* DENALI_CTL_253_DATA */
+			0x00000000,	/* DENALI_CTL_254_DATA */
+			0x00000000,	/* DENALI_CTL_255_DATA */
+			0x000fffff,	/* DENALI_CTL_256_DATA */
+			0x00000000,	/* DENALI_CTL_257_DATA */
+			0x000556aa,	/* DENALI_CTL_258_DATA */
+			0x000aaaaa,	/* DENALI_CTL_259_DATA */
+			0x000b3133,	/* DENALI_CTL_260_DATA */
+			0x0004cd33,	/* DENALI_CTL_261_DATA */
+			0x0004cecc,	/* DENALI_CTL_262_DATA */
+			0x000b32cc,	/* DENALI_CTL_263_DATA */
+			0x00010300,	/* DENALI_CTL_264_DATA */
+			0x03000100,	/* DENALI_CTL_265_DATA */
+			0x00000000,	/* DENALI_CTL_266_DATA */
+			0x00000000,	/* DENALI_CTL_267_DATA */
+			0x00000000,	/* DENALI_CTL_268_DATA */
+			0x00000000,	/* DENALI_CTL_269_DATA */
+			0x00000000,	/* DENALI_CTL_270_DATA */
+			0x00000000,	/* DENALI_CTL_271_DATA */
+			0x00000000,	/* DENALI_CTL_272_DATA */
+			0x00000000,	/* DENALI_CTL_273_DATA */
+			0x00ffff00,	/* DENALI_CTL_274_DATA */
+			0x20200000,	/* DENALI_CTL_275_DATA */
+			0x08000020,	/* DENALI_CTL_276_DATA */
+			0x00001c62,	/* DENALI_CTL_277_DATA */
+			0x00000200,	/* DENALI_CTL_278_DATA */
+			0x00000200,	/* DENALI_CTL_279_DATA */
+			0x00000200,	/* DENALI_CTL_280_DATA */
+			0x00000200,	/* DENALI_CTL_281_DATA */
+			0x00001c62,	/* DENALI_CTL_282_DATA */
+			0x00011bd4,	/* DENALI_CTL_283_DATA */
+			0x1c62070c,	/* DENALI_CTL_284_DATA */
+			0x00000200,	/* DENALI_CTL_285_DATA */
+			0x00000200,	/* DENALI_CTL_286_DATA */
+			0x00000200,	/* DENALI_CTL_287_DATA */
+			0x00000200,	/* DENALI_CTL_288_DATA */
+			0x00001c62,	/* DENALI_CTL_289_DATA */
+			0x00011bd4,	/* DENALI_CTL_290_DATA */
+			0x1c62070c,	/* DENALI_CTL_291_DATA */
+			0x00000200,	/* DENALI_CTL_292_DATA */
+			0x00000200,	/* DENALI_CTL_293_DATA */
+			0x00000200,	/* DENALI_CTL_294_DATA */
+			0x00000200,	/* DENALI_CTL_295_DATA */
+			0x00001c62,	/* DENALI_CTL_296_DATA */
+			0x00011bd4,	/* DENALI_CTL_297_DATA */
+			0x0202070c,	/* DENALI_CTL_298_DATA */
+			0x03030202,	/* DENALI_CTL_299_DATA */
+			0x00000018,	/* DENALI_CTL_300_DATA */
+			0x00000000,	/* DENALI_CTL_301_DATA */
+			0x00000000,	/* DENALI_CTL_302_DATA */
+			0x00001403,	/* DENALI_CTL_303_DATA */
+			0x00000000,	/* DENALI_CTL_304_DATA */
+			0x00000000,	/* DENALI_CTL_305_DATA */
+			0x00000000,	/* DENALI_CTL_306_DATA */
+			0x00030000,	/* DENALI_CTL_307_DATA */
+			0x000f0021,	/* DENALI_CTL_308_DATA */
+			0x000f0021,	/* DENALI_CTL_309_DATA */
+			0x000f0021,	/* DENALI_CTL_310_DATA */
+			0x00000000,	/* DENALI_CTL_311_DATA */
+			0x00000000,	/* DENALI_CTL_312_DATA */
+			0x01000000,	/* DENALI_CTL_313_DATA */
+			0x02090209,	/* DENALI_CTL_314_DATA */
+			0x00050209,	/* DENALI_CTL_315_DATA */
+			0x00000000,	/* DENALI_CTL_316_DATA */
+			0x00000000,	/* DENALI_CTL_317_DATA */
+			0x00000000,	/* DENALI_CTL_318_DATA */
+			0x00000000,	/* DENALI_CTL_319_DATA */
+			0x00000000,	/* DENALI_CTL_320_DATA */
+			0x00000000,	/* DENALI_CTL_321_DATA */
+			0x00000000,	/* DENALI_CTL_322_DATA */
+			0x00000000,	/* DENALI_CTL_323_DATA */
+			0x01000101,	/* DENALI_CTL_324_DATA */
+			0x01010101,	/* DENALI_CTL_325_DATA */
+			0x01000101,	/* DENALI_CTL_326_DATA */
+			0x01000100,	/* DENALI_CTL_327_DATA */
+			0x00010001,	/* DENALI_CTL_328_DATA */
+			0x00010002,	/* DENALI_CTL_329_DATA */
+			0x00020100,	/* DENALI_CTL_330_DATA */
+			0x00000002	/* DENALI_CTL_331_DATA */
+		}
+	},
+	{
+		{
+			0x00000700,	/* DENALI_PI_00_DATA */
+			0x00000000,	/* DENALI_PI_01_DATA */
+			0x000038c4,	/* DENALI_PI_02_DATA */
+			0x00001c62,	/* DENALI_PI_03_DATA */
+			0x000038c4,	/* DENALI_PI_04_DATA */
+			0x00001c62,	/* DENALI_PI_05_DATA */
+			0x000038c4,	/* DENALI_PI_06_DATA */
+			0x1c621c62,	/* DENALI_PI_07_DATA */
+			0x00000200,	/* DENALI_PI_08_DATA */
+			0x00000200,	/* DENALI_PI_09_DATA */
+			0x00000200,	/* DENALI_PI_10_DATA */
+			0x00000200,	/* DENALI_PI_11_DATA */
+			0x00001c62,	/* DENALI_PI_12_DATA */
+			0x00000200,	/* DENALI_PI_13_DATA */
+			0x00000200,	/* DENALI_PI_14_DATA */
+			0x00000200,	/* DENALI_PI_15_DATA */
+			0x00000200,	/* DENALI_PI_16_DATA */
+			0x00001c62,	/* DENALI_PI_17_DATA */
+			0x00000200,	/* DENALI_PI_18_DATA */
+			0x00000200,	/* DENALI_PI_19_DATA */
+			0x00000200,	/* DENALI_PI_20_DATA */
+			0x00000200,	/* DENALI_PI_21_DATA */
+			0x00010000,	/* DENALI_PI_22_DATA */
+			0x00000007,	/* DENALI_PI_23_DATA */
+			0x81000001,	/* DENALI_PI_24_DATA */
+			0x0f0003f0,	/* DENALI_PI_25_DATA */
+			0x3fffffff,	/* DENALI_PI_26_DATA */
+			0x0f0000a0,	/* DENALI_PI_27_DATA */
+			0x377ff000,	/* DENALI_PI_28_DATA */
+			0x0f000020,	/* DENALI_PI_29_DATA */
+			0x377ff000,	/* DENALI_PI_30_DATA */
+			0x0f000030,	/* DENALI_PI_31_DATA */
+			0x377ff000,	/* DENALI_PI_32_DATA */
+			0x0f0000b0,	/* DENALI_PI_33_DATA */
+			0x377ff000,	/* DENALI_PI_34_DATA */
+			0x0f000100,	/* DENALI_PI_35_DATA */
+			0x377ff000,	/* DENALI_PI_36_DATA */
+			0x0f000110,	/* DENALI_PI_37_DATA */
+			0x377ff000,	/* DENALI_PI_38_DATA */
+			0x0f000010,	/* DENALI_PI_39_DATA */
+			0x377ff000,	/* DENALI_PI_40_DATA */
+			0x03000101,	/* DENALI_PI_41_DATA */
+			0x04323232,	/* DENALI_PI_42_DATA */
+			0x081c0008,	/* DENALI_PI_43_DATA */
+			0x00081c00,	/* DENALI_PI_44_DATA */
+			0x0000001c,	/* DENALI_PI_45_DATA */
+			0x0e3100c5,	/* DENALI_PI_46_DATA */
+			0x0e3100c5,	/* DENALI_PI_47_DATA */
+			0x0e3100c5,	/* DENALI_PI_48_DATA */
+			0x00000500,	/* DENALI_PI_49_DATA */
+			0x00000000,	/* DENALI_PI_50_DATA */
+			0x00000000,	/* DENALI_PI_51_DATA */
+			0x00000000,	/* DENALI_PI_52_DATA */
+			0x00000000,	/* DENALI_PI_53_DATA */
+			0x00000000,	/* DENALI_PI_54_DATA */
+			0x00000000,	/* DENALI_PI_55_DATA */
+			0x00000000,	/* DENALI_PI_56_DATA */
+			0x00000000,	/* DENALI_PI_57_DATA */
+			0x04040000,	/* DENALI_PI_58_DATA */
+			0x0d000004,	/* DENALI_PI_59_DATA */
+			0x00000128,	/* DENALI_PI_60_DATA */
+			0x00000000,	/* DENALI_PI_61_DATA */
+			0x00030003,	/* DENALI_PI_62_DATA */
+			0x00000018,	/* DENALI_PI_63_DATA */
+			0x00000000,	/* DENALI_PI_64_DATA */
+			0x00000000,	/* DENALI_PI_65_DATA */
+			0x04060002,	/* DENALI_PI_66_DATA */
+			0x04010401,	/* DENALI_PI_67_DATA */
+			0x01080801,	/* DENALI_PI_68_DATA */
+			0x04020201,	/* DENALI_PI_69_DATA */
+			0x01080804,	/* DENALI_PI_70_DATA */
+			0x00000000,	/* DENALI_PI_71_DATA */
+			0x04040000,	/* DENALI_PI_72_DATA */
+			0x0c0c0c04,	/* DENALI_PI_73_DATA */
+			0x00000000,	/* DENALI_PI_74_DATA */
+			0x00000000,	/* DENALI_PI_75_DATA */
+			0x00000000,	/* DENALI_PI_76_DATA */
+			0x00030300,	/* DENALI_PI_77_DATA */
+			0x00000014,	/* DENALI_PI_78_DATA */
+			0x00000000,	/* DENALI_PI_79_DATA */
+			0x01010300,	/* DENALI_PI_80_DATA */
+			0x00000000,	/* DENALI_PI_81_DATA */
+			0x00000000,	/* DENALI_PI_82_DATA */
+			0x01000000,	/* DENALI_PI_83_DATA */
+			0x00000101,	/* DENALI_PI_84_DATA */
+			0x55555a5a,	/* DENALI_PI_85_DATA */
+			0x55555a5a,	/* DENALI_PI_86_DATA */
+			0x55555a5a,	/* DENALI_PI_87_DATA */
+			0x55555a5a,	/* DENALI_PI_88_DATA */
+			0x0c0c0001,	/* DENALI_PI_89_DATA */
+			0x0707000c,	/* DENALI_PI_90_DATA */
+			0x02020007,	/* DENALI_PI_91_DATA */
+			0x00000102,	/* DENALI_PI_92_DATA */
+			0x00030000,	/* DENALI_PI_93_DATA */
+			0x17030000,	/* DENALI_PI_94_DATA */
+			0x000f0021,	/* DENALI_PI_95_DATA */
+			0x000f0021,	/* DENALI_PI_96_DATA */
+			0x000f0021,	/* DENALI_PI_97_DATA */
+			0x00000000,	/* DENALI_PI_98_DATA */
+			0x00000000,	/* DENALI_PI_99_DATA */
+			0x00000100,	/* DENALI_PI_100_DATA */
+			0x140a0000,	/* DENALI_PI_101_DATA */
+			0x000a030a,	/* DENALI_PI_102_DATA */
+			0x03000a03,	/* DENALI_PI_103_DATA */
+			0x010a000a,	/* DENALI_PI_104_DATA */
+			0x00000100,	/* DENALI_PI_105_DATA */
+			0x01000000,	/* DENALI_PI_106_DATA */
+			0x00000000,	/* DENALI_PI_107_DATA */
+			0x00000100,	/* DENALI_PI_108_DATA */
+			0x1e1a0000,	/* DENALI_PI_109_DATA */
+			0x10010204,	/* DENALI_PI_110_DATA */
+			0x07070705,	/* DENALI_PI_111_DATA */
+			0x20000202,	/* DENALI_PI_112_DATA */
+			0x00201000,	/* DENALI_PI_113_DATA */
+			0x00201000,	/* DENALI_PI_114_DATA */
+			0x04041000,	/* DENALI_PI_115_DATA */
+			0x12120100,	/* DENALI_PI_116_DATA */
+			0x00010112,	/* DENALI_PI_117_DATA */
+			0x004b004a,	/* DENALI_PI_118_DATA */
+			0x1a030000,	/* DENALI_PI_119_DATA */
+			0x0102041e,	/* DENALI_PI_120_DATA */
+			0x34000000,	/* DENALI_PI_121_DATA */
+			0x00000000,	/* DENALI_PI_122_DATA */
+			0x00000000,	/* DENALI_PI_123_DATA */
+			0x00000000,	/* DENALI_PI_124_DATA */
+			0x0000c300,	/* DENALI_PI_125_DATA */
+			0x0001001c,	/* DENALI_PI_126_DATA */
+			0x004d4d07,	/* DENALI_PI_127_DATA */
+			0x001c00c3,	/* DENALI_PI_128_DATA */
+			0x4d070001,	/* DENALI_PI_129_DATA */
+			0x0000c34d,	/* DENALI_PI_130_DATA */
+			0x0001001c,	/* DENALI_PI_131_DATA */
+			0x004d4d07,	/* DENALI_PI_132_DATA */
+			0x001c00c3,	/* DENALI_PI_133_DATA */
+			0x4d070001,	/* DENALI_PI_134_DATA */
+			0x0000c34d,	/* DENALI_PI_135_DATA */
+			0x0001001c,	/* DENALI_PI_136_DATA */
+			0x004d4d07,	/* DENALI_PI_137_DATA */
+			0x001c00c3,	/* DENALI_PI_138_DATA */
+			0x4d070001,	/* DENALI_PI_139_DATA */
+			0x00c3004d,	/* DENALI_PI_140_DATA */
+			0x0001001c,	/* DENALI_PI_141_DATA */
+			0x004d4d07,	/* DENALI_PI_142_DATA */
+			0x001c00c3,	/* DENALI_PI_143_DATA */
+			0x4d070001,	/* DENALI_PI_144_DATA */
+			0x0000c34d,	/* DENALI_PI_145_DATA */
+			0x0001001c,	/* DENALI_PI_146_DATA */
+			0x004d4d07,	/* DENALI_PI_147_DATA */
+			0x001c00c3,	/* DENALI_PI_148_DATA */
+			0x4d070001,	/* DENALI_PI_149_DATA */
+			0x0000c34d,	/* DENALI_PI_150_DATA */
+			0x0001001c,	/* DENALI_PI_151_DATA */
+			0x004d4d07,	/* DENALI_PI_152_DATA */
+			0x001c00c3,	/* DENALI_PI_153_DATA */
+			0x4d070001,	/* DENALI_PI_154_DATA */
+			0x0100004d,	/* DENALI_PI_155_DATA */
+			0x00ea00ea,	/* DENALI_PI_156_DATA */
+			0x080400ea,	/* DENALI_PI_157_DATA */
+			0x0f081114,	/* DENALI_PI_158_DATA */
+			0x2800fcc1,	/* DENALI_PI_159_DATA */
+			0x0a0e2006,	/* DENALI_PI_160_DATA */
+			0x1114080a,	/* DENALI_PI_161_DATA */
+			0x00000f08,	/* DENALI_PI_162_DATA */
+			0x2800fcc1,	/* DENALI_PI_163_DATA */
+			0x0a0e2006,	/* DENALI_PI_164_DATA */
+			0x1114080a,	/* DENALI_PI_165_DATA */
+			0x00000f08,	/* DENALI_PI_166_DATA */
+			0x2800fcc1,	/* DENALI_PI_167_DATA */
+			0x0a0e2006,	/* DENALI_PI_168_DATA */
+			0x0200020a,	/* DENALI_PI_169_DATA */
+			0x02000200,	/* DENALI_PI_170_DATA */
+			0x02000200,	/* DENALI_PI_171_DATA */
+			0x02000200,	/* DENALI_PI_172_DATA */
+			0x02000200,	/* DENALI_PI_173_DATA */
+			0x00000000,	/* DENALI_PI_174_DATA */
+			0x00000000,	/* DENALI_PI_175_DATA */
+			0x00000000,	/* DENALI_PI_176_DATA */
+			0x00000000,	/* DENALI_PI_177_DATA */
+			0x00000000,	/* DENALI_PI_178_DATA */
+			0x00000000,	/* DENALI_PI_179_DATA */
+			0x00000000,	/* DENALI_PI_180_DATA */
+			0x00000000,	/* DENALI_PI_181_DATA */
+			0x00000000,	/* DENALI_PI_182_DATA */
+			0x00000000,	/* DENALI_PI_183_DATA */
+			0x00000000,	/* DENALI_PI_184_DATA */
+			0x00000000,	/* DENALI_PI_185_DATA */
+			0x01000300,	/* DENALI_PI_186_DATA */
+			0x001c6200,	/* DENALI_PI_187_DATA */
+			0x00011bd4,	/* DENALI_PI_188_DATA */
+			0x00001c62,	/* DENALI_PI_189_DATA */
+			0x00011bd4,	/* DENALI_PI_190_DATA */
+			0x00001c62,	/* DENALI_PI_191_DATA */
+			0x00011bd4,	/* DENALI_PI_192_DATA */
+			0x08000000,	/* DENALI_PI_193_DATA */
+			0x00000100,	/* DENALI_PI_194_DATA */
+			0x00000000,	/* DENALI_PI_195_DATA */
+			0x00000000,	/* DENALI_PI_196_DATA */
+			0x00000000,	/* DENALI_PI_197_DATA */
+			0x00000000,	/* DENALI_PI_198_DATA */
+			0x00000002	/* DENALI_PI_199_DATA */
+		}
+	},
+	{
+		{
+			0x76543210,	/* DENALI_PHY_00_DATA */
+			0x0004c008,	/* DENALI_PHY_01_DATA */
+			0x000001a2,	/* DENALI_PHY_02_DATA */
+			0x00000000,	/* DENALI_PHY_03_DATA */
+			0x00000000,	/* DENALI_PHY_04_DATA */
+			0x00010000,	/* DENALI_PHY_05_DATA */
+			0x01665555,	/* DENALI_PHY_06_DATA */
+			0x00665555,	/* DENALI_PHY_07_DATA */
+			0x00010f00,	/* DENALI_PHY_08_DATA */
+			0x06010200,	/* DENALI_PHY_09_DATA */
+			0x00000003,	/* DENALI_PHY_10_DATA */
+			0x001700c0,	/* DENALI_PHY_11_DATA */
+			0x00cc0101,	/* DENALI_PHY_12_DATA */
+			0x00030066,	/* DENALI_PHY_13_DATA */
+			0x00000000,	/* DENALI_PHY_14_DATA */
+			0x00000000,	/* DENALI_PHY_15_DATA */
+			0x00000000,	/* DENALI_PHY_16_DATA */
+			0x00000000,	/* DENALI_PHY_17_DATA */
+			0x00000000,	/* DENALI_PHY_18_DATA */
+			0x00000000,	/* DENALI_PHY_19_DATA */
+			0x00000000,	/* DENALI_PHY_20_DATA */
+			0x00000000,	/* DENALI_PHY_21_DATA */
+			0x04080000,	/* DENALI_PHY_22_DATA */
+			0x04080400,	/* DENALI_PHY_23_DATA */
+			0x08000000,	/* DENALI_PHY_24_DATA */
+			0x0c00c007,	/* DENALI_PHY_25_DATA */
+			0x00000100,	/* DENALI_PHY_26_DATA */
+			0x00000100,	/* DENALI_PHY_27_DATA */
+			0x55555555,	/* DENALI_PHY_28_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_29_DATA */
+			0x55555555,	/* DENALI_PHY_30_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_31_DATA */
+			0x00005555,	/* DENALI_PHY_32_DATA */
+			0x00000000,	/* DENALI_PHY_33_DATA */
+			0x00000000,	/* DENALI_PHY_34_DATA */
+			0x00000000,	/* DENALI_PHY_35_DATA */
+			0x00000000,	/* DENALI_PHY_36_DATA */
+			0x00000000,	/* DENALI_PHY_37_DATA */
+			0x00000000,	/* DENALI_PHY_38_DATA */
+			0x00000000,	/* DENALI_PHY_39_DATA */
+			0x00000000,	/* DENALI_PHY_40_DATA */
+			0x00000000,	/* DENALI_PHY_41_DATA */
+			0x00000000,	/* DENALI_PHY_42_DATA */
+			0x00000000,	/* DENALI_PHY_43_DATA */
+			0x00000000,	/* DENALI_PHY_44_DATA */
+			0x00000000,	/* DENALI_PHY_45_DATA */
+			0x00000000,	/* DENALI_PHY_46_DATA */
+			0x00000000,	/* DENALI_PHY_47_DATA */
+			0x00000000,	/* DENALI_PHY_48_DATA */
+			0x00000000,	/* DENALI_PHY_49_DATA */
+			0x00000000,	/* DENALI_PHY_50_DATA */
+			0x00000000,	/* DENALI_PHY_51_DATA */
+			0x00200000,	/* DENALI_PHY_52_DATA */
+			0x00000000,	/* DENALI_PHY_53_DATA */
+			0x00000000,	/* DENALI_PHY_54_DATA */
+			0x00000000,	/* DENALI_PHY_55_DATA */
+			0x00000000,	/* DENALI_PHY_56_DATA */
+			0x00000000,	/* DENALI_PHY_57_DATA */
+			0x00000000,	/* DENALI_PHY_58_DATA */
+			0x02700270,	/* DENALI_PHY_59_DATA */
+			0x02700270,	/* DENALI_PHY_60_DATA */
+			0x02700270,	/* DENALI_PHY_61_DATA */
+			0x02700270,	/* DENALI_PHY_62_DATA */
+			0x00000270,	/* DENALI_PHY_63_DATA */
+			0x00000000,	/* DENALI_PHY_64_DATA */
+			0x00000000,	/* DENALI_PHY_65_DATA */
+			0x00000000,	/* DENALI_PHY_66_DATA */
+			0x00000000,	/* DENALI_PHY_67_DATA */
+			0x00800000,	/* DENALI_PHY_68_DATA */
+			0x00800080,	/* DENALI_PHY_69_DATA */
+			0x00800080,	/* DENALI_PHY_70_DATA */
+			0x00800080,	/* DENALI_PHY_71_DATA */
+			0x00800080,	/* DENALI_PHY_72_DATA */
+			0x00800080,	/* DENALI_PHY_73_DATA */
+			0x00800080,	/* DENALI_PHY_74_DATA */
+			0x00800080,	/* DENALI_PHY_75_DATA */
+			0x00800080,	/* DENALI_PHY_76_DATA */
+			0x01a20080,	/* DENALI_PHY_77_DATA */
+			0x00000003,	/* DENALI_PHY_78_DATA */
+			0x00000000,	/* DENALI_PHY_79_DATA */
+			0x00030000,	/* DENALI_PHY_80_DATA */
+			0x00000200,	/* DENALI_PHY_81_DATA */
+			0x00000000,	/* DENALI_PHY_82_DATA */
+			0x51315152,	/* DENALI_PHY_83_DATA */
+			0xc0013150,	/* DENALI_PHY_84_DATA */
+			0x020000c0,	/* DENALI_PHY_85_DATA */
+			0x00100001,	/* DENALI_PHY_86_DATA */
+			0x07064208,	/* DENALI_PHY_87_DATA */
+			0x000f0c18,	/* DENALI_PHY_88_DATA */
+			0x01000140,	/* DENALI_PHY_89_DATA */
+			0x00000c20,	/* DENALI_PHY_90_DATA */
+			0x00000000,	/* DENALI_PHY_91_DATA */
+			0x00000000,	/* DENALI_PHY_92_DATA */
+			0x00000000,	/* DENALI_PHY_93_DATA */
+			0x00000000,	/* DENALI_PHY_94_DATA */
+			0x00000000,	/* DENALI_PHY_95_DATA */
+			0x00000000,	/* DENALI_PHY_96_DATA */
+			0x00000000,	/* DENALI_PHY_97_DATA */
+			0x00000000,	/* DENALI_PHY_98_DATA */
+			0x00000000,	/* DENALI_PHY_99_DATA */
+			0x00000000,	/* DENALI_PHY_100_DATA */
+			0x00000000,	/* DENALI_PHY_101_DATA */
+			0x00000000,	/* DENALI_PHY_102_DATA */
+			0x00000000,	/* DENALI_PHY_103_DATA */
+			0x00000000,	/* DENALI_PHY_104_DATA */
+			0x00000000,	/* DENALI_PHY_105_DATA */
+			0x00000000,	/* DENALI_PHY_106_DATA */
+			0x00000000,	/* DENALI_PHY_107_DATA */
+			0x00000000,	/* DENALI_PHY_108_DATA */
+			0x00000000,	/* DENALI_PHY_109_DATA */
+			0x00000000,	/* DENALI_PHY_110_DATA */
+			0x00000000,	/* DENALI_PHY_111_DATA */
+			0x00000000,	/* DENALI_PHY_112_DATA */
+			0x00000000,	/* DENALI_PHY_113_DATA */
+			0x00000000,	/* DENALI_PHY_114_DATA */
+			0x00000000,	/* DENALI_PHY_115_DATA */
+			0x00000000,	/* DENALI_PHY_116_DATA */
+			0x00000000,	/* DENALI_PHY_117_DATA */
+			0x00000000,	/* DENALI_PHY_118_DATA */
+			0x00000000,	/* DENALI_PHY_119_DATA */
+			0x00000000,	/* DENALI_PHY_120_DATA */
+			0x00000000,	/* DENALI_PHY_121_DATA */
+			0x00000000,	/* DENALI_PHY_122_DATA */
+			0x00000000,	/* DENALI_PHY_123_DATA */
+			0x00000000,	/* DENALI_PHY_124_DATA */
+			0x00000000,	/* DENALI_PHY_125_DATA */
+			0x00000000,	/* DENALI_PHY_126_DATA */
+			0x00000000,	/* DENALI_PHY_127_DATA */
+			0x76543210,	/* DENALI_PHY_128_DATA */
+			0x0004c008,	/* DENALI_PHY_129_DATA */
+			0x000001a2,	/* DENALI_PHY_130_DATA */
+			0x00000000,	/* DENALI_PHY_131_DATA */
+			0x00000000,	/* DENALI_PHY_132_DATA */
+			0x00010000,	/* DENALI_PHY_133_DATA */
+			0x01665555,	/* DENALI_PHY_134_DATA */
+			0x00665555,	/* DENALI_PHY_135_DATA */
+			0x00010f00,	/* DENALI_PHY_136_DATA */
+			0x06010200,	/* DENALI_PHY_137_DATA */
+			0x00000003,	/* DENALI_PHY_138_DATA */
+			0x001700c0,	/* DENALI_PHY_139_DATA */
+			0x00cc0101,	/* DENALI_PHY_140_DATA */
+			0x00030066,	/* DENALI_PHY_141_DATA */
+			0x00000000,	/* DENALI_PHY_142_DATA */
+			0x00000000,	/* DENALI_PHY_143_DATA */
+			0x00000000,	/* DENALI_PHY_144_DATA */
+			0x00000000,	/* DENALI_PHY_145_DATA */
+			0x00000000,	/* DENALI_PHY_146_DATA */
+			0x00000000,	/* DENALI_PHY_147_DATA */
+			0x00000000,	/* DENALI_PHY_148_DATA */
+			0x00000000,	/* DENALI_PHY_149_DATA */
+			0x04080000,	/* DENALI_PHY_150_DATA */
+			0x04080400,	/* DENALI_PHY_151_DATA */
+			0x08000000,	/* DENALI_PHY_152_DATA */
+			0x0c00c007,	/* DENALI_PHY_153_DATA */
+			0x00000100,	/* DENALI_PHY_154_DATA */
+			0x00000100,	/* DENALI_PHY_155_DATA */
+			0x55555555,	/* DENALI_PHY_156_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_157_DATA */
+			0x55555555,	/* DENALI_PHY_158_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_159_DATA */
+			0x00005555,	/* DENALI_PHY_160_DATA */
+			0x00000000,	/* DENALI_PHY_161_DATA */
+			0x00000000,	/* DENALI_PHY_162_DATA */
+			0x00000000,	/* DENALI_PHY_163_DATA */
+			0x00000000,	/* DENALI_PHY_164_DATA */
+			0x00000000,	/* DENALI_PHY_165_DATA */
+			0x00000000,	/* DENALI_PHY_166_DATA */
+			0x00000000,	/* DENALI_PHY_167_DATA */
+			0x00000000,	/* DENALI_PHY_168_DATA */
+			0x00000000,	/* DENALI_PHY_169_DATA */
+			0x00000000,	/* DENALI_PHY_170_DATA */
+			0x00000000,	/* DENALI_PHY_171_DATA */
+			0x00000000,	/* DENALI_PHY_172_DATA */
+			0x00000000,	/* DENALI_PHY_173_DATA */
+			0x00000000,	/* DENALI_PHY_174_DATA */
+			0x00000000,	/* DENALI_PHY_175_DATA */
+			0x00000000,	/* DENALI_PHY_176_DATA */
+			0x00000000,	/* DENALI_PHY_177_DATA */
+			0x00000000,	/* DENALI_PHY_178_DATA */
+			0x00000000,	/* DENALI_PHY_179_DATA */
+			0x00200000,	/* DENALI_PHY_180_DATA */
+			0x00000000,	/* DENALI_PHY_181_DATA */
+			0x00000000,	/* DENALI_PHY_182_DATA */
+			0x00000000,	/* DENALI_PHY_183_DATA */
+			0x00000000,	/* DENALI_PHY_184_DATA */
+			0x00000000,	/* DENALI_PHY_185_DATA */
+			0x00000000,	/* DENALI_PHY_186_DATA */
+			0x02700270,	/* DENALI_PHY_187_DATA */
+			0x02700270,	/* DENALI_PHY_188_DATA */
+			0x02700270,	/* DENALI_PHY_189_DATA */
+			0x02700270,	/* DENALI_PHY_190_DATA */
+			0x00000270,	/* DENALI_PHY_191_DATA */
+			0x00000000,	/* DENALI_PHY_192_DATA */
+			0x00000000,	/* DENALI_PHY_193_DATA */
+			0x00000000,	/* DENALI_PHY_194_DATA */
+			0x00000000,	/* DENALI_PHY_195_DATA */
+			0x00800000,	/* DENALI_PHY_196_DATA */
+			0x00800080,	/* DENALI_PHY_197_DATA */
+			0x00800080,	/* DENALI_PHY_198_DATA */
+			0x00800080,	/* DENALI_PHY_199_DATA */
+			0x00800080,	/* DENALI_PHY_200_DATA */
+			0x00800080,	/* DENALI_PHY_201_DATA */
+			0x00800080,	/* DENALI_PHY_202_DATA */
+			0x00800080,	/* DENALI_PHY_203_DATA */
+			0x00800080,	/* DENALI_PHY_204_DATA */
+			0x01a20080,	/* DENALI_PHY_205_DATA */
+			0x00000003,	/* DENALI_PHY_206_DATA */
+			0x00000000,	/* DENALI_PHY_207_DATA */
+			0x00030000,	/* DENALI_PHY_208_DATA */
+			0x00000200,	/* DENALI_PHY_209_DATA */
+			0x00000000,	/* DENALI_PHY_210_DATA */
+			0x51315152,	/* DENALI_PHY_211_DATA */
+			0xc0013150,	/* DENALI_PHY_212_DATA */
+			0x020000c0,	/* DENALI_PHY_213_DATA */
+			0x00100001,	/* DENALI_PHY_214_DATA */
+			0x07064208,	/* DENALI_PHY_215_DATA */
+			0x000f0c18,	/* DENALI_PHY_216_DATA */
+			0x01000140,	/* DENALI_PHY_217_DATA */
+			0x00000c20,	/* DENALI_PHY_218_DATA */
+			0x00000000,	/* DENALI_PHY_219_DATA */
+			0x00000000,	/* DENALI_PHY_220_DATA */
+			0x00000000,	/* DENALI_PHY_221_DATA */
+			0x00000000,	/* DENALI_PHY_222_DATA */
+			0x00000000,	/* DENALI_PHY_223_DATA */
+			0x00000000,	/* DENALI_PHY_224_DATA */
+			0x00000000,	/* DENALI_PHY_225_DATA */
+			0x00000000,	/* DENALI_PHY_226_DATA */
+			0x00000000,	/* DENALI_PHY_227_DATA */
+			0x00000000,	/* DENALI_PHY_228_DATA */
+			0x00000000,	/* DENALI_PHY_229_DATA */
+			0x00000000,	/* DENALI_PHY_230_DATA */
+			0x00000000,	/* DENALI_PHY_231_DATA */
+			0x00000000,	/* DENALI_PHY_232_DATA */
+			0x00000000,	/* DENALI_PHY_233_DATA */
+			0x00000000,	/* DENALI_PHY_234_DATA */
+			0x00000000,	/* DENALI_PHY_235_DATA */
+			0x00000000,	/* DENALI_PHY_236_DATA */
+			0x00000000,	/* DENALI_PHY_237_DATA */
+			0x00000000,	/* DENALI_PHY_238_DATA */
+			0x00000000,	/* DENALI_PHY_239_DATA */
+			0x00000000,	/* DENALI_PHY_240_DATA */
+			0x00000000,	/* DENALI_PHY_241_DATA */
+			0x00000000,	/* DENALI_PHY_242_DATA */
+			0x00000000,	/* DENALI_PHY_243_DATA */
+			0x00000000,	/* DENALI_PHY_244_DATA */
+			0x00000000,	/* DENALI_PHY_245_DATA */
+			0x00000000,	/* DENALI_PHY_246_DATA */
+			0x00000000,	/* DENALI_PHY_247_DATA */
+			0x00000000,	/* DENALI_PHY_248_DATA */
+			0x00000000,	/* DENALI_PHY_249_DATA */
+			0x00000000,	/* DENALI_PHY_250_DATA */
+			0x00000000,	/* DENALI_PHY_251_DATA */
+			0x00000000,	/* DENALI_PHY_252_DATA */
+			0x00000000,	/* DENALI_PHY_253_DATA */
+			0x00000000,	/* DENALI_PHY_254_DATA */
+			0x00000000,	/* DENALI_PHY_255_DATA */
+			0x76543210,	/* DENALI_PHY_256_DATA */
+			0x0004c008,	/* DENALI_PHY_257_DATA */
+			0x000001a2,	/* DENALI_PHY_258_DATA */
+			0x00000000,	/* DENALI_PHY_259_DATA */
+			0x00000000,	/* DENALI_PHY_260_DATA */
+			0x00010000,	/* DENALI_PHY_261_DATA */
+			0x01665555,	/* DENALI_PHY_262_DATA */
+			0x00665555,	/* DENALI_PHY_263_DATA */
+			0x00010f00,	/* DENALI_PHY_264_DATA */
+			0x06010200,	/* DENALI_PHY_265_DATA */
+			0x00000003,	/* DENALI_PHY_266_DATA */
+			0x001700c0,	/* DENALI_PHY_267_DATA */
+			0x00cc0101,	/* DENALI_PHY_268_DATA */
+			0x00030066,	/* DENALI_PHY_269_DATA */
+			0x00000000,	/* DENALI_PHY_270_DATA */
+			0x00000000,	/* DENALI_PHY_271_DATA */
+			0x00000000,	/* DENALI_PHY_272_DATA */
+			0x00000000,	/* DENALI_PHY_273_DATA */
+			0x00000000,	/* DENALI_PHY_274_DATA */
+			0x00000000,	/* DENALI_PHY_275_DATA */
+			0x00000000,	/* DENALI_PHY_276_DATA */
+			0x00000000,	/* DENALI_PHY_277_DATA */
+			0x04080000,	/* DENALI_PHY_278_DATA */
+			0x04080400,	/* DENALI_PHY_279_DATA */
+			0x08000000,	/* DENALI_PHY_280_DATA */
+			0x0c00c007,	/* DENALI_PHY_281_DATA */
+			0x00000100,	/* DENALI_PHY_282_DATA */
+			0x00000100,	/* DENALI_PHY_283_DATA */
+			0x55555555,	/* DENALI_PHY_284_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_285_DATA */
+			0x55555555,	/* DENALI_PHY_286_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_287_DATA */
+			0x00005555,	/* DENALI_PHY_288_DATA */
+			0x00000000,	/* DENALI_PHY_289_DATA */
+			0x00000000,	/* DENALI_PHY_290_DATA */
+			0x00000000,	/* DENALI_PHY_291_DATA */
+			0x00000000,	/* DENALI_PHY_292_DATA */
+			0x00000000,	/* DENALI_PHY_293_DATA */
+			0x00000000,	/* DENALI_PHY_294_DATA */
+			0x00000000,	/* DENALI_PHY_295_DATA */
+			0x00000000,	/* DENALI_PHY_296_DATA */
+			0x00000000,	/* DENALI_PHY_297_DATA */
+			0x00000000,	/* DENALI_PHY_298_DATA */
+			0x00000000,	/* DENALI_PHY_299_DATA */
+			0x00000000,	/* DENALI_PHY_300_DATA */
+			0x00000000,	/* DENALI_PHY_301_DATA */
+			0x00000000,	/* DENALI_PHY_302_DATA */
+			0x00000000,	/* DENALI_PHY_303_DATA */
+			0x00000000,	/* DENALI_PHY_304_DATA */
+			0x00000000,	/* DENALI_PHY_305_DATA */
+			0x00000000,	/* DENALI_PHY_306_DATA */
+			0x00000000,	/* DENALI_PHY_307_DATA */
+			0x00200000,	/* DENALI_PHY_308_DATA */
+			0x00000000,	/* DENALI_PHY_309_DATA */
+			0x00000000,	/* DENALI_PHY_310_DATA */
+			0x00000000,	/* DENALI_PHY_311_DATA */
+			0x00000000,	/* DENALI_PHY_312_DATA */
+			0x00000000,	/* DENALI_PHY_313_DATA */
+			0x00000000,	/* DENALI_PHY_314_DATA */
+			0x02700270,	/* DENALI_PHY_315_DATA */
+			0x02700270,	/* DENALI_PHY_316_DATA */
+			0x02700270,	/* DENALI_PHY_317_DATA */
+			0x02700270,	/* DENALI_PHY_318_DATA */
+			0x00000270,	/* DENALI_PHY_319_DATA */
+			0x00000000,	/* DENALI_PHY_320_DATA */
+			0x00000000,	/* DENALI_PHY_321_DATA */
+			0x00000000,	/* DENALI_PHY_322_DATA */
+			0x00000000,	/* DENALI_PHY_323_DATA */
+			0x00800000,	/* DENALI_PHY_324_DATA */
+			0x00800080,	/* DENALI_PHY_325_DATA */
+			0x00800080,	/* DENALI_PHY_326_DATA */
+			0x00800080,	/* DENALI_PHY_327_DATA */
+			0x00800080,	/* DENALI_PHY_328_DATA */
+			0x00800080,	/* DENALI_PHY_329_DATA */
+			0x00800080,	/* DENALI_PHY_330_DATA */
+			0x00800080,	/* DENALI_PHY_331_DATA */
+			0x00800080,	/* DENALI_PHY_332_DATA */
+			0x01a20080,	/* DENALI_PHY_333_DATA */
+			0x00000003,	/* DENALI_PHY_334_DATA */
+			0x00000000,	/* DENALI_PHY_335_DATA */
+			0x00030000,	/* DENALI_PHY_336_DATA */
+			0x00000200,	/* DENALI_PHY_337_DATA */
+			0x00000000,	/* DENALI_PHY_338_DATA */
+			0x51315152,	/* DENALI_PHY_339_DATA */
+			0xc0013150,	/* DENALI_PHY_340_DATA */
+			0x020000c0,	/* DENALI_PHY_341_DATA */
+			0x00100001,	/* DENALI_PHY_342_DATA */
+			0x07064208,	/* DENALI_PHY_343_DATA */
+			0x000f0c18,	/* DENALI_PHY_344_DATA */
+			0x01000140,	/* DENALI_PHY_345_DATA */
+			0x00000c20,	/* DENALI_PHY_346_DATA */
+			0x00000000,	/* DENALI_PHY_347_DATA */
+			0x00000000,	/* DENALI_PHY_348_DATA */
+			0x00000000,	/* DENALI_PHY_349_DATA */
+			0x00000000,	/* DENALI_PHY_350_DATA */
+			0x00000000,	/* DENALI_PHY_351_DATA */
+			0x00000000,	/* DENALI_PHY_352_DATA */
+			0x00000000,	/* DENALI_PHY_353_DATA */
+			0x00000000,	/* DENALI_PHY_354_DATA */
+			0x00000000,	/* DENALI_PHY_355_DATA */
+			0x00000000,	/* DENALI_PHY_356_DATA */
+			0x00000000,	/* DENALI_PHY_357_DATA */
+			0x00000000,	/* DENALI_PHY_358_DATA */
+			0x00000000,	/* DENALI_PHY_359_DATA */
+			0x00000000,	/* DENALI_PHY_360_DATA */
+			0x00000000,	/* DENALI_PHY_361_DATA */
+			0x00000000,	/* DENALI_PHY_362_DATA */
+			0x00000000,	/* DENALI_PHY_363_DATA */
+			0x00000000,	/* DENALI_PHY_364_DATA */
+			0x00000000,	/* DENALI_PHY_365_DATA */
+			0x00000000,	/* DENALI_PHY_366_DATA */
+			0x00000000,	/* DENALI_PHY_367_DATA */
+			0x00000000,	/* DENALI_PHY_368_DATA */
+			0x00000000,	/* DENALI_PHY_369_DATA */
+			0x00000000,	/* DENALI_PHY_370_DATA */
+			0x00000000,	/* DENALI_PHY_371_DATA */
+			0x00000000,	/* DENALI_PHY_372_DATA */
+			0x00000000,	/* DENALI_PHY_373_DATA */
+			0x00000000,	/* DENALI_PHY_374_DATA */
+			0x00000000,	/* DENALI_PHY_375_DATA */
+			0x00000000,	/* DENALI_PHY_376_DATA */
+			0x00000000,	/* DENALI_PHY_377_DATA */
+			0x00000000,	/* DENALI_PHY_378_DATA */
+			0x00000000,	/* DENALI_PHY_379_DATA */
+			0x00000000,	/* DENALI_PHY_380_DATA */
+			0x00000000,	/* DENALI_PHY_381_DATA */
+			0x00000000,	/* DENALI_PHY_382_DATA */
+			0x00000000,	/* DENALI_PHY_383_DATA */
+			0x76543210,	/* DENALI_PHY_384_DATA */
+			0x0004c008,	/* DENALI_PHY_385_DATA */
+			0x000001a2,	/* DENALI_PHY_386_DATA */
+			0x00000000,	/* DENALI_PHY_387_DATA */
+			0x00000000,	/* DENALI_PHY_388_DATA */
+			0x00010000,	/* DENALI_PHY_389_DATA */
+			0x01665555,	/* DENALI_PHY_390_DATA */
+			0x00665555,	/* DENALI_PHY_391_DATA */
+			0x00010f00,	/* DENALI_PHY_392_DATA */
+			0x06010200,	/* DENALI_PHY_393_DATA */
+			0x00000003,	/* DENALI_PHY_394_DATA */
+			0x001700c0,	/* DENALI_PHY_395_DATA */
+			0x00cc0101,	/* DENALI_PHY_396_DATA */
+			0x00030066,	/* DENALI_PHY_397_DATA */
+			0x00000000,	/* DENALI_PHY_398_DATA */
+			0x00000000,	/* DENALI_PHY_399_DATA */
+			0x00000000,	/* DENALI_PHY_400_DATA */
+			0x00000000,	/* DENALI_PHY_401_DATA */
+			0x00000000,	/* DENALI_PHY_402_DATA */
+			0x00000000,	/* DENALI_PHY_403_DATA */
+			0x00000000,	/* DENALI_PHY_404_DATA */
+			0x00000000,	/* DENALI_PHY_405_DATA */
+			0x04080000,	/* DENALI_PHY_406_DATA */
+			0x04080400,	/* DENALI_PHY_407_DATA */
+			0x08000000,	/* DENALI_PHY_408_DATA */
+			0x0c00c007,	/* DENALI_PHY_409_DATA */
+			0x00000100,	/* DENALI_PHY_410_DATA */
+			0x00000100,	/* DENALI_PHY_411_DATA */
+			0x55555555,	/* DENALI_PHY_412_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_413_DATA */
+			0x55555555,	/* DENALI_PHY_414_DATA */
+			0xaaaaaaaa,	/* DENALI_PHY_415_DATA */
+			0x00005555,	/* DENALI_PHY_416_DATA */
+			0x00000000,	/* DENALI_PHY_417_DATA */
+			0x00000000,	/* DENALI_PHY_418_DATA */
+			0x00000000,	/* DENALI_PHY_419_DATA */
+			0x00000000,	/* DENALI_PHY_420_DATA */
+			0x00000000,	/* DENALI_PHY_421_DATA */
+			0x00000000,	/* DENALI_PHY_422_DATA */
+			0x00000000,	/* DENALI_PHY_423_DATA */
+			0x00000000,	/* DENALI_PHY_424_DATA */
+			0x00000000,	/* DENALI_PHY_425_DATA */
+			0x00000000,	/* DENALI_PHY_426_DATA */
+			0x00000000,	/* DENALI_PHY_427_DATA */
+			0x00000000,	/* DENALI_PHY_428_DATA */
+			0x00000000,	/* DENALI_PHY_429_DATA */
+			0x00000000,	/* DENALI_PHY_430_DATA */
+			0x00000000,	/* DENALI_PHY_431_DATA */
+			0x00000000,	/* DENALI_PHY_432_DATA */
+			0x00000000,	/* DENALI_PHY_433_DATA */
+			0x00000000,	/* DENALI_PHY_434_DATA */
+			0x00000000,	/* DENALI_PHY_435_DATA */
+			0x00200000,	/* DENALI_PHY_436_DATA */
+			0x00000000,	/* DENALI_PHY_437_DATA */
+			0x00000000,	/* DENALI_PHY_438_DATA */
+			0x00000000,	/* DENALI_PHY_439_DATA */
+			0x00000000,	/* DENALI_PHY_440_DATA */
+			0x00000000,	/* DENALI_PHY_441_DATA */
+			0x00000000,	/* DENALI_PHY_442_DATA */
+			0x02700270,	/* DENALI_PHY_443_DATA */
+			0x02700270,	/* DENALI_PHY_444_DATA */
+			0x02700270,	/* DENALI_PHY_445_DATA */
+			0x02700270,	/* DENALI_PHY_446_DATA */
+			0x00000270,	/* DENALI_PHY_447_DATA */
+			0x00000000,	/* DENALI_PHY_448_DATA */
+			0x00000000,	/* DENALI_PHY_449_DATA */
+			0x00000000,	/* DENALI_PHY_450_DATA */
+			0x00000000,	/* DENALI_PHY_451_DATA */
+			0x00800000,	/* DENALI_PHY_452_DATA */
+			0x00800080,	/* DENALI_PHY_453_DATA */
+			0x00800080,	/* DENALI_PHY_454_DATA */
+			0x00800080,	/* DENALI_PHY_455_DATA */
+			0x00800080,	/* DENALI_PHY_456_DATA */
+			0x00800080,	/* DENALI_PHY_457_DATA */
+			0x00800080,	/* DENALI_PHY_458_DATA */
+			0x00800080,	/* DENALI_PHY_459_DATA */
+			0x00800080,	/* DENALI_PHY_460_DATA */
+			0x01a20080,	/* DENALI_PHY_461_DATA */
+			0x00000003,	/* DENALI_PHY_462_DATA */
+			0x00000000,	/* DENALI_PHY_463_DATA */
+			0x00030000,	/* DENALI_PHY_464_DATA */
+			0x00000200,	/* DENALI_PHY_465_DATA */
+			0x00000000,	/* DENALI_PHY_466_DATA */
+			0x51315152,	/* DENALI_PHY_467_DATA */
+			0xc0013150,	/* DENALI_PHY_468_DATA */
+			0x020000c0,	/* DENALI_PHY_469_DATA */
+			0x00100001,	/* DENALI_PHY_470_DATA */
+			0x07064208,	/* DENALI_PHY_471_DATA */
+			0x000f0c18,	/* DENALI_PHY_472_DATA */
+			0x01000140,	/* DENALI_PHY_473_DATA */
+			0x00000c20,	/* DENALI_PHY_474_DATA */
+			0x00000000,	/* DENALI_PHY_475_DATA */
+			0x00000000,	/* DENALI_PHY_476_DATA */
+			0x00000000,	/* DENALI_PHY_477_DATA */
+			0x00000000,	/* DENALI_PHY_478_DATA */
+			0x00000000,	/* DENALI_PHY_479_DATA */
+			0x00000000,	/* DENALI_PHY_480_DATA */
+			0x00000000,	/* DENALI_PHY_481_DATA */
+			0x00000000,	/* DENALI_PHY_482_DATA */
+			0x00000000,	/* DENALI_PHY_483_DATA */
+			0x00000000,	/* DENALI_PHY_484_DATA */
+			0x00000000,	/* DENALI_PHY_485_DATA */
+			0x00000000,	/* DENALI_PHY_486_DATA */
+			0x00000000,	/* DENALI_PHY_487_DATA */
+			0x00000000,	/* DENALI_PHY_488_DATA */
+			0x00000000,	/* DENALI_PHY_489_DATA */
+			0x00000000,	/* DENALI_PHY_490_DATA */
+			0x00000000,	/* DENALI_PHY_491_DATA */
+			0x00000000,	/* DENALI_PHY_492_DATA */
+			0x00000000,	/* DENALI_PHY_493_DATA */
+			0x00000000,	/* DENALI_PHY_494_DATA */
+			0x00000000,	/* DENALI_PHY_495_DATA */
+			0x00000000,	/* DENALI_PHY_496_DATA */
+			0x00000000,	/* DENALI_PHY_497_DATA */
+			0x00000000,	/* DENALI_PHY_498_DATA */
+			0x00000000,	/* DENALI_PHY_499_DATA */
+			0x00000000,	/* DENALI_PHY_500_DATA */
+			0x00000000,	/* DENALI_PHY_501_DATA */
+			0x00000000,	/* DENALI_PHY_502_DATA */
+			0x00000000,	/* DENALI_PHY_503_DATA */
+			0x00000000,	/* DENALI_PHY_504_DATA */
+			0x00000000,	/* DENALI_PHY_505_DATA */
+			0x00000000,	/* DENALI_PHY_506_DATA */
+			0x00000000,	/* DENALI_PHY_507_DATA */
+			0x00000000,	/* DENALI_PHY_508_DATA */
+			0x00000000,	/* DENALI_PHY_509_DATA */
+			0x00000000,	/* DENALI_PHY_510_DATA */
+			0x00000000,	/* DENALI_PHY_511_DATA */
+			0x00000000,	/* DENALI_PHY_512_DATA */
+			0x00800000,	/* DENALI_PHY_513_DATA */
+			0x00000000,	/* DENALI_PHY_514_DATA */
+			0x00000000,	/* DENALI_PHY_515_DATA */
+			0x00000000,	/* DENALI_PHY_516_DATA */
+			0x00000000,	/* DENALI_PHY_517_DATA */
+			0x00000000,	/* DENALI_PHY_518_DATA */
+			0x00000001,	/* DENALI_PHY_519_DATA */
+			0x00000000,	/* DENALI_PHY_520_DATA */
+			0x00000000,	/* DENALI_PHY_521_DATA */
+			0x00000000,	/* DENALI_PHY_522_DATA */
+			0x00400320,	/* DENALI_PHY_523_DATA */
+			0x00000040,	/* DENALI_PHY_524_DATA */
+			0x00806420,	/* DENALI_PHY_525_DATA */
+			0x00917531,	/* DENALI_PHY_526_DATA */
+			0x00806420,	/* DENALI_PHY_527_DATA */
+			0x01917531,	/* DENALI_PHY_528_DATA */
+			0x02020003,	/* DENALI_PHY_529_DATA */
+			0x00000000,	/* DENALI_PHY_530_DATA */
+			0x00000000,	/* DENALI_PHY_531_DATA */
+			0x00000000,	/* DENALI_PHY_532_DATA */
+			0x000fffff,	/* DENALI_PHY_533_DATA */
+			0x00000000,	/* DENALI_PHY_534_DATA */
+			0x000556aa,	/* DENALI_PHY_535_DATA */
+			0x000aaaaa,	/* DENALI_PHY_536_DATA */
+			0x000b3133,	/* DENALI_PHY_537_DATA */
+			0x0004cd33,	/* DENALI_PHY_538_DATA */
+			0x0004cecc,	/* DENALI_PHY_539_DATA */
+			0x000b32cc,	/* DENALI_PHY_540_DATA */
+			0x0a418820,	/* DENALI_PHY_541_DATA */
+			0x103f0000,	/* DENALI_PHY_542_DATA */
+			0x0000003f,	/* DENALI_PHY_543_DATA */
+			0x00038055,	/* DENALI_PHY_544_DATA */
+			0x03800380,	/* DENALI_PHY_545_DATA */
+			0x03800380,	/* DENALI_PHY_546_DATA */
+			0x00000380,	/* DENALI_PHY_547_DATA */
+			0x42080010,	/* DENALI_PHY_548_DATA */
+			0x00000003,	/* DENALI_PHY_549_DATA */
+			0x00000000,	/* DENALI_PHY_550_DATA */
+			0x00000000,	/* DENALI_PHY_551_DATA */
+			0x00000000,	/* DENALI_PHY_552_DATA */
+			0x00000000,	/* DENALI_PHY_553_DATA */
+			0x00000000,	/* DENALI_PHY_554_DATA */
+			0x00000000,	/* DENALI_PHY_555_DATA */
+			0x00000000,	/* DENALI_PHY_556_DATA */
+			0x00000000,	/* DENALI_PHY_557_DATA */
+			0x00000000,	/* DENALI_PHY_558_DATA */
+			0x00000000,	/* DENALI_PHY_559_DATA */
+			0x00000000,	/* DENALI_PHY_560_DATA */
+			0x00000000,	/* DENALI_PHY_561_DATA */
+			0x00000000,	/* DENALI_PHY_562_DATA */
+			0x00000000,	/* DENALI_PHY_563_DATA */
+			0x00000000,	/* DENALI_PHY_564_DATA */
+			0x00000000,	/* DENALI_PHY_565_DATA */
+			0x00000000,	/* DENALI_PHY_566_DATA */
+			0x00000000,	/* DENALI_PHY_567_DATA */
+			0x00000000,	/* DENALI_PHY_568_DATA */
+			0x00000000,	/* DENALI_PHY_569_DATA */
+			0x00000000,	/* DENALI_PHY_570_DATA */
+			0x00000000,	/* DENALI_PHY_571_DATA */
+			0x00000000,	/* DENALI_PHY_572_DATA */
+			0x00000000,	/* DENALI_PHY_573_DATA */
+			0x00000000,	/* DENALI_PHY_574_DATA */
+			0x00000000,	/* DENALI_PHY_575_DATA */
+			0x00000000,	/* DENALI_PHY_576_DATA */
+			0x00000000,	/* DENALI_PHY_577_DATA */
+			0x00000000,	/* DENALI_PHY_578_DATA */
+			0x00000000,	/* DENALI_PHY_579_DATA */
+			0x00000000,	/* DENALI_PHY_580_DATA */
+			0x00000000,	/* DENALI_PHY_581_DATA */
+			0x00000000,	/* DENALI_PHY_582_DATA */
+			0x00000000,	/* DENALI_PHY_583_DATA */
+			0x00000000,	/* DENALI_PHY_584_DATA */
+			0x00000000,	/* DENALI_PHY_585_DATA */
+			0x00000000,	/* DENALI_PHY_586_DATA */
+			0x00000000,	/* DENALI_PHY_587_DATA */
+			0x00000000,	/* DENALI_PHY_588_DATA */
+			0x00000000,	/* DENALI_PHY_589_DATA */
+			0x00000000,	/* DENALI_PHY_590_DATA */
+			0x00000000,	/* DENALI_PHY_591_DATA */
+			0x00000000,	/* DENALI_PHY_592_DATA */
+			0x00000000,	/* DENALI_PHY_593_DATA */
+			0x00000000,	/* DENALI_PHY_594_DATA */
+			0x00000000,	/* DENALI_PHY_595_DATA */
+			0x00000000,	/* DENALI_PHY_596_DATA */
+			0x00000000,	/* DENALI_PHY_597_DATA */
+			0x00000000,	/* DENALI_PHY_598_DATA */
+			0x00000000,	/* DENALI_PHY_599_DATA */
+			0x00000000,	/* DENALI_PHY_600_DATA */
+			0x00000000,	/* DENALI_PHY_601_DATA */
+			0x00000000,	/* DENALI_PHY_602_DATA */
+			0x00000000,	/* DENALI_PHY_603_DATA */
+			0x00000000,	/* DENALI_PHY_604_DATA */
+			0x00000000,	/* DENALI_PHY_605_DATA */
+			0x00000000,	/* DENALI_PHY_606_DATA */
+			0x00000000,	/* DENALI_PHY_607_DATA */
+			0x00000000,	/* DENALI_PHY_608_DATA */
+			0x00000000,	/* DENALI_PHY_609_DATA */
+			0x00000000,	/* DENALI_PHY_610_DATA */
+			0x00000000,	/* DENALI_PHY_611_DATA */
+			0x00000000,	/* DENALI_PHY_612_DATA */
+			0x00000000,	/* DENALI_PHY_613_DATA */
+			0x00000000,	/* DENALI_PHY_614_DATA */
+			0x00000000,	/* DENALI_PHY_615_DATA */
+			0x00000000,	/* DENALI_PHY_616_DATA */
+			0x00000000,	/* DENALI_PHY_617_DATA */
+			0x00000000,	/* DENALI_PHY_618_DATA */
+			0x00000000,	/* DENALI_PHY_619_DATA */
+			0x00000000,	/* DENALI_PHY_620_DATA */
+			0x00000000,	/* DENALI_PHY_621_DATA */
+			0x00000000,	/* DENALI_PHY_622_DATA */
+			0x00000000,	/* DENALI_PHY_623_DATA */
+			0x00000000,	/* DENALI_PHY_624_DATA */
+			0x00000000,	/* DENALI_PHY_625_DATA */
+			0x00000000,	/* DENALI_PHY_626_DATA */
+			0x00000000,	/* DENALI_PHY_627_DATA */
+			0x00000000,	/* DENALI_PHY_628_DATA */
+			0x00000000,	/* DENALI_PHY_629_DATA */
+			0x00000000,	/* DENALI_PHY_630_DATA */
+			0x00000000,	/* DENALI_PHY_631_DATA */
+			0x00000000,	/* DENALI_PHY_632_DATA */
+			0x00000000,	/* DENALI_PHY_633_DATA */
+			0x00000000,	/* DENALI_PHY_634_DATA */
+			0x00000000,	/* DENALI_PHY_635_DATA */
+			0x00000000,	/* DENALI_PHY_636_DATA */
+			0x00000000,	/* DENALI_PHY_637_DATA */
+			0x00000000,	/* DENALI_PHY_638_DATA */
+			0x00000000,	/* DENALI_PHY_639_DATA */
+			0x00000000,	/* DENALI_PHY_640_DATA */
+			0x00800000,	/* DENALI_PHY_641_DATA */
+			0x00000000,	/* DENALI_PHY_642_DATA */
+			0x00000000,	/* DENALI_PHY_643_DATA */
+			0x00000000,	/* DENALI_PHY_644_DATA */
+			0x00000000,	/* DENALI_PHY_645_DATA */
+			0x00000000,	/* DENALI_PHY_646_DATA */
+			0x00000001,	/* DENALI_PHY_647_DATA */
+			0x00000000,	/* DENALI_PHY_648_DATA */
+			0x00000000,	/* DENALI_PHY_649_DATA */
+			0x00000000,	/* DENALI_PHY_650_DATA */
+			0x00400320,	/* DENALI_PHY_651_DATA */
+			0x00000040,	/* DENALI_PHY_652_DATA */
+			0x00008eca,	/* DENALI_PHY_653_DATA */
+			0x00009fdb,	/* DENALI_PHY_654_DATA */
+			0x00008eca,	/* DENALI_PHY_655_DATA */
+			0x01009fdb,	/* DENALI_PHY_656_DATA */
+			0x02020003,	/* DENALI_PHY_657_DATA */
+			0x00000000,	/* DENALI_PHY_658_DATA */
+			0x00000000,	/* DENALI_PHY_659_DATA */
+			0x00000000,	/* DENALI_PHY_660_DATA */
+			0x000fffff,	/* DENALI_PHY_661_DATA */
+			0x00000000,	/* DENALI_PHY_662_DATA */
+			0x000556aa,	/* DENALI_PHY_663_DATA */
+			0x000aaaaa,	/* DENALI_PHY_664_DATA */
+			0x000b3133,	/* DENALI_PHY_665_DATA */
+			0x0004cd33,	/* DENALI_PHY_666_DATA */
+			0x0004cecc,	/* DENALI_PHY_667_DATA */
+			0x000b32cc,	/* DENALI_PHY_668_DATA */
+			0x0004a0e6,	/* DENALI_PHY_669_DATA */
+			0x080f0000,	/* DENALI_PHY_670_DATA */
+			0x0000000f,	/* DENALI_PHY_671_DATA */
+			0x00038055,	/* DENALI_PHY_672_DATA */
+			0x03800380,	/* DENALI_PHY_673_DATA */
+			0x03800380,	/* DENALI_PHY_674_DATA */
+			0x00000380,	/* DENALI_PHY_675_DATA */
+			0x42080010,	/* DENALI_PHY_676_DATA */
+			0x00000003,	/* DENALI_PHY_677_DATA */
+			0x00000000,	/* DENALI_PHY_678_DATA */
+			0x00000000,	/* DENALI_PHY_679_DATA */
+			0x00000000,	/* DENALI_PHY_680_DATA */
+			0x00000000,	/* DENALI_PHY_681_DATA */
+			0x00000000,	/* DENALI_PHY_682_DATA */
+			0x00000000,	/* DENALI_PHY_683_DATA */
+			0x00000000,	/* DENALI_PHY_684_DATA */
+			0x00000000,	/* DENALI_PHY_685_DATA */
+			0x00000000,	/* DENALI_PHY_686_DATA */
+			0x00000000,	/* DENALI_PHY_687_DATA */
+			0x00000000,	/* DENALI_PHY_688_DATA */
+			0x00000000,	/* DENALI_PHY_689_DATA */
+			0x00000000,	/* DENALI_PHY_690_DATA */
+			0x00000000,	/* DENALI_PHY_691_DATA */
+			0x00000000,	/* DENALI_PHY_692_DATA */
+			0x00000000,	/* DENALI_PHY_693_DATA */
+			0x00000000,	/* DENALI_PHY_694_DATA */
+			0x00000000,	/* DENALI_PHY_695_DATA */
+			0x00000000,	/* DENALI_PHY_696_DATA */
+			0x00000000,	/* DENALI_PHY_697_DATA */
+			0x00000000,	/* DENALI_PHY_698_DATA */
+			0x00000000,	/* DENALI_PHY_699_DATA */
+			0x00000000,	/* DENALI_PHY_700_DATA */
+			0x00000000,	/* DENALI_PHY_701_DATA */
+			0x00000000,	/* DENALI_PHY_702_DATA */
+			0x00000000,	/* DENALI_PHY_703_DATA */
+			0x00000000,	/* DENALI_PHY_704_DATA */
+			0x00000000,	/* DENALI_PHY_705_DATA */
+			0x00000000,	/* DENALI_PHY_706_DATA */
+			0x00000000,	/* DENALI_PHY_707_DATA */
+			0x00000000,	/* DENALI_PHY_708_DATA */
+			0x00000000,	/* DENALI_PHY_709_DATA */
+			0x00000000,	/* DENALI_PHY_710_DATA */
+			0x00000000,	/* DENALI_PHY_711_DATA */
+			0x00000000,	/* DENALI_PHY_712_DATA */
+			0x00000000,	/* DENALI_PHY_713_DATA */
+			0x00000000,	/* DENALI_PHY_714_DATA */
+			0x00000000,	/* DENALI_PHY_715_DATA */
+			0x00000000,	/* DENALI_PHY_716_DATA */
+			0x00000000,	/* DENALI_PHY_717_DATA */
+			0x00000000,	/* DENALI_PHY_718_DATA */
+			0x00000000,	/* DENALI_PHY_719_DATA */
+			0x00000000,	/* DENALI_PHY_720_DATA */
+			0x00000000,	/* DENALI_PHY_721_DATA */
+			0x00000000,	/* DENALI_PHY_722_DATA */
+			0x00000000,	/* DENALI_PHY_723_DATA */
+			0x00000000,	/* DENALI_PHY_724_DATA */
+			0x00000000,	/* DENALI_PHY_725_DATA */
+			0x00000000,	/* DENALI_PHY_726_DATA */
+			0x00000000,	/* DENALI_PHY_727_DATA */
+			0x00000000,	/* DENALI_PHY_728_DATA */
+			0x00000000,	/* DENALI_PHY_729_DATA */
+			0x00000000,	/* DENALI_PHY_730_DATA */
+			0x00000000,	/* DENALI_PHY_731_DATA */
+			0x00000000,	/* DENALI_PHY_732_DATA */
+			0x00000000,	/* DENALI_PHY_733_DATA */
+			0x00000000,	/* DENALI_PHY_734_DATA */
+			0x00000000,	/* DENALI_PHY_735_DATA */
+			0x00000000,	/* DENALI_PHY_736_DATA */
+			0x00000000,	/* DENALI_PHY_737_DATA */
+			0x00000000,	/* DENALI_PHY_738_DATA */
+			0x00000000,	/* DENALI_PHY_739_DATA */
+			0x00000000,	/* DENALI_PHY_740_DATA */
+			0x00000000,	/* DENALI_PHY_741_DATA */
+			0x00000000,	/* DENALI_PHY_742_DATA */
+			0x00000000,	/* DENALI_PHY_743_DATA */
+			0x00000000,	/* DENALI_PHY_744_DATA */
+			0x00000000,	/* DENALI_PHY_745_DATA */
+			0x00000000,	/* DENALI_PHY_746_DATA */
+			0x00000000,	/* DENALI_PHY_747_DATA */
+			0x00000000,	/* DENALI_PHY_748_DATA */
+			0x00000000,	/* DENALI_PHY_749_DATA */
+			0x00000000,	/* DENALI_PHY_750_DATA */
+			0x00000000,	/* DENALI_PHY_751_DATA */
+			0x00000000,	/* DENALI_PHY_752_DATA */
+			0x00000000,	/* DENALI_PHY_753_DATA */
+			0x00000000,	/* DENALI_PHY_754_DATA */
+			0x00000000,	/* DENALI_PHY_755_DATA */
+			0x00000000,	/* DENALI_PHY_756_DATA */
+			0x00000000,	/* DENALI_PHY_757_DATA */
+			0x00000000,	/* DENALI_PHY_758_DATA */
+			0x00000000,	/* DENALI_PHY_759_DATA */
+			0x00000000,	/* DENALI_PHY_760_DATA */
+			0x00000000,	/* DENALI_PHY_761_DATA */
+			0x00000000,	/* DENALI_PHY_762_DATA */
+			0x00000000,	/* DENALI_PHY_763_DATA */
+			0x00000000,	/* DENALI_PHY_764_DATA */
+			0x00000000,	/* DENALI_PHY_765_DATA */
+			0x00000000,	/* DENALI_PHY_766_DATA */
+			0x00000000,	/* DENALI_PHY_767_DATA */
+			0x00000000,	/* DENALI_PHY_768_DATA */
+			0x00800000,	/* DENALI_PHY_769_DATA */
+			0x00000000,	/* DENALI_PHY_770_DATA */
+			0x00000000,	/* DENALI_PHY_771_DATA */
+			0x00000000,	/* DENALI_PHY_772_DATA */
+			0x00000000,	/* DENALI_PHY_773_DATA */
+			0x00000000,	/* DENALI_PHY_774_DATA */
+			0x00000001,	/* DENALI_PHY_775_DATA */
+			0x00000000,	/* DENALI_PHY_776_DATA */
+			0x00000000,	/* DENALI_PHY_777_DATA */
+			0x00000000,	/* DENALI_PHY_778_DATA */
+			0x00400320,	/* DENALI_PHY_779_DATA */
+			0x00000040,	/* DENALI_PHY_780_DATA */
+			0x00008eca,	/* DENALI_PHY_781_DATA */
+			0x00009fdb,	/* DENALI_PHY_782_DATA */
+			0x00008eca,	/* DENALI_PHY_783_DATA */
+			0x01009fdb,	/* DENALI_PHY_784_DATA */
+			0x02020003,	/* DENALI_PHY_785_DATA */
+			0x00000000,	/* DENALI_PHY_786_DATA */
+			0x00000000,	/* DENALI_PHY_787_DATA */
+			0x00000000,	/* DENALI_PHY_788_DATA */
+			0x000fffff,	/* DENALI_PHY_789_DATA */
+			0x00000000,	/* DENALI_PHY_790_DATA */
+			0x000556aa,	/* DENALI_PHY_791_DATA */
+			0x000aaaaa,	/* DENALI_PHY_792_DATA */
+			0x000b3133,	/* DENALI_PHY_793_DATA */
+			0x0004cd33,	/* DENALI_PHY_794_DATA */
+			0x0004cecc,	/* DENALI_PHY_795_DATA */
+			0x000b32cc,	/* DENALI_PHY_796_DATA */
+			0x1ee6b16a,	/* DENALI_PHY_797_DATA */
+			0x10000000,	/* DENALI_PHY_798_DATA */
+			0x00000000,	/* DENALI_PHY_799_DATA */
+			0x00038055,	/* DENALI_PHY_800_DATA */
+			0x03800380,	/* DENALI_PHY_801_DATA */
+			0x03800380,	/* DENALI_PHY_802_DATA */
+			0x00000380,	/* DENALI_PHY_803_DATA */
+			0x42080010,	/* DENALI_PHY_804_DATA */
+			0x00000003,	/* DENALI_PHY_805_DATA */
+			0x00000000,	/* DENALI_PHY_806_DATA */
+			0x00000000,	/* DENALI_PHY_807_DATA */
+			0x00000000,	/* DENALI_PHY_808_DATA */
+			0x00000000,	/* DENALI_PHY_809_DATA */
+			0x00000000,	/* DENALI_PHY_810_DATA */
+			0x00000000,	/* DENALI_PHY_811_DATA */
+			0x00000000,	/* DENALI_PHY_812_DATA */
+			0x00000000,	/* DENALI_PHY_813_DATA */
+			0x00000000,	/* DENALI_PHY_814_DATA */
+			0x00000000,	/* DENALI_PHY_815_DATA */
+			0x00000000,	/* DENALI_PHY_816_DATA */
+			0x00000000,	/* DENALI_PHY_817_DATA */
+			0x00000000,	/* DENALI_PHY_818_DATA */
+			0x00000000,	/* DENALI_PHY_819_DATA */
+			0x00000000,	/* DENALI_PHY_820_DATA */
+			0x00000000,	/* DENALI_PHY_821_DATA */
+			0x00000000,	/* DENALI_PHY_822_DATA */
+			0x00000000,	/* DENALI_PHY_823_DATA */
+			0x00000000,	/* DENALI_PHY_824_DATA */
+			0x00000000,	/* DENALI_PHY_825_DATA */
+			0x00000000,	/* DENALI_PHY_826_DATA */
+			0x00000000,	/* DENALI_PHY_827_DATA */
+			0x00000000,	/* DENALI_PHY_828_DATA */
+			0x00000000,	/* DENALI_PHY_829_DATA */
+			0x00000000,	/* DENALI_PHY_830_DATA */
+			0x00000000,	/* DENALI_PHY_831_DATA */
+			0x00000000,	/* DENALI_PHY_832_DATA */
+			0x00000000,	/* DENALI_PHY_833_DATA */
+			0x00000000,	/* DENALI_PHY_834_DATA */
+			0x00000000,	/* DENALI_PHY_835_DATA */
+			0x00000000,	/* DENALI_PHY_836_DATA */
+			0x00000000,	/* DENALI_PHY_837_DATA */
+			0x00000000,	/* DENALI_PHY_838_DATA */
+			0x00000000,	/* DENALI_PHY_839_DATA */
+			0x00000000,	/* DENALI_PHY_840_DATA */
+			0x00000000,	/* DENALI_PHY_841_DATA */
+			0x00000000,	/* DENALI_PHY_842_DATA */
+			0x00000000,	/* DENALI_PHY_843_DATA */
+			0x00000000,	/* DENALI_PHY_844_DATA */
+			0x00000000,	/* DENALI_PHY_845_DATA */
+			0x00000000,	/* DENALI_PHY_846_DATA */
+			0x00000000,	/* DENALI_PHY_847_DATA */
+			0x00000000,	/* DENALI_PHY_848_DATA */
+			0x00000000,	/* DENALI_PHY_849_DATA */
+			0x00000000,	/* DENALI_PHY_850_DATA */
+			0x00000000,	/* DENALI_PHY_851_DATA */
+			0x00000000,	/* DENALI_PHY_852_DATA */
+			0x00000000,	/* DENALI_PHY_853_DATA */
+			0x00000000,	/* DENALI_PHY_854_DATA */
+			0x00000000,	/* DENALI_PHY_855_DATA */
+			0x00000000,	/* DENALI_PHY_856_DATA */
+			0x00000000,	/* DENALI_PHY_857_DATA */
+			0x00000000,	/* DENALI_PHY_858_DATA */
+			0x00000000,	/* DENALI_PHY_859_DATA */
+			0x00000000,	/* DENALI_PHY_860_DATA */
+			0x00000000,	/* DENALI_PHY_861_DATA */
+			0x00000000,	/* DENALI_PHY_862_DATA */
+			0x00000000,	/* DENALI_PHY_863_DATA */
+			0x00000000,	/* DENALI_PHY_864_DATA */
+			0x00000000,	/* DENALI_PHY_865_DATA */
+			0x00000000,	/* DENALI_PHY_866_DATA */
+			0x00000000,	/* DENALI_PHY_867_DATA */
+			0x00000000,	/* DENALI_PHY_868_DATA */
+			0x00000000,	/* DENALI_PHY_869_DATA */
+			0x00000000,	/* DENALI_PHY_870_DATA */
+			0x00000000,	/* DENALI_PHY_871_DATA */
+			0x00000000,	/* DENALI_PHY_872_DATA */
+			0x00000000,	/* DENALI_PHY_873_DATA */
+			0x00000000,	/* DENALI_PHY_874_DATA */
+			0x00000000,	/* DENALI_PHY_875_DATA */
+			0x00000000,	/* DENALI_PHY_876_DATA */
+			0x00000000,	/* DENALI_PHY_877_DATA */
+			0x00000000,	/* DENALI_PHY_878_DATA */
+			0x00000000,	/* DENALI_PHY_879_DATA */
+			0x00000000,	/* DENALI_PHY_880_DATA */
+			0x00000000,	/* DENALI_PHY_881_DATA */
+			0x00000000,	/* DENALI_PHY_882_DATA */
+			0x00000000,	/* DENALI_PHY_883_DATA */
+			0x00000000,	/* DENALI_PHY_884_DATA */
+			0x00000000,	/* DENALI_PHY_885_DATA */
+			0x00000000,	/* DENALI_PHY_886_DATA */
+			0x00000000,	/* DENALI_PHY_887_DATA */
+			0x00000000,	/* DENALI_PHY_888_DATA */
+			0x00000000,	/* DENALI_PHY_889_DATA */
+			0x00000000,	/* DENALI_PHY_890_DATA */
+			0x00000000,	/* DENALI_PHY_891_DATA */
+			0x00000000,	/* DENALI_PHY_892_DATA */
+			0x00000000,	/* DENALI_PHY_893_DATA */
+			0x00000000,	/* DENALI_PHY_894_DATA */
+			0x00000000,	/* DENALI_PHY_895_DATA */
+			0x00000001,	/* DENALI_PHY_896_DATA */
+			0x00000000,	/* DENALI_PHY_897_DATA */
+			0x01000005,	/* DENALI_PHY_898_DATA */
+			0x04000f00,	/* DENALI_PHY_899_DATA */
+			0x00020040,	/* DENALI_PHY_900_DATA */
+			0x00020055,	/* DENALI_PHY_901_DATA */
+			0x00000000,	/* DENALI_PHY_902_DATA */
+			0x00000000,	/* DENALI_PHY_903_DATA */
+			0x00000000,	/* DENALI_PHY_904_DATA */
+			0x00000050,	/* DENALI_PHY_905_DATA */
+			0x00000000,	/* DENALI_PHY_906_DATA */
+			0x00010100,	/* DENALI_PHY_907_DATA */
+			0x00000601,	/* DENALI_PHY_908_DATA */
+			0x00000000,	/* DENALI_PHY_909_DATA */
+			0x00006400,	/* DENALI_PHY_910_DATA */
+			0x01221102,	/* DENALI_PHY_911_DATA */
+			0x00000000,	/* DENALI_PHY_912_DATA */
+			0x00051f00,	/* DENALI_PHY_913_DATA */
+			0x051f051f,	/* DENALI_PHY_914_DATA */
+			0x051f051f,	/* DENALI_PHY_915_DATA */
+			0x00030003,	/* DENALI_PHY_916_DATA */
+			0x03000300,	/* DENALI_PHY_917_DATA */
+			0x00000300,	/* DENALI_PHY_918_DATA */
+			0x01221102,	/* DENALI_PHY_919_DATA */
+			0x00000000,	/* DENALI_PHY_920_DATA */
+			0x00000000,	/* DENALI_PHY_921_DATA */
+			0x04020000,	/* DENALI_PHY_922_DATA */
+			0x00000001,	/* DENALI_PHY_923_DATA */
+			0x00000011,	/* DENALI_PHY_924_DATA */
+			0x00000011,	/* DENALI_PHY_925_DATA */
+			0x00000400,	/* DENALI_PHY_926_DATA */
+			0x00000000,	/* DENALI_PHY_927_DATA */
+			0x00000011,	/* DENALI_PHY_928_DATA */
+			0x00000011,	/* DENALI_PHY_929_DATA */
+			0x00004410,	/* DENALI_PHY_930_DATA */
+			0x00004410,	/* DENALI_PHY_931_DATA */
+			0x00004410,	/* DENALI_PHY_932_DATA */
+			0x00004410,	/* DENALI_PHY_933_DATA */
+			0x00004410,	/* DENALI_PHY_934_DATA */
+			0x00000011,	/* DENALI_PHY_935_DATA */
+			0x00004410,	/* DENALI_PHY_936_DATA */
+			0x00000011,	/* DENALI_PHY_937_DATA */
+			0x00004410,	/* DENALI_PHY_938_DATA */
+			0x00000011,	/* DENALI_PHY_939_DATA */
+			0x00004410,	/* DENALI_PHY_940_DATA */
+			0x00000000,	/* DENALI_PHY_941_DATA */
+			0x00000000,	/* DENALI_PHY_942_DATA */
+			0x00000000,	/* DENALI_PHY_943_DATA */
+			0x04000000,	/* DENALI_PHY_944_DATA */
+			0x00000000,	/* DENALI_PHY_945_DATA */
+			0x00000000,	/* DENALI_PHY_946_DATA */
+			0x00000508,	/* DENALI_PHY_947_DATA */
+			0x00000000,	/* DENALI_PHY_948_DATA */
+			0x00000000,	/* DENALI_PHY_949_DATA */
+			0x00000000,	/* DENALI_PHY_950_DATA */
+			0x00000000,	/* DENALI_PHY_951_DATA */
+			0x00000000,	/* DENALI_PHY_952_DATA */
+			0x00000000,	/* DENALI_PHY_953_DATA */
+			0xe4000000,	/* DENALI_PHY_954_DATA */
+			0x00000000,	/* DENALI_PHY_955_DATA */
+			0x00000000,	/* DENALI_PHY_956_DATA */
+			0x01010000,	/* DENALI_PHY_957_DATA */
+			0x00000000	/* DENALI_PHY_958_DATA */
+		}
+	},
+},
diff --git a/arch/arm/mach-rockchip/rk3399/sdram_rk3399.c b/arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
new file mode 100644
index 0000000..67a92cc
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
@@ -0,0 +1,1121 @@ 
+/*
+ * (C) Copyright 2016 Rockchip Inc.
+ *
+ * SPDX-License-Identifier:     GPL-2.0
+ *
+ * Adapted from coreboot.
+ */
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <asm/arch/sdram_rk3399.h>
+#include <asm/arch/cru_rk3399.h>
+#include <asm/arch/grf_rk3399.h>
+#include <asm/arch/hardware.h>
+#include <linux/err.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DDRC0_BASE_ADDR         0xffa80000
+#define SERVER_MSCH0_BASE_ADDR  0xffa84000
+#define DDRC1_BASE_ADDR         0xffa88000
+#define SERVER_MSCH1_BASE_ADDR  0xffa8c000
+
+#define DDR_PI_OFFSET			0x800
+#define DDR_PHY_OFFSET			0x2000
+#define DDRC0_PI_BASE_ADDR		(DDRC0_BASE_ADDR + DDR_PI_OFFSET)
+#define DDRC0_PHY_BASE_ADDR		(DDRC0_BASE_ADDR + DDR_PHY_OFFSET)
+#define DDRC1_PI_BASE_ADDR		(DDRC1_BASE_ADDR + DDR_PI_OFFSET)
+#define DDRC1_PHY_BASE_ADDR		(DDRC1_BASE_ADDR + DDR_PHY_OFFSET)
+
+#define PMUCRU_BASE             0xff750000
+#define CRU_BASE                0xff760000
+#define PMUGRF_BASE             0xff320000
+#define PMUSGRF_BASE            0xff330000
+#define CIC_BASE_ADDR		0xff620000
+
+static struct rk3399_pmucru * const pmucru_ptr = (void *)PMUCRU_BASE;
+static struct rk3399_cru * const cru_ptr = (void *)CRU_BASE;
+static struct rk3399_pmugrf_regs * const rk3399_pmugrf = (void *)PMUGRF_BASE;
+static struct rk3399_pmusgrf_regs * const rk3399_pmusgrf = (void *)PMUSGRF_BASE;
+
+static struct rk3399_ddr_pctl_regs * const rk3399_ddr_pctl[2] = {
+	(void *)DDRC0_BASE_ADDR, (void *)DDRC1_BASE_ADDR };
+static struct rk3399_ddr_pi_regs * const rk3399_ddr_pi[2] = {
+	(void *)DDRC0_PI_BASE_ADDR, (void *)DDRC1_PI_BASE_ADDR };
+static struct rk3399_ddr_publ_regs * const rk3399_ddr_publ[2] = {
+	(void *)DDRC0_PHY_BASE_ADDR, (void *)DDRC1_PHY_BASE_ADDR };
+static struct rk3399_msch_regs * const rk3399_msch[2] = {
+	(void *)SERVER_MSCH0_BASE_ADDR, (void *)SERVER_MSCH1_BASE_ADDR };
+static struct rk3399_ddr_cic_regs *const rk3399_ddr_cic = (void *)CIC_BASE_ADDR;
+
+/*
+ * sys_reg bitfield struct
+ * [31]		row_3_4_ch1
+ * [30]		row_3_4_ch0
+ * [29:28]	chinfo
+ * [27]		rank_ch1
+ * [26:25]	col_ch1
+ * [24]		bk_ch1
+ * [23:22]	cs0_row_ch1
+ * [21:20]	cs1_row_ch1
+ * [19:18]	bw_ch1
+ * [17:16]	dbw_ch1;
+ * [15:13]	ddrtype
+ * [12]		channelnum
+ * [11]		rank_ch0
+ * [10:9]	col_ch0
+ * [8]		bk_ch0
+ * [7:6]	cs0_row_ch0
+ * [5:4]	cs1_row_ch0
+ * [3:2]	bw_ch0
+ * [1:0]	dbw_ch0
+*/
+#define SYS_REG_ENC_ROW_3_4(n, ch)	((n) << (30 + (ch)))
+#define SYS_REG_DEC_ROW_3_4(n, ch)	((n >> (30 + ch)) & 0x1)
+#define SYS_REG_ENC_CHINFO(ch)		(1 << (28 + (ch)))
+#define SYS_REG_ENC_DDRTYPE(n)		((n) << 13)
+#define SYS_REG_ENC_NUM_CH(n)		(((n) - 1) << 12)
+#define SYS_REG_DEC_NUM_CH(n)		(1 + ((n >> 12) & 0x1))
+#define SYS_REG_ENC_RANK(n, ch)		(((n) - 1) << (11 + ((ch) * 16)))
+#define SYS_REG_DEC_RANK(n, ch)		(1 + ((n >> (11 + 16 * ch)) & 0x1))
+#define SYS_REG_ENC_COL(n, ch)		(((n) - 9) << (9 + ((ch) * 16)))
+#define SYS_REG_DEC_COL(n, ch)		(9 + ((n >> (9 + 16 * ch)) & 0x3))
+#define SYS_REG_ENC_BK(n, ch)		(((n) == 3 ? 0 : 1) \
+						<< (8 + ((ch) * 16)))
+#define SYS_REG_DEC_BK(n, ch)		(3 - ((n >> (8 + 16 * ch)) & 0x1))
+#define SYS_REG_ENC_CS0_ROW(n, ch)	(((n) - 13) << (6 + ((ch) * 16)))
+#define SYS_REG_DEC_CS0_ROW(n, ch)	(13 + ((n >> (6 + 16 * ch)) & 0x3))
+#define SYS_REG_ENC_CS1_ROW(n, ch)	(((n) - 13) << (4 + ((ch) * 16)))
+#define SYS_REG_DEC_CS1_ROW(n, ch)	(13 + ((n >> (4 + 16 * ch)) & 0x3))
+#define SYS_REG_ENC_BW(n, ch)		((2 >> (n)) << (2 + ((ch) * 16)))
+#define SYS_REG_DEC_BW(n, ch)		(2 >> ((n >> (2 + 16 * ch)) & 0x3))
+#define SYS_REG_ENC_DBW(n, ch)		((2 >> (n)) << (0 + ((ch) * 16)))
+#define SYS_REG_DEC_DBW(n, ch)		(2 >> ((n >> (0 + 16 * ch)) & 0x3))
+
+#define DDR_STRIDE(n)		writel((0x1F << (10 + 16)) | (n << 10), \
+					&rk3399_pmusgrf->soc_con4)
+
+#define PRESET_SGRF_HOLD(n)	((0x1 << (6+16)) | ((n) << 6))
+#define PRESET_GPIO0_HOLD(n)	((0x1 << (7+16)) | ((n) << 7))
+#define PRESET_GPIO1_HOLD(n)	((0x1 << (8+16)) | ((n) << 8))
+
+#define PHY_DRV_ODT_Hi_Z	(0x0)
+#define PHY_DRV_ODT_240		(0x1)
+#define PHY_DRV_ODT_120		(0x8)
+#define PHY_DRV_ODT_80		(0x9)
+#define PHY_DRV_ODT_60		(0xc)
+#define PHY_DRV_ODT_48		(0xd)
+#define PHY_DRV_ODT_40		(0xe)
+#define PHY_DRV_ODT_34_3	(0xf)
+
+#ifdef CONFIG_SPL_BUILD
+static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
+{
+	int i;
+
+	for (i = 0; i < n / sizeof(u32); i++) {
+		writel(*src, dest);
+		src++;
+		dest++;
+	}
+}
+
+static void phy_dll_bypass_set(u32 channel,
+	struct rk3399_ddr_publ_regs *ddr_publ_regs, u32 freq)
+{
+	u32 *denali_phy = ddr_publ_regs->denali_phy;
+	if (freq <= 125*MHz) {
+		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
+		setbits_le32(&denali_phy[86], (0x3 << 2) << 8);
+		setbits_le32(&denali_phy[214], (0x3 << 2) << 8);
+		setbits_le32(&denali_phy[342], (0x3 << 2) << 8);
+		setbits_le32(&denali_phy[470], (0x3 << 2) << 8);
+
+		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
+		setbits_le32(&denali_phy[547], (0x3 << 2) << 16);
+		setbits_le32(&denali_phy[675], (0x3 << 2) << 16);
+		setbits_le32(&denali_phy[803], (0x3 << 2) << 16);
+	} else {
+		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
+		clrbits_le32(&denali_phy[86], (0x3 << 2) << 8);
+		clrbits_le32(&denali_phy[214], (0x3 << 2) << 8);
+		clrbits_le32(&denali_phy[342], (0x3 << 2) << 8);
+		clrbits_le32(&denali_phy[470], (0x3 << 2) << 8);
+
+		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
+		clrbits_le32(&denali_phy[547], (0x3 << 2) << 16);
+		clrbits_le32(&denali_phy[675], (0x3 << 2) << 16);
+		clrbits_le32(&denali_phy[803], (0x3 << 2) << 16);
+	}
+}
+
+static void set_memory_map(u32 channel,
+			   const struct rk3399_sdram_params *sdram_params)
+{
+	const struct rk3399_sdram_channel *sdram_ch =
+		&sdram_params->ch[channel];
+	u32 *denali_ctl = rk3399_ddr_pctl[channel]->denali_ctl;
+	u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
+	u32 cs_map;
+	u32 reduc;
+	u32 row;
+
+	if ((sdram_ch->ddrconfig < 2) || (sdram_ch->ddrconfig == 4))
+		row = 16;
+	else if (sdram_ch->ddrconfig == 3)
+		row = 14;
+	else
+		row = 15;
+
+	cs_map = (sdram_ch->rank > 1) ? 3 : 1;
+	reduc = (sdram_ch->bw == 2) ? 0 : 1;
+
+	clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->col));
+	clrsetbits_le32(&denali_ctl[190], (0x3 << 16) | (0x7 << 24),
+			((3 - sdram_ch->bk) << 16) |
+			((16 - row) << 24));
+
+	clrsetbits_le32(&denali_ctl[196], 0x3 | (1 << 16),
+			cs_map | (reduc << 16));
+
+	/* PI_199 PI_COL_DIFF:RW:0:4 */
+	clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->col));
+
+	/* PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2 */
+	clrsetbits_le32(&denali_pi[155], (0x3 << 16) | (0x7 << 24),
+			((3 - sdram_ch->bk) << 16) |
+			((16 - row) << 24));
+	/* PI_41 PI_CS_MAP:RW:24:4 */
+	clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24);
+	if ((sdram_ch->rank == 1) && (sdram_params->dramtype == DDR3))
+		writel(0x2EC7FFFF, &denali_pi[34]);
+}
+
+static void set_ds_odt(u32 channel,
+		       const struct rk3399_sdram_params *sdram_params)
+{
+	u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+
+	u32 tsel_idle_en, tsel_wr_en, tsel_rd_en;
+	u32 tsel_idle_select_p, tsel_wr_select_p, tsel_rd_select_p;
+	u32 ca_tsel_wr_select_p, ca_tsel_wr_select_n;
+	u32 tsel_idle_select_n, tsel_wr_select_n, tsel_rd_select_n;
+	u32 reg_value;
+
+	if (sdram_params->dramtype == LPDDR4) {
+		tsel_rd_select_p = PHY_DRV_ODT_Hi_Z;
+		tsel_wr_select_p = PHY_DRV_ODT_40;
+		ca_tsel_wr_select_p = PHY_DRV_ODT_40;
+		tsel_idle_select_p = PHY_DRV_ODT_Hi_Z;
+
+		tsel_rd_select_n = PHY_DRV_ODT_240;
+		tsel_wr_select_n = PHY_DRV_ODT_40;
+		ca_tsel_wr_select_n = PHY_DRV_ODT_40;
+		tsel_idle_select_n = PHY_DRV_ODT_240;
+	} else if (sdram_params->dramtype == LPDDR3) {
+		tsel_rd_select_p = PHY_DRV_ODT_240;
+		tsel_wr_select_p = PHY_DRV_ODT_34_3;
+		ca_tsel_wr_select_p = PHY_DRV_ODT_48;
+		tsel_idle_select_p = PHY_DRV_ODT_240;
+
+		tsel_rd_select_n = PHY_DRV_ODT_Hi_Z;
+		tsel_wr_select_n = PHY_DRV_ODT_34_3;
+		ca_tsel_wr_select_n = PHY_DRV_ODT_48;
+		tsel_idle_select_n = PHY_DRV_ODT_Hi_Z;
+	} else {
+		tsel_rd_select_p = PHY_DRV_ODT_240;
+		tsel_wr_select_p = PHY_DRV_ODT_34_3;
+		ca_tsel_wr_select_p = PHY_DRV_ODT_34_3;
+		tsel_idle_select_p = PHY_DRV_ODT_240;
+
+		tsel_rd_select_n = PHY_DRV_ODT_240;
+		tsel_wr_select_n = PHY_DRV_ODT_34_3;
+		ca_tsel_wr_select_n = PHY_DRV_ODT_34_3;
+		tsel_idle_select_n = PHY_DRV_ODT_240;
+	}
+
+	if (sdram_params->odt == 1)
+		tsel_rd_en = 1;
+	else
+		tsel_rd_en = 0;
+
+	tsel_wr_en = 0;
+	tsel_idle_en = 0;
+
+	/*
+	 * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0
+	 * sets termination values for read/idle cycles and drive strength
+	 * for write cycles for DQ/DM
+	 */
+	reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) |
+		    (tsel_wr_select_n << 8) | (tsel_wr_select_p << 12) |
+		    (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20);
+	clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value);
+	clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value);
+	clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value);
+	clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value);
+
+	/*
+	 * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0
+	 * sets termination values for read/idle cycles and drive strength
+	 * for write cycles for DQS
+	 */
+	clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value);
+	clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value);
+	clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value);
+	clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value);
+
+	/* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
+	reg_value = ca_tsel_wr_select_n | (ca_tsel_wr_select_p << 0x4);
+	clrsetbits_le32(&denali_phy[544], 0xff, reg_value);
+	clrsetbits_le32(&denali_phy[672], 0xff, reg_value);
+	clrsetbits_le32(&denali_phy[800], 0xff, reg_value);
+
+	/* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */
+	clrsetbits_le32(&denali_phy[928], 0xff, reg_value);
+
+	/* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */
+	clrsetbits_le32(&denali_phy[937], 0xff, reg_value);
+
+	/* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */
+	clrsetbits_le32(&denali_phy[935], 0xff, reg_value);
+
+	/* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */
+	clrsetbits_le32(&denali_phy[939], 0xff, reg_value);
+
+	/* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */
+	clrsetbits_le32(&denali_phy[929], 0xff, reg_value);
+
+	/* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
+	clrsetbits_le32(&denali_phy[924], 0xff,
+			tsel_wr_select_n | (tsel_wr_select_p << 4));
+	clrsetbits_le32(&denali_phy[925], 0xff,
+			tsel_rd_select_n | (tsel_rd_select_p << 4));
+
+	/* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
+	reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
+		<< 16;
+	clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value);
+	clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value);
+	clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value);
+	clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value);
+
+	/* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */
+	reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
+		<< 24;
+	clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value);
+	clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value);
+	clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value);
+	clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value);
+
+	/* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */
+	reg_value = tsel_wr_en << 8;
+	clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value);
+	clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value);
+	clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value);
+
+	/* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */
+	reg_value = tsel_wr_en << 17;
+	clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value);
+	/*
+	 * pad_rst/cke/cs/clk_term tsel 1bits
+	 * DENALI_PHY_938/936/940/934 offset_17
+	 */
+	clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value);
+	clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value);
+	clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value);
+	clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value);
+
+	/* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */
+	clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value);
+}
+
+static void phy_io_config(u32 channel,
+			  const struct rk3399_sdram_params *sdram_params)
+{
+	u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+	u32 vref_mode_dq = 0;
+	u32 vref_value_dq = 0;
+	u32 vref_mode_ac = 0;
+	u32 vref_value_ac = 0;
+	u32 mode_sel = 0;
+	u32 reg_value;
+	u32 drv_value, odt_value;
+	u32 speed;
+
+	/* vref setting */
+	if (sdram_params->dramtype == LPDDR4) {
+		/* LPDDR4 */
+		vref_mode_dq = 0x6;
+		vref_value_dq = 0x1f;
+		vref_mode_ac = 0x6;
+		vref_value_ac = 0x1f;
+	} else if (sdram_params->dramtype == LPDDR3) {
+		if (sdram_params->odt == 1) {
+			vref_mode_dq = 0x5;  /* LPDDR3 ODT */
+			drv_value = (readl(&denali_phy[6]) >> 12) & 0xf;
+			odt_value = (readl(&denali_phy[6]) >> 4) & 0xf;
+			if (drv_value == PHY_DRV_ODT_48) {
+				switch (odt_value) {
+				case PHY_DRV_ODT_240:
+					vref_value_dq = 0x16;
+					break;
+				case PHY_DRV_ODT_120:
+					vref_value_dq = 0x26;
+					break;
+				case PHY_DRV_ODT_60:
+					vref_value_dq = 0x36;
+					break;
+				default:
+					error("Halting: Invalid ODT value.\n");
+				}
+			} else if (drv_value == PHY_DRV_ODT_40) {
+				switch (odt_value) {
+				case PHY_DRV_ODT_240:
+					vref_value_dq = 0x19;
+					break;
+				case PHY_DRV_ODT_120:
+					vref_value_dq = 0x23;
+					break;
+				case PHY_DRV_ODT_60:
+					vref_value_dq = 0x31;
+					break;
+				default:
+					error("Halting: Invalid ODT value.\n");
+				}
+			} else if (drv_value == PHY_DRV_ODT_34_3) {
+				switch (odt_value) {
+				case PHY_DRV_ODT_240:
+					vref_value_dq = 0x17;
+					break;
+				case PHY_DRV_ODT_120:
+					vref_value_dq = 0x20;
+					break;
+				case PHY_DRV_ODT_60:
+					vref_value_dq = 0x2e;
+					break;
+				default:
+					error("Halting: Invalid ODT value.\n");
+				}
+			} else {
+				error("Halting: Invalid DRV value.\n");
+			}
+		} else {
+			vref_mode_dq = 0x2;  /* LPDDR3 */
+			vref_value_dq = 0x1f;
+		}
+		vref_mode_ac = 0x2;
+		vref_value_ac = 0x1f;
+	} else if (sdram_params->dramtype == DDR3) {
+		/* DDR3L */
+		vref_mode_dq = 0x1;
+		vref_value_dq = 0x1f;
+		vref_mode_ac = 0x1;
+		vref_value_ac = 0x1f;
+	}
+	else
+		error("Halting: Unknown DRAM type.\n");
+
+	reg_value = (vref_mode_dq << 9) | (0x1 << 8) | vref_value_dq;
+
+	/* PHY_913 PHY_PAD_VREF_CTRL_DQ_0 12bits offset_8 */
+	clrsetbits_le32(&denali_phy[913], 0xfff << 8, reg_value << 8);
+	/* PHY_914 PHY_PAD_VREF_CTRL_DQ_1 12bits offset_0 */
+	clrsetbits_le32(&denali_phy[914], 0xfff, reg_value);
+	/* PHY_914 PHY_PAD_VREF_CTRL_DQ_2 12bits offset_16 */
+	clrsetbits_le32(&denali_phy[914], 0xfff << 16, reg_value << 16);
+	/* PHY_915 PHY_PAD_VREF_CTRL_DQ_3 12bits offset_0 */
+	clrsetbits_le32(&denali_phy[915], 0xfff, reg_value);
+
+	reg_value = (vref_mode_ac << 9) | (0x1 << 8) | vref_value_ac;
+
+	/* PHY_915 PHY_PAD_VREF_CTRL_AC 12bits offset_16 */
+	clrsetbits_le32(&denali_phy[915], 0xfff << 16, reg_value << 16);
+
+	if (sdram_params->dramtype == LPDDR4)
+		mode_sel = 0x6;
+	else if (sdram_params->dramtype == LPDDR3)
+		mode_sel = 0x0;
+	else if (sdram_params->dramtype == DDR3)
+		mode_sel = 0x1;
+
+	/* PHY_924 PHY_PAD_FDBK_DRIVE */
+	clrsetbits_le32(&denali_phy[924], 0x7 << 15, mode_sel << 15);
+	/* PHY_926 PHY_PAD_DATA_DRIVE */
+	clrsetbits_le32(&denali_phy[926], 0x7 << 6, mode_sel << 6);
+	/* PHY_927 PHY_PAD_DQS_DRIVE */
+	clrsetbits_le32(&denali_phy[927], 0x7 << 6, mode_sel << 6);
+	/* PHY_928 PHY_PAD_ADDR_DRIVE */
+	clrsetbits_le32(&denali_phy[928], 0x7 << 14, mode_sel << 14);
+	/* PHY_929 PHY_PAD_CLK_DRIVE */
+	clrsetbits_le32(&denali_phy[929], 0x7 << 14, mode_sel << 14);
+	/* PHY_935 PHY_PAD_CKE_DRIVE */
+	clrsetbits_le32(&denali_phy[935], 0x7 << 14, mode_sel << 14);
+	/* PHY_937 PHY_PAD_RST_DRIVE */
+	clrsetbits_le32(&denali_phy[937], 0x7 << 14, mode_sel << 14);
+	/* PHY_939 PHY_PAD_CS_DRIVE */
+	clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14);
+
+
+	/* speed setting */
+	if (sdram_params->ddr_freq < 400*MHz)
+		speed = 0x0;
+	else if (sdram_params->ddr_freq < 800*MHz)
+		speed = 0x1;
+	else if (sdram_params->ddr_freq < 1200*MHz)
+		speed = 0x2;
+	else
+		speed = 0x3;
+
+	/* PHY_924 PHY_PAD_FDBK_DRIVE */
+	clrsetbits_le32(&denali_phy[924], 0x3 << 21, speed << 21);
+	/* PHY_926 PHY_PAD_DATA_DRIVE */
+	clrsetbits_le32(&denali_phy[926], 0x3 << 9, speed << 9);
+	/* PHY_927 PHY_PAD_DQS_DRIVE */
+	clrsetbits_le32(&denali_phy[927], 0x3 << 9, speed << 9);
+	/* PHY_928 PHY_PAD_ADDR_DRIVE */
+	clrsetbits_le32(&denali_phy[928], 0x3 << 17, speed << 17);
+	/* PHY_929 PHY_PAD_CLK_DRIVE */
+	clrsetbits_le32(&denali_phy[929], 0x3 << 17, speed << 17);
+	/* PHY_935 PHY_PAD_CKE_DRIVE */
+	clrsetbits_le32(&denali_phy[935], 0x3 << 17, speed << 17);
+	/* PHY_937 PHY_PAD_RST_DRIVE */
+	clrsetbits_le32(&denali_phy[937], 0x3 << 17, speed << 17);
+	/* PHY_939 PHY_PAD_CS_DRIVE */
+	clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
+}
+
+static int pctl_cfg(u32 channel,
+		    const struct rk3399_sdram_params *sdram_params)
+{
+	u32 *denali_ctl = rk3399_ddr_pctl[channel]->denali_ctl;
+	u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
+	u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+	const u32 *params_ctl = sdram_params->pctl_regs.denali_ctl;
+	const u32 *params_phy = sdram_params->phy_regs.denali_phy;
+	u32 tmp, tmp1, tmp2;
+	u32 pwrup_srefresh_exit;
+
+	/*
+	 * work around controller bug:
+	 * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
+	 */
+	copy_to_reg(&denali_ctl[1], &params_ctl[1],
+		    sizeof(struct rk3399_ddr_pctl_regs) - 4);
+	writel(params_ctl[0], &denali_ctl[0]);
+	copy_to_reg(denali_pi, &sdram_params->pi_regs.denali_pi[0],
+		    sizeof(struct rk3399_ddr_pi_regs));
+	/* rank count need to set for init */
+	set_memory_map(channel, sdram_params);
+
+	writel(sdram_params->phy_regs.denali_phy[910], &denali_phy[910]);
+	writel(sdram_params->phy_regs.denali_phy[911], &denali_phy[911]);
+	writel(sdram_params->phy_regs.denali_phy[912], &denali_phy[912]);
+
+	pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT;
+	clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
+
+	/* PHY_DLL_RST_EN */
+	clrsetbits_le32(&denali_phy[957], 0x3 << 24, 1 << 24);
+
+	setbits_le32(&denali_pi[0], START);
+	setbits_le32(&denali_ctl[0], START);
+
+	while (1) {
+		tmp = readl(&denali_phy[920]);
+		tmp1 = readl(&denali_phy[921]);
+		tmp2 = readl(&denali_phy[922]);
+		if ((((tmp >> 16) & 0x1) == 0x1) &&
+		    (((tmp1 >> 16) & 0x1) == 0x1) &&
+		    (((tmp1 >> 0) & 0x1) == 0x1) &&
+		    (((tmp2 >> 0) & 0x1) == 0x1))
+			break;
+	}
+
+	copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
+	copy_to_reg(&denali_phy[0], &params_phy[0], (90 - 0 + 1) * 4);
+	copy_to_reg(&denali_phy[128], &params_phy[128], (218 - 128 + 1) * 4);
+	copy_to_reg(&denali_phy[256], &params_phy[256], (346 - 256 + 1) * 4);
+	copy_to_reg(&denali_phy[384], &params_phy[384], (474 - 384 + 1) * 4);
+	copy_to_reg(&denali_phy[512], &params_phy[512], (549 - 512 + 1) * 4);
+	copy_to_reg(&denali_phy[640], &params_phy[640], (677 - 640 + 1) * 4);
+	copy_to_reg(&denali_phy[768], &params_phy[768], (805 - 768 + 1) * 4);
+	set_ds_odt(channel, sdram_params);
+
+	/*
+	 * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
+	 * dqs_tsel_wr_end[7:4] add Half cycle
+	 */
+	tmp = (readl(&denali_phy[84]) >> 8) & 0xff;
+	clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8);
+	tmp = (readl(&denali_phy[212]) >> 8) & 0xff;
+	clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8);
+	tmp = (readl(&denali_phy[340]) >> 8) & 0xff;
+	clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8);
+	tmp = (readl(&denali_phy[468]) >> 8) & 0xff;
+	clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8);
+
+	/*
+	 * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8
+	 * dq_tsel_wr_end[7:4] add Half cycle
+	 */
+	tmp = (readl(&denali_phy[83]) >> 16) & 0xff;
+	clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16);
+	tmp = (readl(&denali_phy[211]) >> 16) & 0xff;
+	clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16);
+	tmp = (readl(&denali_phy[339]) >> 16) & 0xff;
+	clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16);
+	tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
+	clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
+
+	phy_io_config(channel, sdram_params);
+
+	/* PHY_DLL_RST_EN */
+	clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
+
+	/*
+	 * FIXME:
+	 * need to care ERROR bit,
+	 * if 100ms do not get right status, return err
+	 */
+	tmp = 0;
+	while (!(readl(&denali_ctl[203]) & (1 << 3))) {
+		mdelay(10);
+		tmp ++;
+		if (tmp > 10)
+			return -1;
+	}
+
+	clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
+			pwrup_srefresh_exit);
+	return 0;
+}
+
+static void select_per_cs_training_index(u32 channel, u32 rank)
+{
+	u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+
+	/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
+	if ((readl(&denali_phy[84])>>16) & 1) {
+		/*
+		 * PHY_8/136/264/392
+		 * phy_per_cs_training_index_X 1bit offset_24
+		 */
+		clrsetbits_le32(&denali_phy[8], 0x1 << 24, rank << 24);
+		clrsetbits_le32(&denali_phy[136], 0x1 << 24, rank << 24);
+		clrsetbits_le32(&denali_phy[264], 0x1 << 24, rank << 24);
+		clrsetbits_le32(&denali_phy[392], 0x1 << 24, rank << 24);
+	}
+}
+
+static void override_write_leveling_value(u32 channel)
+{
+	u32 *denali_ctl = rk3399_ddr_pctl[channel]->denali_ctl;
+	u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+	u32 byte;
+
+	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
+	setbits_le32(&denali_phy[896], 1);
+
+	/*
+	 * PHY_8/136/264/392
+	 * phy_per_cs_training_multicast_en_X 1bit offset_16
+	 */
+	clrsetbits_le32(&denali_phy[8], 0x1 << 16, 1 << 16);
+	clrsetbits_le32(&denali_phy[136], 0x1 << 16, 1 << 16);
+	clrsetbits_le32(&denali_phy[264], 0x1 << 16, 1 << 16);
+	clrsetbits_le32(&denali_phy[392], 0x1 << 16, 1 << 16);
+
+	for (byte = 0; byte < 4; byte++)
+		clrsetbits_le32(&denali_phy[63 + (128 * byte)], 0xffff << 16,
+			0x200 << 16);
+
+	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
+	clrbits_le32(&denali_phy[896], 1);
+
+	/* CTL_200 ctrlupd_req 1bit offset_8 */
+	clrsetbits_le32(&denali_ctl[200], 0x1 << 8, 0x1 << 8);
+}
+
+static int data_training(u32 channel,
+			 const struct rk3399_sdram_params *sdram_params,
+			 u32 training_flag)
+{
+	u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
+	u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+	u32 i, tmp;
+	u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
+	u32 rank = sdram_params->ch[channel].rank;
+
+	/* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
+	setbits_le32(&denali_phy[927], (1 << 22));
+
+	if (training_flag == PI_FULL_TRAINING) {
+		if (sdram_params->dramtype == LPDDR4) {
+			training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING |
+					PI_READ_LEVELING | PI_WDQ_LEVELING;
+		} else if (sdram_params->dramtype == LPDDR3) {
+			training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING;
+		} else if (sdram_params->dramtype == DDR3) {
+			training_flag = PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING |
+					PI_READ_LEVELING;
+		}
+	}
+
+	/* ca training(LPDDR4,LPDDR3 support) */
+	if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(channel, i);
+			/* PI_100 PI_CALVL_EN:RW:8:2 */
+			clrsetbits_le32(&denali_pi[100], 0x3 << 8, 0x2 << 8);
+			/* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
+			clrsetbits_le32(&denali_pi[92],
+					(0x1 << 16) | (0x3 << 24),
+					(0x1 << 16) | (i << 24));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = readl(&denali_pi[174]) >> 8;
+				/*
+				 * check status obs
+				 * PHY_532/660/789 phy_adr_calvl_obs1_:0:32
+				 */
+				obs_0 = readl(&denali_phy[532]);
+				obs_1 = readl(&denali_phy[660]);
+				obs_2 = readl(&denali_phy[788]);
+				if (((obs_0 >> 30) & 0x3) ||
+				    ((obs_1 >> 30) & 0x3) ||
+				    ((obs_2 >> 30) & 0x3))
+					obs_err = 1;
+				if ((((tmp >> 11) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 5) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 5) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			writel(0x00003f7c, (&denali_pi[175]));
+		}
+		clrbits_le32(&denali_pi[100], 0x3 << 8);
+	}
+
+	/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(channel, i);
+			/* PI_60 PI_WRLVL_EN:RW:8:2 */
+			clrsetbits_le32(&denali_pi[60], 0x3 << 8, 0x2 << 8);
+			/* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
+			clrsetbits_le32(&denali_pi[59],
+					(0x1 << 8) | (0x3 << 16),
+					(0x1 << 8) | (i << 16));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = readl(&denali_pi[174]) >> 8;
+
+				/*
+				 * check status obs, if error maybe can not
+				 * get leveling done PHY_40/168/296/424
+				 * phy_wrlvl_status_obs_X:0:13
+				 */
+				obs_0 = readl(&denali_phy[40]);
+				obs_1 = readl(&denali_phy[168]);
+				obs_2 = readl(&denali_phy[296]);
+				obs_3 = readl(&denali_phy[424]);
+				if (((obs_0 >> 12) & 0x1) ||
+				    ((obs_1 >> 12) & 0x1) ||
+				    ((obs_2 >> 12) & 0x1) ||
+				    ((obs_3 >> 12) & 0x1))
+					obs_err = 1;
+				if ((((tmp >> 10) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 4) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 4) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			writel(0x00003f7c, (&denali_pi[175]));
+		}
+
+		override_write_leveling_value(channel);
+		clrbits_le32(&denali_pi[60], 0x3 << 8);
+	}
+
+	/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(channel, i);
+			/* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
+			clrsetbits_le32(&denali_pi[80], 0x3 << 24, 0x2 << 24);
+			/*
+			 * PI_74 PI_RDLVL_GATE_REQ:WR:16:1
+			 * PI_RDLVL_CS:RW:24:2
+			 */
+			clrsetbits_le32(&denali_pi[74],
+					(0x1 << 16) | (0x3 << 24),
+					(0x1 << 16) | (i << 24));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = readl(&denali_pi[174]) >> 8;
+
+				/*
+				 * check status obs
+				 * PHY_43/171/299/427
+				 *     PHY_GTLVL_STATUS_OBS_x:16:8
+				 */
+				obs_0 = readl(&denali_phy[43]);
+				obs_1 = readl(&denali_phy[171]);
+				obs_2 = readl(&denali_phy[299]);
+				obs_3 = readl(&denali_phy[427]);
+				if (((obs_0 >> (16 + 6)) & 0x3) ||
+				    ((obs_1 >> (16 + 6)) & 0x3) ||
+				    ((obs_2 >> (16 + 6)) & 0x3) ||
+				    ((obs_3 >> (16 + 6)) & 0x3))
+					obs_err = 1;
+				if ((((tmp >> 9) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 3) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 3) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			writel(0x00003f7c, (&denali_pi[175]));
+		}
+		clrbits_le32(&denali_pi[80], 0x3 << 24);
+	}
+
+	/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(channel, i);
+			/* PI_80 PI_RDLVL_EN:RW:16:2 */
+			clrsetbits_le32(&denali_pi[80], 0x3 << 16, 0x2 << 16);
+			/* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
+			clrsetbits_le32(&denali_pi[74],
+					(0x1 << 8) | (0x3 << 24),
+					(0x1 << 8) | (i << 24));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = readl(&denali_pi[174]) >> 8;
+
+				/*
+				 * make sure status obs not report error bit
+				 * PHY_46/174/302/430
+				 *     phy_rdlvl_status_obs_X:16:8
+				 */
+				if ((((tmp >> 8) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 2) & 0x1) == 0x0))
+					break;
+				else if (((tmp >> 2) & 0x1) == 0x1)
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			writel(0x00003f7c, (&denali_pi[175]));
+		}
+		clrbits_le32(&denali_pi[80], 0x3 << 16);
+	}
+
+	/* wdq leveling(LPDDR4 support) */
+	if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(channel, i);
+			/*
+			 * disable PI_WDQLVL_VREF_EN before wdq leveling?
+			 * PI_181 PI_WDQLVL_VREF_EN:RW:8:1
+			 */
+			clrbits_le32(&denali_pi[181], 0x1 << 8);
+			/* PI_124 PI_WDQLVL_EN:RW:16:2 */
+			clrsetbits_le32(&denali_pi[124], 0x3 << 16, 0x2 << 16);
+			/* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
+			clrsetbits_le32(&denali_pi[121],
+					(0x1 << 8) | (0x3 << 16),
+					(0x1 << 8) | (i << 16));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = readl(&denali_pi[174]) >> 8;
+				if ((((tmp >> 12) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 6) & 0x1) == 0x0))
+					break;
+				else if (((tmp >> 6) & 0x1) == 0x1)
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			writel(0x00003f7c, (&denali_pi[175]));
+		}
+		clrbits_le32(&denali_pi[124], 0x3 << 16);
+	}
+
+	/* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
+	clrbits_le32(&denali_phy[927], (1 << 22));
+
+	return 0;
+}
+
+static void set_ddrconfig(const struct rk3399_sdram_params *sdram_params,
+			  unsigned char channel, u32 ddrconfig)
+{
+	/* only need to set ddrconfig */
+	struct rk3399_msch_regs *ddr_msch_regs = rk3399_msch[channel];
+	unsigned int cs0_cap = 0;
+	unsigned int cs1_cap = 0;
+
+	cs0_cap = (1 << (sdram_params->ch[channel].cs0_row
+			+ sdram_params->ch[channel].col
+			+ sdram_params->ch[channel].bk
+			+ sdram_params->ch[channel].bw - 20));
+	if (sdram_params->ch[channel].rank > 1)
+		cs1_cap = cs0_cap >> (sdram_params->ch[channel].cs0_row
+				- sdram_params->ch[channel].cs1_row);
+	if (sdram_params->ch[channel].row_3_4) {
+		cs0_cap = cs0_cap * 3 / 4;
+		cs1_cap = cs1_cap * 3 / 4;
+	}
+
+	writel(ddrconfig | (ddrconfig << 8), &ddr_msch_regs->ddrconf);
+	writel(((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8),
+		&ddr_msch_regs->ddrsize);
+}
+
+static void dram_all_config(const struct rk3399_sdram_params *sdram_params)
+{
+	u32 sys_reg = 0;
+	unsigned int channel;
+	unsigned int use;
+
+	sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype);
+	sys_reg |= SYS_REG_ENC_NUM_CH(sdram_params->num_channels);
+	for (channel = 0, use = 0;
+	     (use < sdram_params->num_channels) && (channel < 2); channel++) {
+		const struct rk3399_sdram_channel *info =
+			&sdram_params->ch[channel];
+		struct rk3399_msch_regs *ddr_msch_regs;
+		const struct rk3399_msch_timings *noc_timing;
+
+		if (sdram_params->ch[channel].col == 0)
+			continue;
+		use++;
+		sys_reg |= SYS_REG_ENC_ROW_3_4(info->row_3_4, channel);
+		sys_reg |= SYS_REG_ENC_CHINFO(channel);
+		sys_reg |= SYS_REG_ENC_RANK(info->rank, channel);
+		sys_reg |= SYS_REG_ENC_COL(info->col, channel);
+		sys_reg |= SYS_REG_ENC_BK(info->bk, channel);
+		sys_reg |= SYS_REG_ENC_CS0_ROW(info->cs0_row, channel);
+		if (sdram_params->ch[channel].rank > 1)
+			sys_reg |= SYS_REG_ENC_CS1_ROW(info->cs1_row, channel);
+		sys_reg |= SYS_REG_ENC_BW(info->bw, channel);
+		sys_reg |= SYS_REG_ENC_DBW(info->dbw, channel);
+
+		ddr_msch_regs = rk3399_msch[channel];
+		noc_timing = &sdram_params->ch[channel].noc_timings;
+		writel(noc_timing->ddrtiminga0.d32,
+		       &ddr_msch_regs->ddrtiminga0.d32);
+		writel(noc_timing->ddrtimingb0.d32,
+			&ddr_msch_regs->ddrtimingb0.d32);
+		writel(noc_timing->ddrtimingc0.d32,
+			&ddr_msch_regs->ddrtimingc0.d32);
+		writel(noc_timing->devtodev0.d32,
+			&ddr_msch_regs->devtodev0.d32);
+		writel(noc_timing->ddrmode.d32,
+			&ddr_msch_regs->ddrmode.d32);
+
+		/* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
+		if (sdram_params->ch[channel].rank == 1)
+			setbits_le32(&rk3399_ddr_pctl[channel]->denali_ctl[276],
+				     1 << 17);
+	}
+
+	writel(sys_reg, &rk3399_pmugrf->os_reg2);
+	DDR_STRIDE(sdram_params->stride);
+
+	/* reboot hold register set */
+	writel(PRESET_SGRF_HOLD(0) | PRESET_GPIO0_HOLD(1) |
+		PRESET_GPIO1_HOLD(1),
+		&pmucru_ptr->pmucru_rstnhold_con[1]);
+	clrsetbits_le32(&cru_ptr->glb_rst_con, 0x3, 0x3);
+}
+
+static void switch_to_phy_index1(const struct rk3399_sdram_params *sdram_params)
+{
+	u32 channel;
+	u32 *denali_phy;
+	u32 ch_count = sdram_params->num_channels;
+	int i = 0;
+
+	writel(RK_CLRSETBITS(0x03 << 4 | 1 << 2 | 1,
+			      1 << 4 | 1 << 2 | 1),
+			&rk3399_ddr_cic->cic_ctrl0);
+	while (!(readl(&rk3399_ddr_cic->cic_status0) & (1 << 2))) {
+		mdelay(10);
+		i++;
+		if (i > 10) {
+			error("index1 frequency change overtime, reset\n");
+			hang();
+		}
+	}
+
+	i = 0;
+	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &rk3399_ddr_cic->cic_ctrl0);
+	while (!(readl(&rk3399_ddr_cic->cic_status0) & (1 << 0))) {
+		mdelay(10);
+		if (i>10) {
+			error("index1 frequency done overtime, reset\n");
+			hang();
+		}
+	}
+
+	for (channel = 0; channel < ch_count; channel++) {
+		denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+		clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8);
+		if (data_training(channel, sdram_params, PI_FULL_TRAINING)) {
+			error("index1 training failed, reset\n");
+			hang();
+		}
+	}
+}
+static struct rk3399_sdram_params sdram_configs[] = {
+#include "sdram-lpddr3-4GB.inc"
+};
+
+void sdram_init(const struct rk3399_sdram_params *sdram_params)
+{
+	unsigned char dramtype = sdram_params->dramtype;
+	unsigned int ddr_freq = sdram_params->ddr_freq;
+	int channel;
+
+	debug("Starting SDRAM initialization...\n");
+
+	if ((dramtype == DDR3 && ddr_freq > 800*MHz) ||
+	    (dramtype == LPDDR3 && ddr_freq > 933*MHz) ||
+	    (dramtype == LPDDR4 && ddr_freq > 800*MHz))
+		error("SDRAM frequency is to high!");
+
+
+	for (channel = 0; channel < 2; channel++) {
+		phy_dll_bypass_set(channel, rk3399_ddr_publ[channel], ddr_freq);
+
+		if (channel >= sdram_params->num_channels)
+			continue;
+
+		/*
+		 * TODO: we need to find the root cause why this
+		 * step may fail, before that, we just reset the
+		 * system, and start again.
+		 */
+		if (pctl_cfg(channel, sdram_params) != 0) {
+			printf("pctl_cfg fail, reset\n");
+			hang();
+		}
+
+		/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
+		if (dramtype == LPDDR3)
+			udelay(10);
+
+		if (data_training(channel, sdram_params, PI_FULL_TRAINING)) {
+			printf("SDRAM initialization failed, reset\n");
+			hang();
+		}
+
+		set_ddrconfig(sdram_params, channel,
+			      sdram_params->ch[channel].ddrconfig);
+	}
+	dram_all_config(sdram_params);
+	switch_to_phy_index1(sdram_params);
+
+	debug("Finish SDRAM initialization...\n");
+}
+#endif
+
+size_t sdram_size_mb(void)
+{
+	u32 rank, col, bk, cs0_row, cs1_row, bw, row_3_4;
+	size_t chipsize_mb = 0;
+	static size_t size_mb = 0;
+	u32 ch;
+
+	if (!size_mb) {
+		u32 sys_reg = readl(&rk3399_pmugrf->os_reg2);
+		u32 ch_num = SYS_REG_DEC_NUM_CH(sys_reg);
+
+		for (ch = 0; ch < ch_num; ch++) {
+			rank = SYS_REG_DEC_RANK(sys_reg, ch);
+			col = SYS_REG_DEC_COL(sys_reg, ch);
+			bk = SYS_REG_DEC_BK(sys_reg, ch);
+			cs0_row = SYS_REG_DEC_CS0_ROW(sys_reg, ch);
+			cs1_row = SYS_REG_DEC_CS1_ROW(sys_reg, ch);
+			bw = SYS_REG_DEC_BW(sys_reg, ch);
+			row_3_4 = SYS_REG_DEC_ROW_3_4(sys_reg, ch);
+
+			chipsize_mb = (1 << (cs0_row + col + bk + bw - 20));
+
+			if (rank > 1)
+				chipsize_mb += chipsize_mb >>
+					(cs0_row - cs1_row);
+			if (row_3_4)
+				chipsize_mb = chipsize_mb * 3 / 4;
+			size_mb += chipsize_mb;
+		}
+
+		/*
+		 * we use the 0x00000000~0xf7ffffff space
+		 * since 0xf8000000~0xffffffff is soc register space
+		 * so we reserve it
+		 */
+		size_mb = min_t(size_t, size_mb, 0xf8000000/(1<<20));
+	}
+
+	return size_mb;
+}
+
+static int rk3399_dmc_probe(struct udevice *dev)
+{
+#ifdef CONFIG_SPL_BUILD
+	struct rk3399_sdram_params *plat = sdram_configs;
+	int ret;
+	struct clk ddr_clk;
+
+	ret = clk_get_by_index(dev, 0, &ddr_clk);
+	if (ret){
+		debug("%s clk get failed %d\n", __func__, ret);
+		return ret;
+	}
+	ret = clk_set_rate(&ddr_clk, plat->ddr_freq);
+	if (ret < 0){
+		debug("%s clk set failed %d\n", __func__, ret);
+		return ret;
+	}
+	sdram_init(plat);
+#endif
+	return 0;
+}
+
+static const struct udevice_id rk3399_dmc_ids[] = {
+	{ .compatible = "rockchip,rk3399-dmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(dmc_rk3399) = {
+	.name = "rockchip_rk3399_dmc",
+	.id = UCLASS_RAM,
+	.of_match = rk3399_dmc_ids,
+	.probe = rk3399_dmc_probe,
+};