All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kever Yang <kever.yang@rock-chips.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v2 13/17] ram: rk3399: use common sdram driver
Date: Fri, 25 Oct 2019 09:34:00 +0800	[thread overview]
Message-ID: <20191025013404.10823-14-kever.yang@rock-chips.com> (raw)
In-Reply-To: <20191025013404.10823-1-kever.yang@rock-chips.com>

From: YouMin Chen <cym@rock-chips.com>

RK3399's controller and phy are able to re-use the common code, migrate
to use the common driver and remove duplicated code.

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

Changes in v2: None

 arch/arm/dts/rk3399-sdram-ddr3-1333.dtsi      |   4 +
 arch/arm/dts/rk3399-sdram-ddr3-1600.dtsi      |   4 +
 arch/arm/dts/rk3399-sdram-ddr3-1866.dtsi      |   4 +
 .../arm/dts/rk3399-sdram-lpddr3-2GB-1600.dtsi |   4 +
 .../arm/dts/rk3399-sdram-lpddr3-4GB-1600.dtsi |   4 +
 .../rk3399-sdram-lpddr3-samsung-4GB-1866.dtsi |   4 +
 arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi     |   4 +
 .../include/asm/arch-rockchip/sdram_rk3399.h  |  97 +-
 arch/arm/mach-rockchip/Kconfig                |   1 +
 drivers/ram/rockchip/Kconfig                  |  21 +-
 drivers/ram/rockchip/Makefile                 |   2 +-
 .../ram/rockchip/sdram-rk3399-lpddr4-400.inc  |  28 +-
 .../ram/rockchip/sdram-rk3399-lpddr4-800.inc  |  28 +-
 drivers/ram/rockchip/sdram_debug.c            | 147 +++
 drivers/ram/rockchip/sdram_rk3399.c           | 968 ++++++++++++------
 15 files changed, 932 insertions(+), 388 deletions(-)
 create mode 100644 drivers/ram/rockchip/sdram_debug.c

diff --git a/arch/arm/dts/rk3399-sdram-ddr3-1333.dtsi b/arch/arm/dts/rk3399-sdram-ddr3-1333.dtsi
index 3708bd674b..7fae249536 100644
--- a/arch/arm/dts/rk3399-sdram-ddr3-1333.dtsi
+++ b/arch/arm/dts/rk3399-sdram-ddr3-1333.dtsi
@@ -13,6 +13,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80120e12
 		0x11030802
@@ -28,6 +30,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80120e12
 		0x11030802
diff --git a/arch/arm/dts/rk3399-sdram-ddr3-1600.dtsi b/arch/arm/dts/rk3399-sdram-ddr3-1600.dtsi
index fcd01f8b46..23c7c34a9a 100644
--- a/arch/arm/dts/rk3399-sdram-ddr3-1600.dtsi
+++ b/arch/arm/dts/rk3399-sdram-ddr3-1600.dtsi
@@ -13,6 +13,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80151015
 		0x14040902
@@ -28,6 +30,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80151015
 		0x14040902
diff --git a/arch/arm/dts/rk3399-sdram-ddr3-1866.dtsi b/arch/arm/dts/rk3399-sdram-ddr3-1866.dtsi
index c46c1996be..ea029ca90a 100644
--- a/arch/arm/dts/rk3399-sdram-ddr3-1866.dtsi
+++ b/arch/arm/dts/rk3399-sdram-ddr3-1866.dtsi
@@ -13,6 +13,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80181219
 		0x17050a03
@@ -28,6 +30,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80181219
 		0x17050a03
diff --git a/arch/arm/dts/rk3399-sdram-lpddr3-2GB-1600.dtsi b/arch/arm/dts/rk3399-sdram-lpddr3-2GB-1600.dtsi
index d14e833d22..7296dbb80e 100644
--- a/arch/arm/dts/rk3399-sdram-lpddr3-2GB-1600.dtsi
+++ b/arch/arm/dts/rk3399-sdram-lpddr3-2GB-1600.dtsi
@@ -14,6 +14,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x1d191519
 		0x14040808
@@ -29,6 +31,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x1d191519
 		0x14040808
diff --git a/arch/arm/dts/rk3399-sdram-lpddr3-4GB-1600.dtsi b/arch/arm/dts/rk3399-sdram-lpddr3-4GB-1600.dtsi
index fc4cccb6a0..bf429c21e4 100644
--- a/arch/arm/dts/rk3399-sdram-lpddr3-4GB-1600.dtsi
+++ b/arch/arm/dts/rk3399-sdram-lpddr3-4GB-1600.dtsi
@@ -13,6 +13,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x1d191519
 		0x14040808
@@ -28,6 +30,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x1d191519
 		0x14040808
diff --git a/arch/arm/dts/rk3399-sdram-lpddr3-samsung-4GB-1866.dtsi b/arch/arm/dts/rk3399-sdram-lpddr3-samsung-4GB-1866.dtsi
index 2a627e1be5..96f459fd0b 100644
--- a/arch/arm/dts/rk3399-sdram-lpddr3-samsung-4GB-1866.dtsi
+++ b/arch/arm/dts/rk3399-sdram-lpddr3-samsung-4GB-1866.dtsi
@@ -13,6 +13,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 
 		0x801d181e
@@ -30,6 +32,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 
 		0x801d181e
diff --git a/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi b/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi
index 4a4414a960..f0c478d189 100644
--- a/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi
+++ b/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi
@@ -15,6 +15,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80241d22
 		0x15050f08
@@ -30,6 +32,8 @@
 		0x0
 		0xf
 		0xf
+		0xf
+		0xf
 		1
 		0x80241d22
 		0x15050f08
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
index 485bb3d889..9e1e22520f 100644
--- a/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
+++ b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
@@ -6,6 +6,7 @@
 #ifndef _ASM_ARCH_SDRAM_RK3399_H
 #define _ASM_ARCH_SDRAM_RK3399_H
 #include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_msch.h>
 
 struct rk3399_ddr_pctl_regs {
 	u32 denali_ctl[332];
@@ -19,55 +20,6 @@ struct rk3399_ddr_pi_regs {
 	u32 denali_pi[200];
 };
 
-union noc_ddrtimingc0 {
-	u32 d32;
-	struct {
-		unsigned burstpenalty : 4;
-		unsigned reserved0 : 4;
-		unsigned wrtomwr : 6;
-		unsigned reserved1 : 18;
-	} b;
-};
-
-union noc_ddrmode {
-	u32 d32;
-	struct {
-		unsigned autoprecharge : 1;
-		unsigned bypassfiltering : 1;
-		unsigned fawbank : 1;
-		unsigned burstsize : 2;
-		unsigned mwrsize : 2;
-		unsigned reserved2 : 1;
-		unsigned forceorder : 8;
-		unsigned forceorderstate : 8;
-		unsigned reserved3 : 8;
-	} b;
-};
-
-struct rk3399_msch_regs {
-	u32 coreid;
-	u32 revisionid;
-	u32 ddrconf;
-	u32 ddrsize;
-	u32 ddrtiminga0;
-	u32 ddrtimingb0;
-	u32 ddrtimingc0;
-	u32 devtodev0;
-	u32 reserved0[(0x110 - 0x20) / 4];
-	u32 ddrmode;
-	u32 reserved1[(0x1000 - 0x114) / 4];
-	u32 agingx0;
-};
-
-struct rk3399_msch_timings {
-	u32 ddrtiminga0;
-	u32 ddrtimingb0;
-	union noc_ddrtimingc0 ddrtimingc0;
-	u32 devtodev0;
-	union noc_ddrmode ddrmode;
-	u32 agingx0;
-};
-
 struct rk3399_ddr_cic_regs {
 	u32 cic_ctrl0;
 	u32 cic_ctrl1;
@@ -84,14 +36,38 @@ struct rk3399_ddr_cic_regs {
 #define START		1
 
 /* DENALI_CTL_68 */
-#define PWRUP_SREFRESH_EXIT	(1 << 16)
+#define PWRUP_SREFRESH_EXIT	BIT(16)
 
 /* DENALI_CTL_274 */
 #define MEM_RST_VALID	1
 
+struct msch_regs {
+	u32 coreid;
+	u32 revisionid;
+	u32 ddrconf;
+	u32 ddrsize;
+	union noc_ddrtiminga0 ddrtiminga0;
+	union noc_ddrtimingb0 ddrtimingb0;
+	union noc_ddrtimingc0 ddrtimingc0;
+	union noc_devtodev0 devtodev0;
+	u32 reserved0[(0x110 - 0x20) / 4];
+	union noc_ddrmode ddrmode;
+	u32 reserved1[(0x1000 - 0x114) / 4];
+	u32 agingx0;
+};
+
+struct sdram_msch_timings {
+	union noc_ddrtiminga0 ddrtiminga0;
+	union noc_ddrtimingb0 ddrtimingb0;
+	union noc_ddrtimingc0 ddrtimingc0;
+	union noc_devtodev0 devtodev0;
+	union noc_ddrmode ddrmode;
+	u32 agingx0;
+};
+
 struct rk3399_sdram_channel {
 	struct sdram_cap_info cap_info;
-	struct rk3399_msch_timings noc_timings;
+	struct sdram_msch_timings noc_timings;
 };
 
 struct rk3399_sdram_params {
@@ -102,11 +78,20 @@ struct rk3399_sdram_params {
 	struct rk3399_ddr_publ_regs phy_regs;
 };
 
-#define PI_CA_TRAINING		(1 << 0)
-#define PI_WRITE_LEVELING	(1 << 1)
-#define PI_READ_GATE_TRAINING	(1 << 2)
-#define PI_READ_LEVELING	(1 << 3)
-#define PI_WDQ_LEVELING		(1 << 4)
+#define PI_CA_TRAINING		BIT(0)
+#define PI_WRITE_LEVELING	BIT(1)
+#define PI_READ_GATE_TRAINING	BIT(2)
+#define PI_READ_LEVELING	BIT(3)
+#define PI_WDQ_LEVELING		BIT(4)
 #define PI_FULL_TRAINING	0xff
 
+enum {
+	STRIDE_128B = 0,
+	STRIDE_256B = 1,
+	STRIDE_512B = 2,
+	STRIDE_4KB = 3,
+	UN_STRIDE = 4,
+	PART_STRIDE = 5
+};
+
 #endif
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 5f1ad51cac..7746b661e5 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -184,6 +184,7 @@ config ROCKCHIP_RK3399
 	select DM_REGULATOR_FIXED
 	select BOARD_LATE_INIT
 	imply ROCKCHIP_COMMON_BOARD
+	imply ROCKCHIP_SDRAM_COMMON
 	imply SPL_ROCKCHIP_COMMON_BOARD
 	imply TPL_SERIAL_SUPPORT
 	imply TPL_LIBCOMMON_SUPPORT
diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig
index dcc06b3fd3..3f44fb3fce 100644
--- a/drivers/ram/rockchip/Kconfig
+++ b/drivers/ram/rockchip/Kconfig
@@ -11,29 +11,10 @@ config ROCKCHIP_SDRAM_COMMON
 	help
 	  This enable sdram common driver
 
-if RAM_ROCKCHIP
-
-config RAM_ROCKCHIP_DEBUG
-	bool "Rockchip ram drivers debugging"
-	help
-	  This enables debugging ram driver API's for the platforms
-	  based on Rockchip SoCs.
-
-	  This is an option for developers to understand the ram drivers
-	  initialization, configurations and etc.
-
-config RAM_RK3399
-	bool "Ram driver for Rockchip RK3399"
-	default ROCKCHIP_RK3399
-	help
-	  This enables ram drivers support for the platforms based on
-	  Rockchip RK3399 SoC.
-
 config RAM_RK3399_LPDDR4
 	bool "LPDDR4 support for Rockchip RK3399"
-	depends on RAM_RK3399
+	depends on RAM_ROCKCHIP && ROCKCHIP_RK3399
 	help
 	  This enables LPDDR4 sdram code support for the platforms based
 	  on Rockchip RK3399 SoC.
 
-endif # RAM_ROCKCHIP
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index b42ef91c21..47b9b1bebb 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o
 obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o
 obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o
 obj-$(CONFIG_ROCKCHIP_RK3328) += sdram_rk3328.o sdram_pctl_px30.o sdram_phy_px30.o
-obj-$(CONFIG_RAM_RK3399) += sdram_rk3399.o
+obj-$(CONFIG_ROCKCHIP_RK3399) += sdram_rk3399.o
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
index c50a03d9dd..6ddc01c49d 100644
--- a/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
@@ -16,15 +16,23 @@
 				.row_3_4 = 0x0,
 				.cs0_row = 0xF,
 				.cs1_row = 0xF,
+				.cs0_high16bit_row = 0xF,
+				.cs1_high16bit_row = 0xF,
 				.ddrconfig = 1,
 			},
 			{
-				.ddrtiminga0 = 0x80241d22,
-				.ddrtimingb0 = 0x15050f08,
+				.ddrtiminga0 = {
+					0x80241d22,
+				},
+				.ddrtimingb0 = {
+					0x15050f08,
+				},
 				.ddrtimingc0 = {
 					0x00000602,
 				},
-				.devtodev0 = 0x00002122,
+				.devtodev0 = {
+					0x00002122,
+				},
 				.ddrmode = {
 					0x0000004c,
 				},
@@ -41,15 +49,23 @@
 				.row_3_4 = 0x0,
 				.cs0_row = 0xF,
 				.cs1_row = 0xF,
+				.cs0_high16bit_row = 0xF,
+				.cs1_high16bit_row = 0xF,
 				.ddrconfig = 1,
 			},
 			{
-				.ddrtiminga0 = 0x80241d22,
-				.ddrtimingb0 = 0x15050f08,
+				.ddrtiminga0 = {
+					0x80241d22,
+				},
+				.ddrtimingb0 = {
+					0x15050f08,
+				},
 				.ddrtimingc0 = {
 					0x00000602,
 				},
-				.devtodev0 = 0x00002122,
+				.devtodev0 = {
+					0x00002122,
+				},
 				.ddrmode = {
 					0x0000004c,
 				},
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
index d8ae3359a3..307f6ee458 100644
--- a/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
@@ -16,15 +16,23 @@
 				.row_3_4 = 0x0,
 				.cs0_row = 0xF,
 				.cs1_row = 0xF,
+				.cs0_high16bit_row = 0xF,
+				.cs1_high16bit_row = 0xF,
 				.ddrconfig = 1,
 			},
 			{
-				.ddrtiminga0 = 0x80241d22,
-				.ddrtimingb0 = 0x15050f08,
+				.ddrtiminga0 = {
+					0x80241d22,
+				},
+				.ddrtimingb0 = {
+					0x15050f08,
+				},
 				.ddrtimingc0 = {
 					0x00000602,
 				},
-				.devtodev0 = 0x00002122,
+				.devtodev0 = {
+					0x00002122,
+				},
 				.ddrmode = {
 					0x0000004c,
 				},
@@ -41,15 +49,23 @@
 				.row_3_4 = 0x0,
 				.cs0_row = 0xF,
 				.cs1_row = 0xF,
+				.cs0_high16bit_row = 0xF,
+				.cs1_high16bit_row = 0xF,
 				.ddrconfig = 1,
 			},
 			{
-				.ddrtiminga0 = 0x80241d22,
-				.ddrtimingb0 = 0x15050f08,
+				.ddrtiminga0 = {
+					0x80241d22,
+				},
+				.ddrtimingb0 = {
+					0x15050f08,
+				},
 				.ddrtimingc0 = {
 					0x00000602,
 				},
-				.devtodev0 = 0x00002122,
+				.devtodev0 = {
+					0x00002122,
+				},
 				.ddrmode = {
 					0x0000004c,
 				},
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c
new file mode 100644
index 0000000000..133d1938d5
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_debug.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ * (C) Copyright 2019 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <asm/arch-rockchip/sdram.h>
+
+void sdram_print_dram_type(unsigned char dramtype)
+{
+	switch (dramtype) {
+	case DDR3:
+		printascii("DDR3");
+		break;
+	case DDR4:
+		printascii("DDR4");
+		break;
+	case LPDDR2:
+		printascii("LPDDR2");
+		break;
+	case LPDDR3:
+		printascii("LPDDR3");
+		break;
+	case LPDDR4:
+		printascii("LPDDR4");
+		break;
+	default:
+		printascii("Unknown Device");
+		break;
+	}
+}
+
+/**
+ * cs  = 0, cs0
+ * cs  = 1, cs1
+ * cs => 2, cs0+cs1
+ * note: it didn't consider about row_3_4
+ */
+u64 sdram_get_cs_cap(struct sdram_cap_info *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]);
+}
+
+void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
+			  struct sdram_base_params *base)
+{
+	u32 bg, cap;
+
+	bg = (cap_info->dbw == 0) ? 2 : 1;
+
+	sdram_print_dram_type(base->dramtype);
+
+	printascii(", ");
+	printdec(base->ddr_freq);
+	printascii("MHz\n");
+
+	printascii("BW=");
+	printdec(8 << cap_info->bw);
+
+	printascii(" Col=");
+	printdec(cap_info->col);
+
+	printascii(" Bk=");
+	printdec(0x1 << cap_info->bk);
+	if (base->dramtype == DDR4) {
+		printascii(" BG=");
+		printdec(1 << bg);
+	}
+
+	printascii(" CS0 Row=");
+	printdec(cap_info->cs0_row);
+	if (cap_info->rank > 1) {
+		printascii(" CS1 Row=");
+		printdec(cap_info->cs1_row);
+	}
+
+	printascii(" CS=");
+	printdec(cap_info->rank);
+
+	printascii(" Die BW=");
+	printdec(8 << cap_info->dbw);
+
+	cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
+	if (cap_info->row_3_4)
+		cap = cap * 3 / 4;
+
+	printascii(" Size=");
+	printdec(cap >> 20);
+	printascii("MB\n");
+}
+
+void sdram_print_stride(unsigned int stride)
+{
+	switch (stride) {
+	case 0xc:
+		printf("128B stride\n");
+		break;
+	case 5:
+	case 9:
+	case 0xd:
+	case 0x11:
+	case 0x19:
+		printf("256B stride\n");
+		break;
+	case 0xa:
+	case 0xe:
+	case 0x12:
+		printf("512B stride\n");
+		break;
+	case 0xf:
+		printf("4K stride\n");
+		break;
+	case 0x1f:
+		printf("32MB + 256B stride\n");
+		break;
+	default:
+		printf("no stride\n");
+	}
+}
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
index 9b7de4ae41..073fba0990 100644
--- a/drivers/ram/rockchip/sdram_rk3399.c
+++ b/drivers/ram/rockchip/sdram_rk3399.c
@@ -52,7 +52,7 @@ struct chan_info {
 	struct rk3399_ddr_pctl_regs *pctl;
 	struct rk3399_ddr_pi_regs *pi;
 	struct rk3399_ddr_publ_regs *publ;
-	struct rk3399_msch_regs *msch;
+	struct msch_regs *msch;
 };
 
 struct dram_info {
@@ -74,10 +74,15 @@ struct dram_info {
 };
 
 struct sdram_rk3399_ops {
-	int (*data_training)(struct dram_info *dram, u32 channel, u8 rank,
-			     struct rk3399_sdram_params *sdram);
-	int (*set_rate)(struct dram_info *dram,
-			struct rk3399_sdram_params *params);
+	int (*data_training_first)(struct dram_info *dram, u32 channel, u8 rank,
+				   struct rk3399_sdram_params *sdram);
+	int (*set_rate_index)(struct dram_info *dram,
+			      struct rk3399_sdram_params *params);
+	void (*modify_param)(const struct chan_info *chan,
+			     struct rk3399_sdram_params *params);
+	struct rk3399_sdram_params *
+		(*get_phy_index_params)(u32 phy_fn,
+					struct rk3399_sdram_params *params);
 };
 
 #if defined(CONFIG_TPL_BUILD) || \
@@ -196,11 +201,6 @@ struct io_setting {
 	},
 };
 
-/**
- * phy = 0, PHY boot freq
- * phy = 1, PHY index 0
- * phy = 2, PHY index 1
- */
 static struct io_setting *
 lpddr4_get_io_settings(const struct rk3399_sdram_params *params, u32 mr5)
 {
@@ -223,32 +223,21 @@ lpddr4_get_io_settings(const struct rk3399_sdram_params *params, u32 mr5)
 	return io;
 }
 
-static void *get_denali_phy(const struct chan_info *chan,
-			    struct rk3399_sdram_params *params, bool reg)
-{
-	return reg ? &chan->publ->denali_phy : &params->phy_regs.denali_phy;
-}
-
 static void *get_denali_ctl(const struct chan_info *chan,
 			    struct rk3399_sdram_params *params, bool reg)
 {
 	return reg ? &chan->pctl->denali_ctl : &params->pctl_regs.denali_ctl;
 }
 
-static void *get_ddrc0_con(struct dram_info *dram, u8 channel)
+static void *get_denali_phy(const struct chan_info *chan,
+			    struct rk3399_sdram_params *params, bool reg)
 {
-	return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc0_con1;
+	return reg ? &chan->publ->denali_phy : &params->phy_regs.denali_phy;
 }
 
-static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
+static void *get_ddrc0_con(struct dram_info *dram, u8 channel)
 {
-	int i;
-
-	for (i = 0; i < n / sizeof(u32); i++) {
-		writel(*src, dest);
-		src++;
-		dest++;
-	}
+	return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc1_con0;
 }
 
 static void rkclk_ddr_reset(struct rk3399_cru *cru, u32 channel, u32 ctl,
@@ -344,7 +333,7 @@ static void set_memory_map(const struct chan_info *chan, u32 channel,
 			((3 - sdram_ch->cap_info.bk) << 16) |
 			((16 - row) << 24));
 
-	if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+	if (params->base.dramtype == LPDDR4) {
 		if (cs_map == 1)
 			cs_map = 0x5;
 		else if (cs_map == 2)
@@ -496,7 +485,7 @@ static int phy_io_config(const struct chan_info *chan,
 	/* PHY_939 PHY_PAD_CS_DRIVE */
 	clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14);
 
-	if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+	if (params->base.dramtype == LPDDR4) {
 		/* BOOSTP_EN & BOOSTN_EN */
 		reg_value = ((PHY_BOOSTP_EN << 4) | PHY_BOOSTN_EN);
 		/* PHY_925 PHY_PAD_FDBK_DRIVE2 */
@@ -563,7 +552,7 @@ static int phy_io_config(const struct chan_info *chan,
 	/* PHY_939 PHY_PAD_CS_DRIVE */
 	clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
 
-	if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+	if (params->base.dramtype == LPDDR4) {
 		/* RX_CM_INPUT */
 		reg_value = PHY_RX_CM_INPUT;
 		/* PHY_924 PHY_PAD_FDBK_DRIVE */
@@ -733,7 +722,7 @@ static void set_ds_odt(const struct chan_info *chan,
 
 	/* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
 	reg_value = tsel_wr_select_ca_n | (tsel_wr_select_ca_p << 0x4);
-	if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+	if (params->base.dramtype == LPDDR4) {
 		/* LPDDR4 these register read always return 0, so
 		 * can not use clrsetbits_le32(), need to write32
 		 */
@@ -810,46 +799,107 @@ static void set_ds_odt(const struct chan_info *chan,
 	phy_io_config(chan, params, mr5);
 }
 
-static void pctl_start(struct dram_info *dram, u8 channel)
+static void pctl_start(struct dram_info *dram,
+		       struct rk3399_sdram_params *params,
+		       u32 channel_mask)
 {
-	const struct chan_info *chan = &dram->chan[channel];
-	u32 *denali_ctl = chan->pctl->denali_ctl;
-	u32 *denali_phy = chan->publ->denali_phy;
-	u32 *ddrc0_con = get_ddrc0_con(dram, channel);
+	const struct chan_info *chan_0 = &dram->chan[0];
+	const struct chan_info *chan_1 = &dram->chan[1];
+
+	u32 *denali_ctl_0 = chan_0->pctl->denali_ctl;
+	u32 *denali_phy_0 = chan_0->publ->denali_phy;
+	u32 *ddrc0_con_0 = get_ddrc0_con(dram, 0);
+	u32 *denali_ctl_1 = chan_1->pctl->denali_ctl;
+	u32 *denali_phy_1 = chan_1->publ->denali_phy;
+	u32 *ddrc1_con_0 = get_ddrc0_con(dram, 1);
 	u32 count = 0;
 	u32 byte, tmp;
 
-	writel(0x01000000, &ddrc0_con);
+	/* PHY_DLL_RST_EN */
+	if (channel_mask & 1) {
+		writel(0x01000000, &ddrc0_con_0);
+		clrsetbits_le32(&denali_phy_0[957], 0x3 << 24, 0x2 << 24);
+	}
 
-	clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
+	if (channel_mask & 1) {
+		count = 0;
+		while (!(readl(&denali_ctl_0[203]) & (1 << 3))) {
+			if (count > 1000) {
+				printf("%s: Failed to init pctl channel 0\n",
+				       __func__);
+				while (1)
+					;
+			}
+			udelay(1);
+			count++;
+		}
 
-	while (!(readl(&denali_ctl[203]) & (1 << 3))) {
-		if (count > 1000) {
-			printf("%s: Failed to init pctl for channel %d\n",
-			       __func__, channel);
-			while (1)
-				;
+		writel(0x01000100, &ddrc0_con_0);
+		for (byte = 0; byte < 4; byte++)	{
+			tmp = 0x820;
+			writel((tmp << 16) | tmp,
+			       &denali_phy_0[53 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_0[54 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_0[55 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_0[56 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_0[57 + (128 * byte)]);
+			clrsetbits_le32(&denali_phy_0[58 + (128 * byte)],
+					0xffff, tmp);
 		}
+		clrsetbits_le32(&denali_ctl_0[68], PWRUP_SREFRESH_EXIT,
+				dram->pwrup_srefresh_exit[0]);
+	}
 
-		udelay(1);
-		count++;
+	if (channel_mask & 2) {
+		writel(0x01000000, &ddrc1_con_0);
+		clrsetbits_le32(&denali_phy_1[957], 0x3 << 24, 0x2 << 24);
 	}
+	if (channel_mask & 2) {
+		count = 0;
+		while (!(readl(&denali_ctl_1[203]) & (1 << 3))) {
+			if (count > 1000) {
+				printf("%s: Failed to init pctl channel 1\n",
+				       __func__);
+				while (1)
+					;
+			}
+			udelay(1);
+			count++;
+		}
 
-	writel(0x01000100, &ddrc0_con);
+		writel(0x01000100, &ddrc1_con_0);
+		for (byte = 0; byte < 4; byte++)	{
+			tmp = 0x820;
+			writel((tmp << 16) | tmp,
+			       &denali_phy_1[53 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_1[54 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_1[55 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_1[56 + (128 * byte)]);
+			writel((tmp << 16) | tmp,
+			       &denali_phy_1[57 + (128 * byte)]);
+			clrsetbits_le32(&denali_phy_1[58 + (128 * byte)],
+					0xffff, tmp);
+		}
 
-	for (byte = 0; byte < 4; byte++) {
-		tmp = 0x820;
-		writel((tmp << 16) | tmp, &denali_phy[53 + (128 * byte)]);
-		writel((tmp << 16) | tmp, &denali_phy[54 + (128 * byte)]);
-		writel((tmp << 16) | tmp, &denali_phy[55 + (128 * byte)]);
-		writel((tmp << 16) | tmp, &denali_phy[56 + (128 * byte)]);
-		writel((tmp << 16) | tmp, &denali_phy[57 + (128 * byte)]);
+		clrsetbits_le32(&denali_ctl_1[68], PWRUP_SREFRESH_EXIT,
+				dram->pwrup_srefresh_exit[1]);
 
-		clrsetbits_le32(&denali_phy[58 + (128 * byte)], 0xffff, tmp);
+		/*
+		 * restore channel 1 RESET original setting
+		 * to avoid 240ohm too weak to prevent ESD test
+		 */
+		if (params->base.dramtype == LPDDR4)
+			clrsetbits_le32(&denali_phy_1[937], 0xff,
+					params->phy_regs.denali_phy[937] &
+					0xFF);
 	}
-
-	clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
-			dram->pwrup_srefresh_exit[channel]);
 }
 
 static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
@@ -861,13 +911,16 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
 	const u32 *params_ctl = params->pctl_regs.denali_ctl;
 	const u32 *params_phy = params->phy_regs.denali_phy;
 	u32 tmp, tmp1, tmp2;
+	struct rk3399_sdram_params *params_cfg;
+	u32 byte;
 
+	dram->ops->modify_param(chan, params);
 	/*
 	 * work around controller bug:
 	 * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
 	 */
-	copy_to_reg(&denali_ctl[1], &params_ctl[1],
-		    sizeof(struct rk3399_ddr_pctl_regs) - 4);
+	sdram_copy_to_reg(&denali_ctl[1], &params_ctl[1],
+			  sizeof(struct rk3399_ddr_pctl_regs) - 4);
 	writel(params_ctl[0], &denali_ctl[0]);
 
 	/*
@@ -884,8 +937,8 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
 		writel(tmp + tmp1, &denali_ctl[14]);
 	}
 
-	copy_to_reg(denali_pi, &params->pi_regs.denali_pi[0],
-		    sizeof(struct rk3399_ddr_pi_regs));
+	sdram_copy_to_reg(denali_pi, &params->pi_regs.denali_pi[0],
+			  sizeof(struct rk3399_ddr_pi_regs));
 
 	/* rank count need to set for init */
 	set_memory_map(chan, channel, params);
@@ -894,7 +947,7 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
 	writel(params->phy_regs.denali_phy[911], &denali_phy[911]);
 	writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
 
-	if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+	if (params->base.dramtype == LPDDR4) {
 		writel(params->phy_regs.denali_phy[898], &denali_phy[898]);
 		writel(params->phy_regs.denali_phy[919], &denali_phy[919]);
 	}
@@ -927,41 +980,67 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
 		}
 	}
 
-	copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
-	copy_to_reg(&denali_phy[0], &params_phy[0], (90 - 0 + 1) * 4);
-	copy_to_reg(&denali_phy[128], &params_phy[128], (218 - 128 + 1) * 4);
-	copy_to_reg(&denali_phy[256], &params_phy[256], (346 - 256 + 1) * 4);
-	copy_to_reg(&denali_phy[384], &params_phy[384], (474 - 384 + 1) * 4);
-	copy_to_reg(&denali_phy[512], &params_phy[512], (549 - 512 + 1) * 4);
-	copy_to_reg(&denali_phy[640], &params_phy[640], (677 - 640 + 1) * 4);
-	copy_to_reg(&denali_phy[768], &params_phy[768], (805 - 768 + 1) * 4);
-	set_ds_odt(chan, params, true, 0);
+	sdram_copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
+	sdram_copy_to_reg(&denali_phy[0], &params_phy[0], (90 - 0 + 1) * 4);
+	sdram_copy_to_reg(&denali_phy[128], &params_phy[128],
+			  (218 - 128 + 1) * 4);
+	sdram_copy_to_reg(&denali_phy[256], &params_phy[256],
+			  (346 - 256 + 1) * 4);
+	sdram_copy_to_reg(&denali_phy[384], &params_phy[384],
+			  (474 - 384 + 1) * 4);
+	sdram_copy_to_reg(&denali_phy[512], &params_phy[512],
+			  (549 - 512 + 1) * 4);
+	sdram_copy_to_reg(&denali_phy[640], &params_phy[640],
+			  (677 - 640 + 1) * 4);
+	sdram_copy_to_reg(&denali_phy[768], &params_phy[768],
+			  (805 - 768 + 1) * 4);
 
-	/*
-	 * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
-	 * dqs_tsel_wr_end[7:4] add Half cycle
-	 */
-	tmp = (readl(&denali_phy[84]) >> 8) & 0xff;
-	clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8);
-	tmp = (readl(&denali_phy[212]) >> 8) & 0xff;
-	clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8);
-	tmp = (readl(&denali_phy[340]) >> 8) & 0xff;
-	clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8);
-	tmp = (readl(&denali_phy[468]) >> 8) & 0xff;
-	clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8);
+	if (params->base.dramtype == LPDDR4)
+		params_cfg = dram->ops->get_phy_index_params(1, params);
+	else
+		params_cfg = dram->ops->get_phy_index_params(0, params);
+
+	clrsetbits_le32(&params_cfg->phy_regs.denali_phy[896], 0x3 << 8,
+			0 << 8);
+	writel(params_cfg->phy_regs.denali_phy[896], &denali_phy[896]);
+
+	writel(params->phy_regs.denali_phy[83] + (0x10 << 16),
+	       &denali_phy[83]);
+	writel(params->phy_regs.denali_phy[84] + (0x10 << 8),
+	       &denali_phy[84]);
+	writel(params->phy_regs.denali_phy[211] + (0x10 << 16),
+	       &denali_phy[211]);
+	writel(params->phy_regs.denali_phy[212] + (0x10 << 8),
+	       &denali_phy[212]);
+	writel(params->phy_regs.denali_phy[339] + (0x10 << 16),
+	       &denali_phy[339]);
+	writel(params->phy_regs.denali_phy[340] + (0x10 << 8),
+	       &denali_phy[340]);
+	writel(params->phy_regs.denali_phy[467] + (0x10 << 16),
+	       &denali_phy[467]);
+	writel(params->phy_regs.denali_phy[468] + (0x10 << 8),
+	       &denali_phy[468]);
 
-	/*
-	 * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8
-	 * dq_tsel_wr_end[7:4] add Half cycle
-	 */
-	tmp = (readl(&denali_phy[83]) >> 16) & 0xff;
-	clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16);
-	tmp = (readl(&denali_phy[211]) >> 16) & 0xff;
-	clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16);
-	tmp = (readl(&denali_phy[339]) >> 16) & 0xff;
-	clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16);
-	tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
-	clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
+	if (params->base.dramtype == LPDDR4) {
+		/*
+		 * to improve write dqs and dq phase from 1.5ns to 3.5ns
+		 * at 50MHz. this's the measure result from oscilloscope
+		 * of dqs and dq write signal.
+		 */
+		for (byte = 0; byte < 4; byte++) {
+			tmp = 0x680;
+			clrsetbits_le32(&denali_phy[1 + (128 * byte)],
+					0xfff << 8, tmp << 8);
+		}
+		/*
+		 * to workaround 366ball two channel's RESET connect to
+		 * one RESET signal of die
+		 */
+		if (channel == 1)
+			clrsetbits_le32(&denali_phy[937], 0xff,
+					PHY_DRV_ODT_240 |
+					(PHY_DRV_ODT_240 << 0x4));
+	}
 
 	return 0;
 }
@@ -1392,7 +1471,7 @@ static void set_ddrconfig(const struct chan_info *chan,
 			  unsigned char channel, u32 ddrconfig)
 {
 	/* only need to set ddrconfig */
-	struct rk3399_msch_regs *ddr_msch_regs = chan->msch;
+	struct msch_regs *ddr_msch_regs = chan->msch;
 	unsigned int cs0_cap = 0;
 	unsigned int cs1_cap = 0;
 
@@ -1413,52 +1492,43 @@ static void set_ddrconfig(const struct chan_info *chan,
 	       &ddr_msch_regs->ddrsize);
 }
 
+static void sdram_msch_config(struct msch_regs *msch,
+			      struct sdram_msch_timings *noc_timings)
+{
+	writel(noc_timings->ddrtiminga0.d32,
+	       &msch->ddrtiminga0.d32);
+	writel(noc_timings->ddrtimingb0.d32,
+	       &msch->ddrtimingb0.d32);
+	writel(noc_timings->ddrtimingc0.d32,
+	       &msch->ddrtimingc0.d32);
+	writel(noc_timings->devtodev0.d32,
+	       &msch->devtodev0.d32);
+	writel(noc_timings->ddrmode.d32,
+	       &msch->ddrmode.d32);
+}
+
 static void dram_all_config(struct dram_info *dram,
-			    const struct rk3399_sdram_params *params)
+			    struct rk3399_sdram_params *params)
 {
 	u32 sys_reg2 = 0;
 	u32 sys_reg3 = 0;
 	unsigned int channel, idx;
 
-	sys_reg2 |= SYS_REG_ENC_DDRTYPE(params->base.dramtype);
-	sys_reg2 |= SYS_REG_ENC_NUM_CH(params->base.num_channels);
-
 	for (channel = 0, idx = 0;
 	     (idx < params->base.num_channels) && (channel < 2);
 	     channel++) {
-		const struct rk3399_sdram_channel *info = &params->ch[channel];
-		struct rk3399_msch_regs *ddr_msch_regs;
-		const struct rk3399_msch_timings *noc_timing;
+		struct msch_regs *ddr_msch_regs;
+		struct sdram_msch_timings *noc_timing;
 
 		if (params->ch[channel].cap_info.col == 0)
 			continue;
 		idx++;
-		sys_reg2 |= SYS_REG_ENC_ROW_3_4(info->cap_info.row_3_4, channel);
-		sys_reg2 |= SYS_REG_ENC_CHINFO(channel);
-		sys_reg2 |= SYS_REG_ENC_RANK(info->cap_info.rank, channel);
-		sys_reg2 |= SYS_REG_ENC_COL(info->cap_info.col, channel);
-		sys_reg2 |= SYS_REG_ENC_BK(info->cap_info.bk, channel);
-		sys_reg2 |= SYS_REG_ENC_BW(info->cap_info.bw, channel);
-		sys_reg2 |= SYS_REG_ENC_DBW(info->cap_info.dbw, channel);
-		SYS_REG_ENC_CS0_ROW(info->cap_info.cs0_row, sys_reg2, sys_reg3, channel);
-		if (info->cap_info.cs1_row)
-			SYS_REG_ENC_CS1_ROW(info->cap_info.cs1_row, sys_reg2,
-					    sys_reg3, channel);
-		sys_reg3 |= SYS_REG_ENC_CS1_COL(info->cap_info.col, channel);
-		sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
-
+		sdram_org_config(&params->ch[channel].cap_info,
+				 &params->base, &sys_reg2,
+				 &sys_reg3, channel);
 		ddr_msch_regs = dram->chan[channel].msch;
 		noc_timing = &params->ch[channel].noc_timings;
-		writel(noc_timing->ddrtiminga0,
-		       &ddr_msch_regs->ddrtiminga0);
-		writel(noc_timing->ddrtimingb0,
-		       &ddr_msch_regs->ddrtimingb0);
-		writel(noc_timing->ddrtimingc0.d32,
-		       &ddr_msch_regs->ddrtimingc0);
-		writel(noc_timing->devtodev0,
-		       &ddr_msch_regs->devtodev0);
-		writel(noc_timing->ddrmode.d32,
-		       &ddr_msch_regs->ddrmode);
+		sdram_msch_config(ddr_msch_regs, noc_timing);
 
 		/**
 		 * rank 1 memory clock disable (dfi_dram_clk_disable = 1)
@@ -1494,7 +1564,7 @@ static void set_cap_relate_config(const struct chan_info *chan,
 {
 	u32 *denali_ctl = chan->pctl->denali_ctl;
 	u32 tmp;
-	struct rk3399_msch_timings *noc_timing;
+	struct sdram_msch_timings *noc_timing;
 
 	if (params->base.dramtype == LPDDR3) {
 		tmp = (8 << params->ch[channel].cap_info.bw) /
@@ -1566,9 +1636,14 @@ static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel)
 	return i;
 }
 
+static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
+{
+	rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
+}
+
 #if !defined(CONFIG_RAM_RK3399_LPDDR4)
-static int default_data_training(struct dram_info *dram, u32 channel, u8 rank,
-				 struct rk3399_sdram_params *params)
+static int data_training_first(struct dram_info *dram, u32 channel, u8 rank,
+			       struct rk3399_sdram_params *params)
 {
 	u8 training_flag = PI_READ_GATE_TRAINING;
 
@@ -1629,31 +1704,72 @@ static int switch_to_phy_index1(struct dram_info *dram,
 	return 0;
 }
 
+struct rk3399_sdram_params
+	*get_phy_index_params(u32 phy_fn,
+			      struct rk3399_sdram_params *params)
+{
+	if (phy_fn == 0)
+		return params;
+	else
+		return NULL;
+}
+
+void modify_param(const struct chan_info *chan,
+		  struct rk3399_sdram_params *params)
+{
+	struct rk3399_sdram_params *params_cfg;
+	u32 *denali_pi_params;
+
+	denali_pi_params = params->pi_regs.denali_pi;
+
+	/* modify PHY F0/F1/F2 params */
+	params_cfg = get_phy_index_params(0, params);
+	set_ds_odt(chan, params_cfg, false, 0);
+
+	clrsetbits_le32(&denali_pi_params[45], 0x1 << 24, 0x1 << 24);
+	clrsetbits_le32(&denali_pi_params[61], 0x1 << 24, 0x1 << 24);
+	clrsetbits_le32(&denali_pi_params[76], 0x1 << 24, 0x1 << 24);
+	clrsetbits_le32(&denali_pi_params[77], 0x1, 0x1);
+}
 #else
 
-struct rk3399_sdram_params lpddr4_timings[] = {
-	#include "sdram-rk3399-lpddr4-400.inc"
-	#include "sdram-rk3399-lpddr4-800.inc"
+struct rk3399_sdram_params dfs_cfgs_lpddr4[] = {
+#include "sdram-rk3399-lpddr4-400.inc"
+#include "sdram-rk3399-lpddr4-800.inc"
 };
 
+static struct rk3399_sdram_params
+	*lpddr4_get_phy_index_params(u32 phy_fn,
+				     struct rk3399_sdram_params *params)
+{
+	if (phy_fn == 0)
+		return params;
+	else if (phy_fn == 1)
+		return &dfs_cfgs_lpddr4[1];
+	else if (phy_fn == 2)
+		return &dfs_cfgs_lpddr4[0];
+	else
+		return NULL;
+}
+
 static void *get_denali_pi(const struct chan_info *chan,
 			   struct rk3399_sdram_params *params, bool reg)
 {
 	return reg ? &chan->pi->denali_pi : &params->pi_regs.denali_pi;
 }
 
-static u32 lpddr4_get_phy(struct rk3399_sdram_params *params, u32 ctl)
+static u32 lpddr4_get_phy_fn(struct rk3399_sdram_params *params, u32 ctl_fn)
 {
-	u32 lpddr4_phy[] = {1, 0, 0xb};
+	u32 lpddr4_phy_fn[] = {1, 0, 0xb};
 
-	return lpddr4_phy[ctl];
+	return lpddr4_phy_fn[ctl_fn];
 }
 
-static u32 lpddr4_get_ctl(struct rk3399_sdram_params *params, u32 phy)
+static u32 lpddr4_get_ctl_fn(struct rk3399_sdram_params *params, u32 phy_fn)
 {
-	u32 lpddr4_ctl[] = {1, 0, 2};
+	u32 lpddr4_ctl_fn[] = {1, 0, 2};
 
-	return lpddr4_ctl[phy];
+	return lpddr4_ctl_fn[phy_fn];
 }
 
 static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
@@ -1661,12 +1777,7 @@ static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
 	return ((readl(&pmusgrf->soc_con4) >> 10) & 0x1F);
 }
 
-static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
-{
-	rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
-}
-
-/**
+/*
  * read mr_num mode register
  * rank = 1: cs0
  * rank = 2: cs1
@@ -1797,7 +1908,7 @@ end:
 }
 
 static void set_lpddr4_dq_odt(const struct chan_info *chan,
-			      struct rk3399_sdram_params *params, u32 ctl,
+			      struct rk3399_sdram_params *params, u32 ctl_fn,
 			      bool en, bool ctl_phy_reg, u32 mr5)
 {
 	u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1805,14 +1916,13 @@ static void set_lpddr4_dq_odt(const struct chan_info *chan,
 	struct io_setting *io;
 	u32 reg_value;
 
-	if (!en)
-		return;
-
 	io = lpddr4_get_io_settings(params, mr5);
+	if (en)
+		reg_value = io->dq_odt;
+	else
+		reg_value = 0;
 
-	reg_value = io->dq_odt;
-
-	switch (ctl) {
+	switch (ctl_fn) {
 	case 0:
 		clrsetbits_le32(&denali_ctl[139], 0x7 << 24, reg_value << 24);
 		clrsetbits_le32(&denali_ctl[153], 0x7 << 24, reg_value << 24);
@@ -1845,7 +1955,7 @@ static void set_lpddr4_dq_odt(const struct chan_info *chan,
 }
 
 static void set_lpddr4_ca_odt(const struct chan_info *chan,
-			      struct rk3399_sdram_params *params, u32 ctl,
+			      struct rk3399_sdram_params *params, u32 ctl_fn,
 			      bool en, bool ctl_phy_reg, u32 mr5)
 {
 	u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1853,14 +1963,13 @@ static void set_lpddr4_ca_odt(const struct chan_info *chan,
 	struct io_setting *io;
 	u32 reg_value;
 
-	if (!en)
-		return;
-
 	io = lpddr4_get_io_settings(params, mr5);
+	if (en)
+		reg_value = io->ca_odt;
+	else
+		reg_value = 0;
 
-	reg_value = io->ca_odt;
-
-	switch (ctl) {
+	switch (ctl_fn) {
 	case 0:
 		clrsetbits_le32(&denali_ctl[139], 0x7 << 28, reg_value << 28);
 		clrsetbits_le32(&denali_ctl[153], 0x7 << 28, reg_value << 28);
@@ -1893,7 +2002,7 @@ static void set_lpddr4_ca_odt(const struct chan_info *chan,
 }
 
 static void set_lpddr4_MR3(const struct chan_info *chan,
-			   struct rk3399_sdram_params *params, u32 ctl,
+			   struct rk3399_sdram_params *params, u32 ctl_fn,
 			   bool ctl_phy_reg, u32 mr5)
 {
 	u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1905,7 +2014,7 @@ static void set_lpddr4_MR3(const struct chan_info *chan,
 
 	reg_value = ((io->pdds << 3) | 1);
 
-	switch (ctl) {
+	switch (ctl_fn) {
 	case 0:
 		clrsetbits_le32(&denali_ctl[138], 0xFFFF, reg_value);
 		clrsetbits_le32(&denali_ctl[152], 0xFFFF, reg_value);
@@ -1940,7 +2049,7 @@ static void set_lpddr4_MR3(const struct chan_info *chan,
 }
 
 static void set_lpddr4_MR12(const struct chan_info *chan,
-			    struct rk3399_sdram_params *params, u32 ctl,
+			    struct rk3399_sdram_params *params, u32 ctl_fn,
 			    bool ctl_phy_reg, u32 mr5)
 {
 	u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1952,7 +2061,7 @@ static void set_lpddr4_MR12(const struct chan_info *chan,
 
 	reg_value = io->ca_vref;
 
-	switch (ctl) {
+	switch (ctl_fn) {
 	case 0:
 		clrsetbits_le32(&denali_ctl[140], 0xFFFF << 16,
 				reg_value << 16);
@@ -1989,7 +2098,7 @@ static void set_lpddr4_MR12(const struct chan_info *chan,
 }
 
 static void set_lpddr4_MR14(const struct chan_info *chan,
-			    struct rk3399_sdram_params *params, u32 ctl,
+			    struct rk3399_sdram_params *params, u32 ctl_fn,
 			    bool ctl_phy_reg, u32 mr5)
 {
 	u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -2001,7 +2110,7 @@ static void set_lpddr4_MR14(const struct chan_info *chan,
 
 	reg_value = io->dq_vref;
 
-	switch (ctl) {
+	switch (ctl_fn) {
 	case 0:
 		clrsetbits_le32(&denali_ctl[142], 0xFFFF << 16,
 				reg_value << 16);
@@ -2037,22 +2146,73 @@ static void set_lpddr4_MR14(const struct chan_info *chan,
 	}
 }
 
+void lpddr4_modify_param(const struct chan_info *chan,
+			 struct rk3399_sdram_params *params)
+{
+	struct rk3399_sdram_params *params_cfg;
+	u32 *denali_ctl_params;
+	u32 *denali_pi_params;
+	u32 *denali_phy_params;
+
+	denali_ctl_params = params->pctl_regs.denali_ctl;
+	denali_pi_params = params->pi_regs.denali_pi;
+	denali_phy_params = params->phy_regs.denali_phy;
+
+	set_lpddr4_dq_odt(chan, params, 2, true, false, 0);
+	set_lpddr4_ca_odt(chan, params, 2, true, false, 0);
+	set_lpddr4_MR3(chan, params, 2, false, 0);
+	set_lpddr4_MR12(chan, params, 2, false, 0);
+	set_lpddr4_MR14(chan, params, 2, false, 0);
+	params_cfg = lpddr4_get_phy_index_params(0, params);
+	set_ds_odt(chan, params_cfg, false, 0);
+	/* read two cycle preamble */
+	clrsetbits_le32(&denali_ctl_params[200], 0x3 << 24, 0x3 << 24);
+	clrsetbits_le32(&denali_phy_params[7], 0x3 << 24, 0x3 << 24);
+	clrsetbits_le32(&denali_phy_params[135], 0x3 << 24, 0x3 << 24);
+	clrsetbits_le32(&denali_phy_params[263], 0x3 << 24, 0x3 << 24);
+	clrsetbits_le32(&denali_phy_params[391], 0x3 << 24, 0x3 << 24);
+
+	/* boot frequency two cycle preamble */
+	clrsetbits_le32(&denali_phy_params[2], 0x3 << 16, 0x3 << 16);
+	clrsetbits_le32(&denali_phy_params[130], 0x3 << 16, 0x3 << 16);
+	clrsetbits_le32(&denali_phy_params[258], 0x3 << 16, 0x3 << 16);
+	clrsetbits_le32(&denali_phy_params[386], 0x3 << 16, 0x3 << 16);
+
+	clrsetbits_le32(&denali_pi_params[45], 0x3 << 8, 0x3 << 8);
+	clrsetbits_le32(&denali_pi_params[58], 0x1, 0x1);
+
+	/*
+	 * bypass mode need PHY_SLICE_PWR_RDC_DISABLE_x = 1,
+	 * boot frequency mode use bypass mode
+	 */
+	setbits_le32(&denali_phy_params[10], 1 << 16);
+	setbits_le32(&denali_phy_params[138], 1 << 16);
+	setbits_le32(&denali_phy_params[266], 1 << 16);
+	setbits_le32(&denali_phy_params[394], 1 << 16);
+
+	clrsetbits_le32(&denali_pi_params[45], 0x1 << 24, 0x1 << 24);
+	clrsetbits_le32(&denali_pi_params[61], 0x1 << 24, 0x1 << 24);
+	clrsetbits_le32(&denali_pi_params[76], 0x1 << 24, 0x1 << 24);
+	clrsetbits_le32(&denali_pi_params[77], 0x1, 0x1);
+}
+
 static void lpddr4_copy_phy(struct dram_info *dram,
-			    struct rk3399_sdram_params *params, u32 phy,
-			    struct rk3399_sdram_params *timings,
+			    struct rk3399_sdram_params *params, u32 phy_fn,
+			    struct rk3399_sdram_params *params_cfg,
 			    u32 channel)
 {
 	u32 *denali_ctl, *denali_phy;
 	u32 *denali_phy_params;
 	u32 speed = 0;
-	u32 ctl, mr5;
+	u32 ctl_fn, mr5;
 
 	denali_ctl = dram->chan[channel].pctl->denali_ctl;
 	denali_phy = dram->chan[channel].publ->denali_phy;
-	denali_phy_params = timings->phy_regs.denali_phy;
+	denali_phy_params = params_cfg->phy_regs.denali_phy;
 
 	/* switch index */
-	clrsetbits_le32(&denali_phy_params[896], 0x3 << 8, phy << 8);
+	clrsetbits_le32(&denali_phy_params[896], 0x3 << 8,
+			phy_fn << 8);
 	writel(denali_phy_params[896], &denali_phy[896]);
 
 	/* phy_pll_ctrl_ca, phy_pll_ctrl */
@@ -2112,14 +2272,14 @@ static void lpddr4_copy_phy(struct dram_info *dram,
 	 * phy_clk_wrdqz_slave_delay_x
 	 * phy_clk_wrdqs_slave_delay_x
 	 */
-	copy_to_reg((u32 *)&denali_phy[59], (u32 *)&denali_phy_params[59],
-		    (63 - 58) * 4);
-	copy_to_reg((u32 *)&denali_phy[187], (u32 *)&denali_phy_params[187],
-		    (191 - 186) * 4);
-	copy_to_reg((u32 *)&denali_phy[315], (u32 *)&denali_phy_params[315],
-		    (319 - 314) * 4);
-	copy_to_reg((u32 *)&denali_phy[443], (u32 *)&denali_phy_params[443],
-		    (447 - 442) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[59],
+			  (u32 *)&denali_phy_params[59], (63 - 58) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[187],
+			  (u32 *)&denali_phy_params[187], (191 - 186) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[315],
+			  (u32 *)&denali_phy_params[315], (319 - 314) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[443],
+			  (u32 *)&denali_phy_params[443], (447 - 442) * 4);
 
 	/*
 	 * phy_dqs_tsel_wr_timing_x 8bits denali_phy_84/212/340/468 offset_8
@@ -2218,31 +2378,30 @@ static void lpddr4_copy_phy(struct dram_info *dram,
 	 * phy_wrlvl_delay_period_threshold_x
 	 * phy_wrlvl_early_force_zero_x
 	 */
-	copy_to_reg((u32 *)&denali_phy[64], (u32 *)&denali_phy_params[64],
-		    (67 - 63) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[64],
+			  (u32 *)&denali_phy_params[64], (67 - 63) * 4);
 	clrsetbits_le32(&denali_phy[68], 0xfffffc00,
 			denali_phy_params[68] & 0xfffffc00);
-	copy_to_reg((u32 *)&denali_phy[69], (u32 *)&denali_phy_params[69],
-		    (79 - 68) * 4);
-	copy_to_reg((u32 *)&denali_phy[192], (u32 *)&denali_phy_params[192],
-		    (195 - 191) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[69],
+			  (u32 *)&denali_phy_params[69], (79 - 68) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[192],
+			  (u32 *)&denali_phy_params[192], (195 - 191) * 4);
 	clrsetbits_le32(&denali_phy[196], 0xfffffc00,
 			denali_phy_params[196] & 0xfffffc00);
-	copy_to_reg((u32 *)&denali_phy[197], (u32 *)&denali_phy_params[197],
-		    (207 - 196) * 4);
-	copy_to_reg((u32 *)&denali_phy[320], (u32 *)&denali_phy_params[320],
-		    (323 - 319) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[197],
+			  (u32 *)&denali_phy_params[197], (207 - 196) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[320],
+			  (u32 *)&denali_phy_params[320], (323 - 319) * 4);
 	clrsetbits_le32(&denali_phy[324], 0xfffffc00,
 			denali_phy_params[324] & 0xfffffc00);
-	copy_to_reg((u32 *)&denali_phy[325], (u32 *)&denali_phy_params[325],
-		    (335 - 324) * 4);
-
-	copy_to_reg((u32 *)&denali_phy[448], (u32 *)&denali_phy_params[448],
-		    (451 - 447) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[325],
+			  (u32 *)&denali_phy_params[325], (335 - 324) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[448],
+			  (u32 *)&denali_phy_params[448], (451 - 447) * 4);
 	clrsetbits_le32(&denali_phy[452], 0xfffffc00,
 			denali_phy_params[452] & 0xfffffc00);
-	copy_to_reg((u32 *)&denali_phy[453], (u32 *)&denali_phy_params[453],
-		    (463 - 452) * 4);
+	sdram_copy_to_reg((u32 *)&denali_phy[453],
+			  (u32 *)&denali_phy_params[453], (463 - 452) * 4);
 
 	/* phy_two_cyc_preamble_x */
 	clrsetbits_le32(&denali_phy[7], 0x3 << 24,
@@ -2255,11 +2414,11 @@ static void lpddr4_copy_phy(struct dram_info *dram,
 			denali_phy_params[391] & (0x3 << 24));
 
 	/* speed */
-	if (timings->base.ddr_freq < 400 * MHz)
+	if (params_cfg->base.ddr_freq < 400)
 		speed = 0x0;
-	else if (timings->base.ddr_freq < 800 * MHz)
+	else if (params_cfg->base.ddr_freq < 800)
 		speed = 0x1;
-	else if (timings->base.ddr_freq < 1200 * MHz)
+	else if (params_cfg->base.ddr_freq < 1200)
 		speed = 0x2;
 
 	/* phy_924 phy_pad_fdbk_drive */
@@ -2279,52 +2438,75 @@ static void lpddr4_copy_phy(struct dram_info *dram,
 	/* phy_939 phy_pad_cs_drive */
 	clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
 
-	read_mr(dram->chan[channel].pctl, 1, 5, &mr5);
-	set_ds_odt(&dram->chan[channel], timings, true, mr5);
+	if (params_cfg->base.dramtype == LPDDR4) {
+		read_mr(dram->chan[channel].pctl, 1, 5, &mr5);
+		set_ds_odt(&dram->chan[channel], params_cfg, true, mr5);
+		set_ds_odt(&dram->chan[channel], params_cfg, true, mr5);
+
+		ctl_fn = lpddr4_get_ctl_fn(params_cfg, phy_fn);
+		set_lpddr4_dq_odt(&dram->chan[channel], params_cfg,
+				  ctl_fn, true, true, mr5);
+		set_lpddr4_ca_odt(&dram->chan[channel], params_cfg,
+				  ctl_fn, true, true, mr5);
+		set_lpddr4_MR3(&dram->chan[channel], params_cfg,
+			       ctl_fn, true, mr5);
+		set_lpddr4_MR12(&dram->chan[channel], params_cfg,
+				ctl_fn, true, mr5);
+		set_lpddr4_MR14(&dram->chan[channel], params_cfg,
+				ctl_fn, true, mr5);
+
+		set_lpddr4_dq_odt(&dram->chan[channel], params_cfg,
+				  ctl_fn, true, true, mr5);
+		set_lpddr4_ca_odt(&dram->chan[channel], params_cfg,
+				  ctl_fn, true, true, mr5);
+		set_lpddr4_MR3(&dram->chan[channel], params_cfg,
+			       ctl_fn, true, mr5);
+		set_lpddr4_MR12(&dram->chan[channel], params_cfg,
+				ctl_fn, true, mr5);
+		set_lpddr4_MR14(&dram->chan[channel], params_cfg,
+				ctl_fn, true, mr5);
 
-	ctl = lpddr4_get_ctl(timings, phy);
-	set_lpddr4_dq_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
-	set_lpddr4_ca_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
-	set_lpddr4_MR3(&dram->chan[channel], timings, ctl, true, mr5);
-	set_lpddr4_MR12(&dram->chan[channel], timings, ctl, true, mr5);
-	set_lpddr4_MR14(&dram->chan[channel], timings, ctl, true, mr5);
-
-	/*
-	 * if phy_sw_master_mode_x not bypass mode,
-	 * clear phy_slice_pwr_rdc_disable.
-	 * note: need use timings, not ddr_publ_regs
-	 */
-	if (!((denali_phy_params[86] >> 8) & (1 << 2))) {
-		clrbits_le32(&denali_phy[10], 1 << 16);
-		clrbits_le32(&denali_phy[138], 1 << 16);
-		clrbits_le32(&denali_phy[266], 1 << 16);
-		clrbits_le32(&denali_phy[394], 1 << 16);
-	}
+		/*
+		 * if phy_sw_master_mode_x not bypass mode,
+		 * clear phy_slice_pwr_rdc_disable.
+		 * note: need use timings, not ddr_publ_regs
+		 */
+		if (!((denali_phy_params[86] >> 8) & (1 << 2))) {
+			clrbits_le32(&denali_phy[10], 1 << 16);
+			clrbits_le32(&denali_phy[138], 1 << 16);
+			clrbits_le32(&denali_phy[266], 1 << 16);
+			clrbits_le32(&denali_phy[394], 1 << 16);
+		}
 
-	/*
-	 * when PHY_PER_CS_TRAINING_EN=1, W2W_DIFFCS_DLY_Fx can't
-	 * smaller than 8
-	 * NOTE: need use timings, not ddr_publ_regs
-	 */
-	if ((denali_phy_params[84] >> 16) & 1) {
-		if (((readl(&denali_ctl[217 + ctl]) >> 16) & 0x1f) < 8)
-			clrsetbits_le32(&denali_ctl[217 + ctl],
-					0x1f << 16, 8 << 16);
+		/*
+		 * when PHY_PER_CS_TRAINING_EN=1, W2W_DIFFCS_DLY_Fx can't
+		 * smaller than 8
+		 * NOTE: need use timings, not ddr_publ_regs
+		 */
+		if ((denali_phy_params[84] >> 16) & 1) {
+			if (((readl(&denali_ctl[217 + ctl_fn]) >>
+				16) & 0x1f) < 8)
+				clrsetbits_le32(&denali_ctl[217 + ctl_fn],
+						0x1f << 16,
+						8 << 16);
+		}
 	}
 }
 
 static void lpddr4_set_phy(struct dram_info *dram,
-			   struct rk3399_sdram_params *params, u32 phy,
-			   struct rk3399_sdram_params *timings)
+			   struct rk3399_sdram_params *params, u32 phy_fn,
+			   struct rk3399_sdram_params *params_cfg)
 {
 	u32 channel;
 
 	for (channel = 0; channel < 2; channel++)
-		lpddr4_copy_phy(dram, params, phy, timings, channel);
+		lpddr4_copy_phy(dram, params, phy_fn, params_cfg,
+				channel);
 }
 
 static int lpddr4_set_ctl(struct dram_info *dram,
-			  struct rk3399_sdram_params *params, u32 ctl, u32 hz)
+			  struct rk3399_sdram_params *params,
+			  u32 fn, u32 hz)
 {
 	u32 channel;
 	int ret_clk, ret;
@@ -2343,7 +2525,7 @@ static int lpddr4_set_ctl(struct dram_info *dram,
 
 	/* change freq */
 	writel((((0x3 << 4) | (1 << 2) | 1) << 16) |
-		(ctl << 4) | (1 << 2) | 1, &dram->cic->cic_ctrl0);
+		(fn << 4) | (1 << 2) | 1, &dram->cic->cic_ctrl0);
 	while (!(readl(&dram->cic->cic_status0) & (1 << 2)))
 		;
 
@@ -2366,12 +2548,12 @@ static int lpddr4_set_ctl(struct dram_info *dram,
 	clrbits_le32(&dram->pmu->pmu_noc_auto_ena, (0x3 << 7));
 
 	/* lpddr4 ctl2 can not do training, all training will fail */
-	if (!(params->base.dramtype == LPDDR4 && ctl == 2)) {
+	if (!(params->base.dramtype == LPDDR4 && fn == 2)) {
 		for (channel = 0; channel < 2; channel++) {
 			if (!(params->ch[channel].cap_info.col))
 				continue;
 			ret = data_training(dram, channel, params,
-						     PI_FULL_TRAINING);
+					    PI_FULL_TRAINING);
 			if (ret)
 				printf("%s: channel %d training failed!\n",
 				       __func__, channel);
@@ -2387,24 +2569,221 @@ static int lpddr4_set_ctl(struct dram_info *dram,
 static int lpddr4_set_rate(struct dram_info *dram,
 			   struct rk3399_sdram_params *params)
 {
-	u32 ctl;
-	u32 phy;
+	u32 ctl_fn;
+	u32 phy_fn;
 
-	for (ctl = 0; ctl < 2; ctl++) {
-		phy = lpddr4_get_phy(params, ctl);
+	for (ctl_fn = 0; ctl_fn < 2; ctl_fn++) {
+		phy_fn = lpddr4_get_phy_fn(params, ctl_fn);
 
-		lpddr4_set_phy(dram, params, phy, &lpddr4_timings[ctl]);
-		lpddr4_set_ctl(dram, params, ctl,
-			       lpddr4_timings[ctl].base.ddr_freq);
+		lpddr4_set_phy(dram, params, phy_fn, &dfs_cfgs_lpddr4[ctl_fn]);
+		lpddr4_set_ctl(dram, params, ctl_fn,
+			       dfs_cfgs_lpddr4[ctl_fn].base.ddr_freq);
 
-		debug("%s: change freq to %d mhz %d, %d\n", __func__,
-		      lpddr4_timings[ctl].base.ddr_freq / MHz, ctl, phy);
+		printf("%s: change freq to %d mhz %d, %d\n", __func__,
+		       dfs_cfgs_lpddr4[ctl_fn].base.ddr_freq, ctl_fn, phy_fn);
 	}
 
 	return 0;
 }
 #endif /* CONFIG_RAM_RK3399_LPDDR4 */
 
+/* CS0,n=1
+ * CS1,n=2
+ * CS0 & CS1, n=3
+ * cs0_cap: MB unit
+ */
+static void dram_set_cs(const struct chan_info *chan, u32 cs_map, u32 cs0_cap,
+			unsigned char dramtype)
+{
+	u32 *denali_ctl = chan->pctl->denali_ctl;
+	u32 *denali_pi = chan->pi->denali_pi;
+	struct msch_regs *ddr_msch_regs = chan->msch;
+
+	clrsetbits_le32(&denali_ctl[196], 0x3, cs_map);
+	writel((cs0_cap / 32) | (((4096 - cs0_cap) / 32) << 8),
+	       &ddr_msch_regs->ddrsize);
+	if (dramtype == LPDDR4) {
+		if (cs_map == 1)
+			cs_map = 0x5;
+		else if (cs_map == 2)
+			cs_map = 0xa;
+		else
+			cs_map = 0xF;
+	}
+	/*PI_41 PI_CS_MAP:RW:24:4*/
+	clrsetbits_le32(&denali_pi[41],
+			0xf << 24, cs_map << 24);
+	if (cs_map == 1 && dramtype == DDR3)
+		writel(0x2EC7FFFF, &denali_pi[34]);
+}
+
+static void dram_set_bw(const struct chan_info *chan, u32 bw)
+{
+	u32 *denali_ctl = chan->pctl->denali_ctl;
+
+	if (bw == 2)
+		clrbits_le32(&denali_ctl[196], 1 << 16);
+	else
+		setbits_le32(&denali_ctl[196], 1 << 16);
+}
+
+static void dram_set_max_col(const struct chan_info *chan, u32 bw, u32 *pcol)
+{
+	u32 *denali_ctl = chan->pctl->denali_ctl;
+	struct msch_regs *ddr_msch_regs = chan->msch;
+	u32 *denali_pi = chan->pi->denali_pi;
+	u32 ddrconfig;
+
+	clrbits_le32(&denali_ctl[191], 0xf);
+	clrsetbits_le32(&denali_ctl[190],
+			(7 << 24),
+			((16 - ((bw == 2) ? 14 : 15)) << 24));
+	/*PI_199 PI_COL_DIFF:RW:0:4*/
+	clrbits_le32(&denali_pi[199], 0xf);
+	/*PI_155 PI_ROW_DIFF:RW:24:3*/
+	clrsetbits_le32(&denali_pi[155],
+			(7 << 24),
+			((16 - 12) << 24));
+	ddrconfig = (bw == 2) ? 3 : 2;
+	writel(ddrconfig | (ddrconfig << 8), &ddr_msch_regs->ddrconf);
+	/* set max cs0 size */
+	writel((4096 / 32) | ((0 / 32) << 8),
+	       &ddr_msch_regs->ddrsize);
+
+	*pcol = 12;
+}
+
+static void dram_set_max_bank(const struct chan_info *chan, u32 bw, u32 *pbank,
+			      u32 *pcol)
+{
+	u32 *denali_ctl = chan->pctl->denali_ctl;
+	u32 *denali_pi = chan->pi->denali_pi;
+
+	clrbits_le32(&denali_ctl[191], 0xf);
+	clrbits_le32(&denali_ctl[190], (3 << 16));
+	/*PI_199 PI_COL_DIFF:RW:0:4*/
+	clrbits_le32(&denali_pi[199], 0xf);
+	/*PI_155 PI_BANK_DIFF:RW:16:2*/
+	clrbits_le32(&denali_pi[155], (3 << 16));
+
+	*pbank = 3;
+	*pcol = 12;
+}
+
+static void dram_set_max_row(const struct chan_info *chan, u32 bw, u32 *prow,
+			     u32 *pbank, u32 *pcol)
+{
+	u32 *denali_ctl = chan->pctl->denali_ctl;
+	u32 *denali_pi = chan->pi->denali_pi;
+	struct msch_regs *ddr_msch_regs = chan->msch;
+
+	clrsetbits_le32(&denali_ctl[191], 0xf, 12 - 10);
+	clrbits_le32(&denali_ctl[190],
+		     (0x3 << 16) | (0x7 << 24));
+	/*PI_199 PI_COL_DIFF:RW:0:4*/
+	clrsetbits_le32(&denali_pi[199], 0xf, 12 - 10);
+	/*PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2*/
+	clrbits_le32(&denali_pi[155],
+		     (0x3 << 16) | (0x7 << 24));
+	writel(1 | (1 << 8), &ddr_msch_regs->ddrconf);
+	/* set max cs0 size */
+	writel((4096 / 32) | ((0 / 32) << 8),
+	       &ddr_msch_regs->ddrsize);
+
+	*prow = 16;
+	*pbank = 3;
+	*pcol = (bw == 2) ? 10 : 11;
+}
+
+static u64 dram_detect_cap(struct dram_info *dram,
+			   struct rk3399_sdram_params *params,
+			   unsigned char channel)
+{
+	const struct chan_info *chan = &dram->chan[channel];
+	struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
+	u32 bw;
+	u32 col_tmp;
+	u32 bk_tmp;
+	u32 row_tmp;
+	u32 cs0_cap;
+	u32 training_flag;
+	u32 ddrconfig;
+
+	/* detect bw */
+	bw = 2;
+	if (params->base.dramtype != LPDDR4) {
+		dram_set_bw(chan, bw);
+		cap_info->bw = bw;
+		if (data_training(dram, channel, params,
+				  PI_READ_GATE_TRAINING)) {
+			bw = 1;
+			dram_set_bw(chan, 1);
+			cap_info->bw = bw;
+			if (data_training(dram, channel, params,
+					  PI_READ_GATE_TRAINING)) {
+				printf("16bit error!!!\n");
+				goto error;
+			}
+		}
+	}
+	/*
+	 * LPDDR3 CA training msut be trigger before other training.
+	 * DDR3 is not have CA training.
+	 */
+	if (params->base.dramtype == LPDDR3)
+		training_flag = PI_WRITE_LEVELING;
+	else
+		training_flag = PI_FULL_TRAINING;
+
+	if (params->base.dramtype != LPDDR4) {
+		if (data_training(dram, channel, params, training_flag)) {
+			printf("full training error!!!\n");
+			goto error;
+		}
+	}
+
+	/* detect col */
+	dram_set_max_col(chan, bw, &col_tmp);
+	if (sdram_detect_col(cap_info, col_tmp) != 0)
+		goto error;
+
+	/* detect bank */
+	dram_set_max_bank(chan, bw, &bk_tmp, &col_tmp);
+	sdram_detect_bank(cap_info, col_tmp, bk_tmp);
+
+	/* detect row */
+	dram_set_max_row(chan, bw, &row_tmp, &bk_tmp, &col_tmp);
+	if (sdram_detect_row(cap_info, col_tmp, bk_tmp, row_tmp) != 0)
+		goto error;
+
+	/* detect row_3_4 */
+	sdram_detect_row_3_4(cap_info, col_tmp, bk_tmp);
+
+	/* set ddrconfig */
+	cs0_cap = (1 << (cap_info->cs0_row + cap_info->col + cap_info->bk +
+			 cap_info->bw - 20));
+	if (cap_info->row_3_4)
+		cs0_cap = cs0_cap * 3 / 4;
+
+	cap_info->cs1_row = cap_info->cs0_row;
+	set_memory_map(chan, channel, params);
+	ddrconfig = calculate_ddrconfig(params, channel);
+	if (-1 == ddrconfig)
+		goto error;
+	set_ddrconfig(chan, params, channel,
+		      cap_info->ddrconfig);
+
+	/* detect cs1 row */
+	sdram_detect_cs1_row(cap_info, params->base.dramtype);
+
+	/* detect die bw */
+	sdram_detect_dbw(cap_info, params->base.dramtype);
+
+	return 0;
+error:
+	return (-1);
+}
+
 static unsigned char calculate_stride(struct rk3399_sdram_params *params)
 {
 	unsigned int stride = params->base.stride;
@@ -2491,39 +2870,13 @@ static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel)
 	params->ch[channel].cap_info.ddrconfig = 0;
 }
 
-static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params)
-{
-	int channel;
-	int ret;
-
-	for (channel = 0; channel < 2; channel++) {
-		const struct chan_info *chan = &dram->chan[channel];
-		struct rk3399_cru *cru = dram->cru;
-		struct rk3399_ddr_publ_regs *publ = chan->publ;
-
-		phy_pctrl_reset(cru, channel);
-		phy_dll_bypass_set(publ, params->base.ddr_freq);
-
-		ret = pctl_cfg(dram, chan, channel, params);
-		if (ret < 0) {
-			printf("%s: pctl config failed\n", __func__);
-			return ret;
-		}
-
-		/* start to trigger initialization */
-		pctl_start(dram, channel);
-	}
-
-	return 0;
-}
-
 static int sdram_init(struct dram_info *dram,
 		      struct rk3399_sdram_params *params)
 {
 	unsigned char dramtype = params->base.dramtype;
 	unsigned int ddr_freq = params->base.ddr_freq;
 	int channel, ch, rank;
-	int ret;
+	u32 tmp, ret;
 
 	debug("Starting SDRAM initialization...\n");
 
@@ -2534,22 +2887,35 @@ static int sdram_init(struct dram_info *dram,
 		return -E2BIG;
 	}
 
+	/* detect rank */
 	for (ch = 0; ch < 2; ch++) {
 		params->ch[ch].cap_info.rank = 2;
 		for (rank = 2; rank != 0; rank--) {
-			ret = pctl_init(dram, params);
-			if (ret < 0) {
-				printf("%s: pctl init failed\n", __func__);
-				return ret;
+			for (channel = 0; channel < 2; channel++) {
+				const struct chan_info *chan =
+					&dram->chan[channel];
+				struct rk3399_cru *cru = dram->cru;
+				struct rk3399_ddr_publ_regs *publ = chan->publ;
+
+				phy_pctrl_reset(cru, channel);
+				phy_dll_bypass_set(publ, ddr_freq);
+				pctl_cfg(dram, chan, channel, params);
 			}
 
+			/* start to trigger initialization */
+			pctl_start(dram, params, 3);
+
 			/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
 			if (dramtype == LPDDR3)
 				udelay(10);
 
+			tmp = (rank == 2) ? 3 : 1;
+			dram_set_cs(&dram->chan[ch], tmp, 2048,
+				    params->base.dramtype);
 			params->ch[ch].cap_info.rank = rank;
 
-			ret = dram->ops->data_training(dram, ch, rank, params);
+			ret = dram->ops->data_training_first(dram, ch,
+							     rank, params);
 			if (!ret) {
 				debug("%s: data trained for rank %d, ch %d\n",
 				      __func__, rank, ch);
@@ -2563,38 +2929,37 @@ static int sdram_init(struct dram_info *dram,
 	params->base.num_channels = 0;
 	for (channel = 0; channel < 2; channel++) {
 		const struct chan_info *chan = &dram->chan[channel];
-		struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
-		u8 training_flag = PI_FULL_TRAINING;
+		struct sdram_cap_info *cap_info =
+			&params->ch[channel].cap_info;
 
 		if (cap_info->rank == 0) {
-			clear_channel_params(params, channel);
+			clear_channel_params(params, 1);
 			continue;
 		} else {
 			params->base.num_channels++;
 		}
 
-		debug("Channel ");
-		debug(channel ? "1: " : "0: ");
+		printf("Channel ");
+		printf(channel ? "1: " : "0: ");
 
-		/* LPDDR3 should have write and read gate training */
-		if (params->base.dramtype == LPDDR3)
-			training_flag = PI_WRITE_LEVELING |
-					PI_READ_GATE_TRAINING;
+		if (channel == 0)
+			set_ddr_stride(dram->pmusgrf, 0x17);
+		else
+			set_ddr_stride(dram->pmusgrf, 0x18);
 
-		if (params->base.dramtype != LPDDR4) {
-			ret = data_training(dram, channel, params,
-					    training_flag);
-			if (!ret) {
-				debug("%s: data train failed for channel %d\n",
-				      __func__, ret);
-				continue;
-			}
+		if (dram_detect_cap(dram, params, channel)) {
+			printf("Cap error!\n");
+			continue;
 		}
 
 		sdram_print_ddr_info(cap_info, &params->base);
 		set_memory_map(chan, channel, params);
-		cap_info->ddrconfig = calculate_ddrconfig(params, channel);
-
+		cap_info->ddrconfig =
+			calculate_ddrconfig(params, channel);
+		if (-1 == cap_info->ddrconfig) {
+			printf("no ddrconfig find, Cap not support!\n");
+			continue;
+		}
 		set_ddrconfig(chan, params, channel, cap_info->ddrconfig);
 		set_cap_relate_config(chan, params, channel);
 	}
@@ -2608,7 +2973,8 @@ static int sdram_init(struct dram_info *dram,
 
 	params->base.stride = calculate_stride(params);
 	dram_all_config(dram, params);
-	dram->ops->set_rate(dram, params);
+
+	dram->ops->set_rate_index(dram, params);
 
 	debug("Finish SDRAM initialization...\n");
 	return 0;
@@ -2655,11 +3021,15 @@ static int conv_of_platdata(struct udevice *dev)
 
 static const struct sdram_rk3399_ops rk3399_ops = {
 #if !defined(CONFIG_RAM_RK3399_LPDDR4)
-	.data_training = default_data_training,
-	.set_rate = switch_to_phy_index1,
+	.data_training_first = data_training_first,
+	.set_rate_index = switch_to_phy_index1,
+	.modify_param = modify_param,
+	.get_phy_index_params = get_phy_index_params,
 #else
-	.data_training = lpddr4_mr_detect,
-	.set_rate = lpddr4_set_rate,
+	.data_training_first = lpddr4_mr_detect,
+	.set_rate_index = lpddr4_set_rate,
+	.modify_param = lpddr4_modify_param,
+	.get_phy_index_params = lpddr4_get_phy_index_params,
 #endif
 };
 
-- 
2.17.1

  parent reply	other threads:[~2019-10-25  1:34 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-25  1:33 [U-Boot] [PATCH v2 00/17] rockchip: ram: add common code for sdram driver Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 01/17] ram: rockchip: rename sdram.h to sdram_rk3288.h Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 02/17] ram: rockchip: rename sdram_common.c/h to sdram.c Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 03/17] rockchip: sdram: move cap structure and debug function to sdram_common.h Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 04/17] rockchip: sdram: extend to use sys_reg3 for capacity info Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 05/17] rockchip: sdram: update the sys_reg to sys_reg2 Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 06/17] ram: rockchip: add common code for sdram driver Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 07/17] ram: rockchip: move sdram_debug function into sdram_common Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 08/17] ram: rockchip: add controller code for PX30 Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 09/17] ram: rockchip: add phy driver " Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 10/17] ram: rockchip: add common msch reg definition Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 11/17] ram: px30: add sdram driver Kever Yang
2019-10-25  1:33 ` [U-Boot] [PATCH v2 12/17] ram: rk3328: use common " Kever Yang
2019-10-25  1:34 ` Kever Yang [this message]
2019-10-25  1:34 ` [U-Boot] [PATCH v2 14/17] ram: rockchip: update lpddr4 timing for rk3399 Kever Yang
2019-10-25  1:34 ` [U-Boot] [PATCH v2 15/17] ram: rk3399: Sync the io setting from Rockchip vendor code Kever Yang
2019-10-25  1:34 ` [U-Boot] [PATCH v2 16/17] ram: rk3399: update calculate_stride Kever Yang
2019-10-25  1:34 ` [U-Boot] [PATCH v2 17/17] ram: rk3399: Sync code from rockchip vendor code Kever Yang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191025013404.10823-14-kever.yang@rock-chips.com \
    --to=kever.yang@rock-chips.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.