All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support
@ 2016-12-29 10:25 Kever Yang
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support Kever Yang
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Kever Yang @ 2016-12-29 10:25 UTC (permalink / raw)
  To: u-boot


RK3399 SPL is not enable bacause of the lack of ATF support in SPL,
after port some source code from ATF, I manage to enable the support for
ATF in SPL. This patch set depends on some patch for SPL support multi
binary in FIT which is from Andre.

The patch of sdram controller is still not clean, because I want to get
comments from upstream.I port this driver from coreboot, and I don't
want to make much change on it. The rk3399 dram controller has many registers
to config, I want to make them directly used by driver instead of parse
and copy them one by one from dts.

Another part of comment is welcome for the implementation of spl_atf.c
and the entry in spl.c



Kever Yang (3):
  arm64: rk3399: add SPL support
  arm64: rk3399: add ddr controller driver
  spl: add support to booting with ATF

 arch/arm/Kconfig                                   |    1 +
 arch/arm/dts/rk3399.dtsi                           |   24 +
 arch/arm/include/asm/arch-rockchip/grf_rk3399.h    |  118 ++
 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h  |  188 +++
 arch/arm/mach-rockchip/Kconfig                     |    2 +
 arch/arm/mach-rockchip/Makefile                    |    1 +
 arch/arm/mach-rockchip/rk3399-board-spl.c          |  157 ++
 arch/arm/mach-rockchip/rk3399/Makefile             |    1 +
 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc | 1565 ++++++++++++++++++++
 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c       | 1121 ++++++++++++++
 common/spl/Kconfig                                 |   14 +
 common/spl/Makefile                                |    1 +
 common/spl/spl.c                                   |    4 +
 common/spl/spl_atf.c                               |   91 ++
 configs/evb-rk3399_defconfig                       |   17 +
 drivers/clk/rockchip/clk_rk3399.c                  |   42 +-
 drivers/pinctrl/rockchip/pinctrl_rk3399.c          |  106 --
 include/atf_common.h                               |  295 ++++
 include/configs/rk3399_common.h                    |   11 +
 include/dt-bindings/clock/rk3399-cru.h             |   16 +-
 include/spl.h                                      |    1 +
 21 files changed, 3663 insertions(+), 113 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
 create mode 100644 arch/arm/mach-rockchip/rk3399-board-spl.c
 create mode 100644 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
 create mode 100644 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
 create mode 100644 common/spl/spl_atf.c
 create mode 100644 include/atf_common.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support
  2016-12-29 10:25 [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Kever Yang
@ 2016-12-29 10:25 ` Kever Yang
  2017-01-13  2:11   ` Simon Glass
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver Kever Yang
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Kever Yang @ 2016-12-29 10:25 UTC (permalink / raw)
  To: u-boot

Add spl support for rk3399.

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

 arch/arm/Kconfig                                |   1 +
 arch/arm/dts/rk3399.dtsi                        |  24 ++++
 arch/arm/include/asm/arch-rockchip/grf_rk3399.h | 118 ++++++++++++++++++
 arch/arm/mach-rockchip/Kconfig                  |   2 +
 arch/arm/mach-rockchip/Makefile                 |   1 +
 arch/arm/mach-rockchip/rk3399-board-spl.c       | 157 ++++++++++++++++++++++++
 configs/evb-rk3399_defconfig                    |  17 +++
 drivers/clk/rockchip/clk_rk3399.c               |  42 ++++++-
 drivers/pinctrl/rockchip/pinctrl_rk3399.c       | 106 ----------------
 include/configs/rk3399_common.h                 |  11 ++
 include/dt-bindings/clock/rk3399-cru.h          |  16 ++-
 11 files changed, 382 insertions(+), 113 deletions(-)
 create mode 100644 arch/arm/mach-rockchip/rk3399-board-spl.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d871a45..9a0efe4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -882,6 +882,7 @@ config ARCH_ROCKCHIP
 	select DM
 	select SPL_DM if SPL
 	select SYS_MALLOC_F
+	select SPL_SEPARATE_BSS if SPL
 	select SPL_SYS_MALLOC_SIMPLE if SPL
 	select DM_GPIO
 	select DM_I2C
diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi
index 22277ff..c57fa5bc 100644
--- a/arch/arm/dts/rk3399.dtsi
+++ b/arch/arm/dts/rk3399.dtsi
@@ -183,6 +183,7 @@
 	};
 
 	sdhci: sdhci at fe330000 {
+		u-boot,dm-pre-reloc;
 		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
 		reg = <0x0 0xfe330000 0x0 0x10000>;
 		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
@@ -416,6 +417,7 @@
 	};
 
 	pmugrf: syscon at ff320000 {
+		u-boot,dm-pre-reloc;
 		compatible = "rockchip,rk3399-pmugrf", "syscon", "simple-mfd";
 		reg = <0x0 0xff320000 0x0 0x1000>;
 		#address-cells = <1>;
@@ -497,7 +499,26 @@
 		status = "disabled";
 	};
 
+	dfi: dfi at ff630000 {
+		reg = <0x00 0xff630000 0x00 0x4000>;
+		compatible = "rockchip,rk3399-dfi";
+		rockchip,pmu = <&pmugrf>;
+		clocks = <&cru PCLK_DDR_MON>;
+		clock-names = "pclk_ddr_mon";
+		status = "disabled";
+	};
+
+	dmc: dmc {
+		u-boot,dm-pre-reloc;
+		compatible = "rockchip,rk3399-dmc";
+		devfreq-events = <&dfi>;
+		interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru SCLK_DDRCLK>;
+		clock-names = "dmc_clk";
+	};
+
 	pmucru: pmu-clock-controller at ff750000 {
+		u-boot,dm-pre-reloc;
 		compatible = "rockchip,rk3399-pmucru";
 		reg = <0x0 0xff750000 0x0 0x1000>;
 		#clock-cells = <1>;
@@ -507,6 +528,7 @@
 	};
 
 	cru: clock-controller at ff760000 {
+		u-boot,dm-pre-reloc;
 		compatible = "rockchip,rk3399-cru";
 		reg = <0x0 0xff760000 0x0 0x1000>;
 		#clock-cells = <1>;
@@ -530,6 +552,7 @@
 	};
 
 	grf: syscon at ff770000 {
+		u-boot,dm-pre-reloc;
 		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x10000>;
 		#address-cells = <1>;
@@ -607,6 +630,7 @@
 	};
 
 	pinctrl: pinctrl {
+		u-boot,dm-pre-reloc;
 		compatible = "rockchip,rk3399-pinctrl";
 		rockchip,grf = <&grf>;
 		rockchip,pmu = <&pmugrf>;
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
index d3d1467..62d8496 100644
--- a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
+++ b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
@@ -318,4 +318,122 @@ struct rk3399_pmusgrf_regs {
 };
 check_member(rk3399_pmusgrf_regs, slv_secure_con4, 0xe3d4);
 
+enum {
+	/* GRF_GPIO2B_IOMUX */
+	GRF_GPIO2B1_SEL_SHIFT	= 0,
+	GRF_GPIO2B1_SEL_MASK	= 3 << GRF_GPIO2B1_SEL_SHIFT,
+	GRF_SPI2TPM_RXD		= 1,
+	GRF_GPIO2B2_SEL_SHIFT	= 2,
+	GRF_GPIO2B2_SEL_MASK	= 3 << GRF_GPIO2B2_SEL_SHIFT,
+	GRF_SPI2TPM_TXD		= 1,
+	GRF_GPIO2B3_SEL_SHIFT	= 6,
+	GRF_GPIO2B3_SEL_MASK	= 3 << GRF_GPIO2B3_SEL_SHIFT,
+	GRF_SPI2TPM_CLK		= 1,
+	GRF_GPIO2B4_SEL_SHIFT	= 8,
+	GRF_GPIO2B4_SEL_MASK	= 3 << GRF_GPIO2B4_SEL_SHIFT,
+	GRF_SPI2TPM_CSN0	= 1,
+
+	/* GRF_GPIO3A_IOMUX */
+	GRF_GPIO3A4_SEL_SHIFT	= 8,
+	GRF_GPIO3A4_SEL_MASK	= 3 << GRF_GPIO3A4_SEL_SHIFT,
+	GRF_SPI0NORCODEC_RXD	= 2,
+	GRF_GPIO3A5_SEL_SHIFT	= 10,
+	GRF_GPIO3A5_SEL_MASK	= 3 << GRF_GPIO3A5_SEL_SHIFT,
+	GRF_SPI0NORCODEC_TXD	= 2,
+	GRF_GPIO3A6_SEL_SHIFT	= 12,
+	GRF_GPIO3A6_SEL_MASK	= 3 << GRF_GPIO3A6_SEL_SHIFT,
+	GRF_SPI0NORCODEC_CLK	= 2,
+	GRF_GPIO3A7_SEL_SHIFT	= 14,
+	GRF_GPIO3A7_SEL_MASK	= 3 << GRF_GPIO3A7_SEL_SHIFT,
+	GRF_SPI0NORCODEC_CSN0	= 2,
+
+	/* GRF_GPIO3B_IOMUX */
+	GRF_GPIO3B0_SEL_SHIFT	= 0,
+	GRF_GPIO3B0_SEL_MASK	= 3 << GRF_GPIO3B0_SEL_SHIFT,
+	GRF_SPI0NORCODEC_CSN1	= 2,
+
+	/* GRF_GPIO4B_IOMUX */
+	GRF_GPIO4B0_SEL_SHIFT	= 0,
+	GRF_GPIO4B0_SEL_MASK	= 3 << GRF_GPIO4B0_SEL_SHIFT,
+	GRF_SDMMC_DATA0		= 1,
+	GRF_UART2DBGA_SIN	= 2,
+	GRF_GPIO4B1_SEL_SHIFT	= 2,
+	GRF_GPIO4B1_SEL_MASK	= 3 << GRF_GPIO4B1_SEL_SHIFT,
+	GRF_SDMMC_DATA1		= 1,
+	GRF_UART2DBGA_SOUT	= 2,
+	GRF_GPIO4B2_SEL_SHIFT	= 4,
+	GRF_GPIO4B2_SEL_MASK	= 3 << GRF_GPIO4B2_SEL_SHIFT,
+	GRF_SDMMC_DATA2		= 1,
+	GRF_GPIO4B3_SEL_SHIFT	= 6,
+	GRF_GPIO4B3_SEL_MASK	= 3 << GRF_GPIO4B3_SEL_SHIFT,
+	GRF_SDMMC_DATA3		= 1,
+	GRF_GPIO4B4_SEL_SHIFT	= 8,
+	GRF_GPIO4B4_SEL_MASK    = 3 << GRF_GPIO4B4_SEL_SHIFT,
+	GRF_SDMMC_CLKOUT        = 1,
+	GRF_GPIO4B5_SEL_SHIFT   = 10,
+	GRF_GPIO4B5_SEL_MASK    = 3 << GRF_GPIO4B5_SEL_SHIFT,
+	GRF_SDMMC_CMD           = 1,
+
+	/*  GRF_GPIO4C_IOMUX */
+	GRF_GPIO4C0_SEL_SHIFT   = 0,
+	GRF_GPIO4C0_SEL_MASK    = 3 << GRF_GPIO4C0_SEL_SHIFT,
+	GRF_UART2DGBB_SIN       = 2,
+	GRF_GPIO4C1_SEL_SHIFT   = 2,
+	GRF_GPIO4C1_SEL_MASK    = 3 << GRF_GPIO4C1_SEL_SHIFT,
+	GRF_UART2DGBB_SOUT      = 2,
+	GRF_GPIO4C2_SEL_SHIFT   = 4,
+	GRF_GPIO4C2_SEL_MASK    = 3 << GRF_GPIO4C2_SEL_SHIFT,
+	GRF_PWM_0               = 1,
+	GRF_GPIO4C3_SEL_SHIFT   = 6,
+	GRF_GPIO4C3_SEL_MASK    = 3 << GRF_GPIO4C3_SEL_SHIFT,
+	GRF_UART2DGBC_SIN       = 1,
+	GRF_GPIO4C4_SEL_SHIFT   = 8,
+	GRF_GPIO4C4_SEL_MASK    = 3 << GRF_GPIO4C4_SEL_SHIFT,
+	GRF_UART2DBGC_SOUT      = 1,
+	GRF_GPIO4C6_SEL_SHIFT   = 12,
+	GRF_GPIO4C6_SEL_MASK    = 3 << GRF_GPIO4C6_SEL_SHIFT,
+	GRF_PWM_1               = 1,
+
+	/* GRF_SOC_CON7 */
+	GRF_UART_DBG_SEL_SHIFT	= 10,
+	GRF_UART_DBG_SEL_MASK	= 3 << GRF_UART_DBG_SEL_SHIFT,
+	GRF_UART_DBG_SEL_C	= 2,
+
+	/*  PMUGRF_GPIO0A_IOMUX */
+	PMUGRF_GPIO0A6_SEL_SHIFT        = 12,
+	PMUGRF_GPIO0A6_SEL_MASK = 3 << PMUGRF_GPIO0A6_SEL_SHIFT,
+	PMUGRF_PWM_3A           = 1,
+
+	/*  PMUGRF_GPIO1A_IOMUX */
+	PMUGRF_GPIO1A7_SEL_SHIFT        = 14,
+	PMUGRF_GPIO1A7_SEL_MASK = 3 << PMUGRF_GPIO1A7_SEL_SHIFT,
+	PMUGRF_SPI1EC_RXD       = 2,
+
+	/*  PMUGRF_GPIO1B_IOMUX */
+	PMUGRF_GPIO1B0_SEL_SHIFT        = 0,
+	PMUGRF_GPIO1B0_SEL_MASK = 3 << PMUGRF_GPIO1B0_SEL_SHIFT,
+	PMUGRF_SPI1EC_TXD       = 2,
+	PMUGRF_GPIO1B1_SEL_SHIFT        = 2,
+	PMUGRF_GPIO1B1_SEL_MASK = 3 << PMUGRF_GPIO1B1_SEL_SHIFT,
+	PMUGRF_SPI1EC_CLK       = 2,
+	PMUGRF_GPIO1B2_SEL_SHIFT        = 4,
+	PMUGRF_GPIO1B2_SEL_MASK = 3 << PMUGRF_GPIO1B2_SEL_SHIFT,
+	PMUGRF_SPI1EC_CSN0      = 2,
+	PMUGRF_GPIO1B6_SEL_SHIFT        = 12,
+	PMUGRF_GPIO1B6_SEL_MASK = 3 << PMUGRF_GPIO1B6_SEL_SHIFT,
+	PMUGRF_PWM_3B           = 1,
+	PMUGRF_GPIO1B7_SEL_SHIFT        = 14,
+	PMUGRF_GPIO1B7_SEL_MASK = 3 << PMUGRF_GPIO1B7_SEL_SHIFT,
+	PMUGRF_I2C0PMU_SDA      = 2,
+
+	/*  PMUGRF_GPIO1C_IOMUX */
+	PMUGRF_GPIO1C0_SEL_SHIFT        = 0,
+	PMUGRF_GPIO1C0_SEL_MASK = 3 << PMUGRF_GPIO1C0_SEL_SHIFT,
+	PMUGRF_I2C0PMU_SCL      = 2,
+	PMUGRF_GPIO1C3_SEL_SHIFT        = 6,
+	PMUGRF_GPIO1C3_SEL_MASK = 3 << PMUGRF_GPIO1C3_SEL_SHIFT,
+	PMUGRF_PWM_2            = 1,
+
+};
+
 #endif	/* __SOC_ROCKCHIP_RK3399_GRF_H__ */
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 5c4a4c2..cd8fef8 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -26,6 +26,8 @@ config ROCKCHIP_RK3288
 config ROCKCHIP_RK3399
 	bool "Support Rockchip RK3399"
 	select ARM64
+	select SUPPORT_SPL
+	select SPL
 	help
 	  The Rockchip RK3399 is a ARM-based SoC with a dual-core Cortex-A72
 	  and quad-core Cortex-A53.
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 6e79fed..b58c02d 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -7,6 +7,7 @@
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o
 obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-spl.o
+obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399-board-spl.o
 obj-$(CONFIG_ROCKCHIP_SPL_BACK_TO_BROM) += save_boot_param.o
 else
 obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board.o
diff --git a/arch/arm/mach-rockchip/rk3399-board-spl.c b/arch/arm/mach-rockchip/rk3399-board-spl.c
new file mode 100644
index 0000000..504c8f9
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3399-board-spl.c
@@ -0,0 +1,157 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <led.h>
+#include <malloc.h>
+#include <ram.h>
+#include <spl.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/periph.h>
+#include <asm/arch/sdram.h>
+#include <asm/arch/timer.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/util.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_MMC1;
+}
+
+u32 spl_boot_mode(const u32 boot_device)
+{
+	return MMCSD_MODE_RAW;
+}
+
+#define TIMER_CHN10_BASE	0xff8680a0
+#define TIMER_END_COUNT_L	0x00
+#define TIMER_END_COUNT_H	0x04
+#define TIMER_INIT_COUNT_L	0x10
+#define TIMER_INIT_COUNT_H	0x14
+#define TIMER_CONTROL_REG	0x1c
+
+#define TIMER_EN	0x1
+#define	TIMER_FMODE	(0 << 1)
+#define	TIMER_RMODE	(1 << 1)
+
+void secure_timer_init(void)
+{
+	writel(0xffffffff, TIMER_CHN10_BASE + TIMER_END_COUNT_L);
+	writel(0xffffffff, TIMER_CHN10_BASE + TIMER_END_COUNT_H);
+	writel(0, TIMER_CHN10_BASE + TIMER_INIT_COUNT_L);
+	writel(0, TIMER_CHN10_BASE + TIMER_INIT_COUNT_H);
+	writel(TIMER_EN | TIMER_FMODE, TIMER_CHN10_BASE + TIMER_CONTROL_REG);
+}
+
+#define GRF_EMMCCORE_CON11 0xff77f02c
+void board_init_f(ulong dummy)
+{
+	struct udevice *pinctrl;
+	struct udevice *dev;
+	int ret;
+
+	/* Example code showing how to enable the debug UART on RK3288 */
+#include <asm/arch/grf_rk3399.h>
+	/* Enable early UART2 channel C on the RK3399 */
+#define GRF_BASE	0xff770000
+	struct rk3399_grf_regs * const grf = (void *)GRF_BASE;
+
+	rk_clrsetreg(&grf->gpio4c_iomux,
+		     GRF_GPIO4C3_SEL_MASK,
+		     GRF_UART2DGBC_SIN << GRF_GPIO4C3_SEL_SHIFT);
+	rk_clrsetreg(&grf->gpio4c_iomux,
+		     GRF_GPIO4C4_SEL_MASK,
+		     GRF_UART2DBGC_SOUT << GRF_GPIO4C4_SEL_SHIFT);
+	/* Set channel C as UART2 input */
+	rk_clrsetreg(&grf->soc_con7,
+		     GRF_UART_DBG_SEL_MASK,
+		     GRF_UART_DBG_SEL_C << GRF_UART_DBG_SEL_SHIFT);
+#ifdef EARLY_UART
+	/*
+	 * Debug UART can be used from here if required:
+	 *
+	 * debug_uart_init();
+	 * printch('a');
+	 * printhex8(0x1234);
+	 * printascii("string");
+	 */
+	debug_uart_init();
+	printascii("U-Boot SPL board init");
+#endif
+	/*  Emmc clock generator: disable the clock multipilier */
+	rk_clrreg(GRF_EMMCCORE_CON11, 0x0ff);
+
+	ret = spl_init();
+	if (ret) {
+		debug("spl_init() failed: %d\n", ret);
+		hang();
+	}
+
+	secure_timer_init();
+
+	ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
+	if (ret) {
+		debug("Pinctrl init failed: %d\n", ret);
+		return;
+	}
+
+	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+	if (ret) {
+		debug("DRAM init failed: %d\n", ret);
+		return;
+	}
+}
+
+void spl_board_init(void)
+{
+	struct udevice *pinctrl;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
+	if (ret) {
+		debug("%s: Cannot find pinctrl device\n", __func__);
+		goto err;
+	}
+
+	/* Enable debug UART */
+	ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_UART_DBG);
+	if (ret) {
+		debug("%s: Failed to set up console UART\n", __func__);
+		goto err;
+	}
+
+	preloader_console_init();
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+	back_to_bootrom();
+#endif
+	return;
+err:
+	printf("spl_board_init: Error %d\n", ret);
+
+	/* No way to report error here */
+	hang();
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+	/* Just empty function now - can't decide what to choose */
+	debug("%s: %s\n", __func__, name);
+
+	return 0;
+}
+#endif
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig
index 40a8295..78c2846 100644
--- a/configs/evb-rk3399_defconfig
+++ b/configs/evb-rk3399_defconfig
@@ -3,7 +3,16 @@ CONFIG_ARCH_ROCKCHIP=y
 CONFIG_ROCKCHIP_RK3399=y
 CONFIG_DEFAULT_DEVICE_TREE="rk3399-evb"
 CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_OF_LIBFDT=y
+CONFIG_SPL_ATF_SUPPORT=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x200
+CONFIG_SPL_ATF_TEXT_BASE=0x00010000
 # CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_ADDR=0x80000
+CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x4000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
 # CONFIG_CMD_IMLS is not set
@@ -16,18 +25,26 @@ CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_PXE=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
 CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
 CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
 CONFIG_CLK=y
+CONFIG_SPL_CLK=y
 CONFIG_ROCKCHIP_GPIO=y
 CONFIG_ROCKCHIP_DWMMC=y
 CONFIG_ROCKCHIP_SDHCI=y
 CONFIG_PINCTRL=y
+CONFIG_SPL_PINCTRL=y
 CONFIG_ROCKCHIP_RK3399_PINCTRL=y
 CONFIG_PWM_ROCKCHIP=y
 CONFIG_REGULATOR_PWM=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_RAM=y
+CONFIG_SPL_RAM=y
 CONFIG_DEBUG_UART=y
 CONFIG_DEBUG_UART_BASE=0xFF1A0000
 CONFIG_DEBUG_UART_CLOCK=24000000
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index 2e87e4b..d259a1c 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -709,6 +709,44 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
 	return rk3399_mmc_get_clk(cru, clk_id);
 }
 
+#define PMUSGRF_DDR_RGN_CON16 0xff330040
+static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
+				ulong set_rate)
+{
+	struct pll_div dpll_cfg;
+
+	/*  IC ECO bug, need to set this register */
+	writel(0xc000c000, PMUSGRF_DDR_RGN_CON16);
+
+	/*  clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
+	switch (set_rate) {
+	case 200*MHz:
+		dpll_cfg = (struct pll_div)
+		{.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
+		break;
+	case 300*MHz:
+		dpll_cfg = (struct pll_div)
+		{.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
+		break;
+	case 666*MHz:
+		dpll_cfg = (struct pll_div)
+		{.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
+		break;
+	case 800*MHz:
+		dpll_cfg = (struct pll_div)
+		{.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
+		break;
+	case 933*MHz:
+		dpll_cfg = (struct pll_div)
+		{.refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1};
+		break;
+	default:
+		error("Unsupported SDRAM frequency!,%ld\n", set_rate);
+	}
+	rkclk_set_pll(&cru->dpll_con[0], &dpll_cfg);
+
+	return set_rate;
+}
 static ulong rk3399_clk_get_rate(struct clk *clk)
 {
 	struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
@@ -763,6 +801,9 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
 	case DCLK_VOP1:
 		ret = rk3399_vop_set_clk(priv->cru, clk->id, rate);
 		break;
+	case SCLK_DDRCLK:
+		ret = rk3399_ddr_set_clk(priv->cru, rate);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -939,7 +980,6 @@ static void pmuclk_init(struct rk3399_pmucru *pmucru)
 
 	/*  configure pmu pclk */
 	pclk_div = PPLL_HZ / PMU_PCLK_HZ - 1;
-	assert((pclk_div + 1) * PMU_PCLK_HZ == PPLL_HZ && pclk_div < 0x1f);
 	rk_clrsetreg(&pmucru->pmucru_clksel[0],
 		     PMU_PCLK_DIV_CON_MASK,
 		     pclk_div << PMU_PCLK_DIV_CON_SHIFT);
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3399.c b/drivers/pinctrl/rockchip/pinctrl_rk3399.c
index 17ea165..2f8aa64 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3399.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3399.c
@@ -22,112 +22,6 @@ struct rk3399_pinctrl_priv {
 	struct rk3399_pmugrf_regs *pmugrf;
 };
 
-enum {
-	/* GRF_GPIO2B_IOMUX */
-	GRF_GPIO2B1_SEL_SHIFT	= 0,
-	GRF_GPIO2B1_SEL_MASK	= 3 << GRF_GPIO2B1_SEL_SHIFT,
-	GRF_SPI2TPM_RXD		= 1,
-	GRF_GPIO2B2_SEL_SHIFT	= 2,
-	GRF_GPIO2B2_SEL_MASK	= 3 << GRF_GPIO2B2_SEL_SHIFT,
-	GRF_SPI2TPM_TXD		= 1,
-	GRF_GPIO2B3_SEL_SHIFT	= 6,
-	GRF_GPIO2B3_SEL_MASK	= 3 << GRF_GPIO2B3_SEL_SHIFT,
-	GRF_SPI2TPM_CLK		= 1,
-	GRF_GPIO2B4_SEL_SHIFT	= 8,
-	GRF_GPIO2B4_SEL_MASK	= 3 << GRF_GPIO2B4_SEL_SHIFT,
-	GRF_SPI2TPM_CSN0	= 1,
-
-	/* GRF_GPIO3A_IOMUX */
-	GRF_GPIO3A4_SEL_SHIFT	= 8,
-	GRF_GPIO3A4_SEL_MASK	= 3 << GRF_GPIO3A4_SEL_SHIFT,
-	GRF_SPI0NORCODEC_RXD	= 2,
-	GRF_GPIO3A5_SEL_SHIFT	= 10,
-	GRF_GPIO3A5_SEL_MASK	= 3 << GRF_GPIO3A5_SEL_SHIFT,
-	GRF_SPI0NORCODEC_TXD	= 2,
-	GRF_GPIO3A6_SEL_SHIFT	= 12,
-	GRF_GPIO3A6_SEL_MASK	= 3 << GRF_GPIO3A6_SEL_SHIFT,
-	GRF_SPI0NORCODEC_CLK	= 2,
-	GRF_GPIO3A7_SEL_SHIFT	= 14,
-	GRF_GPIO3A7_SEL_MASK	= 3 << GRF_GPIO3A7_SEL_SHIFT,
-	GRF_SPI0NORCODEC_CSN0	= 2,
-
-	/* GRF_GPIO3B_IOMUX */
-	GRF_GPIO3B0_SEL_SHIFT	= 0,
-	GRF_GPIO3B0_SEL_MASK	= 3 << GRF_GPIO3B0_SEL_SHIFT,
-	GRF_SPI0NORCODEC_CSN1	= 2,
-
-	/* GRF_GPIO4B_IOMUX */
-	GRF_GPIO4B0_SEL_SHIFT	= 0,
-	GRF_GPIO4B0_SEL_MASK	= 3 << GRF_GPIO4B0_SEL_SHIFT,
-	GRF_SDMMC_DATA0		= 1,
-	GRF_UART2DBGA_SIN	= 2,
-	GRF_GPIO4B1_SEL_SHIFT	= 2,
-	GRF_GPIO4B1_SEL_MASK	= 3 << GRF_GPIO4B1_SEL_SHIFT,
-	GRF_SDMMC_DATA1		= 1,
-	GRF_UART2DBGA_SOUT	= 2,
-	GRF_GPIO4B2_SEL_SHIFT	= 4,
-	GRF_GPIO4B2_SEL_MASK	= 3 << GRF_GPIO4B2_SEL_SHIFT,
-	GRF_SDMMC_DATA2		= 1,
-	GRF_GPIO4B3_SEL_SHIFT	= 6,
-	GRF_GPIO4B3_SEL_MASK	= 3 << GRF_GPIO4B3_SEL_SHIFT,
-	GRF_SDMMC_DATA3		= 1,
-	GRF_GPIO4B4_SEL_SHIFT	= 8,
-	GRF_GPIO4B4_SEL_MASK	= 3 << GRF_GPIO4B4_SEL_SHIFT,
-	GRF_SDMMC_CLKOUT	= 1,
-	GRF_GPIO4B5_SEL_SHIFT	= 10,
-	GRF_GPIO4B5_SEL_MASK	= 3 << GRF_GPIO4B5_SEL_SHIFT,
-	GRF_SDMMC_CMD		= 1,
-
-	/* GRF_GPIO4C_IOMUX */
-	GRF_GPIO4C2_SEL_SHIFT	= 4,
-	GRF_GPIO4C2_SEL_MASK	= 3 << GRF_GPIO4C2_SEL_SHIFT,
-	GRF_PWM_0		= 1,
-	GRF_GPIO4C3_SEL_SHIFT	= 6,
-	GRF_GPIO4C3_SEL_MASK	= 3 << GRF_GPIO4C3_SEL_SHIFT,
-	GRF_UART2DGBC_SIN	= 1,
-	GRF_GPIO4C4_SEL_SHIFT	= 8,
-	GRF_GPIO4C4_SEL_MASK	= 3 << GRF_GPIO4C4_SEL_SHIFT,
-	GRF_UART2DBGC_SOUT	= 1,
-	GRF_GPIO4C6_SEL_SHIFT	= 12,
-	GRF_GPIO4C6_SEL_MASK	= 3 << GRF_GPIO4C6_SEL_SHIFT,
-	GRF_PWM_1		= 1,
-
-	/* PMUGRF_GPIO0A_IOMUX */
-	PMUGRF_GPIO0A6_SEL_SHIFT	= 12,
-	PMUGRF_GPIO0A6_SEL_MASK	= 3 << PMUGRF_GPIO0A6_SEL_SHIFT,
-	PMUGRF_PWM_3A		= 1,
-
-	/* PMUGRF_GPIO1A_IOMUX */
-	PMUGRF_GPIO1A7_SEL_SHIFT	= 14,
-	PMUGRF_GPIO1A7_SEL_MASK	= 3 << PMUGRF_GPIO1A7_SEL_SHIFT,
-	PMUGRF_SPI1EC_RXD	= 2,
-
-	/* PMUGRF_GPIO1B_IOMUX */
-	PMUGRF_GPIO1B0_SEL_SHIFT	= 0,
-	PMUGRF_GPIO1B0_SEL_MASK = 3 << PMUGRF_GPIO1B0_SEL_SHIFT,
-	PMUGRF_SPI1EC_TXD	= 2,
-	PMUGRF_GPIO1B1_SEL_SHIFT	= 2,
-	PMUGRF_GPIO1B1_SEL_MASK = 3 << PMUGRF_GPIO1B1_SEL_SHIFT,
-	PMUGRF_SPI1EC_CLK	= 2,
-	PMUGRF_GPIO1B2_SEL_SHIFT	= 4,
-	PMUGRF_GPIO1B2_SEL_MASK = 3 << PMUGRF_GPIO1B2_SEL_SHIFT,
-	PMUGRF_SPI1EC_CSN0	= 2,
-	PMUGRF_GPIO1B6_SEL_SHIFT	= 12,
-	PMUGRF_GPIO1B6_SEL_MASK	= 3 << PMUGRF_GPIO1B6_SEL_SHIFT,
-	PMUGRF_PWM_3B		= 1,
-	PMUGRF_GPIO1B7_SEL_SHIFT	= 14,
-	PMUGRF_GPIO1B7_SEL_MASK	= 3 << PMUGRF_GPIO1B7_SEL_SHIFT,
-	PMUGRF_I2C0PMU_SDA	= 2,
-
-	/* PMUGRF_GPIO1C_IOMUX */
-	PMUGRF_GPIO1C0_SEL_SHIFT	= 0,
-	PMUGRF_GPIO1C0_SEL_MASK	= 3 << PMUGRF_GPIO1C0_SEL_SHIFT,
-	PMUGRF_I2C0PMU_SCL	= 2,
-	PMUGRF_GPIO1C3_SEL_SHIFT	= 6,
-	PMUGRF_GPIO1C3_SEL_MASK	= 3 << PMUGRF_GPIO1C3_SEL_SHIFT,
-	PMUGRF_PWM_2		= 1,
-
-};
 static void pinctrl_rk3399_pwm_config(struct rk3399_grf_regs *grf,
 		struct rk3399_pmugrf_regs *pmugrf, int pwm_id)
 {
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h
index aa646c6..3699a9d 100644
--- a/include/configs/rk3399_common.h
+++ b/include/configs/rk3399_common.h
@@ -17,12 +17,23 @@
 #define CONFIG_SYS_MALLOC_LEN		(32 << 20)
 #define CONFIG_SYS_CBSIZE		1024
 #define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_DRIVERS_MISC_SUPPORT
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
 
 #define CONFIG_SYS_NS16550_MEM32
 
 #define CONFIG_SYS_TEXT_BASE		0x00200000
 #define CONFIG_SYS_INIT_SP_ADDR		0x00300000
 #define CONFIG_SYS_LOAD_ADDR		0x00800800
+#define CONFIG_SPL_STACK		0xff8effff
+#define CONFIG_SPL_TEXT_BASE		0xff8c2008
+#define CONFIG_SPL_MAX_SIZE		0x30000
+/*  BSS setup */
+#define CONFIG_SPL_BSS_START_ADDR       0xff8e0000
+#define CONFIG_SPL_BSS_MAX_SIZE         0x10000
 
 #define CONFIG_SYS_BOOTM_LEN	(64 << 20)	/* 64M */
 
diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h
index 0a86aec..d4bdcc6 100644
--- a/include/dt-bindings/clock/rk3399-cru.h
+++ b/include/dt-bindings/clock/rk3399-cru.h
@@ -122,6 +122,10 @@
 #define SCLK_DPHY_RX0_CFG		165
 #define SCLK_RMII_SRC			166
 #define SCLK_PCIEPHY_REF100M		167
+#define SCLK_USBPHY0_480M_SRC		168
+#define SCLK_USBPHY1_480M_SRC		169
+#define SCLK_DDRCLK			170
+#define SCLK_TESTOUT2			171
 
 #define DCLK_VOP0			180
 #define DCLK_VOP1			181
@@ -589,13 +593,13 @@
 #define SRST_P_SPI0			214
 #define SRST_P_SPI1			215
 #define SRST_P_SPI2			216
-#define SRST_P_SPI3			217
-#define SRST_P_SPI4			218
+#define SRST_P_SPI4			217
+#define SRST_P_SPI5			218
 #define SRST_SPI0			219
 #define SRST_SPI1			220
 #define SRST_SPI2			221
-#define SRST_SPI3			222
-#define SRST_SPI4			223
+#define SRST_SPI4			222
+#define SRST_SPI5			223
 
 /* cru_softrst_con14 */
 #define SRST_I2S0_8CH			224
@@ -717,8 +721,8 @@
 #define SRST_H_CM0S_NOC			3
 #define SRST_DBG_CM0S			4
 #define SRST_PO_CM0S			5
-#define SRST_P_SPI6			6
-#define SRST_SPI6			7
+#define SRST_P_SPI3			6
+#define SRST_SPI3			7
 #define SRST_P_TIMER_0_1		8
 #define SRST_P_TIMER_0			9
 #define SRST_P_TIMER_1			10
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver
  2016-12-29 10:25 [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Kever Yang
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support Kever Yang
@ 2016-12-29 10:25 ` Kever Yang
  2017-01-13  2:18   ` Simon Glass
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF Kever Yang
  2017-01-02 15:05 ` [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Michal Simek
  3 siblings, 1 reply; 15+ messages in thread
From: Kever Yang @ 2016-12-29 10:25 UTC (permalink / raw)
  To: u-boot

RK3399 support DDR3, LPDDR3, DDR4 sdram, this patch is porting from
coreboot, support 4GB lpddr3 in this version.

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

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

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

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2016-12-29 10:25 [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Kever Yang
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support Kever Yang
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver Kever Yang
@ 2016-12-29 10:25 ` Kever Yang
  2017-01-02 15:05   ` Michal Simek
  2017-01-18 12:20   ` Kever Yang
  2017-01-02 15:05 ` [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Michal Simek
  3 siblings, 2 replies; 15+ messages in thread
From: Kever Yang @ 2016-12-29 10:25 UTC (permalink / raw)
  To: u-boot

ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
about ATF at:

SPL is consider as BL2 in ATF, it needs to load other part of ATF binary
like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
parameter for BL31 which including entry and image information for all
other images. Then the SPL handle PC to BL31 with the parameter, the
BL31 will do the rest of work and at last get into U-Boot(BL33).

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

 common/spl/Kconfig   |  14 +++
 common/spl/Makefile  |   1 +
 common/spl/spl.c     |   4 +
 common/spl/spl_atf.c |  91 ++++++++++++++++
 include/atf_common.h | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/spl.h        |   1 +
 6 files changed, 406 insertions(+)
 create mode 100644 common/spl/spl_atf.c
 create mode 100644 include/atf_common.h

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index cba51f5..1bb4360 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
 	  means of transmitting U-Boot over a serial line for using in SPL,
 	  with a checksum to ensure correctness.
 
+config SPL_ATF_SUPPORT
+	bool "Support ARM trust firmware"
+	depends on SPL
+	help
+	  ATF(ARM Trust Firmware) is component for ARM arch64 which need to
+	  load by SPL(consider as BL2 in ATF).
+	  More detail at: https://github.com/ARM-software/arm-trusted-firmware
+
+config SPL_ATF_TEXT_BASE
+	depends on SPL_ATF_SUPPORT
+	hex "ATF TEXT BASE addr"
+	help
+	  This is the base address in memory for ATF text and entry point.
+
 config TPL_ENV_SUPPORT
 	bool "Support an environment"
 	depends on TPL
diff --git a/common/spl/Makefile b/common/spl/Makefile
index ed02635..620ae90 100644
--- a/common/spl/Makefile
+++ b/common/spl/Makefile
@@ -20,6 +20,7 @@ endif
 obj-$(CONFIG_SPL_UBI) += spl_ubi.o
 obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
 obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
+obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
 obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
 obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
 obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 1729034..7daf7bd 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
 	      gd->malloc_ptr / 1024);
 #endif
 
+#ifdef CONFIG_SPL_ATF_SUPPORT
+	bl31_entry();
+#endif
+
 	debug("loaded - jumping to U-Boot...");
 	spl_board_prepare_for_boot();
 	jump_to_image_no_args(&spl_image);
diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
new file mode 100644
index 0000000..cf23b7a
--- /dev/null
+++ b/common/spl/spl_atf.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
+ * Written by Kever Yang <kever.yang@rock-chips.com>
+ *
+ * origin from arm-trust-firmware
+ * plat/arm/common/arm_bl2_setup.c
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <spl.h>
+#include <atf_common.h>
+
+static struct bl2_to_bl31_params_mem_t bl31_params_mem;
+static struct bl31_params_t *bl2_to_bl31_params;
+
+/*******************************************************************************
+ * This function assigns a pointer to the memory that the platform has kept
+ * aside to pass platform specific and trusted firmware related information
+ * to BL31. This memory is allocated by allocating memory to
+ * bl2_to_bl31_params_mem_t structure which is a superset of all the
+ * structure whose information is passed to BL31
+ * NOTE: This function should be called only once and should be done
+ * before generating params to BL31
+ ******************************************************************************/
+struct bl31_params_t *bl2_plat_get_bl31_params(void)
+{
+	struct entry_point_info_t *bl33_ep_info;
+
+	/*
+	 * Initialise the memory for all the arguments that needs to
+	 * be passed to BL31
+	 */
+	memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem_t));
+
+	/* Assign memory for TF related information */
+	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
+	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
+
+	/* Fill BL31 related information */
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
+		       VERSION_1, 0);
+
+	/* Fill BL32 related information if it exists */
+#ifdef BL32_BASE
+	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
+		       VERSION_1, 0);
+	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
+		       VERSION_1, 0);
+#endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+	bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+	SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
+
+	/* BL33 expects to receive the primary CPU MPID (through x0) */
+	bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
+	bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
+	bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+				     DISABLE_ALL_EXECPTIONS);
+
+	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
+		       VERSION_1, 0);
+
+
+	return bl2_to_bl31_params;
+}
+
+void raw_write_daif(uint32_t daif)
+{
+	__asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
+}
+
+void bl31_entry(void)
+{
+	struct bl31_params_t *bl31_params;
+	void (*entry)(struct bl31_params_t *params, void *plat_params) = NULL;
+
+	bl31_params = bl2_plat_get_bl31_params();
+	entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
+
+	raw_write_daif(SPSR_EXCEPTION_MASK);
+	dcache_disable();
+
+	entry(bl31_params, NULL);
+}
diff --git a/include/atf_common.h b/include/atf_common.h
new file mode 100644
index 0000000..8351302
--- /dev/null
+++ b/include/atf_common.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BL_COMMON_H__
+#define __BL_COMMON_H__
+
+#define SECURE		0x0
+#define NON_SECURE	0x1
+#define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
+
+#define UP	1
+#define DOWN	0
+
+/*******************************************************************************
+ * Constants to identify the location of a memory region in a given memory
+ * layout.
+******************************************************************************/
+#define TOP	0x1
+#define BOTTOM	!TOP
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the
+ * 'entry_point_info' structure at their correct offsets.
+ ******************************************************************************/
+#define ENTRY_POINT_INFO_PC_OFFSET	0x08
+#define ENTRY_POINT_INFO_ARGS_OFFSET	0x18
+
+/* The following are used to set/get image attributes. */
+#define PARAM_EP_SECURITY_MASK		(0x1)
+
+#define GET_SECURITY_STATE(x) (x & PARAM_EP_SECURITY_MASK)
+#define SET_SECURITY_STATE(x, security) \
+			((x) = ((x) & ~PARAM_EP_SECURITY_MASK) | (security))
+
+
+/*
+ * The following are used for image state attributes.
+ * Image can only be in one of the following state.
+ */
+#define IMAGE_STATE_RESET			0
+#define IMAGE_STATE_COPIED			1
+#define IMAGE_STATE_COPYING			2
+#define IMAGE_STATE_AUTHENTICATED		3
+#define IMAGE_STATE_EXECUTED			4
+#define IMAGE_STATE_INTERRUPTED			5
+
+#define EP_SECURE	0x0
+#define EP_NON_SECURE	0x1
+
+#define EP_EE_MASK	0x2
+#define EP_EE_LITTLE	0x0
+#define EP_EE_BIG	0x2
+#define EP_GET_EE(x) (x & EP_EE_MASK)
+#define EP_SET_EE(x, ee) ((x) = ((x) & ~EP_EE_MASK) | (ee))
+
+#define EP_ST_MASK	0x4
+#define EP_ST_DISABLE	0x0
+#define EP_ST_ENABLE	0x4
+#define EP_GET_ST(x) (x & EP_ST_MASK)
+#define EP_SET_ST(x, ee) ((x) = ((x) & ~EP_ST_MASK) | (ee))
+
+#define EP_EXE_MASK	0x8
+#define NON_EXECUTABLE	0x0
+#define EXECUTABLE	0x8
+#define EP_GET_EXE(x) (x & EP_EXE_MASK)
+#define EP_SET_EXE(x, ee) ((x) = ((x) & ~EP_EXE_MASK) | (ee))
+
+#define PARAM_EP		0x01
+#define PARAM_IMAGE_BINARY	0x02
+#define PARAM_BL31		0x03
+
+#define VERSION_1	0x01
+
+#define INVALID_IMAGE_ID		(0xFFFFFFFF)
+
+#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \
+	(_p)->h.type = (uint8_t)(_type); \
+	(_p)->h.version = (uint8_t)(_ver); \
+	(_p)->h.size = (uint16_t)sizeof(*_p); \
+	(_p)->h.attr = (uint32_t)(_attr) ; \
+	} while (0)
+
+/* Following is used for populating structure members statically. */
+#define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr)	\
+	._p.h.type = (uint8_t)(_type), \
+	._p.h.version = (uint8_t)(_ver), \
+	._p.h.size = (uint16_t)sizeof(_p_type), \
+	._p.h.attr = (uint32_t)(_attr)
+
+#define MODE_RW_SHIFT	0x4
+#define MODE_RW_MASK	0x1
+#define MODE_RW_64	0x0
+#define MODE_RW_32	0x1
+
+#define MODE_EL_SHIFT	0x2
+#define MODE_EL_MASK	0x3
+#define MODE_EL3	0x3
+#define MODE_EL2	0x2
+#define MODE_EL1	0x1
+#define MODE_EL0	0x0
+
+#define MODE_SP_SHIFT	0x0
+#define MODE_SP_MASK	0x1
+#define MODE_SP_EL0	0x0
+#define MODE_SP_ELX	0x1
+
+#define SPSR_DAIF_SHIFT	6
+#define SPSR_DAIF_MASK	0x0f
+
+#define DAIF_FIQ_BIT (1<<0)
+#define DAIF_IRQ_BIT (1<<0)
+#define DAIF_ABT_BIT (1<<0)
+#define DAIF_DBG_BIT (1<<0)
+#define DISABLE_ALL_EXECPTIONS	\
+	(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
+
+#define SPSR_64(el, sp, daif)		\
+	(MODE_RW_64 << MODE_RW_SHIFT |	\
+	 ((el) & MODE_EL_MASK) << MODE_EL_SHIFT |	\
+	 ((sp) & MODE_SP_MASK) << MODE_SP_SHIFT |	\
+	 ((daif) & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)
+
+/*******************************************************************************
+ * Constants to indicate type of exception to the common exception handler.
+ ******************************************************************************/
+#define SYNC_EXCEPTION_SP_EL0		0x0
+#define IRQ_SP_EL0			0x1
+#define FIQ_SP_EL0			0x2
+#define SERROR_SP_EL0			0x3
+#define SYNC_EXCEPTION_SP_ELX		0x4
+#define IRQ_SP_ELX			0x5
+#define FIQ_SP_ELX			0x6
+#define SERROR_SP_ELX			0x7
+#define SYNC_EXCEPTION_AARCH64		0x8
+#define IRQ_AARCH64			0x9
+#define FIQ_AARCH64			0xa
+#define SERROR_AARCH64			0xb
+#define SYNC_EXCEPTION_AARCH32		0xc
+#define IRQ_AARCH32			0xd
+#define FIQ_AARCH32			0xe
+#define SERROR_AARCH32			0xf
+
+#define SPSR_USE_L           0
+#define SPSR_USE_H           1
+#define SPSR_L_H_MASK        1
+#define SPSR_M_SHIFT         4
+#define SPSR_ERET_32         (1 << SPSR_M_SHIFT)
+#define SPSR_ERET_64         (0 << SPSR_M_SHIFT)
+#define SPSR_FIQ             (1 << 6)
+#define SPSR_IRQ             (1 << 7)
+#define SPSR_SERROR          (1 << 8)
+#define SPSR_DEBUG           (1 << 9)
+#define SPSR_EXCEPTION_MASK  (SPSR_FIQ | SPSR_IRQ | SPSR_SERROR | SPSR_DEBUG)
+
+#ifndef __ASSEMBLY__
+
+/*******************************************************************************
+ * Structure used for telling the next BL how much of a particular type of
+ * memory is available for its use and how much is already used.
+ ******************************************************************************/
+struct aapcs64_params_t {
+	unsigned long arg0;
+	unsigned long arg1;
+	unsigned long arg2;
+	unsigned long arg3;
+	unsigned long arg4;
+	unsigned long arg5;
+	unsigned long arg6;
+	unsigned long arg7;
+};
+
+/***************************************************************************
+ * This structure provides version information and the size of the
+ * structure, attributes for the structure it represents
+ ***************************************************************************/
+struct param_header_t {
+	uint8_t type;		/* type of the structure */
+	uint8_t version;    /* version of this structure */
+	uint16_t size;      /* size of this structure in bytes */
+	uint32_t attr;      /* attributes: unused bits SBZ */
+};
+
+/*****************************************************************************
+ * This structure represents the superset of information needed while
+ * switching exception levels. The only two mechanisms to do so are
+ * ERET & SMC. Security state is indicated using bit zero of header
+ * attribute
+ * NOTE: BL1 expects entrypoint followed by spsr@an offset from the start
+ * of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while
+ * processing SMC to jump to BL31.
+ *****************************************************************************/
+struct entry_point_info_t {
+	struct param_header_t h;
+	uintptr_t pc;
+	uint32_t spsr;
+	struct aapcs64_params_t args;
+};
+
+/*****************************************************************************
+ * Image info binary provides information from the image loader that
+ * can be used by the firmware to manage available trusted RAM.
+ * More advanced firmware image formats can provide additional
+ * information that enables optimization or greater flexibility in the
+ * common firmware code
+ *****************************************************************************/
+struct atf_image_info_t {
+	struct param_header_t h;
+	uintptr_t image_base;   /* physical address of base of image */
+	uint32_t image_size;    /* bytes read from image file */
+};
+
+/*****************************************************************************
+ * The image descriptor struct definition.
+ *****************************************************************************/
+struct image_desc_t {
+	/* Contains unique image id for the image. */
+	unsigned int image_id;
+	/*
+	 * This member contains Image state information.
+	 * Refer IMAGE_STATE_XXX defined above.
+	 */
+	unsigned int state;
+	uint32_t copied_size;	/* image size copied in blocks */
+	struct atf_image_info_t atf_image_info;
+	struct entry_point_info_t ep_info;
+};
+
+/*******************************************************************************
+ * This structure represents the superset of information that can be passed to
+ * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be
+ * populated only if BL2 detects its presence. A pointer to a structure of this
+ * type should be passed in X0 to BL31's cold boot entrypoint.
+ *
+ * Use of this structure and the X0 parameter is not mandatory: the BL31
+ * platform code can use other mechanisms to provide the necessary information
+ * about BL32 and BL33 to the common and SPD code.
+ *
+ * BL31 image information is mandatory if this structure is used. If either of
+ * the optional BL32 and BL33 image information is not provided, this is
+ * indicated by the respective image_info pointers being zero.
+ ******************************************************************************/
+struct bl31_params_t {
+	struct param_header_t h;
+	struct atf_image_info_t *bl31_image_info;
+	struct entry_point_info_t *bl32_ep_info;
+	struct atf_image_info_t *bl32_image_info;
+	struct entry_point_info_t *bl33_ep_info;
+	struct atf_image_info_t *bl33_image_info;
+};
+
+/*******************************************************************************
+ * This structure represents the superset of information that is passed to
+ * BL31, e.g. while passing control to it from BL2, bl31_params
+ * and other platform specific params
+ ******************************************************************************/
+struct bl2_to_bl31_params_mem_t {
+	struct bl31_params_t bl31_params;
+	struct atf_image_info_t bl31_image_info;
+	struct atf_image_info_t bl32_image_info;
+	struct atf_image_info_t bl33_image_info;
+	struct entry_point_info_t bl33_ep_info;
+	struct entry_point_info_t bl32_ep_info;
+	struct entry_point_info_t bl31_ep_info;
+};
+
+#endif /*__ASSEMBLY__*/
+
+#endif /* __BL_COMMON_H__ */
diff --git a/include/spl.h b/include/spl.h
index 918c464..ab5eaca 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -251,4 +251,5 @@ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);
 int spl_mmc_load_image(struct spl_image_info *spl_image,
 		       struct spl_boot_device *bootdev);
 
+void bl31_entry(void);
 #endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF Kever Yang
@ 2017-01-02 15:05   ` Michal Simek
  2017-01-06  7:09     ` Kever Yang
  2017-01-18 12:20   ` Kever Yang
  1 sibling, 1 reply; 15+ messages in thread
From: Michal Simek @ 2017-01-02 15:05 UTC (permalink / raw)
  To: u-boot

On 29.12.2016 11:25, Kever Yang wrote:
> ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
> about ATF at:
> 
> SPL is consider as BL2 in ATF, it needs to load other part of ATF binary

SPL replaces BL2 in ATF

> like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
> parameter for BL31 which including entry and image information for all
> other images. Then the SPL handle PC to BL31 with the parameter, the
> BL31 will do the rest of work and at last get into U-Boot(BL33).

But the main question for this is how do load that images and in which
format. It means I would think that you will introduce fit format which
contain BL33(U-Boot), BL32(secure os) and BL31(ATF) and SPL will be able
to load all of them.

If you look at zynqmp I did a small trick where I consider case that
with ATF it is OS boot where kernel is ATF and dtb is full u-boot to get
it boot.

If you adopt fit format then I expect SPL will be able to remember which
part is where and based on that fill structure for ATF.
Then SPL_ATF_TEXT_BASE address is not needed because it will be read
from fit format.



> 
> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
> ---
> 
>  common/spl/Kconfig   |  14 +++
>  common/spl/Makefile  |   1 +
>  common/spl/spl.c     |   4 +
>  common/spl/spl_atf.c |  91 ++++++++++++++++
>  include/atf_common.h | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/spl.h        |   1 +
>  6 files changed, 406 insertions(+)
>  create mode 100644 common/spl/spl_atf.c
>  create mode 100644 include/atf_common.h
> 
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index cba51f5..1bb4360 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
>  	  means of transmitting U-Boot over a serial line for using in SPL,
>  	  with a checksum to ensure correctness.
>  
> +config SPL_ATF_SUPPORT
> +	bool "Support ARM trust firmware"
> +	depends on SPL
> +	help
> +	  ATF(ARM Trust Firmware) is component for ARM arch64 which need to
> +	  load by SPL(consider as BL2 in ATF).
> +	  More detail at: https://github.com/ARM-software/arm-trusted-firmware
> +
> +config SPL_ATF_TEXT_BASE
> +	depends on SPL_ATF_SUPPORT
> +	hex "ATF TEXT BASE addr"
> +	help
> +	  This is the base address in memory for ATF text and entry point.
> +
>  config TPL_ENV_SUPPORT
>  	bool "Support an environment"
>  	depends on TPL
> diff --git a/common/spl/Makefile b/common/spl/Makefile
> index ed02635..620ae90 100644
> --- a/common/spl/Makefile
> +++ b/common/spl/Makefile
> @@ -20,6 +20,7 @@ endif
>  obj-$(CONFIG_SPL_UBI) += spl_ubi.o
>  obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
>  obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
> +obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
>  obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
>  obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
>  obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
> diff --git a/common/spl/spl.c b/common/spl/spl.c
> index 1729034..7daf7bd 100644
> --- a/common/spl/spl.c
> +++ b/common/spl/spl.c
> @@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
>  	      gd->malloc_ptr / 1024);
>  #endif
>  
> +#ifdef CONFIG_SPL_ATF_SUPPORT
> +	bl31_entry();
> +#endif
> +
>  	debug("loaded - jumping to U-Boot...");
>  	spl_board_prepare_for_boot();
>  	jump_to_image_no_args(&spl_image);
> diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
> new file mode 100644
> index 0000000..cf23b7a
> --- /dev/null
> +++ b/common/spl/spl_atf.c
> @@ -0,0 +1,91 @@
> +/*
> + * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
> + * Written by Kever Yang <kever.yang@rock-chips.com>
> + *
> + * origin from arm-trust-firmware
> + * plat/arm/common/arm_bl2_setup.c
> + * SPDX-License-Identifier:     GPL-2.0+

this is not based on gpl file that's why license should be different.


> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <spl.h>
> +#include <atf_common.h>
> +
> +static struct bl2_to_bl31_params_mem_t bl31_params_mem;
> +static struct bl31_params_t *bl2_to_bl31_params;
> +
> +/*******************************************************************************
> + * This function assigns a pointer to the memory that the platform has kept
> + * aside to pass platform specific and trusted firmware related information
> + * to BL31. This memory is allocated by allocating memory to
> + * bl2_to_bl31_params_mem_t structure which is a superset of all the
> + * structure whose information is passed to BL31
> + * NOTE: This function should be called only once and should be done
> + * before generating params to BL31
> + ******************************************************************************/
> +struct bl31_params_t *bl2_plat_get_bl31_params(void)
> +{
> +	struct entry_point_info_t *bl33_ep_info;
> +
> +	/*
> +	 * Initialise the memory for all the arguments that needs to
> +	 * be passed to BL31
> +	 */
> +	memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem_t));
> +
> +	/* Assign memory for TF related information */
> +	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
> +	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
> +
> +	/* Fill BL31 related information */
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
> +		       VERSION_1, 0);
> +
> +	/* Fill BL32 related information if it exists */
> +#ifdef BL32_BASE
> +	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
> +		       VERSION_1, 0);
> +	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
> +		       VERSION_1, 0);
> +#endif /* BL32_BASE */

Is this used?

> +
> +	/* Fill BL33 related information */
> +	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
> +	bl33_ep_info = &bl31_params_mem.bl33_ep_info;
> +	SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
> +
> +	/* BL33 expects to receive the primary CPU MPID (through x0) */
> +	bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
> +	bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
> +	bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
> +				     DISABLE_ALL_EXECPTIONS);
> +
> +	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
> +		       VERSION_1, 0);
> +
> +

double lines.

> +	return bl2_to_bl31_params;
> +}
> +
> +void raw_write_daif(uint32_t daif)
> +{
> +	__asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
> +}
> +
> +void bl31_entry(void)
> +{
> +	struct bl31_params_t *bl31_params;
> +	void (*entry)(struct bl31_params_t *params, void *plat_params) = NULL;
> +
> +	bl31_params = bl2_plat_get_bl31_params();
> +	entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
> +
> +	raw_write_daif(SPSR_EXCEPTION_MASK);
> +	dcache_disable();
> +
> +	entry(bl31_params, NULL);
> +}
> diff --git a/include/atf_common.h b/include/atf_common.h
> new file mode 100644
> index 0000000..8351302
> --- /dev/null
> +++ b/include/atf_common.h
> @@ -0,0 +1,295 @@
> +/*
> + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + *
> + * Redistributions of source code must retain the above copyright notice, this
> + * list of conditions and the following disclaimer.
> + *
> + * Redistributions in binary form must reproduce the above copyright notice,
> + * this list of conditions and the following disclaimer in the documentation
> + * and/or other materials provided with the distribution.
> + *
> + * Neither the name of ARM nor the names of its contributors may be used
> + * to endorse or promote products derived from this software without specific
> + * prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.

This should be probably in SPDX format.


> + */
> +
> +#ifndef __BL_COMMON_H__
> +#define __BL_COMMON_H__
> +
> +#define SECURE		0x0
> +#define NON_SECURE	0x1
> +#define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
> +
> +#define UP	1
> +#define DOWN	0
> +
> +/*******************************************************************************
> + * Constants to identify the location of a memory region in a given memory
> + * layout.
> +******************************************************************************/
> +#define TOP	0x1
> +#define BOTTOM	!TOP
> +
> +/*******************************************************************************
> + * Constants that allow assembler code to access members of and the
> + * 'entry_point_info' structure at their correct offsets.
> + ******************************************************************************/
> +#define ENTRY_POINT_INFO_PC_OFFSET	0x08
> +#define ENTRY_POINT_INFO_ARGS_OFFSET	0x18
> +
> +/* The following are used to set/get image attributes. */
> +#define PARAM_EP_SECURITY_MASK		(0x1)
> +
> +#define GET_SECURITY_STATE(x) (x & PARAM_EP_SECURITY_MASK)
> +#define SET_SECURITY_STATE(x, security) \
> +			((x) = ((x) & ~PARAM_EP_SECURITY_MASK) | (security))
> +
> +
> +/*
> + * The following are used for image state attributes.
> + * Image can only be in one of the following state.
> + */
> +#define IMAGE_STATE_RESET			0
> +#define IMAGE_STATE_COPIED			1
> +#define IMAGE_STATE_COPYING			2
> +#define IMAGE_STATE_AUTHENTICATED		3
> +#define IMAGE_STATE_EXECUTED			4
> +#define IMAGE_STATE_INTERRUPTED			5
> +
> +#define EP_SECURE	0x0
> +#define EP_NON_SECURE	0x1
> +
> +#define EP_EE_MASK	0x2
> +#define EP_EE_LITTLE	0x0
> +#define EP_EE_BIG	0x2
> +#define EP_GET_EE(x) (x & EP_EE_MASK)
> +#define EP_SET_EE(x, ee) ((x) = ((x) & ~EP_EE_MASK) | (ee))
> +
> +#define EP_ST_MASK	0x4
> +#define EP_ST_DISABLE	0x0
> +#define EP_ST_ENABLE	0x4
> +#define EP_GET_ST(x) (x & EP_ST_MASK)
> +#define EP_SET_ST(x, ee) ((x) = ((x) & ~EP_ST_MASK) | (ee))
> +
> +#define EP_EXE_MASK	0x8
> +#define NON_EXECUTABLE	0x0
> +#define EXECUTABLE	0x8
> +#define EP_GET_EXE(x) (x & EP_EXE_MASK)
> +#define EP_SET_EXE(x, ee) ((x) = ((x) & ~EP_EXE_MASK) | (ee))
> +
> +#define PARAM_EP		0x01
> +#define PARAM_IMAGE_BINARY	0x02
> +#define PARAM_BL31		0x03
> +
> +#define VERSION_1	0x01
> +
> +#define INVALID_IMAGE_ID		(0xFFFFFFFF)
> +
> +#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \
> +	(_p)->h.type = (uint8_t)(_type); \
> +	(_p)->h.version = (uint8_t)(_ver); \
> +	(_p)->h.size = (uint16_t)sizeof(*_p); \
> +	(_p)->h.attr = (uint32_t)(_attr) ; \
> +	} while (0)
> +
> +/* Following is used for populating structure members statically. */
> +#define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr)	\
> +	._p.h.type = (uint8_t)(_type), \
> +	._p.h.version = (uint8_t)(_ver), \
> +	._p.h.size = (uint16_t)sizeof(_p_type), \
> +	._p.h.attr = (uint32_t)(_attr)
> +
> +#define MODE_RW_SHIFT	0x4
> +#define MODE_RW_MASK	0x1
> +#define MODE_RW_64	0x0
> +#define MODE_RW_32	0x1
> +
> +#define MODE_EL_SHIFT	0x2
> +#define MODE_EL_MASK	0x3
> +#define MODE_EL3	0x3
> +#define MODE_EL2	0x2
> +#define MODE_EL1	0x1
> +#define MODE_EL0	0x0
> +
> +#define MODE_SP_SHIFT	0x0
> +#define MODE_SP_MASK	0x1
> +#define MODE_SP_EL0	0x0
> +#define MODE_SP_ELX	0x1
> +
> +#define SPSR_DAIF_SHIFT	6
> +#define SPSR_DAIF_MASK	0x0f
> +
> +#define DAIF_FIQ_BIT (1<<0)
> +#define DAIF_IRQ_BIT (1<<0)
> +#define DAIF_ABT_BIT (1<<0)
> +#define DAIF_DBG_BIT (1<<0)
> +#define DISABLE_ALL_EXECPTIONS	\
> +	(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
> +
> +#define SPSR_64(el, sp, daif)		\
> +	(MODE_RW_64 << MODE_RW_SHIFT |	\
> +	 ((el) & MODE_EL_MASK) << MODE_EL_SHIFT |	\
> +	 ((sp) & MODE_SP_MASK) << MODE_SP_SHIFT |	\
> +	 ((daif) & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)
> +
> +/*******************************************************************************
> + * Constants to indicate type of exception to the common exception handler.
> + ******************************************************************************/
> +#define SYNC_EXCEPTION_SP_EL0		0x0
> +#define IRQ_SP_EL0			0x1
> +#define FIQ_SP_EL0			0x2
> +#define SERROR_SP_EL0			0x3
> +#define SYNC_EXCEPTION_SP_ELX		0x4
> +#define IRQ_SP_ELX			0x5
> +#define FIQ_SP_ELX			0x6
> +#define SERROR_SP_ELX			0x7
> +#define SYNC_EXCEPTION_AARCH64		0x8
> +#define IRQ_AARCH64			0x9
> +#define FIQ_AARCH64			0xa
> +#define SERROR_AARCH64			0xb
> +#define SYNC_EXCEPTION_AARCH32		0xc
> +#define IRQ_AARCH32			0xd
> +#define FIQ_AARCH32			0xe
> +#define SERROR_AARCH32			0xf
> +
> +#define SPSR_USE_L           0
> +#define SPSR_USE_H           1
> +#define SPSR_L_H_MASK        1
> +#define SPSR_M_SHIFT         4
> +#define SPSR_ERET_32         (1 << SPSR_M_SHIFT)
> +#define SPSR_ERET_64         (0 << SPSR_M_SHIFT)
> +#define SPSR_FIQ             (1 << 6)
> +#define SPSR_IRQ             (1 << 7)
> +#define SPSR_SERROR          (1 << 8)
> +#define SPSR_DEBUG           (1 << 9)
> +#define SPSR_EXCEPTION_MASK  (SPSR_FIQ | SPSR_IRQ | SPSR_SERROR | SPSR_DEBUG)
> +
> +#ifndef __ASSEMBLY__
> +
> +/*******************************************************************************
> + * Structure used for telling the next BL how much of a particular type of
> + * memory is available for its use and how much is already used.
> + ******************************************************************************/
> +struct aapcs64_params_t {
> +	unsigned long arg0;
> +	unsigned long arg1;
> +	unsigned long arg2;
> +	unsigned long arg3;
> +	unsigned long arg4;
> +	unsigned long arg5;
> +	unsigned long arg6;
> +	unsigned long arg7;
> +};
> +
> +/***************************************************************************
> + * This structure provides version information and the size of the
> + * structure, attributes for the structure it represents
> + ***************************************************************************/
> +struct param_header_t {
> +	uint8_t type;		/* type of the structure */
> +	uint8_t version;    /* version of this structure */
> +	uint16_t size;      /* size of this structure in bytes */
> +	uint32_t attr;      /* attributes: unused bits SBZ */
> +};
> +
> +/*****************************************************************************
> + * This structure represents the superset of information needed while
> + * switching exception levels. The only two mechanisms to do so are
> + * ERET & SMC. Security state is indicated using bit zero of header
> + * attribute
> + * NOTE: BL1 expects entrypoint followed by spsr at an offset from the start
> + * of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while
> + * processing SMC to jump to BL31.
> + *****************************************************************************/
> +struct entry_point_info_t {
> +	struct param_header_t h;
> +	uintptr_t pc;
> +	uint32_t spsr;
> +	struct aapcs64_params_t args;
> +};
> +
> +/*****************************************************************************
> + * Image info binary provides information from the image loader that
> + * can be used by the firmware to manage available trusted RAM.
> + * More advanced firmware image formats can provide additional
> + * information that enables optimization or greater flexibility in the
> + * common firmware code
> + *****************************************************************************/
> +struct atf_image_info_t {
> +	struct param_header_t h;
> +	uintptr_t image_base;   /* physical address of base of image */
> +	uint32_t image_size;    /* bytes read from image file */
> +};
> +
> +/*****************************************************************************
> + * The image descriptor struct definition.
> + *****************************************************************************/
> +struct image_desc_t {
> +	/* Contains unique image id for the image. */
> +	unsigned int image_id;
> +	/*
> +	 * This member contains Image state information.
> +	 * Refer IMAGE_STATE_XXX defined above.
> +	 */
> +	unsigned int state;
> +	uint32_t copied_size;	/* image size copied in blocks */
> +	struct atf_image_info_t atf_image_info;
> +	struct entry_point_info_t ep_info;
> +};
> +
> +/*******************************************************************************
> + * This structure represents the superset of information that can be passed to
> + * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be
> + * populated only if BL2 detects its presence. A pointer to a structure of this
> + * type should be passed in X0 to BL31's cold boot entrypoint.
> + *
> + * Use of this structure and the X0 parameter is not mandatory: the BL31
> + * platform code can use other mechanisms to provide the necessary information
> + * about BL32 and BL33 to the common and SPD code.
> + *
> + * BL31 image information is mandatory if this structure is used. If either of
> + * the optional BL32 and BL33 image information is not provided, this is
> + * indicated by the respective image_info pointers being zero.
> + ******************************************************************************/
> +struct bl31_params_t {
> +	struct param_header_t h;
> +	struct atf_image_info_t *bl31_image_info;
> +	struct entry_point_info_t *bl32_ep_info;
> +	struct atf_image_info_t *bl32_image_info;
> +	struct entry_point_info_t *bl33_ep_info;
> +	struct atf_image_info_t *bl33_image_info;
> +};
> +
> +/*******************************************************************************
> + * This structure represents the superset of information that is passed to
> + * BL31, e.g. while passing control to it from BL2, bl31_params
> + * and other platform specific params
> + ******************************************************************************/
> +struct bl2_to_bl31_params_mem_t {
> +	struct bl31_params_t bl31_params;
> +	struct atf_image_info_t bl31_image_info;
> +	struct atf_image_info_t bl32_image_info;
> +	struct atf_image_info_t bl33_image_info;
> +	struct entry_point_info_t bl33_ep_info;
> +	struct entry_point_info_t bl32_ep_info;
> +	struct entry_point_info_t bl31_ep_info;
> +};
> +
> +#endif /*__ASSEMBLY__*/
> +
> +#endif /* __BL_COMMON_H__ */
> diff --git a/include/spl.h b/include/spl.h
> index 918c464..ab5eaca 100644
> --- a/include/spl.h
> +++ b/include/spl.h
> @@ -251,4 +251,5 @@ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);
>  int spl_mmc_load_image(struct spl_image_info *spl_image,
>  		       struct spl_boot_device *bootdev);
>  
> +void bl31_entry(void);
>  #endif
> 

Thanks,
Michal

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support
  2016-12-29 10:25 [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Kever Yang
                   ` (2 preceding siblings ...)
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF Kever Yang
@ 2017-01-02 15:05 ` Michal Simek
  2017-01-06  7:11   ` Kever Yang
  3 siblings, 1 reply; 15+ messages in thread
From: Michal Simek @ 2017-01-02 15:05 UTC (permalink / raw)
  To: u-boot

Hi,

separation of rk3399 SPL from ATF SPL would be worth.

Thanks,
Michal

On 29.12.2016 11:25, Kever Yang wrote:
> 
> RK3399 SPL is not enable bacause of the lack of ATF support in SPL,
> after port some source code from ATF, I manage to enable the support for
> ATF in SPL. This patch set depends on some patch for SPL support multi
> binary in FIT which is from Andre.
> 
> The patch of sdram controller is still not clean, because I want to get
> comments from upstream.I port this driver from coreboot, and I don't
> want to make much change on it. The rk3399 dram controller has many registers
> to config, I want to make them directly used by driver instead of parse
> and copy them one by one from dts.
> 
> Another part of comment is welcome for the implementation of spl_atf.c
> and the entry in spl.c
> 
> 
> 
> Kever Yang (3):
>   arm64: rk3399: add SPL support
>   arm64: rk3399: add ddr controller driver
>   spl: add support to booting with ATF
> 
>  arch/arm/Kconfig                                   |    1 +
>  arch/arm/dts/rk3399.dtsi                           |   24 +
>  arch/arm/include/asm/arch-rockchip/grf_rk3399.h    |  118 ++
>  arch/arm/include/asm/arch-rockchip/sdram_rk3399.h  |  188 +++
>  arch/arm/mach-rockchip/Kconfig                     |    2 +
>  arch/arm/mach-rockchip/Makefile                    |    1 +
>  arch/arm/mach-rockchip/rk3399-board-spl.c          |  157 ++
>  arch/arm/mach-rockchip/rk3399/Makefile             |    1 +
>  arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc | 1565 ++++++++++++++++++++
>  arch/arm/mach-rockchip/rk3399/sdram_rk3399.c       | 1121 ++++++++++++++
>  common/spl/Kconfig                                 |   14 +
>  common/spl/Makefile                                |    1 +
>  common/spl/spl.c                                   |    4 +
>  common/spl/spl_atf.c                               |   91 ++
>  configs/evb-rk3399_defconfig                       |   17 +
>  drivers/clk/rockchip/clk_rk3399.c                  |   42 +-
>  drivers/pinctrl/rockchip/pinctrl_rk3399.c          |  106 --
>  include/atf_common.h                               |  295 ++++
>  include/configs/rk3399_common.h                    |   11 +
>  include/dt-bindings/clock/rk3399-cru.h             |   16 +-
>  include/spl.h                                      |    1 +
>  21 files changed, 3663 insertions(+), 113 deletions(-)
>  create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
>  create mode 100644 arch/arm/mach-rockchip/rk3399-board-spl.c
>  create mode 100644 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
>  create mode 100644 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
>  create mode 100644 common/spl/spl_atf.c
>  create mode 100644 include/atf_common.h
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2017-01-02 15:05   ` Michal Simek
@ 2017-01-06  7:09     ` Kever Yang
  2017-01-06  7:55       ` Michal Simek
  0 siblings, 1 reply; 15+ messages in thread
From: Kever Yang @ 2017-01-06  7:09 UTC (permalink / raw)
  To: u-boot

Hi Michal,

     Thanks for your comments.

On 01/02/2017 11:05 PM, Michal Simek wrote:
> On 29.12.2016 11:25, Kever Yang wrote:
>> ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
>> about ATF at:
>>
>> SPL is consider as BL2 in ATF, it needs to load other part of ATF binary
> SPL replaces BL2 in ATF

OK, will follow your comment in next patch.
>
>> like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
>> parameter for BL31 which including entry and image information for all
>> other images. Then the SPL handle PC to BL31 with the parameter, the
>> BL31 will do the rest of work and at last get into U-Boot(BL33).
> But the main question for this is how do load that images and in which
> format. It means I would think that you will introduce fit format which
> contain BL33(U-Boot), BL32(secure os) and BL31(ATF) and SPL will be able
> to load all of them.

Yes, I use FIT format to contain BL33 and BL32 and SPL load all of them.
>
> If you look at zynqmp I did a small trick where I consider case that
> with ATF it is OS boot where kernel is ATF and dtb is full u-boot to get
> it boot.

This is a good idea, and it look fine for support ATF in SPL in local 
source code,
but it will be better if we have an official support for ATF, right?

>
> If you adopt fit format then I expect SPL will be able to remember which
> part is where and based on that fill structure for ATF.
> Then SPL_ATF_TEXT_BASE address is not needed because it will be read
> from fit format.

Yes, you are right, SPL_ATF_TEXT_BASE is not a must, we gen get it from fit.

>
>
>
>> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
>> ---
>>
>>   common/spl/Kconfig   |  14 +++
>>   common/spl/Makefile  |   1 +
>>   common/spl/spl.c     |   4 +
>>   common/spl/spl_atf.c |  91 ++++++++++++++++
>>   include/atf_common.h | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/spl.h        |   1 +
>>   6 files changed, 406 insertions(+)
>>   create mode 100644 common/spl/spl_atf.c
>>   create mode 100644 include/atf_common.h
>>
>> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
>> index cba51f5..1bb4360 100644
>> --- a/common/spl/Kconfig
>> +++ b/common/spl/Kconfig
>> @@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
>>   	  means of transmitting U-Boot over a serial line for using in SPL,
>>   	  with a checksum to ensure correctness.
>>   
>> +config SPL_ATF_SUPPORT
>> +	bool "Support ARM trust firmware"
>> +	depends on SPL
>> +	help
>> +	  ATF(ARM Trust Firmware) is component for ARM arch64 which need to
>> +	  load by SPL(consider as BL2 in ATF).
>> +	  More detail at: https://github.com/ARM-software/arm-trusted-firmware
>> +
>> +config SPL_ATF_TEXT_BASE
>> +	depends on SPL_ATF_SUPPORT
>> +	hex "ATF TEXT BASE addr"
>> +	help
>> +	  This is the base address in memory for ATF text and entry point.
>> +
>>   config TPL_ENV_SUPPORT
>>   	bool "Support an environment"
>>   	depends on TPL
>> diff --git a/common/spl/Makefile b/common/spl/Makefile
>> index ed02635..620ae90 100644
>> --- a/common/spl/Makefile
>> +++ b/common/spl/Makefile
>> @@ -20,6 +20,7 @@ endif
>>   obj-$(CONFIG_SPL_UBI) += spl_ubi.o
>>   obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
>>   obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
>> +obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
>>   obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
>>   obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
>>   obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
>> diff --git a/common/spl/spl.c b/common/spl/spl.c
>> index 1729034..7daf7bd 100644
>> --- a/common/spl/spl.c
>> +++ b/common/spl/spl.c
>> @@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
>>   	      gd->malloc_ptr / 1024);
>>   #endif
>>   
>> +#ifdef CONFIG_SPL_ATF_SUPPORT
>> +	bl31_entry();
>> +#endif
>> +
>>   	debug("loaded - jumping to U-Boot...");
>>   	spl_board_prepare_for_boot();
>>   	jump_to_image_no_args(&spl_image);
>> diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
>> new file mode 100644
>> index 0000000..cf23b7a
>> --- /dev/null
>> +++ b/common/spl/spl_atf.c
>> @@ -0,0 +1,91 @@
>> +/*
>> + * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
>> + * Written by Kever Yang <kever.yang@rock-chips.com>
>> + *
>> + * origin from arm-trust-firmware
>> + * plat/arm/common/arm_bl2_setup.c
>> + * SPDX-License-Identifier:     GPL-2.0+
> this is not based on gpl file that's why license should be different.

Sorry, I do not get what your mean, I'm not good at license policy,
ARM ATF use its own license, what should I do for license when I use code
from ATF?

>
>
>> + */
>> +
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <spl.h>
>> +#include <atf_common.h>
>> +
>> +static struct bl2_to_bl31_params_mem_t bl31_params_mem;
>> +static struct bl31_params_t *bl2_to_bl31_params;
>> +
>> +/*******************************************************************************
>> + * This function assigns a pointer to the memory that the platform has kept
>> + * aside to pass platform specific and trusted firmware related information
>> + * to BL31. This memory is allocated by allocating memory to
>> + * bl2_to_bl31_params_mem_t structure which is a superset of all the
>> + * structure whose information is passed to BL31
>> + * NOTE: This function should be called only once and should be done
>> + * before generating params to BL31
>> + ******************************************************************************/
>> +struct bl31_params_t *bl2_plat_get_bl31_params(void)
>> +{
>> +	struct entry_point_info_t *bl33_ep_info;
>> +
>> +	/*
>> +	 * Initialise the memory for all the arguments that needs to
>> +	 * be passed to BL31
>> +	 */
>> +	memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem_t));
>> +
>> +	/* Assign memory for TF related information */
>> +	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
>> +	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
>> +
>> +	/* Fill BL31 related information */
>> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
>> +		       VERSION_1, 0);
>> +
>> +	/* Fill BL32 related information if it exists */
>> +#ifdef BL32_BASE
>> +	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
>> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
>> +		       VERSION_1, 0);
>> +	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
>> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
>> +		       VERSION_1, 0);
>> +#endif /* BL32_BASE */
> Is this used?

Not use for me now, but it may useful later, because we need to fill 
info about bl32 if there is.

>
>> +
>> +	/* Fill BL33 related information */
>> +	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
>> +	bl33_ep_info = &bl31_params_mem.bl33_ep_info;
>> +	SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
>> +
>> +	/* BL33 expects to receive the primary CPU MPID (through x0) */
>> +	bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
>> +	bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
>> +	bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
>> +				     DISABLE_ALL_EXECPTIONS);
>> +
>> +	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
>> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
>> +		       VERSION_1, 0);
>> +
>> +
> double lines.

Will fix in next patch, confuse why checkpatch did not find this.
>
>> +	return bl2_to_bl31_params;
>> +}
>> +
>> +void raw_write_daif(uint32_t daif)
>> +{
>> +	__asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
>> +}
>> +
>> +void bl31_entry(void)
>> +{
>> +	struct bl31_params_t *bl31_params;
>> +	void (*entry)(struct bl31_params_t *params, void *plat_params) = NULL;
>> +
>> +	bl31_params = bl2_plat_get_bl31_params();
>> +	entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
>> +
>> +	raw_write_daif(SPSR_EXCEPTION_MASK);
>> +	dcache_disable();
>> +
>> +	entry(bl31_params, NULL);
>> +}
>> diff --git a/include/atf_common.h b/include/atf_common.h
>> new file mode 100644
>> index 0000000..8351302
>> --- /dev/null
>> +++ b/include/atf_common.h
>> @@ -0,0 +1,295 @@
>> +/*
>> + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
>> + *
>> + * Redistribution and use in source and binary forms, with or without
>> + * modification, are permitted provided that the following conditions are met:
>> + *
>> + * Redistributions of source code must retain the above copyright notice, this
>> + * list of conditions and the following disclaimer.
>> + *
>> + * Redistributions in binary form must reproduce the above copyright notice,
>> + * this list of conditions and the following disclaimer in the documentation
>> + * and/or other materials provided with the distribution.
>> + *
>> + * Neither the name of ARM nor the names of its contributors may be used
>> + * to endorse or promote products derived from this software without specific
>> + * prior written permission.
>> + *
>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
>> + * POSSIBILITY OF SUCH DAMAGE.
> This should be probably in SPDX format.

Like previous reply, I don't know how to deal with this license, do you 
mean I can use
SPDX license without any information about the origin License?

Thanks,
- Kever
>
>
>> + */
>> +
>> +#ifndef __BL_COMMON_H__
>> +#define __BL_COMMON_H__
>> +
>> +#define SECURE		0x0
>> +#define NON_SECURE	0x1
>> +#define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
>> +
>> +#define UP	1
>> +#define DOWN	0
>> +
>> +/*******************************************************************************
>> + * Constants to identify the location of a memory region in a given memory
>> + * layout.
>> +******************************************************************************/
>> +#define TOP	0x1
>> +#define BOTTOM	!TOP
>> +
>> +/*******************************************************************************
>> + * Constants that allow assembler code to access members of and the
>> + * 'entry_point_info' structure at their correct offsets.
>> + ******************************************************************************/
>> +#define ENTRY_POINT_INFO_PC_OFFSET	0x08
>> +#define ENTRY_POINT_INFO_ARGS_OFFSET	0x18
>> +
>> +/* The following are used to set/get image attributes. */
>> +#define PARAM_EP_SECURITY_MASK		(0x1)
>> +
>> +#define GET_SECURITY_STATE(x) (x & PARAM_EP_SECURITY_MASK)
>> +#define SET_SECURITY_STATE(x, security) \
>> +			((x) = ((x) & ~PARAM_EP_SECURITY_MASK) | (security))
>> +
>> +
>> +/*
>> + * The following are used for image state attributes.
>> + * Image can only be in one of the following state.
>> + */
>> +#define IMAGE_STATE_RESET			0
>> +#define IMAGE_STATE_COPIED			1
>> +#define IMAGE_STATE_COPYING			2
>> +#define IMAGE_STATE_AUTHENTICATED		3
>> +#define IMAGE_STATE_EXECUTED			4
>> +#define IMAGE_STATE_INTERRUPTED			5
>> +
>> +#define EP_SECURE	0x0
>> +#define EP_NON_SECURE	0x1
>> +
>> +#define EP_EE_MASK	0x2
>> +#define EP_EE_LITTLE	0x0
>> +#define EP_EE_BIG	0x2
>> +#define EP_GET_EE(x) (x & EP_EE_MASK)
>> +#define EP_SET_EE(x, ee) ((x) = ((x) & ~EP_EE_MASK) | (ee))
>> +
>> +#define EP_ST_MASK	0x4
>> +#define EP_ST_DISABLE	0x0
>> +#define EP_ST_ENABLE	0x4
>> +#define EP_GET_ST(x) (x & EP_ST_MASK)
>> +#define EP_SET_ST(x, ee) ((x) = ((x) & ~EP_ST_MASK) | (ee))
>> +
>> +#define EP_EXE_MASK	0x8
>> +#define NON_EXECUTABLE	0x0
>> +#define EXECUTABLE	0x8
>> +#define EP_GET_EXE(x) (x & EP_EXE_MASK)
>> +#define EP_SET_EXE(x, ee) ((x) = ((x) & ~EP_EXE_MASK) | (ee))
>> +
>> +#define PARAM_EP		0x01
>> +#define PARAM_IMAGE_BINARY	0x02
>> +#define PARAM_BL31		0x03
>> +
>> +#define VERSION_1	0x01
>> +
>> +#define INVALID_IMAGE_ID		(0xFFFFFFFF)
>> +
>> +#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \
>> +	(_p)->h.type = (uint8_t)(_type); \
>> +	(_p)->h.version = (uint8_t)(_ver); \
>> +	(_p)->h.size = (uint16_t)sizeof(*_p); \
>> +	(_p)->h.attr = (uint32_t)(_attr) ; \
>> +	} while (0)
>> +
>> +/* Following is used for populating structure members statically. */
>> +#define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr)	\
>> +	._p.h.type = (uint8_t)(_type), \
>> +	._p.h.version = (uint8_t)(_ver), \
>> +	._p.h.size = (uint16_t)sizeof(_p_type), \
>> +	._p.h.attr = (uint32_t)(_attr)
>> +
>> +#define MODE_RW_SHIFT	0x4
>> +#define MODE_RW_MASK	0x1
>> +#define MODE_RW_64	0x0
>> +#define MODE_RW_32	0x1
>> +
>> +#define MODE_EL_SHIFT	0x2
>> +#define MODE_EL_MASK	0x3
>> +#define MODE_EL3	0x3
>> +#define MODE_EL2	0x2
>> +#define MODE_EL1	0x1
>> +#define MODE_EL0	0x0
>> +
>> +#define MODE_SP_SHIFT	0x0
>> +#define MODE_SP_MASK	0x1
>> +#define MODE_SP_EL0	0x0
>> +#define MODE_SP_ELX	0x1
>> +
>> +#define SPSR_DAIF_SHIFT	6
>> +#define SPSR_DAIF_MASK	0x0f
>> +
>> +#define DAIF_FIQ_BIT (1<<0)
>> +#define DAIF_IRQ_BIT (1<<0)
>> +#define DAIF_ABT_BIT (1<<0)
>> +#define DAIF_DBG_BIT (1<<0)
>> +#define DISABLE_ALL_EXECPTIONS	\
>> +	(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
>> +
>> +#define SPSR_64(el, sp, daif)		\
>> +	(MODE_RW_64 << MODE_RW_SHIFT |	\
>> +	 ((el) & MODE_EL_MASK) << MODE_EL_SHIFT |	\
>> +	 ((sp) & MODE_SP_MASK) << MODE_SP_SHIFT |	\
>> +	 ((daif) & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)
>> +
>> +/*******************************************************************************
>> + * Constants to indicate type of exception to the common exception handler.
>> + ******************************************************************************/
>> +#define SYNC_EXCEPTION_SP_EL0		0x0
>> +#define IRQ_SP_EL0			0x1
>> +#define FIQ_SP_EL0			0x2
>> +#define SERROR_SP_EL0			0x3
>> +#define SYNC_EXCEPTION_SP_ELX		0x4
>> +#define IRQ_SP_ELX			0x5
>> +#define FIQ_SP_ELX			0x6
>> +#define SERROR_SP_ELX			0x7
>> +#define SYNC_EXCEPTION_AARCH64		0x8
>> +#define IRQ_AARCH64			0x9
>> +#define FIQ_AARCH64			0xa
>> +#define SERROR_AARCH64			0xb
>> +#define SYNC_EXCEPTION_AARCH32		0xc
>> +#define IRQ_AARCH32			0xd
>> +#define FIQ_AARCH32			0xe
>> +#define SERROR_AARCH32			0xf
>> +
>> +#define SPSR_USE_L           0
>> +#define SPSR_USE_H           1
>> +#define SPSR_L_H_MASK        1
>> +#define SPSR_M_SHIFT         4
>> +#define SPSR_ERET_32         (1 << SPSR_M_SHIFT)
>> +#define SPSR_ERET_64         (0 << SPSR_M_SHIFT)
>> +#define SPSR_FIQ             (1 << 6)
>> +#define SPSR_IRQ             (1 << 7)
>> +#define SPSR_SERROR          (1 << 8)
>> +#define SPSR_DEBUG           (1 << 9)
>> +#define SPSR_EXCEPTION_MASK  (SPSR_FIQ | SPSR_IRQ | SPSR_SERROR | SPSR_DEBUG)
>> +
>> +#ifndef __ASSEMBLY__
>> +
>> +/*******************************************************************************
>> + * Structure used for telling the next BL how much of a particular type of
>> + * memory is available for its use and how much is already used.
>> + ******************************************************************************/
>> +struct aapcs64_params_t {
>> +	unsigned long arg0;
>> +	unsigned long arg1;
>> +	unsigned long arg2;
>> +	unsigned long arg3;
>> +	unsigned long arg4;
>> +	unsigned long arg5;
>> +	unsigned long arg6;
>> +	unsigned long arg7;
>> +};
>> +
>> +/***************************************************************************
>> + * This structure provides version information and the size of the
>> + * structure, attributes for the structure it represents
>> + ***************************************************************************/
>> +struct param_header_t {
>> +	uint8_t type;		/* type of the structure */
>> +	uint8_t version;    /* version of this structure */
>> +	uint16_t size;      /* size of this structure in bytes */
>> +	uint32_t attr;      /* attributes: unused bits SBZ */
>> +};
>> +
>> +/*****************************************************************************
>> + * This structure represents the superset of information needed while
>> + * switching exception levels. The only two mechanisms to do so are
>> + * ERET & SMC. Security state is indicated using bit zero of header
>> + * attribute
>> + * NOTE: BL1 expects entrypoint followed by spsr at an offset from the start
>> + * of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while
>> + * processing SMC to jump to BL31.
>> + *****************************************************************************/
>> +struct entry_point_info_t {
>> +	struct param_header_t h;
>> +	uintptr_t pc;
>> +	uint32_t spsr;
>> +	struct aapcs64_params_t args;
>> +};
>> +
>> +/*****************************************************************************
>> + * Image info binary provides information from the image loader that
>> + * can be used by the firmware to manage available trusted RAM.
>> + * More advanced firmware image formats can provide additional
>> + * information that enables optimization or greater flexibility in the
>> + * common firmware code
>> + *****************************************************************************/
>> +struct atf_image_info_t {
>> +	struct param_header_t h;
>> +	uintptr_t image_base;   /* physical address of base of image */
>> +	uint32_t image_size;    /* bytes read from image file */
>> +};
>> +
>> +/*****************************************************************************
>> + * The image descriptor struct definition.
>> + *****************************************************************************/
>> +struct image_desc_t {
>> +	/* Contains unique image id for the image. */
>> +	unsigned int image_id;
>> +	/*
>> +	 * This member contains Image state information.
>> +	 * Refer IMAGE_STATE_XXX defined above.
>> +	 */
>> +	unsigned int state;
>> +	uint32_t copied_size;	/* image size copied in blocks */
>> +	struct atf_image_info_t atf_image_info;
>> +	struct entry_point_info_t ep_info;
>> +};
>> +
>> +/*******************************************************************************
>> + * This structure represents the superset of information that can be passed to
>> + * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be
>> + * populated only if BL2 detects its presence. A pointer to a structure of this
>> + * type should be passed in X0 to BL31's cold boot entrypoint.
>> + *
>> + * Use of this structure and the X0 parameter is not mandatory: the BL31
>> + * platform code can use other mechanisms to provide the necessary information
>> + * about BL32 and BL33 to the common and SPD code.
>> + *
>> + * BL31 image information is mandatory if this structure is used. If either of
>> + * the optional BL32 and BL33 image information is not provided, this is
>> + * indicated by the respective image_info pointers being zero.
>> + ******************************************************************************/
>> +struct bl31_params_t {
>> +	struct param_header_t h;
>> +	struct atf_image_info_t *bl31_image_info;
>> +	struct entry_point_info_t *bl32_ep_info;
>> +	struct atf_image_info_t *bl32_image_info;
>> +	struct entry_point_info_t *bl33_ep_info;
>> +	struct atf_image_info_t *bl33_image_info;
>> +};
>> +
>> +/*******************************************************************************
>> + * This structure represents the superset of information that is passed to
>> + * BL31, e.g. while passing control to it from BL2, bl31_params
>> + * and other platform specific params
>> + ******************************************************************************/
>> +struct bl2_to_bl31_params_mem_t {
>> +	struct bl31_params_t bl31_params;
>> +	struct atf_image_info_t bl31_image_info;
>> +	struct atf_image_info_t bl32_image_info;
>> +	struct atf_image_info_t bl33_image_info;
>> +	struct entry_point_info_t bl33_ep_info;
>> +	struct entry_point_info_t bl32_ep_info;
>> +	struct entry_point_info_t bl31_ep_info;
>> +};
>> +
>> +#endif /*__ASSEMBLY__*/
>> +
>> +#endif /* __BL_COMMON_H__ */
>> diff --git a/include/spl.h b/include/spl.h
>> index 918c464..ab5eaca 100644
>> --- a/include/spl.h
>> +++ b/include/spl.h
>> @@ -251,4 +251,5 @@ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);
>>   int spl_mmc_load_image(struct spl_image_info *spl_image,
>>   		       struct spl_boot_device *bootdev);
>>   
>> +void bl31_entry(void);
>>   #endif
>>
> Thanks,
> Michal
>
>
>
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support
  2017-01-02 15:05 ` [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Michal Simek
@ 2017-01-06  7:11   ` Kever Yang
  0 siblings, 0 replies; 15+ messages in thread
From: Kever Yang @ 2017-01-06  7:11 UTC (permalink / raw)
  To: u-boot

Hi Michal,

On 01/02/2017 11:05 PM, Michal Simek wrote:
> Hi,
>
> separation of rk3399 SPL from ATF SPL would be worth.

Thanks for your comment, this may help my rk3399 SPL patches get accept 
faster.
I will do it after people get back from holiday and send me other comments.

Thanks,
- Kever
>
> Thanks,
> Michal
>
> On 29.12.2016 11:25, Kever Yang wrote:
>> RK3399 SPL is not enable bacause of the lack of ATF support in SPL,
>> after port some source code from ATF, I manage to enable the support for
>> ATF in SPL. This patch set depends on some patch for SPL support multi
>> binary in FIT which is from Andre.
>>
>> The patch of sdram controller is still not clean, because I want to get
>> comments from upstream.I port this driver from coreboot, and I don't
>> want to make much change on it. The rk3399 dram controller has many registers
>> to config, I want to make them directly used by driver instead of parse
>> and copy them one by one from dts.
>>
>> Another part of comment is welcome for the implementation of spl_atf.c
>> and the entry in spl.c
>>
>>
>>
>> Kever Yang (3):
>>    arm64: rk3399: add SPL support
>>    arm64: rk3399: add ddr controller driver
>>    spl: add support to booting with ATF
>>
>>   arch/arm/Kconfig                                   |    1 +
>>   arch/arm/dts/rk3399.dtsi                           |   24 +
>>   arch/arm/include/asm/arch-rockchip/grf_rk3399.h    |  118 ++
>>   arch/arm/include/asm/arch-rockchip/sdram_rk3399.h  |  188 +++
>>   arch/arm/mach-rockchip/Kconfig                     |    2 +
>>   arch/arm/mach-rockchip/Makefile                    |    1 +
>>   arch/arm/mach-rockchip/rk3399-board-spl.c          |  157 ++
>>   arch/arm/mach-rockchip/rk3399/Makefile             |    1 +
>>   arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc | 1565 ++++++++++++++++++++
>>   arch/arm/mach-rockchip/rk3399/sdram_rk3399.c       | 1121 ++++++++++++++
>>   common/spl/Kconfig                                 |   14 +
>>   common/spl/Makefile                                |    1 +
>>   common/spl/spl.c                                   |    4 +
>>   common/spl/spl_atf.c                               |   91 ++
>>   configs/evb-rk3399_defconfig                       |   17 +
>>   drivers/clk/rockchip/clk_rk3399.c                  |   42 +-
>>   drivers/pinctrl/rockchip/pinctrl_rk3399.c          |  106 --
>>   include/atf_common.h                               |  295 ++++
>>   include/configs/rk3399_common.h                    |   11 +
>>   include/dt-bindings/clock/rk3399-cru.h             |   16 +-
>>   include/spl.h                                      |    1 +
>>   21 files changed, 3663 insertions(+), 113 deletions(-)
>>   create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
>>   create mode 100644 arch/arm/mach-rockchip/rk3399-board-spl.c
>>   create mode 100644 arch/arm/mach-rockchip/rk3399/sdram-lpddr3-4GB.inc
>>   create mode 100644 arch/arm/mach-rockchip/rk3399/sdram_rk3399.c
>>   create mode 100644 common/spl/spl_atf.c
>>   create mode 100644 include/atf_common.h
>>
>
>
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2017-01-06  7:09     ` Kever Yang
@ 2017-01-06  7:55       ` Michal Simek
  2017-01-26 14:23         ` Simon Glass
  0 siblings, 1 reply; 15+ messages in thread
From: Michal Simek @ 2017-01-06  7:55 UTC (permalink / raw)
  To: u-boot

Hi,

On 6.1.2017 08:09, Kever Yang wrote:
> Hi Michal,
> 
>     Thanks for your comments.
> 
> On 01/02/2017 11:05 PM, Michal Simek wrote:
>> On 29.12.2016 11:25, Kever Yang wrote:
>>> ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
>>> about ATF at:
>>>
>>> SPL is consider as BL2 in ATF, it needs to load other part of ATF binary
>> SPL replaces BL2 in ATF
> 
> OK, will follow your comment in next patch.
>>
>>> like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
>>> parameter for BL31 which including entry and image information for all
>>> other images. Then the SPL handle PC to BL31 with the parameter, the
>>> BL31 will do the rest of work and at last get into U-Boot(BL33).
>> But the main question for this is how do load that images and in which
>> format. It means I would think that you will introduce fit format which
>> contain BL33(U-Boot), BL32(secure os) and BL31(ATF) and SPL will be able
>> to load all of them.
> 
> Yes, I use FIT format to contain BL33 and BL32 and SPL load all of them.

Do you have some logs? I didn't check the latest code but IIRC it was
possible to handle one image and dt not several images which has to be
supported. There is also loadables section in fit which can help with this.

>>
>> If you look at zynqmp I did a small trick where I consider case that
>> with ATF it is OS boot where kernel is ATF and dtb is full u-boot to get
>> it boot.
> 
> This is a good idea, and it look fine for support ATF in SPL in local
> source code,
> but it will be better if we have an official support for ATF, right?

Definitely having support just for ATF is much better solution than what
I use in ZynqMP.

> 
>>
>> If you adopt fit format then I expect SPL will be able to remember which
>> part is where and based on that fill structure for ATF.
>> Then SPL_ATF_TEXT_BASE address is not needed because it will be read
>> from fit format.
> 
> Yes, you are right, SPL_ATF_TEXT_BASE is not a must, we gen get it from
> fit.

ok.

> 
>>
>>
>>
>>> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
>>> ---
>>>
>>>   common/spl/Kconfig   |  14 +++
>>>   common/spl/Makefile  |   1 +
>>>   common/spl/spl.c     |   4 +
>>>   common/spl/spl_atf.c |  91 ++++++++++++++++
>>>   include/atf_common.h | 295
>>> +++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   include/spl.h        |   1 +
>>>   6 files changed, 406 insertions(+)
>>>   create mode 100644 common/spl/spl_atf.c
>>>   create mode 100644 include/atf_common.h
>>>
>>> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
>>> index cba51f5..1bb4360 100644
>>> --- a/common/spl/Kconfig
>>> +++ b/common/spl/Kconfig
>>> @@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
>>>         means of transmitting U-Boot over a serial line for using in
>>> SPL,
>>>         with a checksum to ensure correctness.
>>>   +config SPL_ATF_SUPPORT
>>> +    bool "Support ARM trust firmware"
>>> +    depends on SPL
>>> +    help
>>> +      ATF(ARM Trust Firmware) is component for ARM arch64 which need to
>>> +      load by SPL(consider as BL2 in ATF).
>>> +      More detail at:
>>> https://github.com/ARM-software/arm-trusted-firmware
>>> +
>>> +config SPL_ATF_TEXT_BASE
>>> +    depends on SPL_ATF_SUPPORT
>>> +    hex "ATF TEXT BASE addr"
>>> +    help
>>> +      This is the base address in memory for ATF text and entry point.
>>> +
>>>   config TPL_ENV_SUPPORT
>>>       bool "Support an environment"
>>>       depends on TPL
>>> diff --git a/common/spl/Makefile b/common/spl/Makefile
>>> index ed02635..620ae90 100644
>>> --- a/common/spl/Makefile
>>> +++ b/common/spl/Makefile
>>> @@ -20,6 +20,7 @@ endif
>>>   obj-$(CONFIG_SPL_UBI) += spl_ubi.o
>>>   obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
>>>   obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
>>> +obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
>>>   obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
>>>   obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
>>>   obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
>>> diff --git a/common/spl/spl.c b/common/spl/spl.c
>>> index 1729034..7daf7bd 100644
>>> --- a/common/spl/spl.c
>>> +++ b/common/spl/spl.c
>>> @@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
>>>             gd->malloc_ptr / 1024);
>>>   #endif
>>>   +#ifdef CONFIG_SPL_ATF_SUPPORT
>>> +    bl31_entry();
>>> +#endif
>>> +
>>>       debug("loaded - jumping to U-Boot...");
>>>       spl_board_prepare_for_boot();
>>>       jump_to_image_no_args(&spl_image);
>>> diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
>>> new file mode 100644
>>> index 0000000..cf23b7a
>>> --- /dev/null
>>> +++ b/common/spl/spl_atf.c
>>> @@ -0,0 +1,91 @@
>>> +/*
>>> + * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
>>> + * Written by Kever Yang <kever.yang@rock-chips.com>
>>> + *
>>> + * origin from arm-trust-firmware
>>> + * plat/arm/common/arm_bl2_setup.c
>>> + * SPDX-License-Identifier:     GPL-2.0+
>> this is not based on gpl file that's why license should be different.
> 
> Sorry, I do not get what your mean, I'm not good at license policy,
> ARM ATF use its own license, what should I do for license when I use code
> from ATF?

I am not that guy too. But if you took parts of code which is not GPL
you can't label it as a GPL.


> 
>>
>>
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <errno.h>
>>> +#include <spl.h>
>>> +#include <atf_common.h>
>>> +
>>> +static struct bl2_to_bl31_params_mem_t bl31_params_mem;
>>> +static struct bl31_params_t *bl2_to_bl31_params;
>>> +
>>> +/*******************************************************************************
>>>
>>> + * This function assigns a pointer to the memory that the platform
>>> has kept
>>> + * aside to pass platform specific and trusted firmware related
>>> information
>>> + * to BL31. This memory is allocated by allocating memory to
>>> + * bl2_to_bl31_params_mem_t structure which is a superset of all the
>>> + * structure whose information is passed to BL31
>>> + * NOTE: This function should be called only once and should be done
>>> + * before generating params to BL31
>>> +
>>> ******************************************************************************/
>>>
>>> +struct bl31_params_t *bl2_plat_get_bl31_params(void)
>>> +{
>>> +    struct entry_point_info_t *bl33_ep_info;
>>> +
>>> +    /*
>>> +     * Initialise the memory for all the arguments that needs to
>>> +     * be passed to BL31
>>> +     */
>>> +    memset(&bl31_params_mem, 0, sizeof(struct
>>> bl2_to_bl31_params_mem_t));
>>> +
>>> +    /* Assign memory for TF related information */
>>> +    bl2_to_bl31_params = &bl31_params_mem.bl31_params;
>>> +    SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
>>> +
>>> +    /* Fill BL31 related information */
>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info,
>>> PARAM_IMAGE_BINARY,
>>> +               VERSION_1, 0);
>>> +
>>> +    /* Fill BL32 related information if it exists */
>>> +#ifdef BL32_BASE
>>> +    bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
>>> +               VERSION_1, 0);
>>> +    bl2_to_bl31_params->bl32_image_info =
>>> &bl31_params_mem.bl32_image_info;
>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info,
>>> PARAM_IMAGE_BINARY,
>>> +               VERSION_1, 0);
>>> +#endif /* BL32_BASE */
>> Is this used?
> 
> Not use for me now, but it may useful later, because we need to fill
> info about bl32 if there is.

I think that make sense to look at fit format and try to integrate all
these stuff together.


>>
>>> +
>>> +    /* Fill BL33 related information */
>>> +    bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
>>> +    bl33_ep_info = &bl31_params_mem.bl33_ep_info;
>>> +    SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
>>> +
>>> +    /* BL33 expects to receive the primary CPU MPID (through x0) */
>>> +    bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
>>> +    bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
>>> +    bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
>>> +                     DISABLE_ALL_EXECPTIONS);
>>> +
>>> +    bl2_to_bl31_params->bl33_image_info =
>>> &bl31_params_mem.bl33_image_info;
>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info,
>>> PARAM_IMAGE_BINARY,
>>> +               VERSION_1, 0);
>>> +
>>> +
>> double lines.
> 
> Will fix in next patch, confuse why checkpatch did not find this.
>>
>>> +    return bl2_to_bl31_params;
>>> +}
>>> +
>>> +void raw_write_daif(uint32_t daif)
>>> +{
>>> +    __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
>>> +}
>>> +
>>> +void bl31_entry(void)
>>> +{
>>> +    struct bl31_params_t *bl31_params;
>>> +    void (*entry)(struct bl31_params_t *params, void *plat_params) =
>>> NULL;
>>> +
>>> +    bl31_params = bl2_plat_get_bl31_params();
>>> +    entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
>>> +
>>> +    raw_write_daif(SPSR_EXCEPTION_MASK);
>>> +    dcache_disable();
>>> +
>>> +    entry(bl31_params, NULL);
>>> +}
>>> diff --git a/include/atf_common.h b/include/atf_common.h
>>> new file mode 100644
>>> index 0000000..8351302
>>> --- /dev/null
>>> +++ b/include/atf_common.h
>>> @@ -0,0 +1,295 @@
>>> +/*
>>> + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights
>>> reserved.
>>> + *
>>> + * Redistribution and use in source and binary forms, with or without
>>> + * modification, are permitted provided that the following
>>> conditions are met:
>>> + *
>>> + * Redistributions of source code must retain the above copyright
>>> notice, this
>>> + * list of conditions and the following disclaimer.
>>> + *
>>> + * Redistributions in binary form must reproduce the above copyright
>>> notice,
>>> + * this list of conditions and the following disclaimer in the
>>> documentation
>>> + * and/or other materials provided with the distribution.
>>> + *
>>> + * Neither the name of ARM nor the names of its contributors may be
>>> used
>>> + * to endorse or promote products derived from this software without
>>> specific
>>> + * prior written permission.
>>> + *
>>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
>>> CONTRIBUTORS "AS IS"
>>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
>>> TO, THE
>>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
>>> PARTICULAR PURPOSE
>>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
>>> CONTRIBUTORS BE
>>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
>>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>>> BUSINESS
>>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
>>> WHETHER IN
>>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>>> OTHERWISE)
>>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
>>> ADVISED OF THE
>>> + * POSSIBILITY OF SUCH DAMAGE.
>> This should be probably in SPDX format.
> 
> Like previous reply, I don't know how to deal with this license, do you
> mean I can use
> SPDX license without any information about the origin License?

Tom, Simon: Please correct me if I am wrong.
There are 2 things here.

0. Identify license and especially this part. The rest looks like BSD
license

* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.

1. If this ARM license is compatible with u-boot Licensing model
2. We have Licenses folder where License can go but not sure if only
SPDX licenses can got there and if ARM published this license there to
have official SPDX tag. Please look at Licenses/README

Thanks,
Michal

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support Kever Yang
@ 2017-01-13  2:11   ` Simon Glass
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Glass @ 2017-01-13  2:11 UTC (permalink / raw)
  To: u-boot

Hi Kever,

On 29 December 2016 at 03:25, Kever Yang <kever.yang@rock-chips.com> wrote:
> Add spl support for rk3399.
>
> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
> ---
>
>  arch/arm/Kconfig                                |   1 +
>  arch/arm/dts/rk3399.dtsi                        |  24 ++++
>  arch/arm/include/asm/arch-rockchip/grf_rk3399.h | 118 ++++++++++++++++++
>  arch/arm/mach-rockchip/Kconfig                  |   2 +
>  arch/arm/mach-rockchip/Makefile                 |   1 +
>  arch/arm/mach-rockchip/rk3399-board-spl.c       | 157 ++++++++++++++++++++++++
>  configs/evb-rk3399_defconfig                    |  17 +++
>  drivers/clk/rockchip/clk_rk3399.c               |  42 ++++++-
>  drivers/pinctrl/rockchip/pinctrl_rk3399.c       | 106 ----------------
>  include/configs/rk3399_common.h                 |  11 ++
>  include/dt-bindings/clock/rk3399-cru.h          |  16 ++-
>  11 files changed, 382 insertions(+), 113 deletions(-)
>  create mode 100644 arch/arm/mach-rockchip/rk3399-board-spl.c

The code looks fine. But can you please split this into 3 patches?

- move grf register definitions to grf_rk3399.h
- add clock driver
- add SPL support

Also check your header #ifdef guards - they should not have SOC in them.

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver Kever Yang
@ 2017-01-13  2:18   ` Simon Glass
  2017-01-18  9:55     ` Kever Yang
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2017-01-13  2:18 UTC (permalink / raw)
  To: u-boot

Hi Kever,

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

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

> +
> +#include <stddef.h>

What is this for?

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

Please can you use lower-case hex?

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

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

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

Please add spaces around operators:

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


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

These structures and members should have comments.

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

Drop brackets around simple constants

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

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

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

Multi-line comment style:

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

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

Function comment

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

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

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

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

clk.h should go after common.h

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

These should all come from the device tree, right?

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

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

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

Drop brackets

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

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

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

These should really be defined as SHIFT and MASK values.

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

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

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

These could all use SHIFT/MASK values

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

Don't init here unless you need to.

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

Can we return an error and use debug() ?

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

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

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

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

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

TODO(email):

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

-EIO or something else?

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

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

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

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

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

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

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

Or similar...

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

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


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

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

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

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

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

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

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

Check return value here.

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

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver
  2017-01-13  2:18   ` Simon Glass
@ 2017-01-18  9:55     ` Kever Yang
  0 siblings, 0 replies; 15+ messages in thread
From: Kever Yang @ 2017-01-18  9:55 UTC (permalink / raw)
  To: u-boot

Hi Simon,

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

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

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

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

Thanks,
- Kever

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2016-12-29 10:25 ` [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF Kever Yang
  2017-01-02 15:05   ` Michal Simek
@ 2017-01-18 12:20   ` Kever Yang
  1 sibling, 0 replies; 15+ messages in thread
From: Kever Yang @ 2017-01-18 12:20 UTC (permalink / raw)
  To: u-boot

Hi

     Who is suppose to maintain source in "common/spl"?
I hope to get more comments before my first version patch without 'RFC'
and with suggestion from Michal.

Thanks,
- Kever
On 12/29/2016 06:25 PM, Kever Yang wrote:
> ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
> about ATF at:
>
> SPL is consider as BL2 in ATF, it needs to load other part of ATF binary
> like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
> parameter for BL31 which including entry and image information for all
> other images. Then the SPL handle PC to BL31 with the parameter, the
> BL31 will do the rest of work and at last get into U-Boot(BL33).
>
> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
> ---
>
>   common/spl/Kconfig   |  14 +++
>   common/spl/Makefile  |   1 +
>   common/spl/spl.c     |   4 +
>   common/spl/spl_atf.c |  91 ++++++++++++++++
>   include/atf_common.h | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   include/spl.h        |   1 +
>   6 files changed, 406 insertions(+)
>   create mode 100644 common/spl/spl_atf.c
>   create mode 100644 include/atf_common.h
>
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index cba51f5..1bb4360 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
>   	  means of transmitting U-Boot over a serial line for using in SPL,
>   	  with a checksum to ensure correctness.
>   
> +config SPL_ATF_SUPPORT
> +	bool "Support ARM trust firmware"
> +	depends on SPL
> +	help
> +	  ATF(ARM Trust Firmware) is component for ARM arch64 which need to
> +	  load by SPL(consider as BL2 in ATF).
> +	  More detail at: https://github.com/ARM-software/arm-trusted-firmware
> +
> +config SPL_ATF_TEXT_BASE
> +	depends on SPL_ATF_SUPPORT
> +	hex "ATF TEXT BASE addr"
> +	help
> +	  This is the base address in memory for ATF text and entry point.
> +
>   config TPL_ENV_SUPPORT
>   	bool "Support an environment"
>   	depends on TPL
> diff --git a/common/spl/Makefile b/common/spl/Makefile
> index ed02635..620ae90 100644
> --- a/common/spl/Makefile
> +++ b/common/spl/Makefile
> @@ -20,6 +20,7 @@ endif
>   obj-$(CONFIG_SPL_UBI) += spl_ubi.o
>   obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
>   obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
> +obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
>   obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
>   obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
>   obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
> diff --git a/common/spl/spl.c b/common/spl/spl.c
> index 1729034..7daf7bd 100644
> --- a/common/spl/spl.c
> +++ b/common/spl/spl.c
> @@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
>   	      gd->malloc_ptr / 1024);
>   #endif
>   
> +#ifdef CONFIG_SPL_ATF_SUPPORT
> +	bl31_entry();
> +#endif
> +
>   	debug("loaded - jumping to U-Boot...");
>   	spl_board_prepare_for_boot();
>   	jump_to_image_no_args(&spl_image);
> diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
> new file mode 100644
> index 0000000..cf23b7a
> --- /dev/null
> +++ b/common/spl/spl_atf.c
> @@ -0,0 +1,91 @@
> +/*
> + * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
> + * Written by Kever Yang <kever.yang@rock-chips.com>
> + *
> + * origin from arm-trust-firmware
> + * plat/arm/common/arm_bl2_setup.c
> + * SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <spl.h>
> +#include <atf_common.h>
> +
> +static struct bl2_to_bl31_params_mem_t bl31_params_mem;
> +static struct bl31_params_t *bl2_to_bl31_params;
> +
> +/*******************************************************************************
> + * This function assigns a pointer to the memory that the platform has kept
> + * aside to pass platform specific and trusted firmware related information
> + * to BL31. This memory is allocated by allocating memory to
> + * bl2_to_bl31_params_mem_t structure which is a superset of all the
> + * structure whose information is passed to BL31
> + * NOTE: This function should be called only once and should be done
> + * before generating params to BL31
> + ******************************************************************************/
> +struct bl31_params_t *bl2_plat_get_bl31_params(void)
> +{
> +	struct entry_point_info_t *bl33_ep_info;
> +
> +	/*
> +	 * Initialise the memory for all the arguments that needs to
> +	 * be passed to BL31
> +	 */
> +	memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem_t));
> +
> +	/* Assign memory for TF related information */
> +	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
> +	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
> +
> +	/* Fill BL31 related information */
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
> +		       VERSION_1, 0);
> +
> +	/* Fill BL32 related information if it exists */
> +#ifdef BL32_BASE
> +	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
> +		       VERSION_1, 0);
> +	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
> +		       VERSION_1, 0);
> +#endif /* BL32_BASE */
> +
> +	/* Fill BL33 related information */
> +	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
> +	bl33_ep_info = &bl31_params_mem.bl33_ep_info;
> +	SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
> +
> +	/* BL33 expects to receive the primary CPU MPID (through x0) */
> +	bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
> +	bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
> +	bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
> +				     DISABLE_ALL_EXECPTIONS);
> +
> +	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
> +	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
> +		       VERSION_1, 0);
> +
> +
> +	return bl2_to_bl31_params;
> +}
> +
> +void raw_write_daif(uint32_t daif)
> +{
> +	__asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
> +}
> +
> +void bl31_entry(void)
> +{
> +	struct bl31_params_t *bl31_params;
> +	void (*entry)(struct bl31_params_t *params, void *plat_params) = NULL;
> +
> +	bl31_params = bl2_plat_get_bl31_params();
> +	entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
> +
> +	raw_write_daif(SPSR_EXCEPTION_MASK);
> +	dcache_disable();
> +
> +	entry(bl31_params, NULL);
> +}
> diff --git a/include/atf_common.h b/include/atf_common.h
> new file mode 100644
> index 0000000..8351302
> --- /dev/null
> +++ b/include/atf_common.h
> @@ -0,0 +1,295 @@
> +/*
> + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + *
> + * Redistributions of source code must retain the above copyright notice, this
> + * list of conditions and the following disclaimer.
> + *
> + * Redistributions in binary form must reproduce the above copyright notice,
> + * this list of conditions and the following disclaimer in the documentation
> + * and/or other materials provided with the distribution.
> + *
> + * Neither the name of ARM nor the names of its contributors may be used
> + * to endorse or promote products derived from this software without specific
> + * prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef __BL_COMMON_H__
> +#define __BL_COMMON_H__
> +
> +#define SECURE		0x0
> +#define NON_SECURE	0x1
> +#define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
> +
> +#define UP	1
> +#define DOWN	0
> +
> +/*******************************************************************************
> + * Constants to identify the location of a memory region in a given memory
> + * layout.
> +******************************************************************************/
> +#define TOP	0x1
> +#define BOTTOM	!TOP
> +
> +/*******************************************************************************
> + * Constants that allow assembler code to access members of and the
> + * 'entry_point_info' structure at their correct offsets.
> + ******************************************************************************/
> +#define ENTRY_POINT_INFO_PC_OFFSET	0x08
> +#define ENTRY_POINT_INFO_ARGS_OFFSET	0x18
> +
> +/* The following are used to set/get image attributes. */
> +#define PARAM_EP_SECURITY_MASK		(0x1)
> +
> +#define GET_SECURITY_STATE(x) (x & PARAM_EP_SECURITY_MASK)
> +#define SET_SECURITY_STATE(x, security) \
> +			((x) = ((x) & ~PARAM_EP_SECURITY_MASK) | (security))
> +
> +
> +/*
> + * The following are used for image state attributes.
> + * Image can only be in one of the following state.
> + */
> +#define IMAGE_STATE_RESET			0
> +#define IMAGE_STATE_COPIED			1
> +#define IMAGE_STATE_COPYING			2
> +#define IMAGE_STATE_AUTHENTICATED		3
> +#define IMAGE_STATE_EXECUTED			4
> +#define IMAGE_STATE_INTERRUPTED			5
> +
> +#define EP_SECURE	0x0
> +#define EP_NON_SECURE	0x1
> +
> +#define EP_EE_MASK	0x2
> +#define EP_EE_LITTLE	0x0
> +#define EP_EE_BIG	0x2
> +#define EP_GET_EE(x) (x & EP_EE_MASK)
> +#define EP_SET_EE(x, ee) ((x) = ((x) & ~EP_EE_MASK) | (ee))
> +
> +#define EP_ST_MASK	0x4
> +#define EP_ST_DISABLE	0x0
> +#define EP_ST_ENABLE	0x4
> +#define EP_GET_ST(x) (x & EP_ST_MASK)
> +#define EP_SET_ST(x, ee) ((x) = ((x) & ~EP_ST_MASK) | (ee))
> +
> +#define EP_EXE_MASK	0x8
> +#define NON_EXECUTABLE	0x0
> +#define EXECUTABLE	0x8
> +#define EP_GET_EXE(x) (x & EP_EXE_MASK)
> +#define EP_SET_EXE(x, ee) ((x) = ((x) & ~EP_EXE_MASK) | (ee))
> +
> +#define PARAM_EP		0x01
> +#define PARAM_IMAGE_BINARY	0x02
> +#define PARAM_BL31		0x03
> +
> +#define VERSION_1	0x01
> +
> +#define INVALID_IMAGE_ID		(0xFFFFFFFF)
> +
> +#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \
> +	(_p)->h.type = (uint8_t)(_type); \
> +	(_p)->h.version = (uint8_t)(_ver); \
> +	(_p)->h.size = (uint16_t)sizeof(*_p); \
> +	(_p)->h.attr = (uint32_t)(_attr) ; \
> +	} while (0)
> +
> +/* Following is used for populating structure members statically. */
> +#define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr)	\
> +	._p.h.type = (uint8_t)(_type), \
> +	._p.h.version = (uint8_t)(_ver), \
> +	._p.h.size = (uint16_t)sizeof(_p_type), \
> +	._p.h.attr = (uint32_t)(_attr)
> +
> +#define MODE_RW_SHIFT	0x4
> +#define MODE_RW_MASK	0x1
> +#define MODE_RW_64	0x0
> +#define MODE_RW_32	0x1
> +
> +#define MODE_EL_SHIFT	0x2
> +#define MODE_EL_MASK	0x3
> +#define MODE_EL3	0x3
> +#define MODE_EL2	0x2
> +#define MODE_EL1	0x1
> +#define MODE_EL0	0x0
> +
> +#define MODE_SP_SHIFT	0x0
> +#define MODE_SP_MASK	0x1
> +#define MODE_SP_EL0	0x0
> +#define MODE_SP_ELX	0x1
> +
> +#define SPSR_DAIF_SHIFT	6
> +#define SPSR_DAIF_MASK	0x0f
> +
> +#define DAIF_FIQ_BIT (1<<0)
> +#define DAIF_IRQ_BIT (1<<0)
> +#define DAIF_ABT_BIT (1<<0)
> +#define DAIF_DBG_BIT (1<<0)
> +#define DISABLE_ALL_EXECPTIONS	\
> +	(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
> +
> +#define SPSR_64(el, sp, daif)		\
> +	(MODE_RW_64 << MODE_RW_SHIFT |	\
> +	 ((el) & MODE_EL_MASK) << MODE_EL_SHIFT |	\
> +	 ((sp) & MODE_SP_MASK) << MODE_SP_SHIFT |	\
> +	 ((daif) & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)
> +
> +/*******************************************************************************
> + * Constants to indicate type of exception to the common exception handler.
> + ******************************************************************************/
> +#define SYNC_EXCEPTION_SP_EL0		0x0
> +#define IRQ_SP_EL0			0x1
> +#define FIQ_SP_EL0			0x2
> +#define SERROR_SP_EL0			0x3
> +#define SYNC_EXCEPTION_SP_ELX		0x4
> +#define IRQ_SP_ELX			0x5
> +#define FIQ_SP_ELX			0x6
> +#define SERROR_SP_ELX			0x7
> +#define SYNC_EXCEPTION_AARCH64		0x8
> +#define IRQ_AARCH64			0x9
> +#define FIQ_AARCH64			0xa
> +#define SERROR_AARCH64			0xb
> +#define SYNC_EXCEPTION_AARCH32		0xc
> +#define IRQ_AARCH32			0xd
> +#define FIQ_AARCH32			0xe
> +#define SERROR_AARCH32			0xf
> +
> +#define SPSR_USE_L           0
> +#define SPSR_USE_H           1
> +#define SPSR_L_H_MASK        1
> +#define SPSR_M_SHIFT         4
> +#define SPSR_ERET_32         (1 << SPSR_M_SHIFT)
> +#define SPSR_ERET_64         (0 << SPSR_M_SHIFT)
> +#define SPSR_FIQ             (1 << 6)
> +#define SPSR_IRQ             (1 << 7)
> +#define SPSR_SERROR          (1 << 8)
> +#define SPSR_DEBUG           (1 << 9)
> +#define SPSR_EXCEPTION_MASK  (SPSR_FIQ | SPSR_IRQ | SPSR_SERROR | SPSR_DEBUG)
> +
> +#ifndef __ASSEMBLY__
> +
> +/*******************************************************************************
> + * Structure used for telling the next BL how much of a particular type of
> + * memory is available for its use and how much is already used.
> + ******************************************************************************/
> +struct aapcs64_params_t {
> +	unsigned long arg0;
> +	unsigned long arg1;
> +	unsigned long arg2;
> +	unsigned long arg3;
> +	unsigned long arg4;
> +	unsigned long arg5;
> +	unsigned long arg6;
> +	unsigned long arg7;
> +};
> +
> +/***************************************************************************
> + * This structure provides version information and the size of the
> + * structure, attributes for the structure it represents
> + ***************************************************************************/
> +struct param_header_t {
> +	uint8_t type;		/* type of the structure */
> +	uint8_t version;    /* version of this structure */
> +	uint16_t size;      /* size of this structure in bytes */
> +	uint32_t attr;      /* attributes: unused bits SBZ */
> +};
> +
> +/*****************************************************************************
> + * This structure represents the superset of information needed while
> + * switching exception levels. The only two mechanisms to do so are
> + * ERET & SMC. Security state is indicated using bit zero of header
> + * attribute
> + * NOTE: BL1 expects entrypoint followed by spsr at an offset from the start
> + * of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while
> + * processing SMC to jump to BL31.
> + *****************************************************************************/
> +struct entry_point_info_t {
> +	struct param_header_t h;
> +	uintptr_t pc;
> +	uint32_t spsr;
> +	struct aapcs64_params_t args;
> +};
> +
> +/*****************************************************************************
> + * Image info binary provides information from the image loader that
> + * can be used by the firmware to manage available trusted RAM.
> + * More advanced firmware image formats can provide additional
> + * information that enables optimization or greater flexibility in the
> + * common firmware code
> + *****************************************************************************/
> +struct atf_image_info_t {
> +	struct param_header_t h;
> +	uintptr_t image_base;   /* physical address of base of image */
> +	uint32_t image_size;    /* bytes read from image file */
> +};
> +
> +/*****************************************************************************
> + * The image descriptor struct definition.
> + *****************************************************************************/
> +struct image_desc_t {
> +	/* Contains unique image id for the image. */
> +	unsigned int image_id;
> +	/*
> +	 * This member contains Image state information.
> +	 * Refer IMAGE_STATE_XXX defined above.
> +	 */
> +	unsigned int state;
> +	uint32_t copied_size;	/* image size copied in blocks */
> +	struct atf_image_info_t atf_image_info;
> +	struct entry_point_info_t ep_info;
> +};
> +
> +/*******************************************************************************
> + * This structure represents the superset of information that can be passed to
> + * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be
> + * populated only if BL2 detects its presence. A pointer to a structure of this
> + * type should be passed in X0 to BL31's cold boot entrypoint.
> + *
> + * Use of this structure and the X0 parameter is not mandatory: the BL31
> + * platform code can use other mechanisms to provide the necessary information
> + * about BL32 and BL33 to the common and SPD code.
> + *
> + * BL31 image information is mandatory if this structure is used. If either of
> + * the optional BL32 and BL33 image information is not provided, this is
> + * indicated by the respective image_info pointers being zero.
> + ******************************************************************************/
> +struct bl31_params_t {
> +	struct param_header_t h;
> +	struct atf_image_info_t *bl31_image_info;
> +	struct entry_point_info_t *bl32_ep_info;
> +	struct atf_image_info_t *bl32_image_info;
> +	struct entry_point_info_t *bl33_ep_info;
> +	struct atf_image_info_t *bl33_image_info;
> +};
> +
> +/*******************************************************************************
> + * This structure represents the superset of information that is passed to
> + * BL31, e.g. while passing control to it from BL2, bl31_params
> + * and other platform specific params
> + ******************************************************************************/
> +struct bl2_to_bl31_params_mem_t {
> +	struct bl31_params_t bl31_params;
> +	struct atf_image_info_t bl31_image_info;
> +	struct atf_image_info_t bl32_image_info;
> +	struct atf_image_info_t bl33_image_info;
> +	struct entry_point_info_t bl33_ep_info;
> +	struct entry_point_info_t bl32_ep_info;
> +	struct entry_point_info_t bl31_ep_info;
> +};
> +
> +#endif /*__ASSEMBLY__*/
> +
> +#endif /* __BL_COMMON_H__ */
> diff --git a/include/spl.h b/include/spl.h
> index 918c464..ab5eaca 100644
> --- a/include/spl.h
> +++ b/include/spl.h
> @@ -251,4 +251,5 @@ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);
>   int spl_mmc_load_image(struct spl_image_info *spl_image,
>   		       struct spl_boot_device *bootdev);
>   
> +void bl31_entry(void);
>   #endif

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2017-01-06  7:55       ` Michal Simek
@ 2017-01-26 14:23         ` Simon Glass
  2017-01-28 21:55           ` Tom Rini
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2017-01-26 14:23 UTC (permalink / raw)
  To: u-boot

+Tom for license comment

Hi,

On 6 January 2017 at 00:55, Michal Simek <michal.simek@xilinx.com> wrote:
> Hi,
>
> On 6.1.2017 08:09, Kever Yang wrote:
>> Hi Michal,
>>
>>     Thanks for your comments.
>>
>> On 01/02/2017 11:05 PM, Michal Simek wrote:
>>> On 29.12.2016 11:25, Kever Yang wrote:
>>>> ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
>>>> about ATF at:
>>>>
>>>> SPL is consider as BL2 in ATF, it needs to load other part of ATF binary
>>> SPL replaces BL2 in ATF
>>
>> OK, will follow your comment in next patch.
>>>
>>>> like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
>>>> parameter for BL31 which including entry and image information for all
>>>> other images. Then the SPL handle PC to BL31 with the parameter, the
>>>> BL31 will do the rest of work and at last get into U-Boot(BL33).
>>> But the main question for this is how do load that images and in which
>>> format. It means I would think that you will introduce fit format which
>>> contain BL33(U-Boot), BL32(secure os) and BL31(ATF) and SPL will be able
>>> to load all of them.
>>
>> Yes, I use FIT format to contain BL33 and BL32 and SPL load all of them.
>
> Do you have some logs? I didn't check the latest code but IIRC it was
> possible to handle one image and dt not several images which has to be
> supported. There is also loadables section in fit which can help with this.
>
>>>
>>> If you look at zynqmp I did a small trick where I consider case that
>>> with ATF it is OS boot where kernel is ATF and dtb is full u-boot to get
>>> it boot.
>>
>> This is a good idea, and it look fine for support ATF in SPL in local
>> source code,
>> but it will be better if we have an official support for ATF, right?
>
> Definitely having support just for ATF is much better solution than what
> I use in ZynqMP.
>
>>
>>>
>>> If you adopt fit format then I expect SPL will be able to remember which
>>> part is where and based on that fill structure for ATF.
>>> Then SPL_ATF_TEXT_BASE address is not needed because it will be read
>>> from fit format.
>>
>> Yes, you are right, SPL_ATF_TEXT_BASE is not a must, we gen get it from
>> fit.
>
> ok.
>
>>
>>>
>>>
>>>
>>>> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
>>>> ---
>>>>
>>>>   common/spl/Kconfig   |  14 +++
>>>>   common/spl/Makefile  |   1 +
>>>>   common/spl/spl.c     |   4 +
>>>>   common/spl/spl_atf.c |  91 ++++++++++++++++
>>>>   include/atf_common.h | 295
>>>> +++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>   include/spl.h        |   1 +
>>>>   6 files changed, 406 insertions(+)
>>>>   create mode 100644 common/spl/spl_atf.c
>>>>   create mode 100644 include/atf_common.h
>>>>
>>>> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
>>>> index cba51f5..1bb4360 100644
>>>> --- a/common/spl/Kconfig
>>>> +++ b/common/spl/Kconfig
>>>> @@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
>>>>         means of transmitting U-Boot over a serial line for using in
>>>> SPL,
>>>>         with a checksum to ensure correctness.
>>>>   +config SPL_ATF_SUPPORT
>>>> +    bool "Support ARM trust firmware"
>>>> +    depends on SPL
>>>> +    help
>>>> +      ATF(ARM Trust Firmware) is component for ARM arch64 which need to
>>>> +      load by SPL(consider as BL2 in ATF).
>>>> +      More detail at:
>>>> https://github.com/ARM-software/arm-trusted-firmware
>>>> +
>>>> +config SPL_ATF_TEXT_BASE
>>>> +    depends on SPL_ATF_SUPPORT
>>>> +    hex "ATF TEXT BASE addr"
>>>> +    help
>>>> +      This is the base address in memory for ATF text and entry point.
>>>> +
>>>>   config TPL_ENV_SUPPORT
>>>>       bool "Support an environment"
>>>>       depends on TPL
>>>> diff --git a/common/spl/Makefile b/common/spl/Makefile
>>>> index ed02635..620ae90 100644
>>>> --- a/common/spl/Makefile
>>>> +++ b/common/spl/Makefile
>>>> @@ -20,6 +20,7 @@ endif
>>>>   obj-$(CONFIG_SPL_UBI) += spl_ubi.o
>>>>   obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
>>>>   obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
>>>> +obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
>>>>   obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
>>>>   obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
>>>>   obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
>>>> diff --git a/common/spl/spl.c b/common/spl/spl.c
>>>> index 1729034..7daf7bd 100644
>>>> --- a/common/spl/spl.c
>>>> +++ b/common/spl/spl.c
>>>> @@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
>>>>             gd->malloc_ptr / 1024);
>>>>   #endif
>>>>   +#ifdef CONFIG_SPL_ATF_SUPPORT
>>>> +    bl31_entry();
>>>> +#endif
>>>> +
>>>>       debug("loaded - jumping to U-Boot...");
>>>>       spl_board_prepare_for_boot();
>>>>       jump_to_image_no_args(&spl_image);
>>>> diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
>>>> new file mode 100644
>>>> index 0000000..cf23b7a
>>>> --- /dev/null
>>>> +++ b/common/spl/spl_atf.c
>>>> @@ -0,0 +1,91 @@
>>>> +/*
>>>> + * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
>>>> + * Written by Kever Yang <kever.yang@rock-chips.com>
>>>> + *
>>>> + * origin from arm-trust-firmware
>>>> + * plat/arm/common/arm_bl2_setup.c
>>>> + * SPDX-License-Identifier:     GPL-2.0+
>>> this is not based on gpl file that's why license should be different.
>>
>> Sorry, I do not get what your mean, I'm not good at license policy,
>> ARM ATF use its own license, what should I do for license when I use code
>> from ATF?
>
> I am not that guy too. But if you took parts of code which is not GPL
> you can't label it as a GPL.

That's right. Perhaps rewrite and rename bl2_plat_get_bl31_params()?
Then you can say that it is inspired by that file, and perhaps avoid
the license problem.

The macros are horrible anyway.

>
>
>>
>>>
>>>
>>>> + */
>>>> +
>>>> +#include <common.h>
>>>> +#include <errno.h>
>>>> +#include <spl.h>
>>>> +#include <atf_common.h>
>>>> +
>>>> +static struct bl2_to_bl31_params_mem_t bl31_params_mem;
>>>> +static struct bl31_params_t *bl2_to_bl31_params;
>>>> +
>>>> +/*******************************************************************************
>>>>
>>>> + * This function assigns a pointer to the memory that the platform
>>>> has kept
>>>> + * aside to pass platform specific and trusted firmware related
>>>> information
>>>> + * to BL31. This memory is allocated by allocating memory to
>>>> + * bl2_to_bl31_params_mem_t structure which is a superset of all the
>>>> + * structure whose information is passed to BL31
>>>> + * NOTE: This function should be called only once and should be done
>>>> + * before generating params to BL31
>>>> +
>>>> ******************************************************************************/
>>>>
>>>> +struct bl31_params_t *bl2_plat_get_bl31_params(void)
>>>> +{
>>>> +    struct entry_point_info_t *bl33_ep_info;
>>>> +
>>>> +    /*
>>>> +     * Initialise the memory for all the arguments that needs to
>>>> +     * be passed to BL31
>>>> +     */
>>>> +    memset(&bl31_params_mem, 0, sizeof(struct
>>>> bl2_to_bl31_params_mem_t));
>>>> +
>>>> +    /* Assign memory for TF related information */
>>>> +    bl2_to_bl31_params = &bl31_params_mem.bl31_params;
>>>> +    SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
>>>> +
>>>> +    /* Fill BL31 related information */
>>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info,
>>>> PARAM_IMAGE_BINARY,
>>>> +               VERSION_1, 0);
>>>> +
>>>> +    /* Fill BL32 related information if it exists */
>>>> +#ifdef BL32_BASE
>>>> +    bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
>>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
>>>> +               VERSION_1, 0);
>>>> +    bl2_to_bl31_params->bl32_image_info =
>>>> &bl31_params_mem.bl32_image_info;
>>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info,
>>>> PARAM_IMAGE_BINARY,
>>>> +               VERSION_1, 0);
>>>> +#endif /* BL32_BASE */
>>> Is this used?
>>
>> Not use for me now, but it may useful later, because we need to fill
>> info about bl32 if there is.
>
> I think that make sense to look at fit format and try to integrate all
> these stuff together.
>
>
>>>
>>>> +
>>>> +    /* Fill BL33 related information */
>>>> +    bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
>>>> +    bl33_ep_info = &bl31_params_mem.bl33_ep_info;
>>>> +    SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
>>>> +
>>>> +    /* BL33 expects to receive the primary CPU MPID (through x0) */
>>>> +    bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
>>>> +    bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
>>>> +    bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
>>>> +                     DISABLE_ALL_EXECPTIONS);
>>>> +
>>>> +    bl2_to_bl31_params->bl33_image_info =
>>>> &bl31_params_mem.bl33_image_info;
>>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info,
>>>> PARAM_IMAGE_BINARY,
>>>> +               VERSION_1, 0);
>>>> +
>>>> +
>>> double lines.
>>
>> Will fix in next patch, confuse why checkpatch did not find this.
>>>
>>>> +    return bl2_to_bl31_params;
>>>> +}
>>>> +
>>>> +void raw_write_daif(uint32_t daif)
>>>> +{
>>>> +    __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
>>>> +}
>>>> +
>>>> +void bl31_entry(void)
>>>> +{
>>>> +    struct bl31_params_t *bl31_params;
>>>> +    void (*entry)(struct bl31_params_t *params, void *plat_params) =
>>>> NULL;
>>>> +
>>>> +    bl31_params = bl2_plat_get_bl31_params();
>>>> +    entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
>>>> +
>>>> +    raw_write_daif(SPSR_EXCEPTION_MASK);
>>>> +    dcache_disable();
>>>> +
>>>> +    entry(bl31_params, NULL);
>>>> +}
>>>> diff --git a/include/atf_common.h b/include/atf_common.h
>>>> new file mode 100644
>>>> index 0000000..8351302
>>>> --- /dev/null
>>>> +++ b/include/atf_common.h
>>>> @@ -0,0 +1,295 @@
>>>> +/*
>>>> + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights
>>>> reserved.
>>>> + *
>>>> + * Redistribution and use in source and binary forms, with or without
>>>> + * modification, are permitted provided that the following
>>>> conditions are met:
>>>> + *
>>>> + * Redistributions of source code must retain the above copyright
>>>> notice, this
>>>> + * list of conditions and the following disclaimer.
>>>> + *
>>>> + * Redistributions in binary form must reproduce the above copyright
>>>> notice,
>>>> + * this list of conditions and the following disclaimer in the
>>>> documentation
>>>> + * and/or other materials provided with the distribution.
>>>> + *
>>>> + * Neither the name of ARM nor the names of its contributors may be
>>>> used
>>>> + * to endorse or promote products derived from this software without
>>>> specific
>>>> + * prior written permission.
>>>> + *
>>>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
>>>> CONTRIBUTORS "AS IS"
>>>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
>>>> TO, THE
>>>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
>>>> PARTICULAR PURPOSE
>>>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
>>>> CONTRIBUTORS BE
>>>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>>>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
>>>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>>>> BUSINESS
>>>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
>>>> WHETHER IN
>>>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>>>> OTHERWISE)
>>>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
>>>> ADVISED OF THE
>>>> + * POSSIBILITY OF SUCH DAMAGE.
>>> This should be probably in SPDX format.
>>
>> Like previous reply, I don't know how to deal with this license, do you
>> mean I can use
>> SPDX license without any information about the origin License?
>
> Tom, Simon: Please correct me if I am wrong.
> There are 2 things here.
>
> 0. Identify license and especially this part. The rest looks like BSD
> license
>
> * Neither the name of ARM nor the names of its contributors may be used
> * to endorse or promote products derived from this software without specific
> * prior written permission.
>
> 1. If this ARM license is compatible with u-boot Licensing model
> 2. We have Licenses folder where License can go but not sure if only
> SPDX licenses can got there and if ARM published this license there to
> have official SPDX tag. Please look at Licenses/README

Perhaps we need to get this licence registered with SPDX?

https://spdx.org/spdx-license-list/request-new-license

But it would be better to get that piece removed somehow. It makes a
non-standard license. Failing that, add a new licence:

1. Add to Licenses directory with a suitable identifier (see for
example commit 0f4d2f8e)
2. Submit a new license registration request

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF
  2017-01-26 14:23         ` Simon Glass
@ 2017-01-28 21:55           ` Tom Rini
  0 siblings, 0 replies; 15+ messages in thread
From: Tom Rini @ 2017-01-28 21:55 UTC (permalink / raw)
  To: u-boot

On Thu, Jan 26, 2017 at 07:23:40AM -0700, Simon Glass wrote:
> +Tom for license comment
> 
> Hi,
> 
> On 6 January 2017 at 00:55, Michal Simek <michal.simek@xilinx.com> wrote:
> > Hi,
> >
> > On 6.1.2017 08:09, Kever Yang wrote:
> >> Hi Michal,
> >>
> >>     Thanks for your comments.
> >>
> >> On 01/02/2017 11:05 PM, Michal Simek wrote:
> >>> On 29.12.2016 11:25, Kever Yang wrote:
> >>>> ATF(ARM Trust Firmware) is used by ARM arch64 SoCs, find more infomation
> >>>> about ATF at:
> >>>>
> >>>> SPL is consider as BL2 in ATF, it needs to load other part of ATF binary
> >>> SPL replaces BL2 in ATF
> >>
> >> OK, will follow your comment in next patch.
> >>>
> >>>> like BL31, BL32, SCP-BL30, and BL33(U-Boot). And needs to prepare the
> >>>> parameter for BL31 which including entry and image information for all
> >>>> other images. Then the SPL handle PC to BL31 with the parameter, the
> >>>> BL31 will do the rest of work and at last get into U-Boot(BL33).
> >>> But the main question for this is how do load that images and in which
> >>> format. It means I would think that you will introduce fit format which
> >>> contain BL33(U-Boot), BL32(secure os) and BL31(ATF) and SPL will be able
> >>> to load all of them.
> >>
> >> Yes, I use FIT format to contain BL33 and BL32 and SPL load all of them.
> >
> > Do you have some logs? I didn't check the latest code but IIRC it was
> > possible to handle one image and dt not several images which has to be
> > supported. There is also loadables section in fit which can help with this.
> >
> >>>
> >>> If you look at zynqmp I did a small trick where I consider case that
> >>> with ATF it is OS boot where kernel is ATF and dtb is full u-boot to get
> >>> it boot.
> >>
> >> This is a good idea, and it look fine for support ATF in SPL in local
> >> source code,
> >> but it will be better if we have an official support for ATF, right?
> >
> > Definitely having support just for ATF is much better solution than what
> > I use in ZynqMP.
> >
> >>
> >>>
> >>> If you adopt fit format then I expect SPL will be able to remember which
> >>> part is where and based on that fill structure for ATF.
> >>> Then SPL_ATF_TEXT_BASE address is not needed because it will be read
> >>> from fit format.
> >>
> >> Yes, you are right, SPL_ATF_TEXT_BASE is not a must, we gen get it from
> >> fit.
> >
> > ok.
> >
> >>
> >>>
> >>>
> >>>
> >>>> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
> >>>> ---
> >>>>
> >>>>   common/spl/Kconfig   |  14 +++
> >>>>   common/spl/Makefile  |   1 +
> >>>>   common/spl/spl.c     |   4 +
> >>>>   common/spl/spl_atf.c |  91 ++++++++++++++++
> >>>>   include/atf_common.h | 295
> >>>> +++++++++++++++++++++++++++++++++++++++++++++++++++
> >>>>   include/spl.h        |   1 +
> >>>>   6 files changed, 406 insertions(+)
> >>>>   create mode 100644 common/spl/spl_atf.c
> >>>>   create mode 100644 include/atf_common.h
> >>>>
> >>>> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> >>>> index cba51f5..1bb4360 100644
> >>>> --- a/common/spl/Kconfig
> >>>> +++ b/common/spl/Kconfig
> >>>> @@ -577,6 +577,20 @@ config SPL_YMODEM_SUPPORT
> >>>>         means of transmitting U-Boot over a serial line for using in
> >>>> SPL,
> >>>>         with a checksum to ensure correctness.
> >>>>   +config SPL_ATF_SUPPORT
> >>>> +    bool "Support ARM trust firmware"
> >>>> +    depends on SPL
> >>>> +    help
> >>>> +      ATF(ARM Trust Firmware) is component for ARM arch64 which need to
> >>>> +      load by SPL(consider as BL2 in ATF).
> >>>> +      More detail at:
> >>>> https://github.com/ARM-software/arm-trusted-firmware
> >>>> +
> >>>> +config SPL_ATF_TEXT_BASE
> >>>> +    depends on SPL_ATF_SUPPORT
> >>>> +    hex "ATF TEXT BASE addr"
> >>>> +    help
> >>>> +      This is the base address in memory for ATF text and entry point.
> >>>> +
> >>>>   config TPL_ENV_SUPPORT
> >>>>       bool "Support an environment"
> >>>>       depends on TPL
> >>>> diff --git a/common/spl/Makefile b/common/spl/Makefile
> >>>> index ed02635..620ae90 100644
> >>>> --- a/common/spl/Makefile
> >>>> +++ b/common/spl/Makefile
> >>>> @@ -20,6 +20,7 @@ endif
> >>>>   obj-$(CONFIG_SPL_UBI) += spl_ubi.o
> >>>>   obj-$(CONFIG_SPL_NET_SUPPORT) += spl_net.o
> >>>>   obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
> >>>> +obj-$(CONFIG_SPL_ATF_SUPPORT) += spl_atf.o
> >>>>   obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
> >>>>   obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
> >>>>   obj-$(CONFIG_SPL_EXT_SUPPORT) += spl_ext.o
> >>>> diff --git a/common/spl/spl.c b/common/spl/spl.c
> >>>> index 1729034..7daf7bd 100644
> >>>> --- a/common/spl/spl.c
> >>>> +++ b/common/spl/spl.c
> >>>> @@ -390,6 +390,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
> >>>>             gd->malloc_ptr / 1024);
> >>>>   #endif
> >>>>   +#ifdef CONFIG_SPL_ATF_SUPPORT
> >>>> +    bl31_entry();
> >>>> +#endif
> >>>> +
> >>>>       debug("loaded - jumping to U-Boot...");
> >>>>       spl_board_prepare_for_boot();
> >>>>       jump_to_image_no_args(&spl_image);
> >>>> diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
> >>>> new file mode 100644
> >>>> index 0000000..cf23b7a
> >>>> --- /dev/null
> >>>> +++ b/common/spl/spl_atf.c
> >>>> @@ -0,0 +1,91 @@
> >>>> +/*
> >>>> + * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
> >>>> + * Written by Kever Yang <kever.yang@rock-chips.com>
> >>>> + *
> >>>> + * origin from arm-trust-firmware
> >>>> + * plat/arm/common/arm_bl2_setup.c
> >>>> + * SPDX-License-Identifier:     GPL-2.0+
> >>> this is not based on gpl file that's why license should be different.
> >>
> >> Sorry, I do not get what your mean, I'm not good at license policy,
> >> ARM ATF use its own license, what should I do for license when I use code
> >> from ATF?
> >
> > I am not that guy too. But if you took parts of code which is not GPL
> > you can't label it as a GPL.
> 
> That's right. Perhaps rewrite and rename bl2_plat_get_bl31_params()?
> Then you can say that it is inspired by that file, and perhaps avoid
> the license problem.
> 
> The macros are horrible anyway.
> 
> >
> >
> >>
> >>>
> >>>
> >>>> + */
> >>>> +
> >>>> +#include <common.h>
> >>>> +#include <errno.h>
> >>>> +#include <spl.h>
> >>>> +#include <atf_common.h>
> >>>> +
> >>>> +static struct bl2_to_bl31_params_mem_t bl31_params_mem;
> >>>> +static struct bl31_params_t *bl2_to_bl31_params;
> >>>> +
> >>>> +/*******************************************************************************
> >>>>
> >>>> + * This function assigns a pointer to the memory that the platform
> >>>> has kept
> >>>> + * aside to pass platform specific and trusted firmware related
> >>>> information
> >>>> + * to BL31. This memory is allocated by allocating memory to
> >>>> + * bl2_to_bl31_params_mem_t structure which is a superset of all the
> >>>> + * structure whose information is passed to BL31
> >>>> + * NOTE: This function should be called only once and should be done
> >>>> + * before generating params to BL31
> >>>> +
> >>>> ******************************************************************************/
> >>>>
> >>>> +struct bl31_params_t *bl2_plat_get_bl31_params(void)
> >>>> +{
> >>>> +    struct entry_point_info_t *bl33_ep_info;
> >>>> +
> >>>> +    /*
> >>>> +     * Initialise the memory for all the arguments that needs to
> >>>> +     * be passed to BL31
> >>>> +     */
> >>>> +    memset(&bl31_params_mem, 0, sizeof(struct
> >>>> bl2_to_bl31_params_mem_t));
> >>>> +
> >>>> +    /* Assign memory for TF related information */
> >>>> +    bl2_to_bl31_params = &bl31_params_mem.bl31_params;
> >>>> +    SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
> >>>> +
> >>>> +    /* Fill BL31 related information */
> >>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info,
> >>>> PARAM_IMAGE_BINARY,
> >>>> +               VERSION_1, 0);
> >>>> +
> >>>> +    /* Fill BL32 related information if it exists */
> >>>> +#ifdef BL32_BASE
> >>>> +    bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
> >>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
> >>>> +               VERSION_1, 0);
> >>>> +    bl2_to_bl31_params->bl32_image_info =
> >>>> &bl31_params_mem.bl32_image_info;
> >>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info,
> >>>> PARAM_IMAGE_BINARY,
> >>>> +               VERSION_1, 0);
> >>>> +#endif /* BL32_BASE */
> >>> Is this used?
> >>
> >> Not use for me now, but it may useful later, because we need to fill
> >> info about bl32 if there is.
> >
> > I think that make sense to look at fit format and try to integrate all
> > these stuff together.
> >
> >
> >>>
> >>>> +
> >>>> +    /* Fill BL33 related information */
> >>>> +    bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
> >>>> +    bl33_ep_info = &bl31_params_mem.bl33_ep_info;
> >>>> +    SET_PARAM_HEAD(bl33_ep_info, PARAM_EP, VERSION_1, EP_NON_SECURE);
> >>>> +
> >>>> +    /* BL33 expects to receive the primary CPU MPID (through x0) */
> >>>> +    bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
> >>>> +    bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE;
> >>>> +    bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
> >>>> +                     DISABLE_ALL_EXECPTIONS);
> >>>> +
> >>>> +    bl2_to_bl31_params->bl33_image_info =
> >>>> &bl31_params_mem.bl33_image_info;
> >>>> +    SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info,
> >>>> PARAM_IMAGE_BINARY,
> >>>> +               VERSION_1, 0);
> >>>> +
> >>>> +
> >>> double lines.
> >>
> >> Will fix in next patch, confuse why checkpatch did not find this.
> >>>
> >>>> +    return bl2_to_bl31_params;
> >>>> +}
> >>>> +
> >>>> +void raw_write_daif(uint32_t daif)
> >>>> +{
> >>>> +    __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
> >>>> +}
> >>>> +
> >>>> +void bl31_entry(void)
> >>>> +{
> >>>> +    struct bl31_params_t *bl31_params;
> >>>> +    void (*entry)(struct bl31_params_t *params, void *plat_params) =
> >>>> NULL;
> >>>> +
> >>>> +    bl31_params = bl2_plat_get_bl31_params();
> >>>> +    entry = (void *)CONFIG_SPL_ATF_TEXT_BASE;
> >>>> +
> >>>> +    raw_write_daif(SPSR_EXCEPTION_MASK);
> >>>> +    dcache_disable();
> >>>> +
> >>>> +    entry(bl31_params, NULL);
> >>>> +}
> >>>> diff --git a/include/atf_common.h b/include/atf_common.h
> >>>> new file mode 100644
> >>>> index 0000000..8351302
> >>>> --- /dev/null
> >>>> +++ b/include/atf_common.h
> >>>> @@ -0,0 +1,295 @@
> >>>> +/*
> >>>> + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights
> >>>> reserved.
> >>>> + *
> >>>> + * Redistribution and use in source and binary forms, with or without
> >>>> + * modification, are permitted provided that the following
> >>>> conditions are met:
> >>>> + *
> >>>> + * Redistributions of source code must retain the above copyright
> >>>> notice, this
> >>>> + * list of conditions and the following disclaimer.
> >>>> + *
> >>>> + * Redistributions in binary form must reproduce the above copyright
> >>>> notice,
> >>>> + * this list of conditions and the following disclaimer in the
> >>>> documentation
> >>>> + * and/or other materials provided with the distribution.
> >>>> + *
> >>>> + * Neither the name of ARM nor the names of its contributors may be
> >>>> used
> >>>> + * to endorse or promote products derived from this software without
> >>>> specific
> >>>> + * prior written permission.
> >>>> + *
> >>>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> >>>> CONTRIBUTORS "AS IS"
> >>>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
> >>>> TO, THE
> >>>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> >>>> PARTICULAR PURPOSE
> >>>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> >>>> CONTRIBUTORS BE
> >>>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> >>>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> >>>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
> >>>> BUSINESS
> >>>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> >>>> WHETHER IN
> >>>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
> >>>> OTHERWISE)
> >>>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
> >>>> ADVISED OF THE
> >>>> + * POSSIBILITY OF SUCH DAMAGE.
> >>> This should be probably in SPDX format.
> >>
> >> Like previous reply, I don't know how to deal with this license, do you
> >> mean I can use
> >> SPDX license without any information about the origin License?
> >
> > Tom, Simon: Please correct me if I am wrong.
> > There are 2 things here.
> >
> > 0. Identify license and especially this part. The rest looks like BSD
> > license
> >
> > * Neither the name of ARM nor the names of its contributors may be used
> > * to endorse or promote products derived from this software without specific
> > * prior written permission.
> >
> > 1. If this ARM license is compatible with u-boot Licensing model
> > 2. We have Licenses folder where License can go but not sure if only
> > SPDX licenses can got there and if ARM published this license there to
> > have official SPDX tag. Please look at Licenses/README
> 
> Perhaps we need to get this licence registered with SPDX?
> 
> https://spdx.org/spdx-license-list/request-new-license
> 
> But it would be better to get that piece removed somehow. It makes a
> non-standard license. Failing that, add a new licence:
> 
> 1. Add to Licenses directory with a suitable identifier (see for
> example commit 0f4d2f8e)
> 2. Submit a new license registration request

For both license questions, we must be correct.  The copy of ATF that I
just looked at has a 3 clause BSD license, with the 3rd clause worded
perhaps oddly, but, that looks right for 3-clause BSD.  This is
compatible with U-Boot.  If on the other hand ATF has some data
structures/etc that non-ATF code really needs to know and it is not
BSD-3-Clause, we should perhaps try and contact someone with the
authority to re-license it, using include/android_image.h as an example
of where U-Boot hosts, officially, this kind of information in a more
permissible license.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170128/b4b9927a/attachment.sig>

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-01-28 21:55 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-29 10:25 [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Kever Yang
2016-12-29 10:25 ` [U-Boot] [RFC PATCH 1/3] arm64: rk3399: add SPL support Kever Yang
2017-01-13  2:11   ` Simon Glass
2016-12-29 10:25 ` [U-Boot] [RFC PATCH 2/3] arm64: rk3399: add ddr controller driver Kever Yang
2017-01-13  2:18   ` Simon Glass
2017-01-18  9:55     ` Kever Yang
2016-12-29 10:25 ` [U-Boot] [RFC PATCH 3/3] spl: add support to booting with ATF Kever Yang
2017-01-02 15:05   ` Michal Simek
2017-01-06  7:09     ` Kever Yang
2017-01-06  7:55       ` Michal Simek
2017-01-26 14:23         ` Simon Glass
2017-01-28 21:55           ` Tom Rini
2017-01-18 12:20   ` Kever Yang
2017-01-02 15:05 ` [U-Boot] [RFC PATCH 0/3] arm64: rk3399: enable SPL with ATF support Michal Simek
2017-01-06  7:11   ` Kever Yang

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.