diff mbox series

[U-Boot,11/12] rockchip: add px30 architecture core

Message ID 20191024232803.10338-12-heiko@sntech.de
State Accepted
Delegated to: Kever Yang
Headers show
Series rockchip: add support for px30 | expand

Commit Message

Heiko Stuebner Oct. 24, 2019, 11:28 p.m. UTC
From: Kever Yang <kever.yang@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.yang@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko.stuebner@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

Comments

Kever Yang Oct. 25, 2019, 2:49 a.m. UTC | #1
Heiko,

On 2019/10/25 上午7:28, Heiko Stuebner wrote:
> From: Kever Yang <kever.yang@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.


Could you leave the sram code and make it possible to use the common 
sdram code

I have send out:

https://patchwork.ozlabs.org/cover/1183700/

The sram driver should goes to driver/ram folder instead of arch/arm folder.

>
> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
> Signed-off-by: Heiko Stuebner <heiko.stuebner@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


This TPL_TINY_FRAMEWORK is not available on upstream, remove it.

Other code looks good for me.

Thanks,

- Kever

> +	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
Heiko Stuebner Oct. 25, 2019, 7:47 a.m. UTC | #2
Hi Kever,

Am Freitag, 25. Oktober 2019, 04:49:54 CEST schrieb Kever Yang:
> On 2019/10/25 上午7:28, Heiko Stuebner wrote:
> > From: Kever Yang <kever.yang@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.
> 
> 
> Could you leave the sram code and make it possible to use the common 
> sdram code
> 
> I have send out:
> 
> https://patchwork.ozlabs.org/cover/1183700/
> 
> The sram driver should goes to driver/ram folder instead of arch/arm folder.

That won't work. For the px30, the ddr-init portion will need to stay in
arch-rockchip/px30 I'm afraid.

To compile things in drivers/ram you need to have TPL_RAM enabled
which in turn depends on TPL_DM which in turn makes the tpl size
to big.

So drivers/ram/... can probably only contain the dm-based part I introduce
in patch9 of this series.


Heiko
Kever Yang Nov. 10, 2019, 2:13 p.m. UTC | #3
On 2019/10/25 下午3:47, Heiko Stübner wrote:
> Hi Kever,
>
> Am Freitag, 25. Oktober 2019, 04:49:54 CEST schrieb Kever Yang:
>> On 2019/10/25 上午7:28, Heiko Stuebner wrote:
>>> From: Kever Yang <kever.yang@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.
>>
>> Could you leave the sram code and make it possible to use the common
>> sdram code
>>
>> I have send out:
>>
>> https://patchwork.ozlabs.org/cover/1183700/
>>
>> The sram driver should goes to driver/ram folder instead of arch/arm folder.
> That won't work. For the px30, the ddr-init portion will need to stay in
> arch-rockchip/px30 I'm afraid.
>
> To compile things in drivers/ram you need to have TPL_RAM enabled
> which in turn depends on TPL_DM which in turn makes the tpl size
> to big.


Can we just update the TPL_RAM not depends on DM, and leave the code in 
the driver/ram folder,

and let the code itself to decide if use DM or not? We do use 
CONFIG_TPL_BUILD and CONFIG_SPL_BUILD

for dram driver code to make choice.

The core implement of PX30 DRAM driver is shared with other SoCs, it 
should be at the same place with

other SoCs.

Thanks,

  - Kever

>
> So drivers/ram/... can probably only contain the dm-based part I introduce
> in patch9 of this series.
>
>
> Heiko
>
>
>
Heiko Stuebner Nov. 10, 2019, 2:46 p.m. UTC | #4
Hi Kever,

Am Sonntag, 10. November 2019, 15:13:52 CET schrieb Kever Yang:
> On 2019/10/25 下午3:47, Heiko Stübner wrote:
> > Am Freitag, 25. Oktober 2019, 04:49:54 CEST schrieb Kever Yang:
> >> On 2019/10/25 上午7:28, Heiko Stuebner wrote:
> >>> From: Kever Yang <kever.yang@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.
> >>
> >> Could you leave the sram code and make it possible to use the common
> >> sdram code
> >>
> >> I have send out:
> >>
> >> https://patchwork.ozlabs.org/cover/1183700/
> >>
> >> The sram driver should goes to driver/ram folder instead of arch/arm folder.
> > That won't work. For the px30, the ddr-init portion will need to stay in
> > arch-rockchip/px30 I'm afraid.
> >
> > To compile things in drivers/ram you need to have TPL_RAM enabled
> > which in turn depends on TPL_DM which in turn makes the tpl size
> > to big.
> 
> 
> Can we just update the TPL_RAM not depends on DM, and leave the code in 
> the driver/ram folder,
> 
> and let the code itself to decide if use DM or not? We do use 
> CONFIG_TPL_BUILD and CONFIG_SPL_BUILD
> 
> for dram driver code to make choice.
> 
> The core implement of PX30 DRAM driver is shared with other SoCs, it 
> should be at the same place with
> other SoCs.

CONFIG_RAM (the core symbol) already depends on CONFIG_DM, so changing
this will cause a lot of churn for us but also other drivers living there.
And thus probably a long and detailed discussion.

And while this will be worthwhile in the long run (also for the rk3036
and future socs), can we maybe do that in 2 steps?

Aka doing your ddr-series and px30-support and then in a second step adapt
drivers/ram as needed and move rk3036 + px30 over there?
That way we don't get stalled until everybody is happy with a solution.


Thanks
Heiko
diff mbox series

Patch

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