From: Kever Yang <kever.y...@rock-chips.com>

Add core architecture code to support the px30 soc.
This includes a separate tpl board file due to very limited
sram size as well as a non-dm sdram driver, as this also has
to fit into the tiny sram.

Signed-off-by: Kever Yang <kever.y...@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko.stueb...@theobroma-systems.com>
---
 arch/arm/include/asm/arch-px30/boot0.h        |   11 +
 arch/arm/include/asm/arch-px30/gpio.h         |   11 +
 .../include/asm/arch-rockchip/sdram_px30.h    |  359 +++++
 arch/arm/mach-rockchip/Kconfig                |   23 +
 arch/arm/mach-rockchip/Makefile               |    2 +
 arch/arm/mach-rockchip/px30-board-tpl.c       |   59 +
 arch/arm/mach-rockchip/px30/Kconfig           |   48 +
 arch/arm/mach-rockchip/px30/Makefile          |   14 +
 arch/arm/mach-rockchip/px30/clk_px30.c        |   31 +
 arch/arm/mach-rockchip/px30/px30.c            |  248 +++
 .../px30/sdram-px30-ddr3-detect-333.inc       |   70 +
 .../px30/sdram-px30-ddr4-detect-333.inc       |   73 +
 .../px30/sdram-px30-ddr_skew.inc              |  121 ++
 .../px30/sdram-px30-lpddr2-detect-333.inc     |   71 +
 .../px30/sdram-px30-lpddr3-detect-333.inc     |   72 +
 arch/arm/mach-rockchip/px30/sdram_px30.c      | 1405 +++++++++++++++++
 arch/arm/mach-rockchip/px30/syscon_px30.c     |   53 +
 17 files changed, 2671 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-px30/boot0.h
 create mode 100644 arch/arm/include/asm/arch-px30/gpio.h
 create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_px30.h
 create mode 100644 arch/arm/mach-rockchip/px30-board-tpl.c
 create mode 100644 arch/arm/mach-rockchip/px30/Kconfig
 create mode 100644 arch/arm/mach-rockchip/px30/Makefile
 create mode 100644 arch/arm/mach-rockchip/px30/clk_px30.c
 create mode 100644 arch/arm/mach-rockchip/px30/px30.c
 create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc
 create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc
 create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc
 create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc
 create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc
 create mode 100644 arch/arm/mach-rockchip/px30/sdram_px30.c
 create mode 100644 arch/arm/mach-rockchip/px30/syscon_px30.c

diff --git a/arch/arm/include/asm/arch-px30/boot0.h 
b/arch/arm/include/asm/arch-px30/boot0.h
new file mode 100644
index 0000000000..2e78b074ad
--- /dev/null
+++ b/arch/arm/include/asm/arch-px30/boot0.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef __ASM_ARCH_BOOT0_H__
+#define __ASM_ARCH_BOOT0_H__
+
+#include <asm/arch-rockchip/boot0.h>
+
+#endif
diff --git a/arch/arm/include/asm/arch-px30/gpio.h 
b/arch/arm/include/asm/arch-px30/gpio.h
new file mode 100644
index 0000000000..eca79d5159
--- /dev/null
+++ b/arch/arm/include/asm/arch-px30/gpio.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef __ASM_ARCH_GPIO_H__
+#define __ASM_ARCH_GPIO_H__
+
+#include <asm/arch-rockchip/gpio.h>
+
+#endif
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_px30.h 
b/arch/arm/include/asm/arch-rockchip/sdram_px30.h
new file mode 100644
index 0000000000..e10eb97b89
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/sdram_px30.h
@@ -0,0 +1,359 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef _ASM_ARCH_SDRAM_PX30_H
+#define _ASM_ARCH_SDRAM_PX30_H
+
+struct ddr_pctl_regs {
+       u32 pctl[30][2];
+};
+
+/* ddr pctl registers define */
+#define DDR_PCTL2_MSTR                 0x0
+#define DDR_PCTL2_STAT                 0x4
+#define DDR_PCTL2_MSTR1                        0x8
+#define DDR_PCTL2_MRCTRL0              0x10
+#define DDR_PCTL2_MRCTRL1              0x14
+#define DDR_PCTL2_MRSTAT               0x18
+#define DDR_PCTL2_MRCTRL2              0x1c
+#define DDR_PCTL2_DERATEEN             0x20
+#define DDR_PCTL2_DERATEINT            0x24
+#define DDR_PCTL2_PWRCTL               0x30
+#define DDR_PCTL2_PWRTMG               0x34
+#define DDR_PCTL2_HWLPCTL              0x38
+#define DDR_PCTL2_RFSHCTL0             0x50
+#define DDR_PCTL2_RFSHCTL1             0x54
+#define DDR_PCTL2_RFSHCTL2             0x58
+#define DDR_PCTL2_RFSHCTL4             0x5c
+#define DDR_PCTL2_RFSHCTL3             0x60
+#define DDR_PCTL2_RFSHTMG              0x64
+#define DDR_PCTL2_RFSHTMG1             0x68
+#define DDR_PCTL2_RFSHCTL5             0x6c
+#define DDR_PCTL2_INIT0                        0xd0
+#define DDR_PCTL2_INIT1                        0xd4
+#define DDR_PCTL2_INIT2                        0xd8
+#define DDR_PCTL2_INIT3                        0xdc
+#define DDR_PCTL2_INIT4                        0xe0
+#define DDR_PCTL2_INIT5                        0xe4
+#define DDR_PCTL2_INIT6                        0xe8
+#define DDR_PCTL2_INIT7                        0xec
+#define DDR_PCTL2_DIMMCTL              0xf0
+#define DDR_PCTL2_RANKCTL              0xf4
+#define DDR_PCTL2_CHCTL                        0xfc
+#define DDR_PCTL2_DRAMTMG0             0x100
+#define DDR_PCTL2_DRAMTMG1             0x104
+#define DDR_PCTL2_DRAMTMG2             0x108
+#define DDR_PCTL2_DRAMTMG3             0x10c
+#define DDR_PCTL2_DRAMTMG4             0x110
+#define DDR_PCTL2_DRAMTMG5             0x114
+#define DDR_PCTL2_DRAMTMG6             0x118
+#define DDR_PCTL2_DRAMTMG7             0x11c
+#define DDR_PCTL2_DRAMTMG8             0x120
+#define DDR_PCTL2_DRAMTMG9             0x124
+#define DDR_PCTL2_DRAMTMG10            0x128
+#define DDR_PCTL2_DRAMTMG11            0x12c
+#define DDR_PCTL2_DRAMTMG12            0x130
+#define DDR_PCTL2_DRAMTMG13            0x134
+#define DDR_PCTL2_DRAMTMG14            0x138
+#define DDR_PCTL2_DRAMTMG15            0x13c
+#define DDR_PCTL2_DRAMTMG16            0x140
+#define DDR_PCTL2_ZQCTL0               0x180
+#define DDR_PCTL2_ZQCTL1               0x184
+#define DDR_PCTL2_ZQCTL2               0x188
+#define DDR_PCTL2_ZQSTAT               0x18c
+#define DDR_PCTL2_DFITMG0              0x190
+#define DDR_PCTL2_DFITMG1              0x194
+#define DDR_PCTL2_DFILPCFG0            0x198
+#define DDR_PCTL2_DFILPCFG1            0x19c
+#define DDR_PCTL2_DFIUPD0              0x1a0
+#define DDR_PCTL2_DFIUPD1              0x1a4
+#define DDR_PCTL2_DFIUPD2              0x1a8
+#define DDR_PCTL2_DFIMISC              0x1b0
+#define DDR_PCTL2_DFITMG2              0x1b4
+#define DDR_PCTL2_DFITMG3              0x1b8
+#define DDR_PCTL2_DFISTAT              0x1bc
+#define DDR_PCTL2_DBICTL               0x1c0
+#define DDR_PCTL2_ADDRMAP0             0x200
+#define DDR_PCTL2_ADDRMAP1             0x204
+#define DDR_PCTL2_ADDRMAP2             0x208
+#define DDR_PCTL2_ADDRMAP3             0x20c
+#define DDR_PCTL2_ADDRMAP4             0x210
+#define DDR_PCTL2_ADDRMAP5             0x214
+#define DDR_PCTL2_ADDRMAP6             0x218
+#define DDR_PCTL2_ADDRMAP7             0x21c
+#define DDR_PCTL2_ADDRMAP8             0x220
+#define DDR_PCTL2_ADDRMAP9             0x224
+#define DDR_PCTL2_ADDRMAP10            0x228
+#define DDR_PCTL2_ADDRMAP11            0x22c
+#define DDR_PCTL2_ODTCFG               0x240
+#define DDR_PCTL2_ODTMAP               0x244
+#define DDR_PCTL2_SCHED                        0x250
+#define DDR_PCTL2_SCHED1               0x254
+#define DDR_PCTL2_PERFHPR1             0x25c
+#define DDR_PCTL2_PERFLPR1             0x264
+#define DDR_PCTL2_PERFWR1              0x26c
+#define DDR_PCTL2_DQMAP0               0x280
+#define DDR_PCTL2_DQMAP1               0x284
+#define DDR_PCTL2_DQMAP2               0x288
+#define DDR_PCTL2_DQMAP3               0x28c
+#define DDR_PCTL2_DQMAP4               0x290
+#define DDR_PCTL2_DQMAP5               0x294
+#define DDR_PCTL2_DBG0                 0x300
+#define DDR_PCTL2_DBG1                 0x304
+#define DDR_PCTL2_DBGCAM               0x308
+#define DDR_PCTL2_DBGCMD               0x30c
+#define DDR_PCTL2_DBGSTAT              0x310
+#define DDR_PCTL2_SWCTL                        0x320
+#define DDR_PCTL2_SWSTAT               0x324
+#define DDR_PCTL2_POISONCFG            0x36c
+#define DDR_PCTL2_POISONSTAT           0x370
+#define DDR_PCTL2_ADVECCINDEX          0x374
+#define DDR_PCTL2_ADVECCSTAT           0x378
+#define DDR_PCTL2_PSTAT                        0x3fc
+#define DDR_PCTL2_PCCFG                        0x400
+#define DDR_PCTL2_PCFGR_n              0x404
+#define DDR_PCTL2_PCFGW_n              0x408
+#define DDR_PCTL2_PCTRL_n              0x490
+
+/* PCTL2_MRSTAT */
+#define MR_WR_BUSY                     BIT(0)
+
+#define PHY_DDR3_RON_RTT_DISABLE       (0)
+#define PHY_DDR3_RON_RTT_451ohm                (1)
+#define PHY_DDR3_RON_RTT_225ohm                (2)
+#define PHY_DDR3_RON_RTT_150ohm                (3)
+#define PHY_DDR3_RON_RTT_112ohm                (4)
+#define PHY_DDR3_RON_RTT_90ohm         (5)
+#define PHY_DDR3_RON_RTT_75ohm         (6)
+#define PHY_DDR3_RON_RTT_64ohm         (7)
+#define PHY_DDR3_RON_RTT_56ohm         (16)
+#define PHY_DDR3_RON_RTT_50ohm         (17)
+#define PHY_DDR3_RON_RTT_45ohm         (18)
+#define PHY_DDR3_RON_RTT_41ohm         (19)
+#define PHY_DDR3_RON_RTT_37ohm         (20)
+#define PHY_DDR3_RON_RTT_34ohm         (21)
+#define PHY_DDR3_RON_RTT_33ohm         (22)
+#define PHY_DDR3_RON_RTT_30ohm         (23)
+#define PHY_DDR3_RON_RTT_28ohm         (24)
+#define PHY_DDR3_RON_RTT_26ohm         (25)
+#define PHY_DDR3_RON_RTT_25ohm         (26)
+#define PHY_DDR3_RON_RTT_23ohm         (27)
+#define PHY_DDR3_RON_RTT_22ohm         (28)
+#define PHY_DDR3_RON_RTT_21ohm         (29)
+#define PHY_DDR3_RON_RTT_20ohm         (30)
+#define PHY_DDR3_RON_RTT_19ohm         (31)
+
+#define PHY_DDR4_LPDDR3_RON_RTT_DISABLE        (0)
+#define PHY_DDR4_LPDDR3_RON_RTT_480ohm (1)
+#define PHY_DDR4_LPDDR3_RON_RTT_240ohm (2)
+#define PHY_DDR4_LPDDR3_RON_RTT_160ohm (3)
+#define PHY_DDR4_LPDDR3_RON_RTT_120ohm (4)
+#define PHY_DDR4_LPDDR3_RON_RTT_96ohm  (5)
+#define PHY_DDR4_LPDDR3_RON_RTT_80ohm  (6)
+#define PHY_DDR4_LPDDR3_RON_RTT_68ohm  (7)
+#define PHY_DDR4_LPDDR3_RON_RTT_60ohm  (16)
+#define PHY_DDR4_LPDDR3_RON_RTT_53ohm  (17)
+#define PHY_DDR4_LPDDR3_RON_RTT_48ohm  (18)
+#define PHY_DDR4_LPDDR3_RON_RTT_43ohm  (19)
+#define PHY_DDR4_LPDDR3_RON_RTT_40ohm  (20)
+#define PHY_DDR4_LPDDR3_RON_RTT_37ohm  (21)
+#define PHY_DDR4_LPDDR3_RON_RTT_34ohm  (22)
+#define PHY_DDR4_LPDDR3_RON_RTT_32ohm  (23)
+#define PHY_DDR4_LPDDR3_RON_RTT_30ohm  (24)
+#define PHY_DDR4_LPDDR3_RON_RTT_28ohm  (25)
+#define PHY_DDR4_LPDDR3_RON_RTT_26ohm  (26)
+#define PHY_DDR4_LPDDR3_RON_RTT_25ohm  (27)
+#define PHY_DDR4_LPDDR3_RON_RTT_24ohm  (28)
+#define PHY_DDR4_LPDDR3_RON_RTT_22ohm  (29)
+#define PHY_DDR4_LPDDR3_RON_RTT_21ohm  (30)
+#define PHY_DDR4_LPDDR3_RON_RTT_20ohm  (31)
+
+struct ddr_phy_regs {
+       u32 phy[5][2];
+};
+
+#define PHY_REG(base, n)               ((base) + 4 * (n))
+
+/* PHY_REG0 */
+#define DIGITAL_DERESET                        BIT(3)
+#define ANALOG_DERESET                 BIT(2)
+#define DIGITAL_RESET                  (0 << 3)
+#define ANALOG_RESET                   (0 << 2)
+
+/* PHY_REG1 */
+#define PHY_DDR2                       (0)
+#define PHY_LPDDR2                     (1)
+#define PHY_DDR3                       (2)
+#define PHY_LPDDR3                     (3)
+#define PHY_DDR4                       (4)
+#define PHY_BL_4                       (0 << 2)
+#define PHY_BL_8                       BIT(2)
+
+/* PHY_REG2 */
+#define PHY_DTT_EN                     BIT(0)
+#define PHY_DTT_DISB                   (0 << 0)
+#define PHY_WRITE_LEVELING_EN          BIT(2)
+#define PHY_WRITE_LEVELING_DISB                (0 << 2)
+#define PHY_SELECT_CS0                 (2)
+#define PHY_SELECT_CS1                 (1)
+#define PHY_SELECT_CS0_1               (0)
+#define PHY_WRITE_LEVELING_SELECTCS(n) ((n) << 6)
+#define PHY_DATA_TRAINING_SELECTCS(n)  ((n) << 4)
+
+struct ddr_phy_skew {
+       u32 a0_a1_skew[15];
+       u32 cs0_dm0_skew[11];
+       u32 cs0_dm1_skew[11];
+       u32 cs0_dm2_skew[11];
+       u32 cs0_dm3_skew[11];
+       u32 cs1_dm0_skew[11];
+       u32 cs1_dm1_skew[11];
+       u32 cs1_dm2_skew[11];
+       u32 cs1_dm3_skew[11];
+};
+
+#define SR_IDLE                                93
+#define PD_IDLE                                13
+
+/* PMUGRF */
+#define PMUGRF_OS_REG0                 (0x200)
+#define PMUGRF_OS_REG(n)               (PMUGRF_OS_REG0 + (n) * 4)
+
+/* DDR GRF */
+#define DDR_GRF_CON(n)                 (0 + (n) * 4)
+#define DDR_GRF_STATUS_BASE            (0X100)
+#define DDR_GRF_STATUS(n)              (DDR_GRF_STATUS_BASE + (n) * 4)
+#define DDR_GRF_LP_CON                 (0x20)
+
+#define SPLIT_MODE_32_L16_VALID                (0)
+#define SPLIT_MODE_32_H16_VALID                (1)
+#define SPLIT_MODE_16_L8_VALID         (2)
+#define SPLIT_MODE_16_H8_VALID         (3)
+
+#define DDR_GRF_SPLIT_CON              (0x8)
+#define SPLIT_MODE_MASK                        (0x3)
+#define SPLIT_MODE_OFFSET              (9)
+#define SPLIT_BYPASS_MASK              (1)
+#define SPLIT_BYPASS_OFFSET            (8)
+#define SPLIT_SIZE_MASK                        (0xff)
+#define SPLIT_SIZE_OFFSET              (0)
+
+/* CRU define */
+/* CRU_PLL_CON0 */
+#define PB(n)                          ((0x1 << (15 + 16)) | ((n) << 15))
+#define POSTDIV1(n)                    ((0x7 << (12 + 16)) | ((n) << 12))
+#define FBDIV(n)                       ((0xFFF << 16) | (n))
+
+/* CRU_PLL_CON1 */
+#define RSTMODE(n)                     ((0x1 << (15 + 16)) | ((n) << 15))
+#define RST(n)                         ((0x1 << (14 + 16)) | ((n) << 14))
+#define PD(n)                          ((0x1 << (13 + 16)) | ((n) << 13))
+#define DSMPD(n)                       ((0x1 << (12 + 16)) | ((n) << 12))
+#define LOCK(n)                                (((n) >> 10) & 0x1)
+#define POSTDIV2(n)                    ((0x7 << (6 + 16)) | ((n) << 6))
+#define REFDIV(n)                      ((0x3F << 16) | (n))
+
+/* CRU_MODE */
+#define CLOCK_FROM_XIN_OSC             (0)
+#define CLOCK_FROM_PLL                 (1)
+#define CLOCK_FROM_RTC_32K             (2)
+#define DPLL_MODE(n)                   ((0x3 << (4 + 16)) | ((n) << 4))
+
+/* CRU_SOFTRESET_CON1 */
+#define upctl2_psrstn_req(n)           (((0x1 << 6) << 16) | ((n) << 6))
+#define upctl2_asrstn_req(n)           (((0x1 << 5) << 16) | ((n) << 5))
+#define upctl2_srstn_req(n)            (((0x1 << 4) << 16) | ((n) << 4))
+
+/* CRU_SOFTRESET_CON2 */
+#define ddrphy_psrstn_req(n)           (((0x1 << 2) << 16) | ((n) << 2))
+#define ddrphy_srstn_req(n)            (((0x1 << 0) << 16) | ((n) << 0))
+
+/* CRU register */
+#define CRU_PLL_CON(pll_id, n)         ((pll_id)  * 0x20 + (n) * 4)
+#define CRU_MODE                       (0xa0)
+#define CRU_GLB_CNT_TH                 (0xb0)
+#define CRU_CLKSEL_CON_BASE            0x100
+#define CRU_CLKSELS_CON(i)             (CRU_CLKSEL_CON_BASE + ((i) * 4))
+#define CRU_CLKGATE_CON_BASE           0x200
+#define CRU_CLKGATE_CON(i)             (CRU_CLKGATE_CON_BASE + ((i) * 4))
+#define CRU_CLKSFTRST_CON_BASE         0x300
+#define CRU_CLKSFTRST_CON(i)           (CRU_CLKSFTRST_CON_BASE + ((i) * 4))
+
+struct px30_ddr_grf_regs {
+       u32 ddr_grf_con[4];
+       u32 reserved1[(0x20 - 0x10) / 4];
+       u32 ddr_grf_lp_con;
+       u32 reserved2[(0x100 - 0x24) / 4];
+       u32 ddr_grf_status[11];
+};
+
+struct px30_msch_timings {
+       u32 ddrtiminga0;
+       u32 ddrtimingb0;
+       u32 ddrtimingc0;
+       u32 devtodev0;
+       u32 ddrmode;
+       u32 ddr4timing;
+       u32 agingx0;
+};
+
+struct px30_sdram_channel {
+       unsigned int rank;
+       unsigned int col;
+       /* 3:8bank, 2:4bank */
+       unsigned int bk;
+       /* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
+       unsigned int bw;
+       /* die buswidth, 2:32bit, 1:16bit, 0:8bit */
+       unsigned int dbw;
+       unsigned int row_3_4;
+       unsigned int cs0_row;
+       unsigned int cs1_row;
+       unsigned int cs0_high16bit_row;
+       unsigned int cs1_high16bit_row;
+       unsigned int ddrconfig;
+       struct px30_msch_timings noc_timings;
+};
+
+struct px30_base_params {
+       unsigned int ddr_freq;
+       unsigned int dramtype;
+       unsigned int num_channels;
+       unsigned int stride;
+       unsigned int odt;
+};
+
+struct px30_sdram_params {
+       struct px30_sdram_channel ch;
+       struct px30_base_params base;
+       struct ddr_pctl_regs pctl_regs;
+       struct ddr_phy_regs phy_regs;
+       struct ddr_phy_skew *skew;
+};
+
+struct px30_msch_regs {
+       u32 coreid;
+       u32 revisionid;
+       u32 deviceconf;
+       u32 devicesize;
+       u32 ddrtiminga0;
+       u32 ddrtimingb0;
+       u32 ddrtimingc0;
+       u32 devtodev0;
+       u32 reserved1[(0x110 - 0x20) / 4];
+       u32 ddrmode;
+       u32 ddr4timing;
+       u32 reserved2[(0x1000 - 0x118) / 4];
+       u32 agingx0;
+       u32 reserved3[(0x1040 - 0x1004) / 4];
+       u32 aging0;
+       u32 aging1;
+       u32 aging2;
+       u32 aging3;
+};
+
+int sdram_init(void);
+
+#endif
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index f5a80b4f0c..116b40a3c5 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -1,5 +1,27 @@
 if ARCH_ROCKCHIP
 
+config ROCKCHIP_PX30
+       bool "Support Rockchip PX30"
+       select ARM64
+       select SUPPORT_SPL
+       select SUPPORT_TPL
+       select SPL
+       select TPL
+       select TPL_TINY_FRAMEWORK if TPL
+       select TPL_NEEDS_SEPARATE_TEXT_BASE if SPL
+       select TPL_NEEDS_SEPARATE_STACK if TPL
+       imply SPL_SEPARATE_BSS
+       select SPL_SERIAL_SUPPORT
+       select TPL_SERIAL_SUPPORT
+       select DEBUG_UART_BOARD_INIT
+       imply ROCKCHIP_COMMON_BOARD
+       imply SPL_ROCKCHIP_COMMON_BOARD
+       help
+         The Rockchip PX30 is a ARM-based SoC with a quad-core Cortex-A35
+         including NEON and GPU, Mali-400 graphics, several DDR3 options
+         and video codec support. Peripherals include Gigabit Ethernet,
+         USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
+
 config ROCKCHIP_RK3036
        bool "Support Rockchip RK3036"
        select CPU_V7A
@@ -315,6 +337,7 @@ config TPL_ROCKCHIP_EARLYRETURN_TO_BROM
 config SPL_MMC_SUPPORT
        default y if !SPL_ROCKCHIP_BACK_TO_BROM
 
+source "arch/arm/mach-rockchip/px30/Kconfig"
 source "arch/arm/mach-rockchip/rk3036/Kconfig"
 source "arch/arm/mach-rockchip/rk3128/Kconfig"
 source "arch/arm/mach-rockchip/rk3188/Kconfig"
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 45d9b06233..ddff566dee 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -11,6 +11,7 @@ obj-spl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o
 obj-spl-$(CONFIG_SPL_ROCKCHIP_COMMON_BOARD) += spl.o spl-boot-order.o
 obj-tpl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o
 obj-tpl-$(CONFIG_TPL_ROCKCHIP_COMMON_BOARD) += tpl.o
+obj-tpl-$(CONFIG_ROCKCHIP_PX30) += px30-board-tpl.o
 
 obj-spl-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o
 
@@ -27,6 +28,7 @@ endif
 
 obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram_common.o
 
+obj-$(CONFIG_ROCKCHIP_PX30) += px30/
 obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/
 obj-$(CONFIG_ROCKCHIP_RK3128) += rk3128/
 obj-$(CONFIG_ROCKCHIP_RK3188) += rk3188/
diff --git a/arch/arm/mach-rockchip/px30-board-tpl.c 
b/arch/arm/mach-rockchip/px30-board-tpl.c
new file mode 100644
index 0000000000..8c8976f61c
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30-board-tpl.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <ram.h>
+#include <spl.h>
+#include <version.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/bootrom.h>
+#include <asm/arch-rockchip/sdram_px30.h>
+
+#define TIMER_LOAD_COUNT0      0x00
+#define TIMER_LOAD_COUNT1      0x04
+#define TIMER_CUR_VALUE0       0x08
+#define TIMER_CUR_VALUE1       0x0c
+#define TIMER_CONTROL_REG      0x10
+
+#define TIMER_EN       0x1
+#define        TIMER_FMODE     (0 << 1)
+#define        TIMER_RMODE     (1 << 1)
+
+void secure_timer_init(void)
+{
+       writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+       writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_LOAD_COUNT0);
+       writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_LOAD_COUNT1);
+       writel(TIMER_EN | TIMER_FMODE,
+              CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+}
+
+void board_init_f(ulong dummy)
+{
+       int ret;
+
+#ifdef CONFIG_DEBUG_UART
+       debug_uart_init();
+       /*
+        * Debug UART can be used from here if required:
+        *
+        * debug_uart_init();
+        * printch('a');
+        * printhex8(0x1234);
+        * printascii("string");
+        */
+       printascii("U-Boot TPL board init\n");
+#endif
+
+       secure_timer_init();
+       ret = sdram_init();
+       if (ret)
+               printascii("sdram_init failed\n");
+
+       /* return to maskrom */
+       back_to_bootrom(BROM_BOOT_NEXTSTAGE);
+}
diff --git a/arch/arm/mach-rockchip/px30/Kconfig 
b/arch/arm/mach-rockchip/px30/Kconfig
new file mode 100644
index 0000000000..ef04afca8d
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/Kconfig
@@ -0,0 +1,48 @@
+if ROCKCHIP_PX30
+
+config TARGET_EVB_PX30
+       bool "EVB_PX30"
+
+config ROCKCHIP_BOOT_MODE_REG
+       default 0xff010200
+
+config SYS_SOC
+       default "px30"
+
+config SYS_MALLOC_F_LEN
+       default 0x400
+
+config SPL_SERIAL_SUPPORT
+       default y
+
+config TPL_LDSCRIPT
+       default "arch/arm/mach-rockchip/u-boot-tpl-v8.lds"
+
+config TPL_TEXT_BASE
+       default 0xff0e1000
+
+config TPL_MAX_SIZE
+       default 10240
+
+config TPL_STACK
+       default 0xff0e4fff
+
+config ROCKCHIP_RK3326
+       bool "Support Rockchip RK3326 "
+       help
+         RK3326 can use most code from PX30, but at some situations we have
+         to distinguish between RK3326 and PX30, so this macro gives help.
+         It is usually selected in rk3326 board defconfig.
+
+config DEBUG_UART2_CHANNEL
+       int "Mux channel to use for debug UART2"
+       depends on DEBUG_UART_BOARD_INIT
+       default 0
+       help
+         UART2 can use two different set of pins to route the output.
+         For using the UART for early debugging the route to use needs
+         to be declared (0 or 1).
+
+source "board/rockchip/evb_px30/Kconfig"
+
+endif
diff --git a/arch/arm/mach-rockchip/px30/Makefile 
b/arch/arm/mach-rockchip/px30/Makefile
new file mode 100644
index 0000000000..6d0742bcab
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/Makefile
@@ -0,0 +1,14 @@
+#
+# (C) Copyright 2017 Rockchip Electronics Co., Ltd.
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y += clk_px30.o
+
+ifndef CONFIG_TPL_BUILD
+obj-y += syscon_px30.o
+endif
+
+obj-y += px30.o
+obj-y += sdram_px30.o
diff --git a/arch/arm/mach-rockchip/px30/clk_px30.c 
b/arch/arm/mach-rockchip/px30/clk_px30.c
new file mode 100644
index 0000000000..0bd6b471da
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/clk_px30.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_px30.h>
+
+int rockchip_get_clk(struct udevice **devp)
+{
+       return uclass_get_device_by_driver(UCLASS_CLK,
+                       DM_GET_DRIVER(rockchip_px30_cru), devp);
+}
+
+void *rockchip_get_cru(void)
+{
+       struct px30_clk_priv *priv;
+       struct udevice *dev;
+       int ret;
+
+       ret = rockchip_get_clk(&dev);
+       if (ret)
+               return ERR_PTR(ret);
+
+       priv = dev_get_priv(dev);
+
+       return priv->cru;
+}
diff --git a/arch/arm/mach-rockchip/px30/px30.c 
b/arch/arm/mach-rockchip/px30/px30.c
new file mode 100644
index 0000000000..7cd2292fe2
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/px30.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 Rockchip Electronics Co., Ltd
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/armv8/mmu.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/grf_px30.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/uart.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_px30.h>
+#include <dt-bindings/clock/px30-cru.h>
+
+static struct mm_region px30_mem_map[] = {
+       {
+               .virt = 0x0UL,
+               .phys = 0x0UL,
+               .size = 0xff000000UL,
+               .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+                        PTE_BLOCK_INNER_SHARE
+       }, {
+               .virt = 0xff000000UL,
+               .phys = 0xff000000UL,
+               .size = 0x01000000UL,
+               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+                        PTE_BLOCK_NON_SHARE |
+                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
+       }, {
+               /* List terminator */
+               0,
+       }
+};
+
+struct mm_region *mem_map = px30_mem_map;
+
+#define PMU_PWRDN_CON                  0xff000018
+#define GRF_BASE                       0xff140000
+#define CRU_BASE                       0xff2b0000
+#define VIDEO_PHY_BASE                 0xff2e0000
+#define SERVICE_CORE_ADDR              0xff508000
+#define DDR_FW_BASE                    0xff534000
+
+#define FW_DDR_CON                     0x40
+
+#define QOS_PRIORITY                   0x08
+
+#define QOS_PRIORITY_LEVEL(h, l)       ((((h) & 3) << 8) | ((l) & 3))
+
+/* GRF_GPIO1CL_IOMUX */
+enum {
+       GPIO1C1_SHIFT           = 4,
+       GPIO1C1_MASK            = 0xf << GPIO1C1_SHIFT,
+       GPIO1C1_GPIO            = 0,
+       GPIO1C1_UART1_TX,
+
+       GPIO1C0_SHIFT           = 0,
+       GPIO1C0_MASK            = 0xf << GPIO1C0_SHIFT,
+       GPIO1C0_GPIO            = 0,
+       GPIO1C0_UART1_RX,
+};
+
+/* GRF_GPIO1DL_IOMUX */
+enum {
+       GPIO1D3_SHIFT           = 12,
+       GPIO1D3_MASK            = 0xf << GPIO1D3_SHIFT,
+       GPIO1D3_GPIO            = 0,
+       GPIO1D3_SDMMC_D1,
+       GPIO1D3_UART2_RXM0,
+
+       GPIO1D2_SHIFT           = 8,
+       GPIO1D2_MASK            = 0xf << GPIO1D2_SHIFT,
+       GPIO1D2_GPIO            = 0,
+       GPIO1D2_SDMMC_D0,
+       GPIO1D2_UART2_TXM0,
+};
+
+/* GRF_GPIO1DH_IOMUX */
+enum {
+       GPIO1D7_SHIFT           = 12,
+       GPIO1D7_MASK            = 0xf << GPIO1D7_SHIFT,
+       GPIO1D7_GPIO            = 0,
+       GPIO1D7_SDMMC_CMD,
+
+       GPIO1D6_SHIFT           = 8,
+       GPIO1D6_MASK            = 0xf << GPIO1D6_SHIFT,
+       GPIO1D6_GPIO            = 0,
+       GPIO1D6_SDMMC_CLK,
+
+       GPIO1D5_SHIFT           = 4,
+       GPIO1D5_MASK            = 0xf << GPIO1D5_SHIFT,
+       GPIO1D5_GPIO            = 0,
+       GPIO1D5_SDMMC_D3,
+
+       GPIO1D4_SHIFT           = 0,
+       GPIO1D4_MASK            = 0xf << GPIO1D4_SHIFT,
+       GPIO1D4_GPIO            = 0,
+       GPIO1D4_SDMMC_D2,
+};
+
+/* GRF_GPIO2BH_IOMUX */
+enum {
+       GPIO2B6_SHIFT           = 8,
+       GPIO2B6_MASK            = 0xf << GPIO2B6_SHIFT,
+       GPIO2B6_GPIO            = 0,
+       GPIO2B6_CIF_D1M0,
+       GPIO2B6_UART2_RXM1,
+
+       GPIO2B4_SHIFT           = 0,
+       GPIO2B4_MASK            = 0xf << GPIO2B4_SHIFT,
+       GPIO2B4_GPIO            = 0,
+       GPIO2B4_CIF_D0M0,
+       GPIO2B4_UART2_TXM1,
+};
+
+/* GRF_GPIO3AL_IOMUX */
+enum {
+       GPIO3A2_SHIFT           = 8,
+       GPIO3A2_MASK            = 0xf << GPIO3A2_SHIFT,
+       GPIO3A2_GPIO            = 0,
+       GPIO3A2_UART5_TX        = 4,
+
+       GPIO3A1_SHIFT           = 4,
+       GPIO3A1_MASK            = 0xf << GPIO3A1_SHIFT,
+       GPIO3A1_GPIO            = 0,
+       GPIO3A1_UART5_RX        = 4,
+};
+
+int arch_cpu_init(void)
+{
+       static struct px30_grf * const grf = (void *)GRF_BASE;
+       u32 __maybe_unused val;
+
+#ifdef CONFIG_SPL_BUILD
+       /* We do some SoC one time setting here. */
+       /* Disable the ddr secure region setting to make it non-secure */
+       writel(0x0, DDR_FW_BASE + FW_DDR_CON);
+
+       /* Set cpu qos priority */
+       writel(QOS_PRIORITY_LEVEL(1, 1), SERVICE_CORE_ADDR + QOS_PRIORITY);
+
+#if !defined(CONFIG_DEBUG_UART_BOARD_INIT) || \
+    (CONFIG_DEBUG_UART_BASE != 0xff160000) || \
+    (CONFIG_DEBUG_UART_CHANNEL != 0)
+       /* fix sdmmc pinmux if not using uart2-channel0 as debug uart */
+       rk_clrsetreg(&grf->gpio1dl_iomux,
+                    GPIO1D3_MASK | GPIO1D2_MASK,
+                    GPIO1D3_SDMMC_D1 << GPIO1D3_SHIFT |
+                    GPIO1D2_SDMMC_D0 << GPIO1D2_SHIFT);
+       rk_clrsetreg(&grf->gpio1dh_iomux,
+                    GPIO1D7_MASK | GPIO1D6_MASK | GPIO1D5_MASK | GPIO1D4_MASK,
+                    GPIO1D7_SDMMC_CMD << GPIO1D7_SHIFT |
+                    GPIO1D6_SDMMC_CLK << GPIO1D6_SHIFT |
+                    GPIO1D5_SDMMC_D3 << GPIO1D5_SHIFT |
+                    GPIO1D4_SDMMC_D2 << GPIO1D4_SHIFT);
+#endif
+
+#endif
+
+       /* Enable PD_VO (default disable at reset) */
+       rk_clrreg(PMU_PWRDN_CON, 1 << 13);
+
+       /* Disable video phy bandgap by default */
+       writel(0x82, VIDEO_PHY_BASE + 0x0000);
+       writel(0x05, VIDEO_PHY_BASE + 0x03ac);
+
+       /* Clear the force_jtag */
+       rk_clrreg(&grf->cpu_con[1], 1 << 7);
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+       static struct px30_grf * const grf = (void *)GRF_BASE;
+       static struct px30_cru * const cru = (void *)CRU_BASE;
+
+#if defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff158000)
+       /* uart_sel_clk default select 24MHz */
+       rk_clrsetreg(&cru->clksel_con[34],
+                    UART1_PLL_SEL_MASK | UART1_DIV_CON_MASK,
+                    UART1_PLL_SEL_24M << UART1_PLL_SEL_SHIFT | 0);
+       rk_clrsetreg(&cru->clksel_con[35],
+                    UART1_CLK_SEL_MASK,
+                    UART1_CLK_SEL_UART1 << UART1_CLK_SEL_SHIFT);
+
+       rk_clrsetreg(&grf->gpio1cl_iomux,
+                    GPIO1C1_MASK | GPIO1C0_MASK,
+                    GPIO1C1_UART1_TX << GPIO1C1_SHIFT |
+                    GPIO1C0_UART1_RX << GPIO1C0_SHIFT);
+#elif defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff178000)
+       /* uart_sel_clk default select 24MHz */
+       rk_clrsetreg(&cru->clksel_con[46],
+                    UART5_PLL_SEL_MASK | UART5_DIV_CON_MASK,
+                    UART5_PLL_SEL_24M << UART5_PLL_SEL_SHIFT | 0);
+       rk_clrsetreg(&cru->clksel_con[47],
+                    UART5_CLK_SEL_MASK,
+                    UART5_CLK_SEL_UART5 << UART5_CLK_SEL_SHIFT);
+
+       rk_clrsetreg(&grf->gpio3al_iomux,
+                    GPIO3A2_MASK | GPIO3A1_MASK,
+                    GPIO3A2_UART5_TX << GPIO3A2_SHIFT |
+                    GPIO3A1_UART5_RX << GPIO3A1_SHIFT);
+#else
+       /* GRF_IOFUNC_CON0 */
+       enum {
+               CON_IOMUX_UART2SEL_SHIFT        = 10,
+               CON_IOMUX_UART2SEL_MASK = 3 << CON_IOMUX_UART2SEL_SHIFT,
+               CON_IOMUX_UART2SEL_M0   = 0,
+               CON_IOMUX_UART2SEL_M1,
+               CON_IOMUX_UART2SEL_USBPHY,
+       };
+
+       /* uart_sel_clk default select 24MHz */
+       rk_clrsetreg(&cru->clksel_con[37],
+                    UART2_PLL_SEL_MASK | UART2_DIV_CON_MASK,
+                    UART2_PLL_SEL_24M << UART2_PLL_SEL_SHIFT | 0);
+       rk_clrsetreg(&cru->clksel_con[38],
+                    UART2_CLK_SEL_MASK,
+                    UART2_CLK_SEL_UART2 << UART2_CLK_SEL_SHIFT);
+
+#if (CONFIG_DEBUG_UART2_CHANNEL == 1)
+       /* Enable early UART2 */
+       rk_clrsetreg(&grf->iofunc_con0,
+                    CON_IOMUX_UART2SEL_MASK,
+                    CON_IOMUX_UART2SEL_M1 << CON_IOMUX_UART2SEL_SHIFT);
+
+       rk_clrsetreg(&grf->gpio2bh_iomux,
+                    GPIO2B6_MASK | GPIO2B4_MASK,
+                    GPIO2B6_UART2_RXM1 << GPIO2B6_SHIFT |
+                    GPIO2B4_UART2_TXM1 << GPIO2B4_SHIFT);
+#else
+       rk_clrsetreg(&grf->iofunc_con0,
+                    CON_IOMUX_UART2SEL_MASK,
+                    CON_IOMUX_UART2SEL_M0 << CON_IOMUX_UART2SEL_SHIFT);
+
+       rk_clrsetreg(&grf->gpio1dl_iomux,
+                    GPIO1D3_MASK | GPIO1D2_MASK,
+                    GPIO1D3_UART2_RXM0 << GPIO1D3_SHIFT |
+                    GPIO1D2_UART2_TXM0 << GPIO1D2_SHIFT);
+#endif /* CONFIG_DEBUG_UART2_CHANNEL == 1 */
+
+#endif /* CONFIG_DEBUG_UART_BASE && CONFIG_DEBUG_UART_BASE == ... */
+}
+#endif /* CONFIG_DEBUG_UART_BOARD_INIT */
diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc 
b/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc
new file mode 100644
index 0000000000..e17b2ed86c
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc
@@ -0,0 +1,70 @@
+{
+       {
+               .rank = 0x1,
+               .col = 0xC,
+               .bk = 0x3,
+               .bw = 0x1,
+               .dbw = 0x0,
+               .row_3_4 = 0x0,
+               .cs0_row = 0x10,
+               .cs1_row = 0x10,
+               .cs0_high16bit_row = 0x10,
+               .cs1_high16bit_row = 0x10,
+               .ddrconfig = 0,
+               {
+                       0x290b0609,
+                       0x08020401,
+                       0x00000002,
+                       0x00001111,
+                       0x0000000c,
+                       0x00000222,
+                       0x000000ff
+               }
+       },
+       {
+               .ddr_freq = 333,
+               .dramtype = DDR3,
+               .num_channels = 1,
+               .stride = 0,
+               .odt = 0,
+       },
+       {
+               {
+                       {0x00000000, 0x43041001},       /* MSTR */
+                       {0x00000064, 0x0028003b},       /* RFSHTMG */
+                       {0x000000d0, 0x00020053},       /* INIT0 */
+                       {0x000000d4, 0x00020000},       /* INIT1 */
+                       {0x000000d8, 0x00000100},       /* INIT2 */
+                       {0x000000dc, 0x03200000},       /* INIT3 */
+                       {0x000000e0, 0x00000000},       /* INIT4 */
+                       {0x000000e4, 0x00090000},       /* INIT5 */
+                       {0x000000f4, 0x000f012f},       /* RANKCTL */
+                       {0x00000100, 0x07090b06},       /* DRAMTMG0 */
+                       {0x00000104, 0x00050209},       /* DRAMTMG1 */
+                       {0x00000108, 0x03030407},       /* DRAMTMG2 */
+                       {0x0000010c, 0x00202006},       /* DRAMTMG3 */
+                       {0x00000110, 0x03020204},       /* DRAMTMG4 */
+                       {0x00000114, 0x03030202},       /* DRAMTMG5 */
+                       {0x00000120, 0x00000903},       /* DRAMTMG8 */
+                       {0x00000180, 0x00800020},       /* ZQCTL0 */
+                       {0x00000184, 0x00000000},       /* ZQCTL1 */
+                       {0x00000190, 0x07010001},       /* DFITMG0 */
+                       {0x00000198, 0x07000101},       /* DFILPCFG0 */
+                       {0x000001a0, 0xc0400003},       /* DFIUPD0 */
+                       {0x00000240, 0x06000604},       /* ODTCFG */
+                       {0x00000244, 0x00000201},       /* ODTMAP */
+                       {0x00000250, 0x00001f00},       /* SCHED */
+                       {0x00000490, 0x00000001},       /* PCTRL_0 */
+                       {0xffffffff, 0xffffffff}
+               }
+       },
+       {
+               {
+                       {0x00000004, 0x0000000a},       /* PHYREG01 */
+                       {0x00000028, 0x00000006},       /* PHYREG0A */
+                       {0x0000002c, 0x00000000},       /* PHYREG0B */
+                       {0x00000030, 0x00000005},       /* PHYREG0C */
+                       {0xffffffff, 0xffffffff}
+               }
+       }
+},
diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc 
b/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc
new file mode 100644
index 0000000000..cdc417405a
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc
@@ -0,0 +1,73 @@
+{
+       {
+               .rank = 0x1,
+               .col = 0xA,
+               .bk = 0x2,
+               .bw = 0x1,
+               .dbw = 0x0,
+               .row_3_4 = 0x0,
+               .cs0_row = 0x11,
+               .cs1_row = 0x0,
+               .cs0_high16bit_row = 0x11,
+               .cs1_high16bit_row = 0x0,
+               .ddrconfig = 0,
+               {
+                       0x4d110a08,
+                       0x06020501,
+                       0x00000002,
+                       0x00001111,
+                       0x0000000c,
+                       0x0000022a,
+                       0x000000ff
+               }
+       },
+       {
+               .ddr_freq = 333,
+               .dramtype = DDR4,
+               .num_channels = 1,
+               .stride = 0,
+               .odt = 0,
+       },
+       {
+               {
+                       {0x00000000, 0x43049010},       /* MSTR */
+                       {0x00000064, 0x0028003b},       /* RFSHTMG */
+                       {0x000000d0, 0x00020053},       /* INIT0 */
+                       {0x000000d4, 0x00220000},       /* INIT1 */
+                       {0x000000d8, 0x00000100},       /* INIT2 */
+                       {0x000000dc, 0x00040000},       /* INIT3 */
+                       {0x000000e0, 0x00000000},       /* INIT4 */
+                       {0x000000e4, 0x00110000},       /* INIT5 */
+                       {0x000000e8, 0x00000420},       /* INIT6 */
+                       {0x000000ec, 0x00000400},       /* INIT7 */
+                       {0x000000f4, 0x000f012f},       /* RANKCTL */
+                       {0x00000100, 0x09060b06},       /* DRAMTMG0 */
+                       {0x00000104, 0x00020209},       /* DRAMTMG1 */
+                       {0x00000108, 0x0505040a},       /* DRAMTMG2 */
+                       {0x0000010c, 0x0040400c},       /* DRAMTMG3 */
+                       {0x00000110, 0x05030206},       /* DRAMTMG4 */
+                       {0x00000114, 0x03030202},       /* DRAMTMG5 */
+                       {0x00000120, 0x03030b03},       /* DRAMTMG8 */
+                       {0x00000124, 0x00020208},       /* DRAMTMG9 */
+                       {0x00000180, 0x01000040},       /* ZQCTL0 */
+                       {0x00000184, 0x00000000},       /* ZQCTL1 */
+                       {0x00000190, 0x07030003},       /* DFITMG0 */
+                       {0x00000198, 0x07000101},       /* DFILPCFG0 */
+                       {0x000001a0, 0xc0400003},       /* DFIUPD0 */
+                       {0x00000240, 0x06000604},       /* ODTCFG */
+                       {0x00000244, 0x00000201},       /* ODTMAP */
+                       {0x00000250, 0x00001f00},       /* SCHED */
+                       {0x00000490, 0x00000001},       /* PCTRL_0 */
+                       {0xffffffff, 0xffffffff}
+               }
+       },
+       {
+               {
+                       {0x00000004, 0x0000000c},       /* PHYREG01 */
+                       {0x00000028, 0x0000000a},       /* PHYREG0A */
+                       {0x0000002c, 0x00000000},       /* PHYREG0B */
+                       {0x00000030, 0x00000009},       /* PHYREG0C */
+                       {0xffffffff, 0xffffffff}
+               }
+       }
+},
\ No newline at end of file
diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc 
b/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc
new file mode 100644
index 0000000000..f24343dda1
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc
@@ -0,0 +1,121 @@
+               {
+                       0x77,
+                       0x88,
+                       0x79,
+                       0x79,
+                       0x87,
+                       0x97,
+                       0x87,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x87,
+                       0x88,
+                       0x87,
+                       0x87,
+                       0x77
+               },
+               {
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x69,
+                       0x9,
+               },
+               {
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x79,
+                       0x9,
+               },
+               {
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x69,
+                       0x9,
+               },
+               {
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x79,
+                       0x9,
+               },
+               {
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x69,
+                       0x9,
+               },
+               {
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x79,
+                       0x9,
+               },
+               {
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x78,
+                       0x69,
+                       0x9,
+               },
+               {
+                       0x77,
+                       0x78,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x77,
+                       0x79,
+                       0x9,
+               }
diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc 
b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc
new file mode 100644
index 0000000000..3bde062d62
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc
@@ -0,0 +1,71 @@
+{
+       {
+               .rank = 0x1,
+               .col = 0xC,
+               .bk = 0x3,
+               .bw = 0x1,
+               .dbw = 0x0,
+               .row_3_4 = 0x0,
+               .cs0_row = 0xF,
+               .cs1_row = 0xF,
+               .cs0_high16bit_row = 0xF,
+               .cs1_high16bit_row = 0xF,
+               .ddrconfig = 0,
+               {
+                       0x2b0c070a,
+                       0x08020303,
+                       0x00000002,
+                       0x00001111,
+                       0x0000000c,
+                       0x00000219,
+                       0x000000ff
+               }
+       },
+       {
+               .ddr_freq = 333,
+               .dramtype = LPDDR2,
+               .num_channels = 1,
+               .stride = 0,
+               .odt = 0,
+       },
+       {
+               {
+                       {0x00000000, 0x41041004},       /* MSTR */
+                       {0x00000064, 0x00140023},       /* RFSHTMG */
+                       {0x000000d0, 0x00220002},       /* INIT0 */
+                       {0x000000d4, 0x00010000},       /* INIT1 */
+                       {0x000000d8, 0x00000703},       /* INIT2 */
+                       {0x000000dc, 0x00630005},       /* INIT3 */
+                       {0x000000e0, 0x00010000},       /* INIT4 */
+                       {0x000000e4, 0x00070003},       /* INIT5 */
+                       {0x000000f4, 0x000f012f},       /* RANKCTL */
+                       {0x00000100, 0x07090b07},       /* DRAMTMG0 */
+                       {0x00000104, 0x0002010b},       /* DRAMTMG1 */
+                       {0x00000108, 0x02040506},       /* DRAMTMG2 */
+                       {0x0000010c, 0x00303000},       /* DRAMTMG3 */
+                       {0x00000110, 0x04010204},       /* DRAMTMG4 */
+                       {0x00000114, 0x01010303},       /* DRAMTMG5 */
+                       {0x00000118, 0x02020003},       /* DRAMTMG6 */
+                       {0x00000120, 0x00000303},       /* DRAMTMG8 */
+                       {0x00000138, 0x00000025},       /* DRAMTMG14 */
+                       {0x00000180, 0x003c000f},       /* ZQCTL0 */
+                       {0x00000184, 0x00900000},       /* ZQCTL1 */
+                       {0x00000190, 0x07020001},       /* DFITMG0 */
+                       {0x00000198, 0x07000101},       /* DFILPCFG0 */
+                       {0x000001a0, 0xc0400003},       /* DFIUPD0 */
+                       {0x00000240, 0x07030718},       /* ODTCFG */
+                       {0x00000250, 0x00001f00},       /* SCHED */
+                       {0x00000490, 0x00000001},       /* PCTRL_0 */
+                       {0xffffffff, 0xffffffff}
+               }
+       },
+       {
+               {
+                       {0x00000004, 0x00000009},       /* PHYREG01 */
+                       {0x00000028, 0x00000007},       /* PHYREG0A */
+                       {0x0000002c, 0x00000000},       /* PHYREG0B */
+                       {0x00000030, 0x00000004},       /* PHYREG0C */
+                       {0xffffffff, 0xffffffff}
+               }
+       }
+},
diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc 
b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc
new file mode 100644
index 0000000000..a205fc9332
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc
@@ -0,0 +1,72 @@
+{
+       {
+               .rank = 0x1,
+               .col = 0xC,
+               .bk = 0x3,
+               .bw = 0x1,
+               .dbw = 0x0,
+               .row_3_4 = 0x0,
+               .cs0_row = 0x10,
+               .cs1_row = 0x10,
+               .cs0_high16bit_row = 0x10,
+               .cs1_high16bit_row = 0x10,
+               .ddrconfig = 0,
+               {
+                       0x290a060a,
+                       0x08020303,
+                       0x00000002,
+                       0x00001111,
+                       0x0000000c,
+                       0x0000021a,
+                       0x000000ff
+               }
+       },
+       {
+               .ddr_freq = 333,
+               .dramtype = LPDDR3,
+               .num_channels = 1,
+               .stride = 0,
+               .odt = 0,
+       },
+       {
+               {
+                       {0x00000000, 0x43041008},       /* MSTR */
+                       {0x00000064, 0x00140023},       /* RFSHTMG */
+                       {0x000000d0, 0x00220002},       /* INIT0 */
+                       {0x000000d4, 0x00010000},       /* INIT1 */
+                       {0x000000d8, 0x00000703},       /* INIT2 */
+                       {0x000000dc, 0x00830004},       /* INIT3 */
+                       {0x000000e0, 0x00010000},       /* INIT4 */
+                       {0x000000e4, 0x00070003},       /* INIT5 */
+                       {0x000000f4, 0x000f012f},       /* RANKCTL */
+                       {0x00000100, 0x06090b07},       /* DRAMTMG0 */
+                       {0x00000104, 0x0002020b},       /* DRAMTMG1 */
+                       {0x00000108, 0x02030506},       /* DRAMTMG2 */
+                       {0x0000010c, 0x00505000},       /* DRAMTMG3 */
+                       {0x00000110, 0x03020204},       /* DRAMTMG4 */
+                       {0x00000114, 0x01010303},       /* DRAMTMG5 */
+                       {0x00000118, 0x02020003},       /* DRAMTMG6 */
+                       {0x00000120, 0x00000303},       /* DRAMTMG8 */
+                       {0x00000138, 0x00000025},       /* DRAMTMG14 */
+                       {0x00000180, 0x003c000f},       /* ZQCTL0 */
+                       {0x00000184, 0x00900000},       /* ZQCTL1 */
+                       {0x00000190, 0x07020000},       /* DFITMG0 */
+                       {0x00000198, 0x07000101},       /* DFILPCFG0 */
+                       {0x000001a0, 0xc0400003},       /* DFIUPD0 */
+                       {0x00000240, 0x0900090c},       /* ODTCFG */
+                       {0x00000244, 0x00000101},       /* ODTMAP */
+                       {0x00000250, 0x00001f00},       /* SCHED */
+                       {0x00000490, 0x00000001},       /* PCTRL_0 */
+                       {0xffffffff, 0xffffffff}
+               }
+       },
+       {
+               {
+                       {0x00000004, 0x0000000b},       /* PHYREG01 */
+                       {0x00000028, 0x00000006},       /* PHYREG0A */
+                       {0x0000002c, 0x00000000},       /* PHYREG0B */
+                       {0x00000030, 0x00000003},       /* PHYREG0C */
+                       {0xffffffff, 0xffffffff}
+               }
+       }
+},
diff --git a/arch/arm/mach-rockchip/px30/sdram_px30.c 
b/arch/arm/mach-rockchip/px30/sdram_px30.c
new file mode 100644
index 0000000000..2590d9366e
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/sdram_px30.c
@@ -0,0 +1,1405 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <ram.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_px30.h>
+#include <asm/arch-rockchip/grf_px30.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_px30.h>
+
+#define TIMER_CUR_VALUE0       0x08
+#define TIMER_CUR_VALUE1       0x0c
+
+static u64 rockchip_get_ticks(void)
+{
+       u64 timebase_h, timebase_l;
+
+       timebase_l = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CUR_VALUE0);
+       timebase_h = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CUR_VALUE1);
+
+       return timebase_h << 32 | timebase_l;
+}
+
+void rockchip_udelay(unsigned int usec)
+{
+       u64 tmp;
+
+       /* get timestamp */
+       tmp = rockchip_get_ticks() + usec_to_tick(usec);
+
+       /* loop till event */
+       while (rockchip_get_ticks() < tmp + 1)
+               ;
+}
+
+u8 ddr_cfg_2_rbc[] = {
+       /*
+        * [6:4] max row: 13+n
+        * [3]  bank(0:4bank,1:8bank)
+        * [2:0]    col(10+n)
+        */
+       ((5 << 4) | (1 << 3) | 0), /* 0 */
+       ((5 << 4) | (1 << 3) | 1), /* 1 */
+       ((4 << 4) | (1 << 3) | 2), /* 2 */
+       ((3 << 4) | (1 << 3) | 3), /* 3 */
+       ((2 << 4) | (1 << 3) | 4), /* 4 */
+       ((5 << 4) | (0 << 3) | 2), /* 5 */
+       ((4 << 4) | (1 << 3) | 2), /* 6 */
+};
+
+#ifdef CONFIG_TPL_BUILD
+
+/*
+ * for ddr4 if ddrconfig=7, upctl should set 7 and noc should
+ * set to 1 for more efficient.
+ * noc ddrconf, upctl addrmap
+ * 1  7
+ * 2  8
+ * 3  9
+ * 12 10
+ * 5  11
+ */
+static u8 d4_rbc_2_d3_rbc[] = {
+       1, /* 7 */
+       2, /* 8 */
+       3, /* 9 */
+       12, /* 10 */
+       5, /* 11 */
+};
+
+/*
+ * row higher than cs should be disabled by set to 0xf
+ * rank addrmap calculate by real cap.
+ */
+static u32 addrmap[][8] = {
+       /* map0 map1,   map2,       map3,       map4,      map5
+        * map6,        map7,       map8
+        * -------------------------------------------------------
+        * bk2-0       col 5-2     col 9-6    col 11-10   row 11-0
+        * row 15-12   row 17-16   bg1,0
+        * -------------------------------------------------------
+        * 4,3,2       5-2         9-6                    6
+        *                         3,2
+        */
+       {0x00060606, 0x00000000, 0x1f1f0000, 0x00001f1f, 0x05050505,
+               0x05050505, 0x00000505, 0x3f3f}, /* 0 */
+       {0x00070707, 0x00000000, 0x1f000000, 0x00001f1f, 0x06060606,
+               0x06060606, 0x06060606, 0x3f3f}, /* 1 */
+       {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707,
+               0x07070707, 0x00000f07, 0x3f3f}, /* 2 */
+       {0x00090909, 0x00000000, 0x00000000, 0x00001f00, 0x08080808,
+               0x08080808, 0x00000f0f, 0x3f3f}, /* 3 */
+       {0x000a0a0a, 0x00000000, 0x00000000, 0x00000000, 0x09090909,
+               0x0f090909, 0x00000f0f, 0x3f3f}, /* 4 */
+       {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x06060606,
+               0x06060606, 0x00000606, 0x3f3f}, /* 5 */
+       {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707,
+               0x07070707, 0x00000f0f, 0x3f3f}, /* 6 */
+       {0x003f0808, 0x00000006, 0x1f1f0000, 0x00001f1f, 0x06060606,
+               0x06060606, 0x00000606, 0x0600}, /* 7 */
+       {0x003f0909, 0x00000007, 0x1f000000, 0x00001f1f, 0x07070707,
+               0x07070707, 0x00000f07, 0x0700}, /* 8 */
+       {0x003f0a0a, 0x01010100, 0x01010101, 0x00001f1f, 0x08080808,
+               0x08080808, 0x00000f0f, 0x0801}, /* 9 */
+       {0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707,
+               0x07070707, 0x00000f07, 0x3f01}, /* 10 */
+       {0x003f0808, 0x00000007, 0x1f000000, 0x00001f1f, 0x06060606,
+               0x06060606, 0x00000606, 0x3f00}, /* 11 */
+       /* when ddr4 12 map to 10, when ddr3 12 unused */
+       {0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707,
+               0x07070707, 0x00000f07, 0x3f01}, /* 10 */
+       {0x00070706, 0x00000000, 0x1f010000, 0x00001f1f, 0x06060606,
+               0x06060606, 0x00000606, 0x3f3f}, /* 13 */
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+struct dram_info {
+       struct ddr_pctl_regs *pctl;
+       struct ddr_phy_regs *phy;
+       struct px30_cru *cru;
+       struct px30_msch_regs *msch;
+       struct px30_ddr_grf_regs *ddr_grf;
+       struct px30_grf *grf;
+       struct ram_info info;
+       struct px30_pmugrf *pmugrf;
+};
+
+#define PMUGRF_BASE_ADDR               0xFF010000
+#define CRU_BASE_ADDR                  0xFF2B0000
+#define GRF_BASE_ADDR                  0xFF140000
+#define DDRC_BASE_ADDR                 0xFF600000
+#define DDR_PHY_BASE_ADDR              0xFF2A0000
+#define SERVER_MSCH0_BASE_ADDR         0xFF530000
+#define DDR_GRF_BASE_ADDR              0xff630000
+
+struct dram_info dram_info;
+
+struct px30_sdram_params sdram_configs[] = {
+#include       "sdram-px30-ddr3-detect-333.inc"
+};
+
+struct ddr_phy_skew skew = {
+#include       "sdram-px30-ddr_skew.inc"
+};
+
+#define PATTERN                                (0x5aa5f00f)
+
+/*
+ * cs: 0:cs0
+ *        1:cs1
+ *     else cs0+cs1
+ * note: it didn't consider about row_3_4
+ */
+u64 sdram_get_cs_cap(struct px30_sdram_channel *cap_info, u32 cs, u32 
dram_type)
+{
+       u32 bg;
+       u64 cap[2];
+
+       if (dram_type == DDR4)
+               /* DDR4 8bit dram BG = 2(4bank groups),
+                * 16bit dram BG = 1 (2 bank groups)
+                */
+               bg = (cap_info->dbw == 0) ? 2 : 1;
+       else
+               bg = 0;
+       cap[0] = 1llu << (cap_info->bw + cap_info->col +
+               bg + cap_info->bk + cap_info->cs0_row);
+
+       if (cap_info->rank == 2)
+               cap[1] = 1llu << (cap_info->bw + cap_info->col +
+                       bg + cap_info->bk + cap_info->cs1_row);
+       else
+               cap[1] = 0;
+
+       if (cs == 0)
+               return cap[0];
+       else if (cs == 1)
+               return cap[1];
+       else
+               return (cap[0] + cap[1]);
+}
+
+/* n: Unit bytes */
+void sdram_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 sdram_phy_dll_bypass_set(void __iomem *phy_base, u32 freq)
+{
+       u32 tmp;
+       u32 i, j;
+
+       setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
+       clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
+       for (i = 0; i < 4; i++) {
+               j = 0x26 + i * 0x10;
+               setbits_le32(PHY_REG(phy_base, j), 1 << 4);
+               clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
+       }
+
+       if (freq <= (400000000))
+               /* DLL bypass */
+               setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
+       else
+               clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
+
+       if (freq <= (801000000))
+               tmp = 2;
+       else
+               tmp = 1;
+
+       for (i = 0; i < 4; i++) {
+               j = 0x28 + i * 0x10;
+               writel(tmp, PHY_REG(phy_base, j));
+       }
+}
+
+static void sdram_phy_set_ds_odt(void __iomem *phy_base,
+                                u32 dram_type)
+{
+       u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
+       u32 i, j;
+
+       if (dram_type == DDR3) {
+               cmd_drv = PHY_DDR3_RON_RTT_34ohm;
+               clk_drv = PHY_DDR3_RON_RTT_45ohm;
+               dqs_drv = PHY_DDR3_RON_RTT_34ohm;
+               dqs_odt = PHY_DDR3_RON_RTT_225ohm;
+       } else {
+               cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
+               clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
+               dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
+               if (dram_type == LPDDR2)
+                       dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
+               else
+                       dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
+       }
+       /* DS */
+       writel(cmd_drv, PHY_REG(phy_base, 0x11));
+       clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
+       writel(clk_drv, PHY_REG(phy_base, 0x16));
+       writel(clk_drv, PHY_REG(phy_base, 0x18));
+
+       for (i = 0; i < 4; i++) {
+               j = 0x20 + i * 0x10;
+               writel(dqs_drv, PHY_REG(phy_base, j));
+               writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
+               /* ODT */
+               writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
+               writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
+       }
+}
+
+static void phy_soft_reset(void __iomem *phy_base)
+{
+       clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
+       udelay(1);
+       setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
+       udelay(5);
+       setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
+       udelay(1);
+}
+
+static void phy_dram_set_bw(void __iomem *phy_base, u32 bw)
+{
+       if (bw == 2) {
+               clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
+               setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+               setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+       } else if (bw == 1) {
+               clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
+               clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+               clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+       } else if (bw == 0) {
+               clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
+               clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
+               clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+               clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+       }
+
+       phy_soft_reset(phy_base);
+}
+
+static int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype)
+{
+       u32 ret;
+       u32 odt_val;
+       u32 i, j;
+
+       odt_val = readl(PHY_REG(phy_base, 0x2e));
+
+       for (i = 0; i < 4; i++) {
+               j = 0x20 + i * 0x10;
+               writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
+               writel(0, PHY_REG(phy_base, j + 0xe));
+       }
+
+       if (dramtype == DDR4) {
+               clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
+               clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
+               clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
+               clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
+       }
+       /* choose training cs */
+       clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
+       /* enable gate training */
+       clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
+       udelay(50);
+       ret = readl(PHY_REG(phy_base, 0xff));
+       /* disable gate training */
+       clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
+       clrbits_le32(PHY_REG(phy_base, 2), 0x30);
+
+       if (dramtype == DDR4) {
+               clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
+               clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
+               clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
+               clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
+       }
+
+       if (ret & 0x10) {
+               ret = -1;
+       } else {
+               ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
+               ret = (ret == 0) ? 0 : -1;
+       }
+
+       for (i = 0; i < 4; i++) {
+               j = 0x20 + i * 0x10;
+               writel(odt_val, PHY_REG(phy_base, j + 0x1));
+               writel(odt_val, PHY_REG(phy_base, j + 0xe));
+       }
+
+       return ret;
+}
+
+static void phy_cfg(void __iomem *phy_base,
+                   struct ddr_phy_regs *phy_regs, struct ddr_phy_skew *skew,
+                   struct px30_base_params *base, u32 bw)
+{
+       u32 i;
+
+       sdram_phy_dll_bypass_set(phy_base, base->ddr_freq);
+       for (i = 0; phy_regs->phy[i][0] != 0xFFFFFFFF; i++) {
+               writel(phy_regs->phy[i][1],
+                      phy_base + phy_regs->phy[i][0]);
+       }
+       if (bw == 2) {
+               clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
+       } else if (bw == 1) {
+               clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
+               /* disable DQS2,DQS3 tx dll  for saving power */
+               clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+               clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+       } else {
+               clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
+               /* disable DQS2,DQS3 tx dll  for saving power */
+               clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
+               clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+               clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+       }
+       sdram_phy_set_ds_odt(phy_base, base->dramtype);
+
+       /* deskew */
+       setbits_le32(PHY_REG(phy_base, 2), 8);
+       sdram_copy_to_reg(PHY_REG(phy_base, 0xb0),
+                         &skew->a0_a1_skew[0], 15 * 4);
+       sdram_copy_to_reg(PHY_REG(phy_base, 0x70),
+                         &skew->cs0_dm0_skew[0], 44 * 4);
+       sdram_copy_to_reg(PHY_REG(phy_base, 0xc0),
+                         &skew->cs1_dm0_skew[0], 44 * 4);
+}
+
+void sdram_org_config(struct px30_sdram_channel *info,
+                     struct px30_base_params *base,
+                     u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
+{
+       *p_os_reg2 |= base->dramtype << SYS_REG_DDRTYPE_SHIFT;
+       *p_os_reg2 |= (base->num_channels - 1) << SYS_REG_NUM_CH_SHIFT;
+       *p_os_reg2 |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(channel);
+       *p_os_reg2 |= 1 << SYS_REG_CHINFO_SHIFT(channel);
+       *p_os_reg2 |= (info->rank - 1) << SYS_REG_RANK_SHIFT(channel);
+       *p_os_reg2 |= (info->col - 9) << SYS_REG_COL_SHIFT(channel);
+       *p_os_reg2 |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(channel);
+       *p_os_reg2 |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(channel);
+       if (info->cs1_row >= 13)
+               *p_os_reg2 |= (info->cs1_row - 13) << 
SYS_REG_CS1_ROW_SHIFT(channel);
+       *p_os_reg2 |= (2 >> info->bw) << SYS_REG_BW_SHIFT(channel);
+       *p_os_reg2 |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(channel);
+}
+
+void sdram_msch_config(struct px30_msch_regs *msch,
+                      struct px30_msch_timings *noc_timings,
+                      struct px30_sdram_channel *cap_info,
+                      struct px30_base_params *base)
+{
+       u64 cs_cap[2];
+
+       cs_cap[0] = sdram_get_cs_cap(cap_info, 0, base->dramtype);
+       cs_cap[1] = sdram_get_cs_cap(cap_info, 1, base->dramtype);
+       writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) |
+                       (((cs_cap[0] >> 20) / 64) & 0xff),
+                       &msch->devicesize);
+
+       writel(noc_timings->ddrtiminga0, &msch->ddrtiminga0);
+       writel(noc_timings->ddrtimingb0, &msch->ddrtimingb0);
+       writel(noc_timings->ddrtimingc0, &msch->ddrtimingc0);
+       writel(noc_timings->devtodev0, &msch->devtodev0);
+       writel(noc_timings->ddrmode, &msch->ddrmode);
+       writel(noc_timings->ddr4timing, &msch->ddr4timing);
+       writel(noc_timings->agingx0, &msch->agingx0);
+       writel(noc_timings->agingx0, &msch->aging0);
+       writel(noc_timings->agingx0, &msch->aging1);
+       writel(noc_timings->agingx0, &msch->aging2);
+       writel(noc_timings->agingx0, &msch->aging3);
+}
+
+int sdram_detect_bw(struct px30_sdram_channel *cap_info)
+{
+       return 0;
+}
+
+int sdram_detect_cs(struct px30_sdram_channel *cap_info)
+{
+       return 0;
+}
+
+int sdram_detect_col(struct px30_sdram_channel *cap_info,
+                    u32 coltmp)
+{
+       void __iomem *test_addr;
+       u32 col;
+       u32 bw = cap_info->bw;
+
+       for (col = coltmp; col >= 9; col -= 1) {
+               writel(0, CONFIG_SYS_SDRAM_BASE);
+               test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+                               (1ul << (col + bw - 1ul)));
+               writel(PATTERN, test_addr);
+               if ((readl(test_addr) == PATTERN) &&
+                   (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+                       break;
+       }
+       if (col == 8) {
+               printascii("col error\n");
+               return -1;
+       }
+
+       cap_info->col = col;
+
+       return 0;
+}
+
+int sdram_detect_bank(struct px30_sdram_channel *cap_info,
+                     u32 coltmp, u32 bktmp)
+{
+       void __iomem *test_addr;
+       u32 bk;
+       u32 bw = cap_info->bw;
+
+       test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+                       (1ul << (coltmp + bktmp + bw - 1ul)));
+       writel(0, CONFIG_SYS_SDRAM_BASE);
+       writel(PATTERN, test_addr);
+       if ((readl(test_addr) == PATTERN) &&
+           (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+               bk = 3;
+       else
+               bk = 2;
+
+       cap_info->bk = bk;
+
+       return 0;
+}
+
+/* detect bg for ddr4 */
+int sdram_detect_bg(struct px30_sdram_channel *cap_info,
+                   u32 coltmp)
+{
+       void __iomem *test_addr;
+       u32 dbw;
+       u32 bw = cap_info->bw;
+
+       test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+                       (1ul << (coltmp + bw + 1ul)));
+       writel(0, CONFIG_SYS_SDRAM_BASE);
+       writel(PATTERN, test_addr);
+       if ((readl(test_addr) == PATTERN) &&
+           (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+               dbw = 0;
+       else
+               dbw = 1;
+
+       cap_info->dbw = dbw;
+
+       return 0;
+}
+
+/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
+int sdram_detect_dbw(struct px30_sdram_channel *cap_info, u32 dram_type)
+{
+       u32 row, col, bk, bw, cs_cap, cs;
+       u32 die_bw_0 = 0, die_bw_1 = 0;
+
+       if (dram_type == DDR3 || dram_type == LPDDR4) {
+               cap_info->dbw = 1;
+       } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
+               row = cap_info->cs0_row;
+               col = cap_info->col;
+               bk = cap_info->bk;
+               cs = cap_info->rank;
+               bw = cap_info->bw;
+               cs_cap = (1 << (row + col + bk + bw - 20));
+               if (bw == 2) {
+                       if (cs_cap <= 0x2000000) /* 256Mb */
+                               die_bw_0 = (col < 9) ? 2 : 1;
+                       else if (cs_cap <= 0x10000000) /* 2Gb */
+                               die_bw_0 = (col < 10) ? 2 : 1;
+                       else if (cs_cap <= 0x40000000) /* 8Gb */
+                               die_bw_0 = (col < 11) ? 2 : 1;
+                       else
+                               die_bw_0 = (col < 12) ? 2 : 1;
+                       if (cs > 1) {
+                               row = cap_info->cs1_row;
+                               cs_cap = (1 << (row + col + bk + bw - 20));
+                               if (cs_cap <= 0x2000000) /* 256Mb */
+                                       die_bw_0 = (col < 9) ? 2 : 1;
+                               else if (cs_cap <= 0x10000000) /* 2Gb */
+                                       die_bw_0 = (col < 10) ? 2 : 1;
+                               else if (cs_cap <= 0x40000000) /* 8Gb */
+                                       die_bw_0 = (col < 11) ? 2 : 1;
+                               else
+                                       die_bw_0 = (col < 12) ? 2 : 1;
+                       }
+               } else {
+                       die_bw_1 = 1;
+                       die_bw_0 = 1;
+               }
+               cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
+       }
+
+       return 0;
+}
+
+int sdram_detect_row(struct px30_sdram_channel *cap_info,
+                    u32 coltmp, u32 bktmp, u32 rowtmp)
+{
+       u32 row;
+       u32 bw = cap_info->bw;
+       void __iomem *test_addr;
+
+       for (row = rowtmp; row > 12; row--) {
+               writel(0, CONFIG_SYS_SDRAM_BASE);
+               test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+                               (1ul << (row + bktmp + coltmp + bw - 1ul)));
+               writel(PATTERN, test_addr);
+               if ((readl(test_addr) == PATTERN) &&
+                   (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+                       break;
+       }
+       if (row == 12) {
+               printascii("row error");
+               return -1;
+       }
+
+       cap_info->cs0_row = row;
+
+       return 0;
+}
+
+int sdram_detect_row_3_4(struct px30_sdram_channel *cap_info,
+                        u32 coltmp, u32 bktmp)
+{
+       u32 row_3_4;
+       u32 bw = cap_info->bw;
+       u32 row = cap_info->cs0_row;
+       void __iomem *test_addr, *test_addr1;
+
+       test_addr = CONFIG_SYS_SDRAM_BASE;
+       test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+                       (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
+
+       writel(0, test_addr);
+       writel(PATTERN, test_addr1);
+       if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
+               row_3_4 = 0;
+       else
+               row_3_4 = 1;
+
+       cap_info->row_3_4 = row_3_4;
+
+       return 0;
+}
+
+int sdram_detect_high_row(struct px30_sdram_channel *cap_info)
+{
+       cap_info->cs0_high16bit_row = cap_info->cs0_row;
+       cap_info->cs1_high16bit_row = cap_info->cs1_row;
+
+       return 0;
+}
+
+int sdram_detect_cs1_row(struct px30_sdram_channel *cap_info, u32 dram_type)
+{
+       void __iomem *test_addr;
+       u32 row = 0, bktmp, coltmp, bw;
+       ulong cs0_cap;
+       u32 byte_mask;
+
+       if (cap_info->rank == 2) {
+               cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
+
+               if (dram_type == DDR4) {
+                       if (cap_info->dbw == 0)
+                               bktmp = cap_info->bk + 2;
+                       else
+                               bktmp = cap_info->bk + 1;
+               } else {
+                       bktmp = cap_info->bk;
+               }
+               bw = cap_info->bw;
+               coltmp = cap_info->col;
+
+               /*
+                * because px30 support axi split,min bandwidth
+                * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
+                * so we check low 16bit data when detect cs1 row.
+                * if cs0 is 16bit/8bit, we check low 8bit data.
+                */
+               if (bw == 2)
+                       byte_mask = 0xFFFF;
+               else
+                       byte_mask = 0xFF;
+
+               /* detect cs1 row */
+               for (row = cap_info->cs0_row; row > 12; row--) {
+                       test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+                                   cs0_cap +
+                                   (1ul << (row + bktmp + coltmp + bw - 1ul)));
+                       writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
+                       writel(PATTERN, test_addr);
+
+                       if (((readl(test_addr) & byte_mask) ==
+                            (PATTERN & byte_mask)) &&
+                           ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
+                             byte_mask) == 0)) {
+                               break;
+                       }
+               }
+       }
+
+       cap_info->cs1_row = row;
+
+       return 0;
+}
+
+static void rkclk_ddr_reset(struct dram_info *dram,
+                           u32 ctl_srstn, u32 ctl_psrstn,
+                           u32 phy_srstn, u32 phy_psrstn)
+{
+       writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) |
+              upctl2_asrstn_req(ctl_srstn),
+              &dram->cru->softrst_con[1]);
+       writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn),
+              &dram->cru->softrst_con[2]);
+}
+
+static void rkclk_set_dpll(struct dram_info *dram, unsigned int hz)
+{
+       unsigned int refdiv, postdiv1, postdiv2, fbdiv;
+       int delay = 1000;
+       u32 mhz = hz / MHz;
+
+       refdiv = 1;
+       if (mhz <= 300) {
+               postdiv1 = 4;
+               postdiv2 = 2;
+       } else if (mhz <= 400) {
+               postdiv1 = 6;
+               postdiv2 = 1;
+       } else if (mhz <= 600) {
+               postdiv1 = 4;
+               postdiv2 = 1;
+       } else if (mhz <= 800) {
+               postdiv1 = 3;
+               postdiv2 = 1;
+       } else if (mhz <= 1600) {
+               postdiv1 = 2;
+               postdiv2 = 1;
+       } else {
+               postdiv1 = 1;
+               postdiv2 = 1;
+       }
+       fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24;
+
+       writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode);
+
+       writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0);
+       writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv),
+              &dram->cru->pll[1].con1);
+
+       while (delay > 0) {
+               rockchip_udelay(1);
+               if (LOCK(readl(&dram->cru->pll[1].con1)))
+                       break;
+               delay--;
+       }
+
+       writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode);
+}
+
+static void rkclk_configure_ddr(struct dram_info *dram,
+                               struct px30_sdram_params *sdram_params)
+{
+       /* for inno ddr phy need 2*freq */
+       rkclk_set_dpll(dram,  sdram_params->base.ddr_freq * MHz * 2);
+}
+
+/* return ddrconfig value
+ *       (-1), find ddrconfig fail
+ *       other, the ddrconfig value
+ * only support cs0_row >= cs1_row
+ */
+static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params)
+{
+       struct px30_sdram_channel *cap_info = &sdram_params->ch;
+       u32 bw, die_bw, col, bank;
+       u32 i, tmp;
+       u32 ddrconf = -1;
+
+       bw = cap_info->bw;
+       die_bw = cap_info->dbw;
+       col = cap_info->col;
+       bank = cap_info->bk;
+
+       if (sdram_params->base.dramtype == DDR4) {
+               if (die_bw == 0)
+                       ddrconf = 7 + bw;
+               else
+                       ddrconf = 12 - bw;
+               ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7];
+       } else {
+               tmp = ((bank - 2) << 3) | (col + bw - 10);
+               for (i = 0; i < 7; i++)
+                       if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) {
+                               ddrconf = i;
+                               break;
+                       }
+               if (i > 6)
+                       printascii("calculate ddrconfig error\n");
+       }
+
+       return ddrconf;
+}
+
+/*
+ * rank = 1: cs0
+ * rank = 2: cs1
+ */
+static void pctl_read_mr(void __iomem *pctl_base, u32 rank, u32 mr_num)
+{
+       writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0);
+       writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1);
+       setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
+       while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
+               continue;
+       while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
+               continue;
+}
+
+/* rank = 1: cs0
+ * rank = 2: cs1
+ * rank = 3: cs0 & cs1
+ * note: be careful of keep mr original val
+ */
+static int pctl_write_mr(void __iomem *pctl_base, u32 rank, u32 mr_num, u32 
arg,
+                        u32 dramtype)
+{
+       while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
+               continue;
+       if (dramtype == DDR3 || dramtype == DDR4) {
+               writel((mr_num << 12) | (rank << 4) | (0 << 0),
+                      pctl_base + DDR_PCTL2_MRCTRL0);
+               writel(arg, pctl_base + DDR_PCTL2_MRCTRL1);
+       } else {
+               writel((rank << 4) | (0 << 0),
+                      pctl_base + DDR_PCTL2_MRCTRL0);
+               writel((mr_num << 8) | (arg & 0xff),
+                      pctl_base + DDR_PCTL2_MRCTRL1);
+       }
+
+       setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
+       while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
+               continue;
+       while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
+               continue;
+
+       return 0;
+}
+
+static int upctl2_update_ref_reg(void __iomem *pctl_base)
+{
+       u32 ret;
+
+       ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1);
+       writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3);
+
+       return 0;
+}
+
+static u32 pctl_dis_zqcs_aref(void __iomem *pctl_base)
+{
+       u32 dis_auto_zq = 0;
+
+       /* disable zqcs */
+       if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
+               (1ul << 31))) {
+               dis_auto_zq = 1;
+               setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
+       }
+
+       /* disable auto refresh */
+       setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
+
+       upctl2_update_ref_reg(pctl_base);
+
+       return dis_auto_zq;
+}
+
+static void pctl_rest_zqcs_aref(void __iomem *pctl_base, u32 dis_auto_zq)
+{
+       /* restore zqcs */
+       if (dis_auto_zq)
+               clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
+
+       /* restore auto refresh */
+       clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
+
+       upctl2_update_ref_reg(pctl_base);
+}
+
+/*
+ * rank : 1:cs0, 2:cs1, 3:cs0&cs1
+ * vrefrate: 4500: 45%,
+ */
+static int pctl_write_vrefdq(void __iomem *pctl_base, u32 rank, u32 vrefrate,
+                            u32 dramtype)
+{
+       u32 tccd_l, value;
+       u32 dis_auto_zq = 0;
+
+       if (dramtype != DDR4 || vrefrate < 4500 ||
+           vrefrate > 9200)
+               return (-1);
+
+       tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf;
+       tccd_l = (tccd_l - 4) << 10;
+
+       if (vrefrate > 7500) {
+               /* range 1 */
+               value = ((vrefrate - 6000) / 65) | tccd_l;
+       } else {
+               /* range 2 */
+               value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6);
+       }
+
+       dis_auto_zq = pctl_dis_zqcs_aref(pctl_base);
+
+       /* enable vrefdq calibratin */
+       pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype);
+       udelay(1);/* tvrefdqe */
+       /* write vrefdq value */
+       pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype);
+       udelay(1);/* tvref_time */
+       pctl_write_mr(pctl_base, rank, 6, value | (0 << 7), dramtype);
+       udelay(1);/* tvrefdqx */
+
+       pctl_rest_zqcs_aref(pctl_base, dis_auto_zq);
+
+       return 0;
+}
+
+static u32 pctl_remodify_sdram_params(struct ddr_pctl_regs *pctl_regs,
+                                     struct px30_sdram_channel *cap_info,
+                              u32 dram_type)
+{
+       u32 tmp = 0, tmp_adr = 0, i;
+
+       for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) {
+               if (pctl_regs->pctl[i][0] == 0) {
+                       tmp = pctl_regs->pctl[i][1];/* MSTR */
+                       tmp_adr = i;
+               }
+       }
+
+       tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12));
+
+       switch (cap_info->dbw) {
+       case 2:
+               tmp |= (3ul << 30);
+               break;
+       case 1:
+               tmp |= (2ul << 30);
+               break;
+       case 0:
+       default:
+               tmp |= (1ul << 30);
+               break;
+       }
+
+       /*
+        * If DDR3 or DDR4 MSTR.active_ranks=1,
+        * it will gate memory clock when enter power down.
+        * Force set active_ranks to 3 to workaround it.
+        */
+       if (cap_info->rank == 2 || dram_type == DDR3 ||
+           dram_type == DDR4)
+               tmp |= 3 << 24;
+       else
+               tmp |= 1 << 24;
+
+       tmp |= (2 - cap_info->bw) << 12;
+
+       pctl_regs->pctl[tmp_adr][1] = tmp;
+
+       return 0;
+}
+
+static int pctl_cfg(void __iomem *pctl_base, struct ddr_pctl_regs *pctl_regs,
+                   u32 sr_idle, u32 pd_idle)
+{
+       u32 i;
+
+       for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) {
+               writel(pctl_regs->pctl[i][1],
+                      pctl_base + pctl_regs->pctl[i][0]);
+       }
+       clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG,
+                       (0xff << 16) | 0x1f,
+                       ((sr_idle & 0xff) << 16) | (pd_idle & 0x1f));
+
+       clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL,
+                       0xfff << 16,
+                       5 << 16);
+       /* disable zqcs */
+       setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31);
+
+       return 0;
+}
+
+/*
+ * calculate controller dram address map, and setting to register.
+ * argument sdram_params->ch.ddrconf must be right value before
+ * call this function.
+ */
+static void set_ctl_address_map(struct dram_info *dram,
+                               struct px30_sdram_params *sdram_params)
+{
+       struct px30_sdram_channel *cap_info = &sdram_params->ch;
+       void __iomem *pctl_base = dram->pctl;
+       u32 cs_pst, bg, max_row, ddrconf;
+       u32 i;
+
+       if (sdram_params->base.dramtype == DDR4)
+               /*
+                * DDR4 8bit dram BG = 2(4bank groups),
+                * 16bit dram BG = 1 (2 bank groups)
+                */
+               bg = (cap_info->dbw == 0) ? 2 : 1;
+       else
+               bg = 0;
+
+       cs_pst = cap_info->bw + cap_info->col +
+               bg + cap_info->bk + cap_info->cs0_row;
+       if (cs_pst >= 32 || cap_info->rank == 1)
+               writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0);
+       else
+               writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0);
+
+       ddrconf = cap_info->ddrconfig;
+       if (sdram_params->base.dramtype == DDR4) {
+               for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) {
+                       if (d4_rbc_2_d3_rbc[i] == ddrconf) {
+                               ddrconf = 7 + i;
+                               break;
+                       }
+               }
+       }
+
+       sdram_copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1),
+                         &addrmap[ddrconf][0], 8 * 4);
+       max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf);
+
+       if (max_row < 12)
+               printascii("set addrmap fail\n");
+       /* need to disable row ahead of rank by set to 0xf */
+       for (i = 17; i > max_row; i--)
+               clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 +
+                       ((i - 12) * 8 / 32) * 4,
+                       0xf << ((i - 12) * 8 % 32),
+                       0xf << ((i - 12) * 8 % 32));
+
+       if ((sdram_params->base.dramtype == LPDDR3 ||
+            sdram_params->base.dramtype == LPDDR2) &&
+                cap_info->row_3_4)
+               setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
+       if (sdram_params->base.dramtype == DDR4 && cap_info->bw != 0x2)
+               setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
+}
+
+/*
+ * rank = 1: cs0
+ * rank = 2: cs1
+ */
+int read_mr(struct dram_info *dram, u32 rank, u32 mr_num)
+{
+       void __iomem *ddr_grf_base = dram->ddr_grf;
+
+       pctl_read_mr(dram->pctl, rank, mr_num);
+
+       return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff);
+}
+
+#define MIN(a, b)      (((a) > (b)) ? (b) : (a))
+#define MAX(a, b)      (((a) > (b)) ? (a) : (b))
+static u32 check_rd_gate(struct dram_info *dram)
+{
+       void __iomem *phy_base = dram->phy;
+
+       u32 max_val = 0;
+       u32 min_val = 0xff;
+       u32 gate[4];
+       u32 i, bw;
+
+       bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf;
+       switch (bw) {
+       case 0x1:
+               bw = 1;
+               break;
+       case 0x3:
+               bw = 2;
+               break;
+       case 0xf:
+       default:
+               bw = 4;
+               break;
+       }
+
+       for (i = 0; i < bw; i++) {
+               gate[i] = readl(PHY_REG(phy_base, 0xfb + i));
+               max_val = MAX(max_val, gate[i]);
+               min_val = MIN(min_val, gate[i]);
+       }
+
+       if (max_val > 0x80 || min_val < 0x20)
+               return -1;
+       else
+               return 0;
+}
+
+static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
+{
+       void __iomem *pctl_base = dram->pctl;
+       u32 dis_auto_zq = 0;
+       u32 pwrctl;
+       u32 ret;
+
+       /* disable auto low-power */
+       pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
+       writel(0, pctl_base + DDR_PCTL2_PWRCTL);
+
+       dis_auto_zq = pctl_dis_zqcs_aref(dram->pctl);
+
+       ret = phy_data_training(dram->phy, cs, dramtype);
+
+       pctl_rest_zqcs_aref(dram->pctl, dis_auto_zq);
+
+       /* restore auto low-power */
+       writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
+
+       return ret;
+}
+
+static void dram_set_bw(struct dram_info *dram, u32 bw)
+{
+       phy_dram_set_bw(dram->phy, bw);
+}
+
+static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
+{
+       writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf);
+       rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14);
+}
+
+static void dram_all_config(struct dram_info *dram,
+                           struct px30_sdram_params *sdram_params)
+{
+       struct px30_sdram_channel *cap_info = &sdram_params->ch;
+       u32 sys_reg2 = 0;
+       u32 sys_reg3 = 0;
+
+       set_ddrconfig(dram, cap_info->ddrconfig);
+       sdram_org_config(cap_info, &sdram_params->base, &sys_reg2,
+                        &sys_reg3, 0);
+       writel(sys_reg2, &dram->pmugrf->os_reg[2]);
+       writel(sys_reg3, &dram->pmugrf->os_reg[3]);
+       sdram_msch_config(dram->msch, &sdram_params->ch.noc_timings, cap_info,
+                         &sdram_params->base);
+}
+
+static void enable_low_power(struct dram_info *dram,
+                            struct px30_sdram_params *sdram_params)
+{
+       void __iomem *pctl_base = dram->pctl;
+       void __iomem *phy_base = dram->phy;
+       void __iomem *ddr_grf_base = dram->ddr_grf;
+       u32 grf_lp_con;
+
+       /*
+        * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating
+        * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access
+        * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating
+        * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr
+        * bit4: grf_upctl_syscreq_cg_en = 1
+        *       ungating coreclk when c_sysreq assert
+        * bit8-11: grf_auto_sr_dly = 6
+        */
+       writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]);
+
+       if (sdram_params->base.dramtype == DDR4)
+               grf_lp_con = (0x7 << 16) | (1 << 1);
+       else if (sdram_params->base.dramtype == DDR3)
+               grf_lp_con = (0x7 << 16) | (1 << 0);
+       else
+               grf_lp_con = (0x7 << 16) | (1 << 2);
+
+       /* en lpckdis_en */
+       grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9);
+       writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON);
+
+       /* off digit module clock when enter power down */
+       setbits_le32(PHY_REG(phy_base, 7), 1 << 7);
+
+       /* enable sr, pd */
+       if (PD_IDLE == 0)
+               clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
+       else
+               setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
+       if (SR_IDLE == 0)
+               clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
+       else
+               setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
+       setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3));
+}
+
+/*
+ * pre_init: 0: pre init for dram cap detect
+ * 1: detect correct cap(except cs1 row)info, than reinit
+ * 2: after reinit, we detect cs1_row, if cs1_row not equal
+ *    to cs0_row and cs is in middle on ddrconf map, we need
+ *    to reinit dram, than set the correct ddrconf.
+ */
+static int sdram_init_(struct dram_info *dram,
+                      struct px30_sdram_params *sdram_params, u32 pre_init)
+{
+       struct px30_sdram_channel *cap_info = &sdram_params->ch;
+       void __iomem *pctl_base = dram->pctl;
+
+       rkclk_ddr_reset(dram, 1, 1, 1, 1);
+       rockchip_udelay(10);
+       /*
+        * dereset ddr phy psrstn to config pll,
+        * if using phy pll psrstn must be dereset
+        * before config pll
+        */
+       rkclk_ddr_reset(dram, 1, 1, 1, 0);
+       rkclk_configure_ddr(dram, sdram_params);
+
+       /* release phy srst to provide clk to ctrl */
+       rkclk_ddr_reset(dram, 1, 1, 0, 0);
+       rockchip_udelay(10);
+       phy_soft_reset(dram->phy);
+
+       /* release ctrl presetn, and config ctl registers */
+       rkclk_ddr_reset(dram, 1, 0, 0, 0);
+       pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE);
+       cap_info->ddrconfig = calculate_ddrconfig(sdram_params);
+       set_ctl_address_map(dram, sdram_params);
+       phy_cfg(dram->phy, &sdram_params->phy_regs, sdram_params->skew,
+               &sdram_params->base, cap_info->bw);
+
+       /* enable dfi_init_start to init phy after ctl srstn deassert */
+       setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
+
+       rkclk_ddr_reset(dram, 0, 0, 0, 0);
+       /* wait for dfi_init_done and dram init complete */
+       while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
+               continue;
+
+       if (sdram_params->base.dramtype == LPDDR3)
+               pctl_write_mr(dram->pctl, 3, 11, 3, LPDDR3);
+
+       /* do ddr gate training */
+redo_cs0_training:
+       if (data_training(dram, 0, sdram_params->base.dramtype) != 0) {
+               if (pre_init != 0)
+                       printascii("DTT cs0 error\n");
+               return -1;
+       }
+       if (check_rd_gate(dram)) {
+               printascii("re training cs0");
+               goto redo_cs0_training;
+       }
+
+       if (sdram_params->base.dramtype == LPDDR3) {
+               if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
+                       return -1;
+       } else if (sdram_params->base.dramtype == LPDDR2) {
+               if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
+                       return -1;
+       }
+
+       /* for px30: when 2cs, both 2 cs should be training */
+       if (pre_init != 0 && cap_info->rank == 2) {
+redo_cs1_training:
+               if (data_training(dram, 1, sdram_params->base.dramtype) != 0) {
+                       printascii("DTT cs1 error\n");
+                       return -1;
+               }
+               if (check_rd_gate(dram)) {
+                       printascii("re training cs1");
+                       goto redo_cs1_training;
+               }
+       }
+
+       if (sdram_params->base.dramtype == DDR4)
+               pctl_write_vrefdq(dram->pctl, 0x3, 5670,
+                                 sdram_params->base.dramtype);
+
+       dram_all_config(dram, sdram_params);
+       enable_low_power(dram, sdram_params);
+
+       return 0;
+}
+
+static int dram_detect_cap(struct dram_info *dram,
+                          struct px30_sdram_params *sdram_params,
+                          unsigned char channel)
+{
+       struct px30_sdram_channel *cap_info = &sdram_params->ch;
+
+       /*
+        * for ddr3: ddrconf = 3
+        * for ddr4: ddrconf = 12
+        * for lpddr3: ddrconf = 3
+        * default bw = 1
+        */
+       u32 bk, bktmp;
+       u32 col, coltmp;
+       u32 rowtmp;
+       u32 cs;
+       u32 bw = 1;
+       u32 dram_type = sdram_params->base.dramtype;
+
+       if (dram_type != DDR4) {
+               /* detect col and bk for ddr3/lpddr3 */
+               coltmp = 12;
+               bktmp = 3;
+               if (dram_type == LPDDR2)
+                       rowtmp = 15;
+               else
+                       rowtmp = 16;
+
+               if (sdram_detect_col(cap_info, coltmp) != 0)
+                       goto cap_err;
+               sdram_detect_bank(cap_info, coltmp, bktmp);
+               sdram_detect_dbw(cap_info, dram_type);
+       } else {
+               /* detect bg for ddr4 */
+               coltmp = 10;
+               bktmp = 4;
+               rowtmp = 17;
+
+               col = 10;
+               bk = 2;
+               cap_info->col = col;
+               cap_info->bk = bk;
+               sdram_detect_bg(cap_info, coltmp);
+       }
+
+       /* detect row */
+       if (sdram_detect_row(cap_info, coltmp, bktmp, rowtmp) != 0)
+               goto cap_err;
+
+       /* detect row_3_4 */
+       sdram_detect_row_3_4(cap_info, coltmp, bktmp);
+
+       /* bw and cs detect using data training */
+       if (data_training(dram, 1, dram_type) == 0)
+               cs = 1;
+       else
+               cs = 0;
+       cap_info->rank = cs + 1;
+
+       dram_set_bw(dram, 2);
+       if (data_training(dram, 0, dram_type) == 0)
+               bw = 2;
+       else
+               bw = 1;
+       cap_info->bw = bw;
+
+       cap_info->cs0_high16bit_row = cap_info->cs0_row;
+       if (cs) {
+               cap_info->cs1_row = cap_info->cs0_row;
+               cap_info->cs1_high16bit_row = cap_info->cs0_row;
+       } else {
+               cap_info->cs1_row = 0;
+               cap_info->cs1_high16bit_row = 0;
+       }
+
+       return 0;
+cap_err:
+       return -1;
+}
+
+static int sdram_init_detect(struct dram_info *dram,
+                            struct px30_sdram_params *sdram_params)
+{
+       struct px30_sdram_channel *cap_info = &sdram_params->ch;
+       u32 ret;
+       u32 sys_reg = 0;
+       u32 sys_reg3 = 0;
+
+       if (sdram_init_(dram, sdram_params, 0) != 0)
+               return -1;
+
+       if (dram_detect_cap(dram, sdram_params, 0) != 0)
+               return -1;
+
+       /* modify bw, cs related timing */
+       pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info,
+                                  sdram_params->base.dramtype);
+       /* reinit sdram by real dram cap */
+       ret = sdram_init_(dram, sdram_params, 1);
+       if (ret != 0)
+               goto out;
+
+       /* redetect cs1 row */
+       sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype);
+       if (cap_info->cs1_row) {
+               sys_reg = readl(&dram->pmugrf->os_reg[2]);
+               sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
+               writel(sys_reg, &dram->pmugrf->os_reg[2]);
+               writel(sys_reg3, &dram->pmugrf->os_reg[3]);
+       }
+
+       ret = sdram_detect_high_row(cap_info);
+
+out:
+       return ret;
+}
+
+struct px30_sdram_params *get_default_sdram_config(void)
+{
+       sdram_configs[0].skew = &skew;
+
+       return &sdram_configs[0];
+}
+
+int sdram_init(void)
+{
+       struct px30_sdram_params *sdram_params;
+       int ret = 0;
+
+       dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
+       dram_info.pctl = (void *)DDRC_BASE_ADDR;
+       dram_info.grf = (void *)GRF_BASE_ADDR;
+       dram_info.cru = (void *)CRU_BASE_ADDR;
+       dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
+       dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
+       dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
+
+       sdram_params = get_default_sdram_config();
+       ret = sdram_init_detect(&dram_info, sdram_params);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+#endif /* CONFIG_TPL_BUILD */
diff --git a/arch/arm/mach-rockchip/px30/syscon_px30.c 
b/arch/arm/mach-rockchip/px30/syscon_px30.c
new file mode 100644
index 0000000000..0331491b40
--- /dev/null
+++ b/arch/arm/mach-rockchip/px30/syscon_px30.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+
+static const struct udevice_id px30_syscon_ids[] = {
+       { .compatible = "rockchip,px30-pmu", .data = ROCKCHIP_SYSCON_PMU },
+       { .compatible = "rockchip,px30-pmugrf", .data = ROCKCHIP_SYSCON_PMUGRF 
},
+       { .compatible = "rockchip,px30-grf", .data = ROCKCHIP_SYSCON_GRF },
+       { }
+};
+
+U_BOOT_DRIVER(syscon_px30) = {
+       .id = UCLASS_SYSCON,
+       .name = "px30_syscon",
+       .of_match = px30_syscon_ids,
+};
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+static int px30_syscon_bind_of_platdata(struct udevice *dev)
+{
+       dev->driver_data = dev->driver->of_match->data;
+       debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data);
+
+       return 0;
+}
+
+U_BOOT_DRIVER(rockchip_px30_pmu) = {
+       .name = "rockchip_px30_pmu",
+       .id = UCLASS_SYSCON,
+       .of_match = px30_syscon_ids,
+       .bind = px30_syscon_bind_of_platdata,
+};
+
+U_BOOT_DRIVER(rockchip_px30_pmugrf) = {
+       .name = "rockchip_px30_pmugrf",
+       .id = UCLASS_SYSCON,
+       .of_match = px30_syscon_ids + 1,
+       .bind = px30_syscon_bind_of_platdata,
+};
+
+U_BOOT_DRIVER(rockchip_px30_grf) = {
+       .name = "rockchip_px30_grf",
+       .id = UCLASS_SYSCON,
+       .of_match = px30_syscon_ids + 2,
+       .bind = px30_syscon_bind_of_platdata,
+};
+#endif
-- 
2.23.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to