]> git.baikalelectronics.ru Git - uboot.git/commitdiff
ddr: imx: Add i.MX9 DDR controller driver
authorYe Li <ye.li@nxp.com>
Tue, 26 Jul 2022 08:41:07 +0000 (16:41 +0800)
committerStefano Babic <sbabic@denx.de>
Tue, 26 Jul 2022 09:29:01 +0000 (11:29 +0200)
Since i.MX9 uses same DDR PHY with i.MX8M, split the DDRPHY to a common
directory under imx, then use dedicated ddr controller driver for each
iMX9 and iMX8M.

The DDRPHY registers are space compressed, so it needs conversion to
access the DDRPHY address. Introduce a common PHY address remap function
for both iMX8M and iMX9 for all PHY registers accessing.

Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
19 files changed:
arch/arm/include/asm/arch-imx8m/ddr.h
arch/arm/include/asm/arch-imx9/ddr.h [new file with mode: 0644]
drivers/Makefile
drivers/ddr/imx/Kconfig
drivers/ddr/imx/imx8m/Kconfig
drivers/ddr/imx/imx8m/Makefile
drivers/ddr/imx/imx8m/ddr_init.c
drivers/ddr/imx/imx8m/ddrphy_csr.c [deleted file]
drivers/ddr/imx/imx8m/ddrphy_train.c [deleted file]
drivers/ddr/imx/imx8m/helper.c [deleted file]
drivers/ddr/imx/imx9/Kconfig [new file with mode: 0644]
drivers/ddr/imx/imx9/Makefile [new file with mode: 0644]
drivers/ddr/imx/imx9/ddr_init.c [new file with mode: 0644]
drivers/ddr/imx/phy/Kconfig [new file with mode: 0644]
drivers/ddr/imx/phy/Makefile [new file with mode: 0644]
drivers/ddr/imx/phy/ddrphy_csr.c [new file with mode: 0644]
drivers/ddr/imx/phy/ddrphy_train.c [new file with mode: 0644]
drivers/ddr/imx/phy/ddrphy_utils.c [new file with mode: 0644]
drivers/ddr/imx/phy/helper.c [new file with mode: 0644]

index 2ce8a8f2d41665e572d336d494f909f74de733a5..2f76e7d69b9c4e30481789d9f5352e64c5e9935c 100644 (file)
@@ -725,6 +725,8 @@ void update_umctl2_rank_space_setting(unsigned int pstat_num);
 void get_trained_CDD(unsigned int fsp);
 unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr);
 
+ulong ddrphy_addr_remap(uint32_t paddr_apb_from_ctlr);
+
 static inline void reg32_write(unsigned long addr, u32 val)
 {
        writel(val, addr);
@@ -741,9 +743,9 @@ static inline void reg32setbit(unsigned long addr, u32 bit)
 }
 
 #define dwc_ddrphy_apb_wr(addr, data) \
-       reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * (addr), data)
+       reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(addr), data)
 #define dwc_ddrphy_apb_rd(addr) \
-       reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * (addr))
+       reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(addr))
 
 extern struct dram_cfg_param ddrphy_trained_csr[];
 extern uint32_t ddrphy_trained_csr_num;
diff --git a/arch/arm/include/asm/arch-imx9/ddr.h b/arch/arm/include/asm/arch-imx9/ddr.h
new file mode 100644 (file)
index 0000000..62e6f7d
--- /dev/null
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022 NXP
+ */
+
+#ifndef __ASM_ARCH_IMX8M_DDR_H
+#define __ASM_ARCH_IMX8M_DDR_H
+
+#include <asm/io.h>
+#include <asm/types.h>
+
+#define DDR_CTL_BASE                   0x4E300000
+#define DDR_PHY_BASE                   0x4E100000
+#define DDRMIX_BLK_CTRL_BASE           0x4E010000
+
+#define REG_DDRDSR_2                   (DDR_CTL_BASE + 0xB24)
+#define REG_DDR_SDRAM_CFG              (DDR_CTL_BASE + 0x110)
+#define REG_DDR_DEBUG_19               (DDR_CTL_BASE + 0xF48)
+
+#define SRC_BASE_ADDR                  (0x44460000)
+#define SRC_DPHY_BASE_ADDR             (SRC_BASE_ADDR + 0x1400)
+#define REG_SRC_DPHY_SW_CTRL           (SRC_DPHY_BASE_ADDR + 0x20)
+#define REG_SRC_DPHY_SINGLE_RESET_SW_CTRL      (SRC_DPHY_BASE_ADDR + 0x24)
+
+#define IP2APB_DDRPHY_IPS_BASE_ADDR(X) (DDR_PHY_BASE + ((X) * 0x2000000))
+#define DDRPHY_MEM(X)                  (DDR_PHY_BASE + ((X) * 0x2000000) + 0x50000)
+
+/* PHY State */
+enum pstate {
+       PS0,
+       PS1,
+       PS2,
+       PS3,
+};
+
+enum msg_response {
+       TRAIN_SUCCESS = 0x7,
+       TRAIN_STREAM_START = 0x8,
+       TRAIN_FAIL = 0xff,
+};
+
+/* user data type */
+enum fw_type {
+       FW_1D_IMAGE,
+       FW_2D_IMAGE,
+};
+
+struct dram_cfg_param {
+       unsigned int reg;
+       unsigned int val;
+};
+
+struct dram_fsp_msg {
+       unsigned int drate;
+       enum fw_type fw_type;
+       struct dram_cfg_param *fsp_cfg;
+       unsigned int fsp_cfg_num;
+};
+
+struct dram_timing_info {
+       /* umctl2 config */
+       struct dram_cfg_param *ddrc_cfg;
+       unsigned int ddrc_cfg_num;
+       /* ddrphy config */
+       struct dram_cfg_param *ddrphy_cfg;
+       unsigned int ddrphy_cfg_num;
+       /* ddr fsp train info */
+       struct dram_fsp_msg *fsp_msg;
+       unsigned int fsp_msg_num;
+       /* ddr phy trained CSR */
+       struct dram_cfg_param *ddrphy_trained_csr;
+       unsigned int ddrphy_trained_csr_num;
+       /* ddr phy PIE */
+       struct dram_cfg_param *ddrphy_pie;
+       unsigned int ddrphy_pie_num;
+       /* initialized drate table */
+       unsigned int fsp_table[4];
+};
+
+extern struct dram_timing_info dram_timing;
+
+void ddr_load_train_firmware(enum fw_type type);
+int ddr_init(struct dram_timing_info *timing_info);
+int ddr_cfg_phy(struct dram_timing_info *timing_info);
+void load_lpddr4_phy_pie(void);
+void ddrphy_trained_csr_save(struct dram_cfg_param *param, unsigned int num);
+void dram_config_save(struct dram_timing_info *info, unsigned long base);
+void board_dram_ecc_scrub(void);
+void ddrc_inline_ecc_scrub(unsigned int start_address,
+                          unsigned int range_address);
+void ddrc_inline_ecc_scrub_end(unsigned int start_address,
+                              unsigned int range_address);
+
+/* utils function for ddr phy training */
+int wait_ddrphy_training_complete(void);
+void ddrphy_init_set_dfi_clk(unsigned int drate);
+void ddrphy_init_read_msg_block(enum fw_type type);
+
+void get_trained_CDD(unsigned int fsp);
+
+ulong ddrphy_addr_remap(u32 paddr_apb_from_ctlr);
+
+static inline void reg32_write(unsigned long addr, u32 val)
+{
+       writel(val, addr);
+}
+
+static inline u32 reg32_read(unsigned long addr)
+{
+       return readl(addr);
+}
+
+static inline void reg32setbit(unsigned long addr, u32 bit)
+{
+       setbits_le32(addr, (1 << bit));
+}
+
+#define dwc_ddrphy_apb_wr(addr, data) \
+       reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(addr), data)
+#define dwc_ddrphy_apb_rd(addr) \
+       reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(addr))
+
+extern struct dram_cfg_param ddrphy_trained_csr[];
+extern u32 ddrphy_trained_csr_num;
+
+#endif
index d63fd1c04d1140bb80e025946113c9425bf10df3..eba9940231f9c925ca39d9999fcc2b5bcbe6e6dc 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/
 obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/
 obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/
 obj-$(CONFIG_IMX8ULP_DRAM) += ddr/imx/imx8ulp/
+obj-$(CONFIG_ARCH_IMX9) += ddr/imx/imx9/
 obj-$(CONFIG_SPL_DM_RESET) += reset/
 obj-$(CONFIG_SPL_MUSB_NEW) += usb/musb-new/
 obj-$(CONFIG_SPL_USB_GADGET) += usb/gadget/
index 179f34530d794a4e03c2622f9c83e38fc5607671..328fbabb6db1bee8c79b7308f44f8708de8a6d17 100644 (file)
@@ -1,2 +1,4 @@
 source "drivers/ddr/imx/imx8m/Kconfig"
 source "drivers/ddr/imx/imx8ulp/Kconfig"
+source "drivers/ddr/imx/imx9/Kconfig"
+source "drivers/ddr/imx/phy/Kconfig"
index a90b7db4940cf0246b2d1d66fc3cee4d7017ba2e..08b6787a54311d27265c0bbcc6d347ae1d9998f3 100644 (file)
@@ -3,6 +3,7 @@ menu "i.MX8M DDR controllers"
 
 config IMX8M_DRAM
        bool "imx8m dram"
+       select IMX_SNPS_DDR_PHY
 
 config IMX8M_LPDDR4
        bool "imx8m lpddr4"
index bd9bcb8d53bccb5a093913a7f7015823c11c1099..aed91dc23f4bdff29b8e4f7302795da7c340d7ba 100644 (file)
@@ -5,5 +5,6 @@
 #
 
 ifdef CONFIG_SPL_BUILD
-obj-$(CONFIG_IMX8M_DRAM) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o ddr_init.o
+obj-$(CONFIG_IMX8M_DRAM) += ddr_init.o
+obj-y += ../phy/
 endif
index b70bcc383fa7d57a4b5151e5201e416c99278b62..d964184ddc8d070588158591d355c29ac494fbcb 100644 (file)
 #include <asm/arch/clock.h>
 #include <asm/arch/sys_proto.h>
 
+static unsigned int g_cdd_rr_max[4];
+static unsigned int g_cdd_rw_max[4];
+static unsigned int g_cdd_wr_max[4];
+static unsigned int g_cdd_ww_max[4];
+
 void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
 {
        int i = 0;
@@ -91,6 +96,215 @@ void __weak board_dram_ecc_scrub(void)
 {
 }
 
+void lpddr4_mr_write(unsigned int mr_rank, unsigned int mr_addr,
+                    unsigned int mr_data)
+{
+       unsigned int tmp;
+       /*
+        * 1. Poll MRSTAT.mr_wr_busy until it is 0.
+        * This checks that there is no outstanding MR transaction.
+        * No writes should be performed to MRCTRL0 and MRCTRL1 if
+        * MRSTAT.mr_wr_busy = 1.
+        */
+       do {
+               tmp = reg32_read(DDRC_MRSTAT(0));
+       } while (tmp & 0x1);
+       /*
+        * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank and
+        * (for MRWs) MRCTRL1.mr_data to define the MR transaction.
+        */
+       reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4));
+       reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data);
+       reg32setbit(DDRC_MRCTRL0(0), 31);
+}
+
+unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr)
+{
+       unsigned int tmp;
+
+       reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1);
+       do {
+               tmp = reg32_read(DDRC_MRSTAT(0));
+       } while (tmp & 0x1);
+
+       reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1);
+       reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8));
+       reg32setbit(DDRC_MRCTRL0(0), 31);
+       do {
+               tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0));
+       } while ((tmp & 0x8) == 0);
+       tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0));
+       tmp = tmp & 0xff;
+       reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4);
+
+       return tmp;
+}
+
+static unsigned int look_for_max(unsigned int data[], unsigned int addr_start,
+                                unsigned int addr_end)
+{
+       unsigned int i, imax = 0;
+
+       for (i = addr_start; i <= addr_end; i++) {
+               if (((data[i] >> 7) == 0) && data[i] > imax)
+                       imax = data[i];
+       }
+
+       return imax;
+}
+
+void get_trained_CDD(u32 fsp)
+{
+       unsigned int i, ddr_type, tmp;
+       unsigned int cdd_cha[12], cdd_chb[12];
+       unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max;
+       unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max;
+
+       ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
+       if (ddr_type == 0x20) {
+               for (i = 0; i < 6; i++) {
+                       tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54013 + i) * 4);
+                       cdd_cha[i * 2] = tmp & 0xff;
+                       cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
+               }
+
+               for (i = 0; i < 7; i++) {
+                       tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x5402c + i) * 4);
+                       if (i == 0) {
+                               cdd_cha[0] = (tmp >> 8) & 0xff;
+                       } else if (i == 6) {
+                               cdd_cha[11] = tmp & 0xff;
+                       } else {
+                               cdd_chb[i * 2 - 1] = tmp & 0xff;
+                               cdd_chb[i * 2] = (tmp >> 8) & 0xff;
+                       }
+               }
+
+               cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1);
+               cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5);
+               cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9);
+               cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11);
+               cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1);
+               cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5);
+               cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9);
+               cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11);
+               g_cdd_rr_max[fsp] =
+                       cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max;
+               g_cdd_rw_max[fsp] =
+                       cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max;
+               g_cdd_wr_max[fsp] =
+                       cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max;
+               g_cdd_ww_max[fsp] =
+                       cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max;
+       } else {
+               unsigned int ddr4_cdd[64];
+
+               for (i = 0; i < 29; i++) {
+                       tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54012 + i) * 4);
+                       ddr4_cdd[i * 2] = tmp & 0xff;
+                       ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff;
+               }
+
+               g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12);
+               g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24);
+               g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40);
+               g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56);
+       }
+}
+
+void update_umctl2_rank_space_setting(unsigned int pstat_num)
+{
+       unsigned int i, ddr_type;
+       unsigned int addr_slot, rdata, tmp, tmp_t;
+       unsigned int ddrc_w2r, ddrc_r2w, ddrc_wr_gap, ddrc_rd_gap;
+
+       ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
+       for (i = 0; i < pstat_num; i++) {
+               addr_slot = i ? (i + 1) * 0x1000 : 0;
+               if (ddr_type == 0x20) {
+                       /* update r2w:[13:8], w2r:[5:0] */
+                       rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
+                       ddrc_w2r = rdata & 0x3f;
+                       if (is_imx8mp())
+                               tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
+                       else
+                               tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
+                       ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
+
+                       ddrc_r2w = (rdata >> 8) & 0x3f;
+                       if (is_imx8mp())
+                               tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
+                       else
+                               tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
+                       ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
+
+                       tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r;
+                       reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
+               } else {
+                       /* update w2r:[5:0] */
+                       rdata = reg32_read(DDRC_DRAMTMG9(0) + addr_slot);
+                       ddrc_w2r = rdata & 0x3f;
+                       if (is_imx8mp())
+                               tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
+                       else
+                               tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
+                       ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
+                       tmp_t = (rdata & 0xffffffc0) | ddrc_w2r;
+                       reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t);
+
+                       /* update r2w:[13:8] */
+                       rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
+                       ddrc_r2w = (rdata >> 8) & 0x3f;
+                       if (is_imx8mp())
+                               tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
+                       else
+                               tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
+                       ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
+
+                       tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8);
+                       reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
+               }
+
+               if (!is_imx8mq()) {
+                       /*
+                        * update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static)
+                        */
+                       rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot);
+                       ddrc_wr_gap = (rdata >> 8) & 0xf;
+                       if (is_imx8mp())
+                               tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1);
+                       else
+                               tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1;
+                       ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
+
+                       ddrc_rd_gap = (rdata >> 4) & 0xf;
+                       if (is_imx8mp())
+                               tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1);
+                       else
+                               tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1;
+                       ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
+
+                       tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
+                       reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t);
+               }
+       }
+
+       if (is_imx8mq()) {
+               /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
+               rdata = reg32_read(DDRC_RANKCTL(0));
+               ddrc_wr_gap = (rdata >> 8) & 0xf;
+               tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1;
+               ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
+
+               ddrc_rd_gap = (rdata >> 4) & 0xf;
+               tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1;
+               ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
+
+               tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
+               reg32_write(DDRC_RANKCTL(0), tmp_t);
+       }
+}
+
 int ddr_init(struct dram_timing_info *dram_timing)
 {
        unsigned int tmp, initial_drate, target_freq;
@@ -250,3 +464,8 @@ int ddr_init(struct dram_timing_info *dram_timing)
 
        return 0;
 }
+
+ulong ddrphy_addr_remap(uint32_t paddr_apb_from_ctlr)
+{
+       return 4 * paddr_apb_from_ctlr;
+}
diff --git a/drivers/ddr/imx/imx8m/ddrphy_csr.c b/drivers/ddr/imx/imx8m/ddrphy_csr.c
deleted file mode 100644 (file)
index 67dd4e7..0000000
+++ /dev/null
@@ -1,732 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2018 NXP
- */
-
-#include <linux/kernel.h>
-#include <asm/arch/ddr.h>
-
-/* ddr phy trained csr */
-struct dram_cfg_param ddrphy_trained_csr[] = {
-       { 0x200b2, 0x0 },
-       { 0x1200b2, 0x0 },
-       { 0x2200b2, 0x0 },
-       { 0x200cb, 0x0 },
-       { 0x10043, 0x0 },
-       { 0x110043, 0x0 },
-       { 0x210043, 0x0 },
-       { 0x10143, 0x0 },
-       { 0x110143, 0x0 },
-       { 0x210143, 0x0 },
-       { 0x11043, 0x0 },
-       { 0x111043, 0x0 },
-       { 0x211043, 0x0 },
-       { 0x11143, 0x0 },
-       { 0x111143, 0x0 },
-       { 0x211143, 0x0 },
-       { 0x12043, 0x0 },
-       { 0x112043, 0x0 },
-       { 0x212043, 0x0 },
-       { 0x12143, 0x0 },
-       { 0x112143, 0x0 },
-       { 0x212143, 0x0 },
-       { 0x13043, 0x0 },
-       { 0x113043, 0x0 },
-       { 0x213043, 0x0 },
-       { 0x13143, 0x0 },
-       { 0x113143, 0x0 },
-       { 0x213143, 0x0 },
-       { 0x80, 0x0 },
-       { 0x100080, 0x0 },
-       { 0x200080, 0x0 },
-       { 0x1080, 0x0 },
-       { 0x101080, 0x0 },
-       { 0x201080, 0x0 },
-       { 0x2080, 0x0 },
-       { 0x102080, 0x0 },
-       { 0x202080, 0x0 },
-       { 0x3080, 0x0 },
-       { 0x103080, 0x0 },
-       { 0x203080, 0x0 },
-       { 0x4080, 0x0 },
-       { 0x104080, 0x0 },
-       { 0x204080, 0x0 },
-       { 0x5080, 0x0 },
-       { 0x105080, 0x0 },
-       { 0x205080, 0x0 },
-       { 0x6080, 0x0 },
-       { 0x106080, 0x0 },
-       { 0x206080, 0x0 },
-       { 0x7080, 0x0 },
-       { 0x107080, 0x0 },
-       { 0x207080, 0x0 },
-       { 0x8080, 0x0 },
-       { 0x108080, 0x0 },
-       { 0x208080, 0x0 },
-       { 0x9080, 0x0 },
-       { 0x109080, 0x0 },
-       { 0x209080, 0x0 },
-       { 0x10080, 0x0 },
-       { 0x110080, 0x0 },
-       { 0x210080, 0x0 },
-       { 0x10180, 0x0 },
-       { 0x110180, 0x0 },
-       { 0x210180, 0x0 },
-       { 0x11080, 0x0 },
-       { 0x111080, 0x0 },
-       { 0x211080, 0x0 },
-       { 0x11180, 0x0 },
-       { 0x111180, 0x0 },
-       { 0x211180, 0x0 },
-       { 0x12080, 0x0 },
-       { 0x112080, 0x0 },
-       { 0x212080, 0x0 },
-       { 0x12180, 0x0 },
-       { 0x112180, 0x0 },
-       { 0x212180, 0x0 },
-       { 0x13080, 0x0 },
-       { 0x113080, 0x0 },
-       { 0x213080, 0x0 },
-       { 0x13180, 0x0 },
-       { 0x113180, 0x0 },
-       { 0x213180, 0x0 },
-       { 0x10081, 0x0 },
-       { 0x110081, 0x0 },
-       { 0x210081, 0x0 },
-       { 0x10181, 0x0 },
-       { 0x110181, 0x0 },
-       { 0x210181, 0x0 },
-       { 0x11081, 0x0 },
-       { 0x111081, 0x0 },
-       { 0x211081, 0x0 },
-       { 0x11181, 0x0 },
-       { 0x111181, 0x0 },
-       { 0x211181, 0x0 },
-       { 0x12081, 0x0 },
-       { 0x112081, 0x0 },
-       { 0x212081, 0x0 },
-       { 0x12181, 0x0 },
-       { 0x112181, 0x0 },
-       { 0x212181, 0x0 },
-       { 0x13081, 0x0 },
-       { 0x113081, 0x0 },
-       { 0x213081, 0x0 },
-       { 0x13181, 0x0 },
-       { 0x113181, 0x0 },
-       { 0x213181, 0x0 },
-       { 0x100d0, 0x0 },
-       { 0x1100d0, 0x0 },
-       { 0x2100d0, 0x0 },
-       { 0x101d0, 0x0 },
-       { 0x1101d0, 0x0 },
-       { 0x2101d0, 0x0 },
-       { 0x110d0, 0x0 },
-       { 0x1110d0, 0x0 },
-       { 0x2110d0, 0x0 },
-       { 0x111d0, 0x0 },
-       { 0x1111d0, 0x0 },
-       { 0x2111d0, 0x0 },
-       { 0x120d0, 0x0 },
-       { 0x1120d0, 0x0 },
-       { 0x2120d0, 0x0 },
-       { 0x121d0, 0x0 },
-       { 0x1121d0, 0x0 },
-       { 0x2121d0, 0x0 },
-       { 0x130d0, 0x0 },
-       { 0x1130d0, 0x0 },
-       { 0x2130d0, 0x0 },
-       { 0x131d0, 0x0 },
-       { 0x1131d0, 0x0 },
-       { 0x2131d0, 0x0 },
-       { 0x100d1, 0x0 },
-       { 0x1100d1, 0x0 },
-       { 0x2100d1, 0x0 },
-       { 0x101d1, 0x0 },
-       { 0x1101d1, 0x0 },
-       { 0x2101d1, 0x0 },
-       { 0x110d1, 0x0 },
-       { 0x1110d1, 0x0 },
-       { 0x2110d1, 0x0 },
-       { 0x111d1, 0x0 },
-       { 0x1111d1, 0x0 },
-       { 0x2111d1, 0x0 },
-       { 0x120d1, 0x0 },
-       { 0x1120d1, 0x0 },
-       { 0x2120d1, 0x0 },
-       { 0x121d1, 0x0 },
-       { 0x1121d1, 0x0 },
-       { 0x2121d1, 0x0 },
-       { 0x130d1, 0x0 },
-       { 0x1130d1, 0x0 },
-       { 0x2130d1, 0x0 },
-       { 0x131d1, 0x0 },
-       { 0x1131d1, 0x0 },
-       { 0x2131d1, 0x0 },
-       { 0x10068, 0x0 },
-       { 0x10168, 0x0 },
-       { 0x10268, 0x0 },
-       { 0x10368, 0x0 },
-       { 0x10468, 0x0 },
-       { 0x10568, 0x0 },
-       { 0x10668, 0x0 },
-       { 0x10768, 0x0 },
-       { 0x10868, 0x0 },
-       { 0x11068, 0x0 },
-       { 0x11168, 0x0 },
-       { 0x11268, 0x0 },
-       { 0x11368, 0x0 },
-       { 0x11468, 0x0 },
-       { 0x11568, 0x0 },
-       { 0x11668, 0x0 },
-       { 0x11768, 0x0 },
-       { 0x11868, 0x0 },
-       { 0x12068, 0x0 },
-       { 0x12168, 0x0 },
-       { 0x12268, 0x0 },
-       { 0x12368, 0x0 },
-       { 0x12468, 0x0 },
-       { 0x12568, 0x0 },
-       { 0x12668, 0x0 },
-       { 0x12768, 0x0 },
-       { 0x12868, 0x0 },
-       { 0x13068, 0x0 },
-       { 0x13168, 0x0 },
-       { 0x13268, 0x0 },
-       { 0x13368, 0x0 },
-       { 0x13468, 0x0 },
-       { 0x13568, 0x0 },
-       { 0x13668, 0x0 },
-       { 0x13768, 0x0 },
-       { 0x13868, 0x0 },
-       { 0x10069, 0x0 },
-       { 0x10169, 0x0 },
-       { 0x10269, 0x0 },
-       { 0x10369, 0x0 },
-       { 0x10469, 0x0 },
-       { 0x10569, 0x0 },
-       { 0x10669, 0x0 },
-       { 0x10769, 0x0 },
-       { 0x10869, 0x0 },
-       { 0x11069, 0x0 },
-       { 0x11169, 0x0 },
-       { 0x11269, 0x0 },
-       { 0x11369, 0x0 },
-       { 0x11469, 0x0 },
-       { 0x11569, 0x0 },
-       { 0x11669, 0x0 },
-       { 0x11769, 0x0 },
-       { 0x11869, 0x0 },
-       { 0x12069, 0x0 },
-       { 0x12169, 0x0 },
-       { 0x12269, 0x0 },
-       { 0x12369, 0x0 },
-       { 0x12469, 0x0 },
-       { 0x12569, 0x0 },
-       { 0x12669, 0x0 },
-       { 0x12769, 0x0 },
-       { 0x12869, 0x0 },
-       { 0x13069, 0x0 },
-       { 0x13169, 0x0 },
-       { 0x13269, 0x0 },
-       { 0x13369, 0x0 },
-       { 0x13469, 0x0 },
-       { 0x13569, 0x0 },
-       { 0x13669, 0x0 },
-       { 0x13769, 0x0 },
-       { 0x13869, 0x0 },
-       { 0x1008c, 0x0 },
-       { 0x11008c, 0x0 },
-       { 0x21008c, 0x0 },
-       { 0x1018c, 0x0 },
-       { 0x11018c, 0x0 },
-       { 0x21018c, 0x0 },
-       { 0x1108c, 0x0 },
-       { 0x11108c, 0x0 },
-       { 0x21108c, 0x0 },
-       { 0x1118c, 0x0 },
-       { 0x11118c, 0x0 },
-       { 0x21118c, 0x0 },
-       { 0x1208c, 0x0 },
-       { 0x11208c, 0x0 },
-       { 0x21208c, 0x0 },
-       { 0x1218c, 0x0 },
-       { 0x11218c, 0x0 },
-       { 0x21218c, 0x0 },
-       { 0x1308c, 0x0 },
-       { 0x11308c, 0x0 },
-       { 0x21308c, 0x0 },
-       { 0x1318c, 0x0 },
-       { 0x11318c, 0x0 },
-       { 0x21318c, 0x0 },
-       { 0x1008d, 0x0 },
-       { 0x11008d, 0x0 },
-       { 0x21008d, 0x0 },
-       { 0x1018d, 0x0 },
-       { 0x11018d, 0x0 },
-       { 0x21018d, 0x0 },
-       { 0x1108d, 0x0 },
-       { 0x11108d, 0x0 },
-       { 0x21108d, 0x0 },
-       { 0x1118d, 0x0 },
-       { 0x11118d, 0x0 },
-       { 0x21118d, 0x0 },
-       { 0x1208d, 0x0 },
-       { 0x11208d, 0x0 },
-       { 0x21208d, 0x0 },
-       { 0x1218d, 0x0 },
-       { 0x11218d, 0x0 },
-       { 0x21218d, 0x0 },
-       { 0x1308d, 0x0 },
-       { 0x11308d, 0x0 },
-       { 0x21308d, 0x0 },
-       { 0x1318d, 0x0 },
-       { 0x11318d, 0x0 },
-       { 0x21318d, 0x0 },
-       { 0x100c0, 0x0 },
-       { 0x1100c0, 0x0 },
-       { 0x2100c0, 0x0 },
-       { 0x101c0, 0x0 },
-       { 0x1101c0, 0x0 },
-       { 0x2101c0, 0x0 },
-       { 0x102c0, 0x0 },
-       { 0x1102c0, 0x0 },
-       { 0x2102c0, 0x0 },
-       { 0x103c0, 0x0 },
-       { 0x1103c0, 0x0 },
-       { 0x2103c0, 0x0 },
-       { 0x104c0, 0x0 },
-       { 0x1104c0, 0x0 },
-       { 0x2104c0, 0x0 },
-       { 0x105c0, 0x0 },
-       { 0x1105c0, 0x0 },
-       { 0x2105c0, 0x0 },
-       { 0x106c0, 0x0 },
-       { 0x1106c0, 0x0 },
-       { 0x2106c0, 0x0 },
-       { 0x107c0, 0x0 },
-       { 0x1107c0, 0x0 },
-       { 0x2107c0, 0x0 },
-       { 0x108c0, 0x0 },
-       { 0x1108c0, 0x0 },
-       { 0x2108c0, 0x0 },
-       { 0x110c0, 0x0 },
-       { 0x1110c0, 0x0 },
-       { 0x2110c0, 0x0 },
-       { 0x111c0, 0x0 },
-       { 0x1111c0, 0x0 },
-       { 0x2111c0, 0x0 },
-       { 0x112c0, 0x0 },
-       { 0x1112c0, 0x0 },
-       { 0x2112c0, 0x0 },
-       { 0x113c0, 0x0 },
-       { 0x1113c0, 0x0 },
-       { 0x2113c0, 0x0 },
-       { 0x114c0, 0x0 },
-       { 0x1114c0, 0x0 },
-       { 0x2114c0, 0x0 },
-       { 0x115c0, 0x0 },
-       { 0x1115c0, 0x0 },
-       { 0x2115c0, 0x0 },
-       { 0x116c0, 0x0 },
-       { 0x1116c0, 0x0 },
-       { 0x2116c0, 0x0 },
-       { 0x117c0, 0x0 },
-       { 0x1117c0, 0x0 },
-       { 0x2117c0, 0x0 },
-       { 0x118c0, 0x0 },
-       { 0x1118c0, 0x0 },
-       { 0x2118c0, 0x0 },
-       { 0x120c0, 0x0 },
-       { 0x1120c0, 0x0 },
-       { 0x2120c0, 0x0 },
-       { 0x121c0, 0x0 },
-       { 0x1121c0, 0x0 },
-       { 0x2121c0, 0x0 },
-       { 0x122c0, 0x0 },
-       { 0x1122c0, 0x0 },
-       { 0x2122c0, 0x0 },
-       { 0x123c0, 0x0 },
-       { 0x1123c0, 0x0 },
-       { 0x2123c0, 0x0 },
-       { 0x124c0, 0x0 },
-       { 0x1124c0, 0x0 },
-       { 0x2124c0, 0x0 },
-       { 0x125c0, 0x0 },
-       { 0x1125c0, 0x0 },
-       { 0x2125c0, 0x0 },
-       { 0x126c0, 0x0 },
-       { 0x1126c0, 0x0 },
-       { 0x2126c0, 0x0 },
-       { 0x127c0, 0x0 },
-       { 0x1127c0, 0x0 },
-       { 0x2127c0, 0x0 },
-       { 0x128c0, 0x0 },
-       { 0x1128c0, 0x0 },
-       { 0x2128c0, 0x0 },
-       { 0x130c0, 0x0 },
-       { 0x1130c0, 0x0 },
-       { 0x2130c0, 0x0 },
-       { 0x131c0, 0x0 },
-       { 0x1131c0, 0x0 },
-       { 0x2131c0, 0x0 },
-       { 0x132c0, 0x0 },
-       { 0x1132c0, 0x0 },
-       { 0x2132c0, 0x0 },
-       { 0x133c0, 0x0 },
-       { 0x1133c0, 0x0 },
-       { 0x2133c0, 0x0 },
-       { 0x134c0, 0x0 },
-       { 0x1134c0, 0x0 },
-       { 0x2134c0, 0x0 },
-       { 0x135c0, 0x0 },
-       { 0x1135c0, 0x0 },
-       { 0x2135c0, 0x0 },
-       { 0x136c0, 0x0 },
-       { 0x1136c0, 0x0 },
-       { 0x2136c0, 0x0 },
-       { 0x137c0, 0x0 },
-       { 0x1137c0, 0x0 },
-       { 0x2137c0, 0x0 },
-       { 0x138c0, 0x0 },
-       { 0x1138c0, 0x0 },
-       { 0x2138c0, 0x0 },
-       { 0x100c1, 0x0 },
-       { 0x1100c1, 0x0 },
-       { 0x2100c1, 0x0 },
-       { 0x101c1, 0x0 },
-       { 0x1101c1, 0x0 },
-       { 0x2101c1, 0x0 },
-       { 0x102c1, 0x0 },
-       { 0x1102c1, 0x0 },
-       { 0x2102c1, 0x0 },
-       { 0x103c1, 0x0 },
-       { 0x1103c1, 0x0 },
-       { 0x2103c1, 0x0 },
-       { 0x104c1, 0x0 },
-       { 0x1104c1, 0x0 },
-       { 0x2104c1, 0x0 },
-       { 0x105c1, 0x0 },
-       { 0x1105c1, 0x0 },
-       { 0x2105c1, 0x0 },
-       { 0x106c1, 0x0 },
-       { 0x1106c1, 0x0 },
-       { 0x2106c1, 0x0 },
-       { 0x107c1, 0x0 },
-       { 0x1107c1, 0x0 },
-       { 0x2107c1, 0x0 },
-       { 0x108c1, 0x0 },
-       { 0x1108c1, 0x0 },
-       { 0x2108c1, 0x0 },
-       { 0x110c1, 0x0 },
-       { 0x1110c1, 0x0 },
-       { 0x2110c1, 0x0 },
-       { 0x111c1, 0x0 },
-       { 0x1111c1, 0x0 },
-       { 0x2111c1, 0x0 },
-       { 0x112c1, 0x0 },
-       { 0x1112c1, 0x0 },
-       { 0x2112c1, 0x0 },
-       { 0x113c1, 0x0 },
-       { 0x1113c1, 0x0 },
-       { 0x2113c1, 0x0 },
-       { 0x114c1, 0x0 },
-       { 0x1114c1, 0x0 },
-       { 0x2114c1, 0x0 },
-       { 0x115c1, 0x0 },
-       { 0x1115c1, 0x0 },
-       { 0x2115c1, 0x0 },
-       { 0x116c1, 0x0 },
-       { 0x1116c1, 0x0 },
-       { 0x2116c1, 0x0 },
-       { 0x117c1, 0x0 },
-       { 0x1117c1, 0x0 },
-       { 0x2117c1, 0x0 },
-       { 0x118c1, 0x0 },
-       { 0x1118c1, 0x0 },
-       { 0x2118c1, 0x0 },
-       { 0x120c1, 0x0 },
-       { 0x1120c1, 0x0 },
-       { 0x2120c1, 0x0 },
-       { 0x121c1, 0x0 },
-       { 0x1121c1, 0x0 },
-       { 0x2121c1, 0x0 },
-       { 0x122c1, 0x0 },
-       { 0x1122c1, 0x0 },
-       { 0x2122c1, 0x0 },
-       { 0x123c1, 0x0 },
-       { 0x1123c1, 0x0 },
-       { 0x2123c1, 0x0 },
-       { 0x124c1, 0x0 },
-       { 0x1124c1, 0x0 },
-       { 0x2124c1, 0x0 },
-       { 0x125c1, 0x0 },
-       { 0x1125c1, 0x0 },
-       { 0x2125c1, 0x0 },
-       { 0x126c1, 0x0 },
-       { 0x1126c1, 0x0 },
-       { 0x2126c1, 0x0 },
-       { 0x127c1, 0x0 },
-       { 0x1127c1, 0x0 },
-       { 0x2127c1, 0x0 },
-       { 0x128c1, 0x0 },
-       { 0x1128c1, 0x0 },
-       { 0x2128c1, 0x0 },
-       { 0x130c1, 0x0 },
-       { 0x1130c1, 0x0 },
-       { 0x2130c1, 0x0 },
-       { 0x131c1, 0x0 },
-       { 0x1131c1, 0x0 },
-       { 0x2131c1, 0x0 },
-       { 0x132c1, 0x0 },
-       { 0x1132c1, 0x0 },
-       { 0x2132c1, 0x0 },
-       { 0x133c1, 0x0 },
-       { 0x1133c1, 0x0 },
-       { 0x2133c1, 0x0 },
-       { 0x134c1, 0x0 },
-       { 0x1134c1, 0x0 },
-       { 0x2134c1, 0x0 },
-       { 0x135c1, 0x0 },
-       { 0x1135c1, 0x0 },
-       { 0x2135c1, 0x0 },
-       { 0x136c1, 0x0 },
-       { 0x1136c1, 0x0 },
-       { 0x2136c1, 0x0 },
-       { 0x137c1, 0x0 },
-       { 0x1137c1, 0x0 },
-       { 0x2137c1, 0x0 },
-       { 0x138c1, 0x0 },
-       { 0x1138c1, 0x0 },
-       { 0x2138c1, 0x0 },
-       { 0x10020, 0x0 },
-       { 0x110020, 0x0 },
-       { 0x210020, 0x0 },
-       { 0x11020, 0x0 },
-       { 0x111020, 0x0 },
-       { 0x211020, 0x0 },
-       { 0x12020, 0x0 },
-       { 0x112020, 0x0 },
-       { 0x212020, 0x0 },
-       { 0x13020, 0x0 },
-       { 0x113020, 0x0 },
-       { 0x213020, 0x0 },
-       { 0x20072, 0x0 },
-       { 0x20073, 0x0 },
-       { 0x20074, 0x0 },
-       { 0x100aa, 0x0 },
-       { 0x110aa, 0x0 },
-       { 0x120aa, 0x0 },
-       { 0x130aa, 0x0 },
-       { 0x20010, 0x0 },
-       { 0x120010, 0x0 },
-       { 0x220010, 0x0 },
-       { 0x20011, 0x0 },
-       { 0x120011, 0x0 },
-       { 0x220011, 0x0 },
-       { 0x100ae, 0x0 },
-       { 0x1100ae, 0x0 },
-       { 0x2100ae, 0x0 },
-       { 0x100af, 0x0 },
-       { 0x1100af, 0x0 },
-       { 0x2100af, 0x0 },
-       { 0x110ae, 0x0 },
-       { 0x1110ae, 0x0 },
-       { 0x2110ae, 0x0 },
-       { 0x110af, 0x0 },
-       { 0x1110af, 0x0 },
-       { 0x2110af, 0x0 },
-       { 0x120ae, 0x0 },
-       { 0x1120ae, 0x0 },
-       { 0x2120ae, 0x0 },
-       { 0x120af, 0x0 },
-       { 0x1120af, 0x0 },
-       { 0x2120af, 0x0 },
-       { 0x130ae, 0x0 },
-       { 0x1130ae, 0x0 },
-       { 0x2130ae, 0x0 },
-       { 0x130af, 0x0 },
-       { 0x1130af, 0x0 },
-       { 0x2130af, 0x0 },
-       { 0x20020, 0x0 },
-       { 0x120020, 0x0 },
-       { 0x220020, 0x0 },
-       { 0x100a0, 0x0 },
-       { 0x100a1, 0x0 },
-       { 0x100a2, 0x0 },
-       { 0x100a3, 0x0 },
-       { 0x100a4, 0x0 },
-       { 0x100a5, 0x0 },
-       { 0x100a6, 0x0 },
-       { 0x100a7, 0x0 },
-       { 0x110a0, 0x0 },
-       { 0x110a1, 0x0 },
-       { 0x110a2, 0x0 },
-       { 0x110a3, 0x0 },
-       { 0x110a4, 0x0 },
-       { 0x110a5, 0x0 },
-       { 0x110a6, 0x0 },
-       { 0x110a7, 0x0 },
-       { 0x120a0, 0x0 },
-       { 0x120a1, 0x0 },
-       { 0x120a2, 0x0 },
-       { 0x120a3, 0x0 },
-       { 0x120a4, 0x0 },
-       { 0x120a5, 0x0 },
-       { 0x120a6, 0x0 },
-       { 0x120a7, 0x0 },
-       { 0x130a0, 0x0 },
-       { 0x130a1, 0x0 },
-       { 0x130a2, 0x0 },
-       { 0x130a3, 0x0 },
-       { 0x130a4, 0x0 },
-       { 0x130a5, 0x0 },
-       { 0x130a6, 0x0 },
-       { 0x130a7, 0x0 },
-       { 0x2007c, 0x0 },
-       { 0x12007c, 0x0 },
-       { 0x22007c, 0x0 },
-       { 0x2007d, 0x0 },
-       { 0x12007d, 0x0 },
-       { 0x22007d, 0x0 },
-       { 0x400fd, 0x0 },
-       { 0x400c0, 0x0 },
-       { 0x90201, 0x0 },
-       { 0x190201, 0x0 },
-       { 0x290201, 0x0 },
-       { 0x90202, 0x0 },
-       { 0x190202, 0x0 },
-       { 0x290202, 0x0 },
-       { 0x90203, 0x0 },
-       { 0x190203, 0x0 },
-       { 0x290203, 0x0 },
-       { 0x90204, 0x0 },
-       { 0x190204, 0x0 },
-       { 0x290204, 0x0 },
-       { 0x90205, 0x0 },
-       { 0x190205, 0x0 },
-       { 0x290205, 0x0 },
-       { 0x90206, 0x0 },
-       { 0x190206, 0x0 },
-       { 0x290206, 0x0 },
-       { 0x90207, 0x0 },
-       { 0x190207, 0x0 },
-       { 0x290207, 0x0 },
-       { 0x90208, 0x0 },
-       { 0x190208, 0x0 },
-       { 0x290208, 0x0 },
-       { 0x10062, 0x0 },
-       { 0x10162, 0x0 },
-       { 0x10262, 0x0 },
-       { 0x10362, 0x0 },
-       { 0x10462, 0x0 },
-       { 0x10562, 0x0 },
-       { 0x10662, 0x0 },
-       { 0x10762, 0x0 },
-       { 0x10862, 0x0 },
-       { 0x11062, 0x0 },
-       { 0x11162, 0x0 },
-       { 0x11262, 0x0 },
-       { 0x11362, 0x0 },
-       { 0x11462, 0x0 },
-       { 0x11562, 0x0 },
-       { 0x11662, 0x0 },
-       { 0x11762, 0x0 },
-       { 0x11862, 0x0 },
-       { 0x12062, 0x0 },
-       { 0x12162, 0x0 },
-       { 0x12262, 0x0 },
-       { 0x12362, 0x0 },
-       { 0x12462, 0x0 },
-       { 0x12562, 0x0 },
-       { 0x12662, 0x0 },
-       { 0x12762, 0x0 },
-       { 0x12862, 0x0 },
-       { 0x13062, 0x0 },
-       { 0x13162, 0x0 },
-       { 0x13262, 0x0 },
-       { 0x13362, 0x0 },
-       { 0x13462, 0x0 },
-       { 0x13562, 0x0 },
-       { 0x13662, 0x0 },
-       { 0x13762, 0x0 },
-       { 0x13862, 0x0 },
-       { 0x20077, 0x0 },
-       { 0x10001, 0x0 },
-       { 0x11001, 0x0 },
-       { 0x12001, 0x0 },
-       { 0x13001, 0x0 },
-       { 0x10040, 0x0 },
-       { 0x10140, 0x0 },
-       { 0x10240, 0x0 },
-       { 0x10340, 0x0 },
-       { 0x10440, 0x0 },
-       { 0x10540, 0x0 },
-       { 0x10640, 0x0 },
-       { 0x10740, 0x0 },
-       { 0x10840, 0x0 },
-       { 0x10030, 0x0 },
-       { 0x10130, 0x0 },
-       { 0x10230, 0x0 },
-       { 0x10330, 0x0 },
-       { 0x10430, 0x0 },
-       { 0x10530, 0x0 },
-       { 0x10630, 0x0 },
-       { 0x10730, 0x0 },
-       { 0x10830, 0x0 },
-       { 0x11040, 0x0 },
-       { 0x11140, 0x0 },
-       { 0x11240, 0x0 },
-       { 0x11340, 0x0 },
-       { 0x11440, 0x0 },
-       { 0x11540, 0x0 },
-       { 0x11640, 0x0 },
-       { 0x11740, 0x0 },
-       { 0x11840, 0x0 },
-       { 0x11030, 0x0 },
-       { 0x11130, 0x0 },
-       { 0x11230, 0x0 },
-       { 0x11330, 0x0 },
-       { 0x11430, 0x0 },
-       { 0x11530, 0x0 },
-       { 0x11630, 0x0 },
-       { 0x11730, 0x0 },
-       { 0x11830, 0x0 },
-       { 0x12040, 0x0 },
-       { 0x12140, 0x0 },
-       { 0x12240, 0x0 },
-       { 0x12340, 0x0 },
-       { 0x12440, 0x0 },
-       { 0x12540, 0x0 },
-       { 0x12640, 0x0 },
-       { 0x12740, 0x0 },
-       { 0x12840, 0x0 },
-       { 0x12030, 0x0 },
-       { 0x12130, 0x0 },
-       { 0x12230, 0x0 },
-       { 0x12330, 0x0 },
-       { 0x12430, 0x0 },
-       { 0x12530, 0x0 },
-       { 0x12630, 0x0 },
-       { 0x12730, 0x0 },
-       { 0x12830, 0x0 },
-       { 0x13040, 0x0 },
-       { 0x13140, 0x0 },
-       { 0x13240, 0x0 },
-       { 0x13340, 0x0 },
-       { 0x13440, 0x0 },
-       { 0x13540, 0x0 },
-       { 0x13640, 0x0 },
-       { 0x13740, 0x0 },
-       { 0x13840, 0x0 },
-       { 0x13030, 0x0 },
-       { 0x13130, 0x0 },
-       { 0x13230, 0x0 },
-       { 0x13330, 0x0 },
-       { 0x13430, 0x0 },
-       { 0x13530, 0x0 },
-       { 0x13630, 0x0 },
-       { 0x13730, 0x0 },
-       { 0x13830, 0x0 },
-};
-
-uint32_t ddrphy_trained_csr_num = ARRAY_SIZE(ddrphy_trained_csr);
diff --git a/drivers/ddr/imx/imx8m/ddrphy_train.c b/drivers/ddr/imx/imx8m/ddrphy_train.c
deleted file mode 100644 (file)
index 08fed61..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2018 NXP
- */
-
-#include <common.h>
-#include <log.h>
-#include <linux/kernel.h>
-#include <asm/arch/ddr.h>
-#include <asm/arch/lpddr4_define.h>
-#include <asm/arch/sys_proto.h>
-
-int ddr_cfg_phy(struct dram_timing_info *dram_timing)
-{
-       struct dram_cfg_param *dram_cfg;
-       struct dram_fsp_msg *fsp_msg;
-       unsigned int num;
-       int i = 0;
-       int j = 0;
-       int ret;
-
-       /* initialize PHY configuration */
-       dram_cfg = dram_timing->ddrphy_cfg;
-       num  = dram_timing->ddrphy_cfg_num;
-       for (i = 0; i < num; i++) {
-               /* config phy reg */
-               dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
-               dram_cfg++;
-       }
-
-       /* load the frequency setpoint message block config */
-       fsp_msg = dram_timing->fsp_msg;
-       for (i = 0; i < dram_timing->fsp_msg_num; i++) {
-               debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
-               /* set dram PHY input clocks to desired frequency */
-               ddrphy_init_set_dfi_clk(fsp_msg->drate);
-
-               /* load the dram training firmware image */
-               dwc_ddrphy_apb_wr(0xd0000, 0x0);
-               ddr_load_train_firmware(fsp_msg->fw_type);
-
-               /* load the frequency set point message block parameter */
-               dram_cfg = fsp_msg->fsp_cfg;
-               num = fsp_msg->fsp_cfg_num;
-               for (j = 0; j < num; j++) {
-                       dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
-                       dram_cfg++;
-               }
-
-               /*
-                * -------------------- excute the firmware --------------------
-                * Running the firmware is a simply process to taking the
-                * PMU out of reset and stall, then the firwmare will be run
-                * 1. reset the PMU;
-                * 2. begin the excution;
-                * 3. wait for the training done;
-                * 4. read the message block result.
-                * -------------------------------------------------------------
-                */
-               dwc_ddrphy_apb_wr(0xd0000, 0x1);
-               dwc_ddrphy_apb_wr(0xd0099, 0x9);
-               dwc_ddrphy_apb_wr(0xd0099, 0x1);
-               dwc_ddrphy_apb_wr(0xd0099, 0x0);
-
-               /* Wait for the training firmware to complete */
-               ret = wait_ddrphy_training_complete();
-               if (ret)
-                       return ret;
-
-               /* Halt the microcontroller. */
-               dwc_ddrphy_apb_wr(0xd0099, 0x1);
-
-               /* Read the Message Block results */
-               dwc_ddrphy_apb_wr(0xd0000, 0x0);
-
-               ddrphy_init_read_msg_block(fsp_msg->fw_type);
-
-               if(fsp_msg->fw_type != FW_2D_IMAGE)
-                       get_trained_CDD(i);
-
-               dwc_ddrphy_apb_wr(0xd0000, 0x1);
-
-
-               fsp_msg++;
-       }
-
-       /* Load PHY Init Engine Image */
-       dram_cfg = dram_timing->ddrphy_pie;
-       num = dram_timing->ddrphy_pie_num;
-       for (i = 0; i < num; i++) {
-               dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
-               dram_cfg++;
-       }
-
-       /* save the ddr PHY trained CSR in memory for low power use */
-       ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num);
-
-       return 0;
-}
diff --git a/drivers/ddr/imx/imx8m/helper.c b/drivers/ddr/imx/imx8m/helper.c
deleted file mode 100644 (file)
index f23904b..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2018 NXP
- */
-
-#include <common.h>
-#include <log.h>
-#include <spl.h>
-#include <asm/global_data.h>
-#include <asm/io.h>
-#include <errno.h>
-#include <asm/io.h>
-#include <asm/arch/ddr.h>
-#include <asm/arch/ddr.h>
-#include <asm/arch/lpddr4_define.h>
-#include <asm/sections.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define IMEM_LEN 32768 /* byte */
-#define DMEM_LEN 16384 /* byte */
-#define IMEM_2D_OFFSET 49152
-
-#define IMEM_OFFSET_ADDR 0x00050000
-#define DMEM_OFFSET_ADDR 0x00054000
-#define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0)
-
-/* We need PHY iMEM PHY is 32KB padded */
-void ddr_load_train_firmware(enum fw_type type)
-{
-       u32 tmp32, i;
-       u32 error = 0;
-       unsigned long pr_to32, pr_from32;
-       unsigned long fw_offset = type ? IMEM_2D_OFFSET : 0;
-       unsigned long imem_start = (unsigned long)&_end + fw_offset;
-       unsigned long dmem_start;
-
-#ifdef CONFIG_SPL_OF_CONTROL
-       if (gd->fdt_blob && !fdt_check_header(gd->fdt_blob)) {
-               imem_start = roundup((unsigned long)&_end +
-                                    fdt_totalsize(gd->fdt_blob), 4) +
-                       fw_offset;
-       }
-#endif
-
-       dmem_start = imem_start + IMEM_LEN;
-
-       pr_from32 = imem_start;
-       pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR;
-       for (i = 0x0; i < IMEM_LEN; ) {
-               tmp32 = readl(pr_from32);
-               writew(tmp32 & 0x0000ffff, pr_to32);
-               pr_to32 += 4;
-               writew((tmp32 >> 16) & 0x0000ffff, pr_to32);
-               pr_to32 += 4;
-               pr_from32 += 4;
-               i += 4;
-       }
-
-       pr_from32 = dmem_start;
-       pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR;
-       for (i = 0x0; i < DMEM_LEN; ) {
-               tmp32 = readl(pr_from32);
-               writew(tmp32 & 0x0000ffff, pr_to32);
-               pr_to32 += 4;
-               writew((tmp32 >> 16) & 0x0000ffff, pr_to32);
-               pr_to32 += 4;
-               pr_from32 += 4;
-               i += 4;
-       }
-
-       debug("check ddr_pmu_train_imem code\n");
-       pr_from32 = imem_start;
-       pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR;
-       for (i = 0x0; i < IMEM_LEN; ) {
-               tmp32 = (readw(pr_to32) & 0x0000ffff);
-               pr_to32 += 4;
-               tmp32 += ((readw(pr_to32) & 0x0000ffff) << 16);
-
-               if (tmp32 != readl(pr_from32)) {
-                       debug("%lx %lx\n", pr_from32, pr_to32);
-                       error++;
-               }
-               pr_from32 += 4;
-               pr_to32 += 4;
-               i += 4;
-       }
-       if (error)
-               printf("check ddr_pmu_train_imem code fail=%d\n", error);
-       else
-               debug("check ddr_pmu_train_imem code pass\n");
-
-       debug("check ddr4_pmu_train_dmem code\n");
-       pr_from32 = dmem_start;
-       pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR;
-       for (i = 0x0; i < DMEM_LEN;) {
-               tmp32 = (readw(pr_to32) & 0x0000ffff);
-               pr_to32 += 4;
-               tmp32 += ((readw(pr_to32) & 0x0000ffff) << 16);
-               if (tmp32 != readl(pr_from32)) {
-                       debug("%lx %lx\n", pr_from32, pr_to32);
-                       error++;
-               }
-               pr_from32 += 4;
-               pr_to32 += 4;
-               i += 4;
-       }
-
-       if (error)
-               printf("check ddr_pmu_train_dmem code fail=%d", error);
-       else
-               debug("check ddr_pmu_train_dmem code pass\n");
-}
-
-void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr,
-                            unsigned int num)
-{
-       int i = 0;
-
-       /* enable the ddrphy apb */
-       dwc_ddrphy_apb_wr(0xd0000, 0x0);
-       dwc_ddrphy_apb_wr(0xc0080, 0x3);
-       for (i = 0; i < num; i++) {
-               ddrphy_csr->val = dwc_ddrphy_apb_rd(ddrphy_csr->reg);
-               ddrphy_csr++;
-       }
-       /* disable the ddrphy apb */
-       dwc_ddrphy_apb_wr(0xc0080, 0x2);
-       dwc_ddrphy_apb_wr(0xd0000, 0x1);
-}
-
-void dram_config_save(struct dram_timing_info *timing_info,
-                     unsigned long saved_timing_base)
-{
-       int i = 0;
-       struct dram_timing_info *saved_timing = (struct dram_timing_info *)saved_timing_base;
-       struct dram_cfg_param *cfg;
-
-       saved_timing->ddrc_cfg_num = timing_info->ddrc_cfg_num;
-       saved_timing->ddrphy_cfg_num = timing_info->ddrphy_cfg_num;
-       saved_timing->ddrphy_trained_csr_num = ddrphy_trained_csr_num;
-       saved_timing->ddrphy_pie_num = timing_info->ddrphy_pie_num;
-
-       /* save the fsp table */
-       for (i = 0; i < 4; i++)
-               saved_timing->fsp_table[i] = timing_info->fsp_table[i];
-
-       cfg = (struct dram_cfg_param *)(saved_timing_base +
-                                       sizeof(*timing_info));
-
-       /* save ddrc config */
-       saved_timing->ddrc_cfg = cfg;
-       for (i = 0; i < timing_info->ddrc_cfg_num; i++) {
-               cfg->reg = timing_info->ddrc_cfg[i].reg;
-               cfg->val = timing_info->ddrc_cfg[i].val;
-               cfg++;
-       }
-
-       /* save ddrphy config */
-       saved_timing->ddrphy_cfg = cfg;
-       for (i = 0; i < timing_info->ddrphy_cfg_num; i++) {
-               cfg->reg = timing_info->ddrphy_cfg[i].reg;
-               cfg->val = timing_info->ddrphy_cfg[i].val;
-               cfg++;
-       }
-
-       /* save the ddrphy csr */
-       saved_timing->ddrphy_trained_csr = cfg;
-       for (i = 0; i < ddrphy_trained_csr_num; i++) {
-               cfg->reg = ddrphy_trained_csr[i].reg;
-               cfg->val = ddrphy_trained_csr[i].val;
-               cfg++;
-       }
-
-       /* save the ddrphy pie */
-       saved_timing->ddrphy_pie = cfg;
-       for (i = 0; i < timing_info->ddrphy_pie_num; i++) {
-               cfg->reg = timing_info->ddrphy_pie[i].reg;
-               cfg->val = timing_info->ddrphy_pie[i].val;
-               cfg++;
-       }
-}
diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig
new file mode 100644 (file)
index 0000000..a16ddc6
--- /dev/null
@@ -0,0 +1,21 @@
+menu "i.MX9 DDR controllers"
+       depends on ARCH_IMX9
+
+config IMX9_DRAM
+       bool "imx9 dram"
+       select IMX_SNPS_DDR_PHY
+
+config IMX9_LPDDR4X
+       bool "imx9 lpddr4 and lpddr4x"
+       select IMX9_DRAM
+       help
+         Select the i.MX9 LPDDR4/4X driver support on i.MX9 SOC.
+
+config SAVED_DRAM_TIMING_BASE
+       hex "Define the base address for saved dram timing"
+       help
+         after DRAM is trained, need to save the dram related timming
+         info into memory for low power use.
+       default 0x204DC000
+
+endmenu
diff --git a/drivers/ddr/imx/imx9/Makefile b/drivers/ddr/imx/imx9/Makefile
new file mode 100644 (file)
index 0000000..9403f98
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright 2018 NXP
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_IMX9_DRAM) += ddr_init.o
+obj-y += ../phy/
+endif
diff --git a/drivers/ddr/imx/imx9/ddr_init.c b/drivers/ddr/imx/imx9/ddr_init.c
new file mode 100644 (file)
index 0000000..16eac65
--- /dev/null
@@ -0,0 +1,485 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch/ddr.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+#include <linux/delay.h>
+
+void ddrphy_coldreset(void)
+{
+       /* dramphy_apb_n default 1 , assert -> 0, de_assert -> 1 */
+       /* dramphy_reset_n default 0 , assert -> 0, de_assert -> 1 */
+       /* dramphy_PwrOKIn default 0 , assert -> 1, de_assert -> 0 */
+
+       /* src_gen_dphy_apb_sw_rst_de_assert */
+       clrbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0));
+       /* src_gen_dphy_sw_rst_de_assert */
+       clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2));
+       /* src_gen_dphy_PwrOKIn_sw_rst_de_assert() */
+       setbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(0));
+       mdelay(10);
+
+       /* src_gen_dphy_apb_sw_rst_assert */
+       setbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0));
+       /* src_gen_dphy_sw_rst_assert */
+       setbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2));
+       mdelay(10);
+       /* src_gen_dphy_PwrOKIn_sw_rst_assert */
+       clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(0));
+       mdelay(10);
+
+       /* src_gen_dphy_apb_sw_rst_de_assert */
+       clrbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0));
+       /* src_gen_dphy_sw_rst_de_assert() */
+       clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2));
+}
+
+void check_ddrc_idle(void)
+{
+       u32 regval;
+
+       do {
+               regval = readl(REG_DDRDSR_2);
+               if (regval & BIT(31))
+                       break;
+       } while (1);
+}
+
+void check_dfi_init_complete(void)
+{
+       u32 regval;
+
+       do {
+               regval = readl(REG_DDRDSR_2);
+               if (regval & BIT(2))
+                       break;
+       } while (1);
+       setbits_le32(REG_DDRDSR_2, BIT(2));
+}
+
+void ddrc_config(struct dram_cfg_param *ddrc_config, int num)
+{
+       int i = 0;
+
+       for (i = 0; i < num; i++) {
+               writel(ddrc_config->val, (ulong)ddrc_config->reg);
+               ddrc_config++;
+       }
+}
+
+void get_trained_CDD(u32 fsp)
+{
+}
+
+int ddr_init(struct dram_timing_info *dram_timing)
+{
+       unsigned int initial_drate;
+       int ret;
+       u32 regval;
+
+       debug("DDRINFO: start DRAM init\n");
+
+       /* reset ddrphy */
+       ddrphy_coldreset();
+
+       debug("DDRINFO: cfg clk\n");
+
+       initial_drate = dram_timing->fsp_msg[0].drate;
+       /* default to the frequency point 0 clock */
+       ddrphy_init_set_dfi_clk(initial_drate);
+
+       /*
+        * Start PHY initialization and training by
+        * accessing relevant PUB registers
+        */
+       debug("DDRINFO:ddrphy config start\n");
+
+       ret = ddr_cfg_phy(dram_timing);
+       if (ret)
+               return ret;
+
+       debug("DDRINFO: ddrphy config done\n");
+
+       /* rogram the ddrc registers */
+       debug("DDRINFO: ddrc config start\n");
+       ddrc_config(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num);
+       debug("DDRINFO: ddrc config done\n");
+
+       check_dfi_init_complete();
+
+       regval = readl(REG_DDR_SDRAM_CFG);
+       writel((regval | 0x80000000), REG_DDR_SDRAM_CFG);
+
+       check_ddrc_idle();
+
+       /* save the dram timing config into memory */
+       dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE);
+
+       return 0;
+}
+
+ulong ddrphy_addr_remap(u32 paddr_apb_from_ctlr)
+{
+       u32 paddr_apb_qual;
+       u32 paddr_apb_unqual_dec_22_13;
+       u32 paddr_apb_unqual_dec_19_13;
+       u32 paddr_apb_unqual_dec_12_1;
+       u32 paddr_apb_unqual;
+       u32 paddr_apb_phy;
+
+       paddr_apb_qual = (paddr_apb_from_ctlr << 1);
+       paddr_apb_unqual_dec_22_13 = ((paddr_apb_qual & 0x7fe000) >> 13);
+       paddr_apb_unqual_dec_12_1  = ((paddr_apb_qual & 0x1ffe) >> 1);
+
+       switch (paddr_apb_unqual_dec_22_13) {
+       case 0x000:
+               paddr_apb_unqual_dec_19_13 = 0x00;
+               break;
+       case 0x001:
+               paddr_apb_unqual_dec_19_13 = 0x01;
+               break;
+       case 0x002:
+               paddr_apb_unqual_dec_19_13 = 0x02;
+               break;
+       case 0x003:
+               paddr_apb_unqual_dec_19_13 = 0x03;
+               break;
+       case 0x004:
+               paddr_apb_unqual_dec_19_13 = 0x04;
+               break;
+       case 0x005:
+               paddr_apb_unqual_dec_19_13 = 0x05;
+               break;
+       case 0x006:
+               paddr_apb_unqual_dec_19_13 = 0x06;
+               break;
+       case 0x007:
+               paddr_apb_unqual_dec_19_13 = 0x07;
+               break;
+       case 0x008:
+               paddr_apb_unqual_dec_19_13 = 0x08;
+               break;
+       case 0x009:
+               paddr_apb_unqual_dec_19_13 = 0x09;
+               break;
+       case 0x00a:
+               paddr_apb_unqual_dec_19_13 = 0x0a;
+               break;
+       case 0x00b:
+               paddr_apb_unqual_dec_19_13 = 0x0b;
+               break;
+       case 0x100:
+               paddr_apb_unqual_dec_19_13 = 0x0c;
+               break;
+       case 0x101:
+               paddr_apb_unqual_dec_19_13 = 0x0d;
+               break;
+       case 0x102:
+               paddr_apb_unqual_dec_19_13 = 0x0e;
+               break;
+       case 0x103:
+               paddr_apb_unqual_dec_19_13 = 0x0f;
+               break;
+       case 0x104:
+               paddr_apb_unqual_dec_19_13 = 0x10;
+               break;
+       case 0x105:
+               paddr_apb_unqual_dec_19_13 = 0x11;
+               break;
+       case 0x106:
+               paddr_apb_unqual_dec_19_13 = 0x12;
+               break;
+       case 0x107:
+               paddr_apb_unqual_dec_19_13 = 0x13;
+               break;
+       case 0x108:
+               paddr_apb_unqual_dec_19_13 = 0x14;
+               break;
+       case 0x109:
+               paddr_apb_unqual_dec_19_13 = 0x15;
+               break;
+       case 0x10a:
+               paddr_apb_unqual_dec_19_13 = 0x16;
+               break;
+       case 0x10b:
+               paddr_apb_unqual_dec_19_13 = 0x17;
+               break;
+       case 0x200:
+               paddr_apb_unqual_dec_19_13 = 0x18;
+               break;
+       case 0x201:
+               paddr_apb_unqual_dec_19_13 = 0x19;
+               break;
+       case 0x202:
+               paddr_apb_unqual_dec_19_13 = 0x1a;
+               break;
+       case 0x203:
+               paddr_apb_unqual_dec_19_13 = 0x1b;
+               break;
+       case 0x204:
+               paddr_apb_unqual_dec_19_13 = 0x1c;
+               break;
+       case 0x205:
+               paddr_apb_unqual_dec_19_13 = 0x1d;
+               break;
+       case 0x206:
+               paddr_apb_unqual_dec_19_13 = 0x1e;
+               break;
+       case 0x207:
+               paddr_apb_unqual_dec_19_13 = 0x1f;
+               break;
+       case 0x208:
+               paddr_apb_unqual_dec_19_13 = 0x20;
+               break;
+       case 0x209:
+               paddr_apb_unqual_dec_19_13 = 0x21;
+               break;
+       case 0x20a:
+               paddr_apb_unqual_dec_19_13 = 0x22;
+               break;
+       case 0x20b:
+               paddr_apb_unqual_dec_19_13 = 0x23;
+               break;
+       case 0x300:
+               paddr_apb_unqual_dec_19_13 = 0x24;
+               break;
+       case 0x301:
+               paddr_apb_unqual_dec_19_13 = 0x25;
+               break;
+       case 0x302:
+               paddr_apb_unqual_dec_19_13 = 0x26;
+               break;
+       case 0x303:
+               paddr_apb_unqual_dec_19_13 = 0x27;
+               break;
+       case 0x304:
+               paddr_apb_unqual_dec_19_13 = 0x28;
+               break;
+       case 0x305:
+               paddr_apb_unqual_dec_19_13 = 0x29;
+               break;
+       case 0x306:
+               paddr_apb_unqual_dec_19_13 = 0x2a;
+               break;
+       case 0x307:
+               paddr_apb_unqual_dec_19_13 = 0x2b;
+               break;
+       case 0x308:
+               paddr_apb_unqual_dec_19_13 = 0x2c;
+               break;
+       case 0x309:
+               paddr_apb_unqual_dec_19_13 = 0x2d;
+               break;
+       case 0x30a:
+               paddr_apb_unqual_dec_19_13 = 0x2e;
+               break;
+       case 0x30b:
+               paddr_apb_unqual_dec_19_13 = 0x2f;
+               break;
+       case 0x010:
+               paddr_apb_unqual_dec_19_13 = 0x30;
+               break;
+       case 0x011:
+               paddr_apb_unqual_dec_19_13 = 0x31;
+               break;
+       case 0x012:
+               paddr_apb_unqual_dec_19_13 = 0x32;
+               break;
+       case 0x013:
+               paddr_apb_unqual_dec_19_13 = 0x33;
+               break;
+       case 0x014:
+               paddr_apb_unqual_dec_19_13 = 0x34;
+               break;
+       case 0x015:
+               paddr_apb_unqual_dec_19_13 = 0x35;
+               break;
+       case 0x016:
+               paddr_apb_unqual_dec_19_13 = 0x36;
+               break;
+       case 0x017:
+               paddr_apb_unqual_dec_19_13 = 0x37;
+               break;
+       case 0x018:
+               paddr_apb_unqual_dec_19_13 = 0x38;
+               break;
+       case 0x019:
+               paddr_apb_unqual_dec_19_13 = 0x39;
+               break;
+       case 0x110:
+               paddr_apb_unqual_dec_19_13 = 0x3a;
+               break;
+       case 0x111:
+               paddr_apb_unqual_dec_19_13 = 0x3b;
+               break;
+       case 0x112:
+               paddr_apb_unqual_dec_19_13 = 0x3c;
+               break;
+       case 0x113:
+               paddr_apb_unqual_dec_19_13 = 0x3d;
+               break;
+       case 0x114:
+               paddr_apb_unqual_dec_19_13 = 0x3e;
+               break;
+       case 0x115:
+               paddr_apb_unqual_dec_19_13 = 0x3f;
+               break;
+       case 0x116:
+               paddr_apb_unqual_dec_19_13 = 0x40;
+               break;
+       case 0x117:
+               paddr_apb_unqual_dec_19_13 = 0x41;
+               break;
+       case 0x118:
+               paddr_apb_unqual_dec_19_13 = 0x42;
+               break;
+       case 0x119:
+               paddr_apb_unqual_dec_19_13 = 0x43;
+               break;
+       case 0x210:
+               paddr_apb_unqual_dec_19_13 = 0x44;
+               break;
+       case 0x211:
+               paddr_apb_unqual_dec_19_13 = 0x45;
+               break;
+       case 0x212:
+               paddr_apb_unqual_dec_19_13 = 0x46;
+               break;
+       case 0x213:
+               paddr_apb_unqual_dec_19_13 = 0x47;
+               break;
+       case 0x214:
+               paddr_apb_unqual_dec_19_13 = 0x48;
+               break;
+       case 0x215:
+               paddr_apb_unqual_dec_19_13 = 0x49;
+               break;
+       case 0x216:
+               paddr_apb_unqual_dec_19_13 = 0x4a;
+               break;
+       case 0x217:
+               paddr_apb_unqual_dec_19_13 = 0x4b;
+               break;
+       case 0x218:
+               paddr_apb_unqual_dec_19_13 = 0x4c;
+               break;
+       case 0x219:
+               paddr_apb_unqual_dec_19_13 = 0x4d;
+               break;
+       case 0x310:
+               paddr_apb_unqual_dec_19_13 = 0x4e;
+               break;
+       case 0x311:
+               paddr_apb_unqual_dec_19_13 = 0x4f;
+               break;
+       case 0x312:
+               paddr_apb_unqual_dec_19_13 = 0x50;
+               break;
+       case 0x313:
+               paddr_apb_unqual_dec_19_13 = 0x51;
+               break;
+       case 0x314:
+               paddr_apb_unqual_dec_19_13 = 0x52;
+               break;
+       case 0x315:
+               paddr_apb_unqual_dec_19_13 = 0x53;
+               break;
+       case 0x316:
+               paddr_apb_unqual_dec_19_13 = 0x54;
+               break;
+       case 0x317:
+               paddr_apb_unqual_dec_19_13 = 0x55;
+               break;
+       case 0x318:
+               paddr_apb_unqual_dec_19_13 = 0x56;
+               break;
+       case 0x319:
+               paddr_apb_unqual_dec_19_13 = 0x57;
+               break;
+       case 0x020:
+               paddr_apb_unqual_dec_19_13 = 0x58;
+               break;
+       case 0x120:
+               paddr_apb_unqual_dec_19_13 = 0x59;
+               break;
+       case 0x220:
+               paddr_apb_unqual_dec_19_13 = 0x5a;
+               break;
+       case 0x320:
+               paddr_apb_unqual_dec_19_13 = 0x5b;
+               break;
+       case 0x040:
+               paddr_apb_unqual_dec_19_13 = 0x5c;
+               break;
+       case 0x140:
+               paddr_apb_unqual_dec_19_13 = 0x5d;
+               break;
+       case 0x240:
+               paddr_apb_unqual_dec_19_13 = 0x5e;
+               break;
+       case 0x340:
+               paddr_apb_unqual_dec_19_13 = 0x5f;
+               break;
+       case 0x050:
+               paddr_apb_unqual_dec_19_13 = 0x60;
+               break;
+       case 0x051:
+               paddr_apb_unqual_dec_19_13 = 0x61;
+               break;
+       case 0x052:
+               paddr_apb_unqual_dec_19_13 = 0x62;
+               break;
+       case 0x053:
+               paddr_apb_unqual_dec_19_13 = 0x63;
+               break;
+       case 0x054:
+               paddr_apb_unqual_dec_19_13 = 0x64;
+               break;
+       case 0x055:
+               paddr_apb_unqual_dec_19_13 = 0x65;
+               break;
+       case 0x056:
+               paddr_apb_unqual_dec_19_13 = 0x66;
+               break;
+       case 0x057:
+               paddr_apb_unqual_dec_19_13 = 0x67;
+               break;
+       case 0x070:
+               paddr_apb_unqual_dec_19_13 = 0x68;
+               break;
+       case 0x090:
+               paddr_apb_unqual_dec_19_13 = 0x69;
+               break;
+       case 0x190:
+               paddr_apb_unqual_dec_19_13 = 0x6a;
+               break;
+       case 0x290:
+               paddr_apb_unqual_dec_19_13 = 0x6b;
+               break;
+       case 0x390:
+               paddr_apb_unqual_dec_19_13 = 0x6c;
+               break;
+       case 0x0c0:
+               paddr_apb_unqual_dec_19_13 = 0x6d;
+               break;
+       case 0x0d0:
+               paddr_apb_unqual_dec_19_13 = 0x6e;
+               break;
+       default:
+               paddr_apb_unqual_dec_19_13 = 0x00;
+               break;
+       }
+
+       paddr_apb_unqual = ((paddr_apb_unqual_dec_19_13 << 13) | (paddr_apb_unqual_dec_12_1 << 1));
+
+       paddr_apb_phy = (paddr_apb_unqual << 1);
+
+       return paddr_apb_phy;
+}
diff --git a/drivers/ddr/imx/phy/Kconfig b/drivers/ddr/imx/phy/Kconfig
new file mode 100644 (file)
index 0000000..d3e589b
--- /dev/null
@@ -0,0 +1,4 @@
+config IMX_SNPS_DDR_PHY
+       bool "i.MX Snopsys DDR PHY"
+       help
+         Select the DDR PHY driver support on i.MX8M and i.MX9 SOC.
diff --git a/drivers/ddr/imx/phy/Makefile b/drivers/ddr/imx/phy/Makefile
new file mode 100644 (file)
index 0000000..bb3d4ee
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Copyright 2018 NXP
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_IMX_SNPS_DDR_PHY) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o
+endif
diff --git a/drivers/ddr/imx/phy/ddrphy_csr.c b/drivers/ddr/imx/phy/ddrphy_csr.c
new file mode 100644 (file)
index 0000000..67dd4e7
--- /dev/null
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <linux/kernel.h>
+#include <asm/arch/ddr.h>
+
+/* ddr phy trained csr */
+struct dram_cfg_param ddrphy_trained_csr[] = {
+       { 0x200b2, 0x0 },
+       { 0x1200b2, 0x0 },
+       { 0x2200b2, 0x0 },
+       { 0x200cb, 0x0 },
+       { 0x10043, 0x0 },
+       { 0x110043, 0x0 },
+       { 0x210043, 0x0 },
+       { 0x10143, 0x0 },
+       { 0x110143, 0x0 },
+       { 0x210143, 0x0 },
+       { 0x11043, 0x0 },
+       { 0x111043, 0x0 },
+       { 0x211043, 0x0 },
+       { 0x11143, 0x0 },
+       { 0x111143, 0x0 },
+       { 0x211143, 0x0 },
+       { 0x12043, 0x0 },
+       { 0x112043, 0x0 },
+       { 0x212043, 0x0 },
+       { 0x12143, 0x0 },
+       { 0x112143, 0x0 },
+       { 0x212143, 0x0 },
+       { 0x13043, 0x0 },
+       { 0x113043, 0x0 },
+       { 0x213043, 0x0 },
+       { 0x13143, 0x0 },
+       { 0x113143, 0x0 },
+       { 0x213143, 0x0 },
+       { 0x80, 0x0 },
+       { 0x100080, 0x0 },
+       { 0x200080, 0x0 },
+       { 0x1080, 0x0 },
+       { 0x101080, 0x0 },
+       { 0x201080, 0x0 },
+       { 0x2080, 0x0 },
+       { 0x102080, 0x0 },
+       { 0x202080, 0x0 },
+       { 0x3080, 0x0 },
+       { 0x103080, 0x0 },
+       { 0x203080, 0x0 },
+       { 0x4080, 0x0 },
+       { 0x104080, 0x0 },
+       { 0x204080, 0x0 },
+       { 0x5080, 0x0 },
+       { 0x105080, 0x0 },
+       { 0x205080, 0x0 },
+       { 0x6080, 0x0 },
+       { 0x106080, 0x0 },
+       { 0x206080, 0x0 },
+       { 0x7080, 0x0 },
+       { 0x107080, 0x0 },
+       { 0x207080, 0x0 },
+       { 0x8080, 0x0 },
+       { 0x108080, 0x0 },
+       { 0x208080, 0x0 },
+       { 0x9080, 0x0 },
+       { 0x109080, 0x0 },
+       { 0x209080, 0x0 },
+       { 0x10080, 0x0 },
+       { 0x110080, 0x0 },
+       { 0x210080, 0x0 },
+       { 0x10180, 0x0 },
+       { 0x110180, 0x0 },
+       { 0x210180, 0x0 },
+       { 0x11080, 0x0 },
+       { 0x111080, 0x0 },
+       { 0x211080, 0x0 },
+       { 0x11180, 0x0 },
+       { 0x111180, 0x0 },
+       { 0x211180, 0x0 },
+       { 0x12080, 0x0 },
+       { 0x112080, 0x0 },
+       { 0x212080, 0x0 },
+       { 0x12180, 0x0 },
+       { 0x112180, 0x0 },
+       { 0x212180, 0x0 },
+       { 0x13080, 0x0 },
+       { 0x113080, 0x0 },
+       { 0x213080, 0x0 },
+       { 0x13180, 0x0 },
+       { 0x113180, 0x0 },
+       { 0x213180, 0x0 },
+       { 0x10081, 0x0 },
+       { 0x110081, 0x0 },
+       { 0x210081, 0x0 },
+       { 0x10181, 0x0 },
+       { 0x110181, 0x0 },
+       { 0x210181, 0x0 },
+       { 0x11081, 0x0 },
+       { 0x111081, 0x0 },
+       { 0x211081, 0x0 },
+       { 0x11181, 0x0 },
+       { 0x111181, 0x0 },
+       { 0x211181, 0x0 },
+       { 0x12081, 0x0 },
+       { 0x112081, 0x0 },
+       { 0x212081, 0x0 },
+       { 0x12181, 0x0 },
+       { 0x112181, 0x0 },
+       { 0x212181, 0x0 },
+       { 0x13081, 0x0 },
+       { 0x113081, 0x0 },
+       { 0x213081, 0x0 },
+       { 0x13181, 0x0 },
+       { 0x113181, 0x0 },
+       { 0x213181, 0x0 },
+       { 0x100d0, 0x0 },
+       { 0x1100d0, 0x0 },
+       { 0x2100d0, 0x0 },
+       { 0x101d0, 0x0 },
+       { 0x1101d0, 0x0 },
+       { 0x2101d0, 0x0 },
+       { 0x110d0, 0x0 },
+       { 0x1110d0, 0x0 },
+       { 0x2110d0, 0x0 },
+       { 0x111d0, 0x0 },
+       { 0x1111d0, 0x0 },
+       { 0x2111d0, 0x0 },
+       { 0x120d0, 0x0 },
+       { 0x1120d0, 0x0 },
+       { 0x2120d0, 0x0 },
+       { 0x121d0, 0x0 },
+       { 0x1121d0, 0x0 },
+       { 0x2121d0, 0x0 },
+       { 0x130d0, 0x0 },
+       { 0x1130d0, 0x0 },
+       { 0x2130d0, 0x0 },
+       { 0x131d0, 0x0 },
+       { 0x1131d0, 0x0 },
+       { 0x2131d0, 0x0 },
+       { 0x100d1, 0x0 },
+       { 0x1100d1, 0x0 },
+       { 0x2100d1, 0x0 },
+       { 0x101d1, 0x0 },
+       { 0x1101d1, 0x0 },
+       { 0x2101d1, 0x0 },
+       { 0x110d1, 0x0 },
+       { 0x1110d1, 0x0 },
+       { 0x2110d1, 0x0 },
+       { 0x111d1, 0x0 },
+       { 0x1111d1, 0x0 },
+       { 0x2111d1, 0x0 },
+       { 0x120d1, 0x0 },
+       { 0x1120d1, 0x0 },
+       { 0x2120d1, 0x0 },
+       { 0x121d1, 0x0 },
+       { 0x1121d1, 0x0 },
+       { 0x2121d1, 0x0 },
+       { 0x130d1, 0x0 },
+       { 0x1130d1, 0x0 },
+       { 0x2130d1, 0x0 },
+       { 0x131d1, 0x0 },
+       { 0x1131d1, 0x0 },
+       { 0x2131d1, 0x0 },
+       { 0x10068, 0x0 },
+       { 0x10168, 0x0 },
+       { 0x10268, 0x0 },
+       { 0x10368, 0x0 },
+       { 0x10468, 0x0 },
+       { 0x10568, 0x0 },
+       { 0x10668, 0x0 },
+       { 0x10768, 0x0 },
+       { 0x10868, 0x0 },
+       { 0x11068, 0x0 },
+       { 0x11168, 0x0 },
+       { 0x11268, 0x0 },
+       { 0x11368, 0x0 },
+       { 0x11468, 0x0 },
+       { 0x11568, 0x0 },
+       { 0x11668, 0x0 },
+       { 0x11768, 0x0 },
+       { 0x11868, 0x0 },
+       { 0x12068, 0x0 },
+       { 0x12168, 0x0 },
+       { 0x12268, 0x0 },
+       { 0x12368, 0x0 },
+       { 0x12468, 0x0 },
+       { 0x12568, 0x0 },
+       { 0x12668, 0x0 },
+       { 0x12768, 0x0 },
+       { 0x12868, 0x0 },
+       { 0x13068, 0x0 },
+       { 0x13168, 0x0 },
+       { 0x13268, 0x0 },
+       { 0x13368, 0x0 },
+       { 0x13468, 0x0 },
+       { 0x13568, 0x0 },
+       { 0x13668, 0x0 },
+       { 0x13768, 0x0 },
+       { 0x13868, 0x0 },
+       { 0x10069, 0x0 },
+       { 0x10169, 0x0 },
+       { 0x10269, 0x0 },
+       { 0x10369, 0x0 },
+       { 0x10469, 0x0 },
+       { 0x10569, 0x0 },
+       { 0x10669, 0x0 },
+       { 0x10769, 0x0 },
+       { 0x10869, 0x0 },
+       { 0x11069, 0x0 },
+       { 0x11169, 0x0 },
+       { 0x11269, 0x0 },
+       { 0x11369, 0x0 },
+       { 0x11469, 0x0 },
+       { 0x11569, 0x0 },
+       { 0x11669, 0x0 },
+       { 0x11769, 0x0 },
+       { 0x11869, 0x0 },
+       { 0x12069, 0x0 },
+       { 0x12169, 0x0 },
+       { 0x12269, 0x0 },
+       { 0x12369, 0x0 },
+       { 0x12469, 0x0 },
+       { 0x12569, 0x0 },
+       { 0x12669, 0x0 },
+       { 0x12769, 0x0 },
+       { 0x12869, 0x0 },
+       { 0x13069, 0x0 },
+       { 0x13169, 0x0 },
+       { 0x13269, 0x0 },
+       { 0x13369, 0x0 },
+       { 0x13469, 0x0 },
+       { 0x13569, 0x0 },
+       { 0x13669, 0x0 },
+       { 0x13769, 0x0 },
+       { 0x13869, 0x0 },
+       { 0x1008c, 0x0 },
+       { 0x11008c, 0x0 },
+       { 0x21008c, 0x0 },
+       { 0x1018c, 0x0 },
+       { 0x11018c, 0x0 },
+       { 0x21018c, 0x0 },
+       { 0x1108c, 0x0 },
+       { 0x11108c, 0x0 },
+       { 0x21108c, 0x0 },
+       { 0x1118c, 0x0 },
+       { 0x11118c, 0x0 },
+       { 0x21118c, 0x0 },
+       { 0x1208c, 0x0 },
+       { 0x11208c, 0x0 },
+       { 0x21208c, 0x0 },
+       { 0x1218c, 0x0 },
+       { 0x11218c, 0x0 },
+       { 0x21218c, 0x0 },
+       { 0x1308c, 0x0 },
+       { 0x11308c, 0x0 },
+       { 0x21308c, 0x0 },
+       { 0x1318c, 0x0 },
+       { 0x11318c, 0x0 },
+       { 0x21318c, 0x0 },
+       { 0x1008d, 0x0 },
+       { 0x11008d, 0x0 },
+       { 0x21008d, 0x0 },
+       { 0x1018d, 0x0 },
+       { 0x11018d, 0x0 },
+       { 0x21018d, 0x0 },
+       { 0x1108d, 0x0 },
+       { 0x11108d, 0x0 },
+       { 0x21108d, 0x0 },
+       { 0x1118d, 0x0 },
+       { 0x11118d, 0x0 },
+       { 0x21118d, 0x0 },
+       { 0x1208d, 0x0 },
+       { 0x11208d, 0x0 },
+       { 0x21208d, 0x0 },
+       { 0x1218d, 0x0 },
+       { 0x11218d, 0x0 },
+       { 0x21218d, 0x0 },
+       { 0x1308d, 0x0 },
+       { 0x11308d, 0x0 },
+       { 0x21308d, 0x0 },
+       { 0x1318d, 0x0 },
+       { 0x11318d, 0x0 },
+       { 0x21318d, 0x0 },
+       { 0x100c0, 0x0 },
+       { 0x1100c0, 0x0 },
+       { 0x2100c0, 0x0 },
+       { 0x101c0, 0x0 },
+       { 0x1101c0, 0x0 },
+       { 0x2101c0, 0x0 },
+       { 0x102c0, 0x0 },
+       { 0x1102c0, 0x0 },
+       { 0x2102c0, 0x0 },
+       { 0x103c0, 0x0 },
+       { 0x1103c0, 0x0 },
+       { 0x2103c0, 0x0 },
+       { 0x104c0, 0x0 },
+       { 0x1104c0, 0x0 },
+       { 0x2104c0, 0x0 },
+       { 0x105c0, 0x0 },
+       { 0x1105c0, 0x0 },
+       { 0x2105c0, 0x0 },
+       { 0x106c0, 0x0 },
+       { 0x1106c0, 0x0 },
+       { 0x2106c0, 0x0 },
+       { 0x107c0, 0x0 },
+       { 0x1107c0, 0x0 },
+       { 0x2107c0, 0x0 },
+       { 0x108c0, 0x0 },
+       { 0x1108c0, 0x0 },
+       { 0x2108c0, 0x0 },
+       { 0x110c0, 0x0 },
+       { 0x1110c0, 0x0 },
+       { 0x2110c0, 0x0 },
+       { 0x111c0, 0x0 },
+       { 0x1111c0, 0x0 },
+       { 0x2111c0, 0x0 },
+       { 0x112c0, 0x0 },
+       { 0x1112c0, 0x0 },
+       { 0x2112c0, 0x0 },
+       { 0x113c0, 0x0 },
+       { 0x1113c0, 0x0 },
+       { 0x2113c0, 0x0 },
+       { 0x114c0, 0x0 },
+       { 0x1114c0, 0x0 },
+       { 0x2114c0, 0x0 },
+       { 0x115c0, 0x0 },
+       { 0x1115c0, 0x0 },
+       { 0x2115c0, 0x0 },
+       { 0x116c0, 0x0 },
+       { 0x1116c0, 0x0 },
+       { 0x2116c0, 0x0 },
+       { 0x117c0, 0x0 },
+       { 0x1117c0, 0x0 },
+       { 0x2117c0, 0x0 },
+       { 0x118c0, 0x0 },
+       { 0x1118c0, 0x0 },
+       { 0x2118c0, 0x0 },
+       { 0x120c0, 0x0 },
+       { 0x1120c0, 0x0 },
+       { 0x2120c0, 0x0 },
+       { 0x121c0, 0x0 },
+       { 0x1121c0, 0x0 },
+       { 0x2121c0, 0x0 },
+       { 0x122c0, 0x0 },
+       { 0x1122c0, 0x0 },
+       { 0x2122c0, 0x0 },
+       { 0x123c0, 0x0 },
+       { 0x1123c0, 0x0 },
+       { 0x2123c0, 0x0 },
+       { 0x124c0, 0x0 },
+       { 0x1124c0, 0x0 },
+       { 0x2124c0, 0x0 },
+       { 0x125c0, 0x0 },
+       { 0x1125c0, 0x0 },
+       { 0x2125c0, 0x0 },
+       { 0x126c0, 0x0 },
+       { 0x1126c0, 0x0 },
+       { 0x2126c0, 0x0 },
+       { 0x127c0, 0x0 },
+       { 0x1127c0, 0x0 },
+       { 0x2127c0, 0x0 },
+       { 0x128c0, 0x0 },
+       { 0x1128c0, 0x0 },
+       { 0x2128c0, 0x0 },
+       { 0x130c0, 0x0 },
+       { 0x1130c0, 0x0 },
+       { 0x2130c0, 0x0 },
+       { 0x131c0, 0x0 },
+       { 0x1131c0, 0x0 },
+       { 0x2131c0, 0x0 },
+       { 0x132c0, 0x0 },
+       { 0x1132c0, 0x0 },
+       { 0x2132c0, 0x0 },
+       { 0x133c0, 0x0 },
+       { 0x1133c0, 0x0 },
+       { 0x2133c0, 0x0 },
+       { 0x134c0, 0x0 },
+       { 0x1134c0, 0x0 },
+       { 0x2134c0, 0x0 },
+       { 0x135c0, 0x0 },
+       { 0x1135c0, 0x0 },
+       { 0x2135c0, 0x0 },
+       { 0x136c0, 0x0 },
+       { 0x1136c0, 0x0 },
+       { 0x2136c0, 0x0 },
+       { 0x137c0, 0x0 },
+       { 0x1137c0, 0x0 },
+       { 0x2137c0, 0x0 },
+       { 0x138c0, 0x0 },
+       { 0x1138c0, 0x0 },
+       { 0x2138c0, 0x0 },
+       { 0x100c1, 0x0 },
+       { 0x1100c1, 0x0 },
+       { 0x2100c1, 0x0 },
+       { 0x101c1, 0x0 },
+       { 0x1101c1, 0x0 },
+       { 0x2101c1, 0x0 },
+       { 0x102c1, 0x0 },
+       { 0x1102c1, 0x0 },
+       { 0x2102c1, 0x0 },
+       { 0x103c1, 0x0 },
+       { 0x1103c1, 0x0 },
+       { 0x2103c1, 0x0 },
+       { 0x104c1, 0x0 },
+       { 0x1104c1, 0x0 },
+       { 0x2104c1, 0x0 },
+       { 0x105c1, 0x0 },
+       { 0x1105c1, 0x0 },
+       { 0x2105c1, 0x0 },
+       { 0x106c1, 0x0 },
+       { 0x1106c1, 0x0 },
+       { 0x2106c1, 0x0 },
+       { 0x107c1, 0x0 },
+       { 0x1107c1, 0x0 },
+       { 0x2107c1, 0x0 },
+       { 0x108c1, 0x0 },
+       { 0x1108c1, 0x0 },
+       { 0x2108c1, 0x0 },
+       { 0x110c1, 0x0 },
+       { 0x1110c1, 0x0 },
+       { 0x2110c1, 0x0 },
+       { 0x111c1, 0x0 },
+       { 0x1111c1, 0x0 },
+       { 0x2111c1, 0x0 },
+       { 0x112c1, 0x0 },
+       { 0x1112c1, 0x0 },
+       { 0x2112c1, 0x0 },
+       { 0x113c1, 0x0 },
+       { 0x1113c1, 0x0 },
+       { 0x2113c1, 0x0 },
+       { 0x114c1, 0x0 },
+       { 0x1114c1, 0x0 },
+       { 0x2114c1, 0x0 },
+       { 0x115c1, 0x0 },
+       { 0x1115c1, 0x0 },
+       { 0x2115c1, 0x0 },
+       { 0x116c1, 0x0 },
+       { 0x1116c1, 0x0 },
+       { 0x2116c1, 0x0 },
+       { 0x117c1, 0x0 },
+       { 0x1117c1, 0x0 },
+       { 0x2117c1, 0x0 },
+       { 0x118c1, 0x0 },
+       { 0x1118c1, 0x0 },
+       { 0x2118c1, 0x0 },
+       { 0x120c1, 0x0 },
+       { 0x1120c1, 0x0 },
+       { 0x2120c1, 0x0 },
+       { 0x121c1, 0x0 },
+       { 0x1121c1, 0x0 },
+       { 0x2121c1, 0x0 },
+       { 0x122c1, 0x0 },
+       { 0x1122c1, 0x0 },
+       { 0x2122c1, 0x0 },
+       { 0x123c1, 0x0 },
+       { 0x1123c1, 0x0 },
+       { 0x2123c1, 0x0 },
+       { 0x124c1, 0x0 },
+       { 0x1124c1, 0x0 },
+       { 0x2124c1, 0x0 },
+       { 0x125c1, 0x0 },
+       { 0x1125c1, 0x0 },
+       { 0x2125c1, 0x0 },
+       { 0x126c1, 0x0 },
+       { 0x1126c1, 0x0 },
+       { 0x2126c1, 0x0 },
+       { 0x127c1, 0x0 },
+       { 0x1127c1, 0x0 },
+       { 0x2127c1, 0x0 },
+       { 0x128c1, 0x0 },
+       { 0x1128c1, 0x0 },
+       { 0x2128c1, 0x0 },
+       { 0x130c1, 0x0 },
+       { 0x1130c1, 0x0 },
+       { 0x2130c1, 0x0 },
+       { 0x131c1, 0x0 },
+       { 0x1131c1, 0x0 },
+       { 0x2131c1, 0x0 },
+       { 0x132c1, 0x0 },
+       { 0x1132c1, 0x0 },
+       { 0x2132c1, 0x0 },
+       { 0x133c1, 0x0 },
+       { 0x1133c1, 0x0 },
+       { 0x2133c1, 0x0 },
+       { 0x134c1, 0x0 },
+       { 0x1134c1, 0x0 },
+       { 0x2134c1, 0x0 },
+       { 0x135c1, 0x0 },
+       { 0x1135c1, 0x0 },
+       { 0x2135c1, 0x0 },
+       { 0x136c1, 0x0 },
+       { 0x1136c1, 0x0 },
+       { 0x2136c1, 0x0 },
+       { 0x137c1, 0x0 },
+       { 0x1137c1, 0x0 },
+       { 0x2137c1, 0x0 },
+       { 0x138c1, 0x0 },
+       { 0x1138c1, 0x0 },
+       { 0x2138c1, 0x0 },
+       { 0x10020, 0x0 },
+       { 0x110020, 0x0 },
+       { 0x210020, 0x0 },
+       { 0x11020, 0x0 },
+       { 0x111020, 0x0 },
+       { 0x211020, 0x0 },
+       { 0x12020, 0x0 },
+       { 0x112020, 0x0 },
+       { 0x212020, 0x0 },
+       { 0x13020, 0x0 },
+       { 0x113020, 0x0 },
+       { 0x213020, 0x0 },
+       { 0x20072, 0x0 },
+       { 0x20073, 0x0 },
+       { 0x20074, 0x0 },
+       { 0x100aa, 0x0 },
+       { 0x110aa, 0x0 },
+       { 0x120aa, 0x0 },
+       { 0x130aa, 0x0 },
+       { 0x20010, 0x0 },
+       { 0x120010, 0x0 },
+       { 0x220010, 0x0 },
+       { 0x20011, 0x0 },
+       { 0x120011, 0x0 },
+       { 0x220011, 0x0 },
+       { 0x100ae, 0x0 },
+       { 0x1100ae, 0x0 },
+       { 0x2100ae, 0x0 },
+       { 0x100af, 0x0 },
+       { 0x1100af, 0x0 },
+       { 0x2100af, 0x0 },
+       { 0x110ae, 0x0 },
+       { 0x1110ae, 0x0 },
+       { 0x2110ae, 0x0 },
+       { 0x110af, 0x0 },
+       { 0x1110af, 0x0 },
+       { 0x2110af, 0x0 },
+       { 0x120ae, 0x0 },
+       { 0x1120ae, 0x0 },
+       { 0x2120ae, 0x0 },
+       { 0x120af, 0x0 },
+       { 0x1120af, 0x0 },
+       { 0x2120af, 0x0 },
+       { 0x130ae, 0x0 },
+       { 0x1130ae, 0x0 },
+       { 0x2130ae, 0x0 },
+       { 0x130af, 0x0 },
+       { 0x1130af, 0x0 },
+       { 0x2130af, 0x0 },
+       { 0x20020, 0x0 },
+       { 0x120020, 0x0 },
+       { 0x220020, 0x0 },
+       { 0x100a0, 0x0 },
+       { 0x100a1, 0x0 },
+       { 0x100a2, 0x0 },
+       { 0x100a3, 0x0 },
+       { 0x100a4, 0x0 },
+       { 0x100a5, 0x0 },
+       { 0x100a6, 0x0 },
+       { 0x100a7, 0x0 },
+       { 0x110a0, 0x0 },
+       { 0x110a1, 0x0 },
+       { 0x110a2, 0x0 },
+       { 0x110a3, 0x0 },
+       { 0x110a4, 0x0 },
+       { 0x110a5, 0x0 },
+       { 0x110a6, 0x0 },
+       { 0x110a7, 0x0 },
+       { 0x120a0, 0x0 },
+       { 0x120a1, 0x0 },
+       { 0x120a2, 0x0 },
+       { 0x120a3, 0x0 },
+       { 0x120a4, 0x0 },
+       { 0x120a5, 0x0 },
+       { 0x120a6, 0x0 },
+       { 0x120a7, 0x0 },
+       { 0x130a0, 0x0 },
+       { 0x130a1, 0x0 },
+       { 0x130a2, 0x0 },
+       { 0x130a3, 0x0 },
+       { 0x130a4, 0x0 },
+       { 0x130a5, 0x0 },
+       { 0x130a6, 0x0 },
+       { 0x130a7, 0x0 },
+       { 0x2007c, 0x0 },
+       { 0x12007c, 0x0 },
+       { 0x22007c, 0x0 },
+       { 0x2007d, 0x0 },
+       { 0x12007d, 0x0 },
+       { 0x22007d, 0x0 },
+       { 0x400fd, 0x0 },
+       { 0x400c0, 0x0 },
+       { 0x90201, 0x0 },
+       { 0x190201, 0x0 },
+       { 0x290201, 0x0 },
+       { 0x90202, 0x0 },
+       { 0x190202, 0x0 },
+       { 0x290202, 0x0 },
+       { 0x90203, 0x0 },
+       { 0x190203, 0x0 },
+       { 0x290203, 0x0 },
+       { 0x90204, 0x0 },
+       { 0x190204, 0x0 },
+       { 0x290204, 0x0 },
+       { 0x90205, 0x0 },
+       { 0x190205, 0x0 },
+       { 0x290205, 0x0 },
+       { 0x90206, 0x0 },
+       { 0x190206, 0x0 },
+       { 0x290206, 0x0 },
+       { 0x90207, 0x0 },
+       { 0x190207, 0x0 },
+       { 0x290207, 0x0 },
+       { 0x90208, 0x0 },
+       { 0x190208, 0x0 },
+       { 0x290208, 0x0 },
+       { 0x10062, 0x0 },
+       { 0x10162, 0x0 },
+       { 0x10262, 0x0 },
+       { 0x10362, 0x0 },
+       { 0x10462, 0x0 },
+       { 0x10562, 0x0 },
+       { 0x10662, 0x0 },
+       { 0x10762, 0x0 },
+       { 0x10862, 0x0 },
+       { 0x11062, 0x0 },
+       { 0x11162, 0x0 },
+       { 0x11262, 0x0 },
+       { 0x11362, 0x0 },
+       { 0x11462, 0x0 },
+       { 0x11562, 0x0 },
+       { 0x11662, 0x0 },
+       { 0x11762, 0x0 },
+       { 0x11862, 0x0 },
+       { 0x12062, 0x0 },
+       { 0x12162, 0x0 },
+       { 0x12262, 0x0 },
+       { 0x12362, 0x0 },
+       { 0x12462, 0x0 },
+       { 0x12562, 0x0 },
+       { 0x12662, 0x0 },
+       { 0x12762, 0x0 },
+       { 0x12862, 0x0 },
+       { 0x13062, 0x0 },
+       { 0x13162, 0x0 },
+       { 0x13262, 0x0 },
+       { 0x13362, 0x0 },
+       { 0x13462, 0x0 },
+       { 0x13562, 0x0 },
+       { 0x13662, 0x0 },
+       { 0x13762, 0x0 },
+       { 0x13862, 0x0 },
+       { 0x20077, 0x0 },
+       { 0x10001, 0x0 },
+       { 0x11001, 0x0 },
+       { 0x12001, 0x0 },
+       { 0x13001, 0x0 },
+       { 0x10040, 0x0 },
+       { 0x10140, 0x0 },
+       { 0x10240, 0x0 },
+       { 0x10340, 0x0 },
+       { 0x10440, 0x0 },
+       { 0x10540, 0x0 },
+       { 0x10640, 0x0 },
+       { 0x10740, 0x0 },
+       { 0x10840, 0x0 },
+       { 0x10030, 0x0 },
+       { 0x10130, 0x0 },
+       { 0x10230, 0x0 },
+       { 0x10330, 0x0 },
+       { 0x10430, 0x0 },
+       { 0x10530, 0x0 },
+       { 0x10630, 0x0 },
+       { 0x10730, 0x0 },
+       { 0x10830, 0x0 },
+       { 0x11040, 0x0 },
+       { 0x11140, 0x0 },
+       { 0x11240, 0x0 },
+       { 0x11340, 0x0 },
+       { 0x11440, 0x0 },
+       { 0x11540, 0x0 },
+       { 0x11640, 0x0 },
+       { 0x11740, 0x0 },
+       { 0x11840, 0x0 },
+       { 0x11030, 0x0 },
+       { 0x11130, 0x0 },
+       { 0x11230, 0x0 },
+       { 0x11330, 0x0 },
+       { 0x11430, 0x0 },
+       { 0x11530, 0x0 },
+       { 0x11630, 0x0 },
+       { 0x11730, 0x0 },
+       { 0x11830, 0x0 },
+       { 0x12040, 0x0 },
+       { 0x12140, 0x0 },
+       { 0x12240, 0x0 },
+       { 0x12340, 0x0 },
+       { 0x12440, 0x0 },
+       { 0x12540, 0x0 },
+       { 0x12640, 0x0 },
+       { 0x12740, 0x0 },
+       { 0x12840, 0x0 },
+       { 0x12030, 0x0 },
+       { 0x12130, 0x0 },
+       { 0x12230, 0x0 },
+       { 0x12330, 0x0 },
+       { 0x12430, 0x0 },
+       { 0x12530, 0x0 },
+       { 0x12630, 0x0 },
+       { 0x12730, 0x0 },
+       { 0x12830, 0x0 },
+       { 0x13040, 0x0 },
+       { 0x13140, 0x0 },
+       { 0x13240, 0x0 },
+       { 0x13340, 0x0 },
+       { 0x13440, 0x0 },
+       { 0x13540, 0x0 },
+       { 0x13640, 0x0 },
+       { 0x13740, 0x0 },
+       { 0x13840, 0x0 },
+       { 0x13030, 0x0 },
+       { 0x13130, 0x0 },
+       { 0x13230, 0x0 },
+       { 0x13330, 0x0 },
+       { 0x13430, 0x0 },
+       { 0x13530, 0x0 },
+       { 0x13630, 0x0 },
+       { 0x13730, 0x0 },
+       { 0x13830, 0x0 },
+};
+
+uint32_t ddrphy_trained_csr_num = ARRAY_SIZE(ddrphy_trained_csr);
diff --git a/drivers/ddr/imx/phy/ddrphy_train.c b/drivers/ddr/imx/phy/ddrphy_train.c
new file mode 100644 (file)
index 0000000..cd905f9
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <log.h>
+#include <linux/kernel.h>
+#include <asm/arch/ddr.h>
+#include <asm/arch/sys_proto.h>
+
+int ddr_cfg_phy(struct dram_timing_info *dram_timing)
+{
+       struct dram_cfg_param *dram_cfg;
+       struct dram_fsp_msg *fsp_msg;
+       unsigned int num;
+       int i = 0;
+       int j = 0;
+       int ret;
+
+       /* initialize PHY configuration */
+       dram_cfg = dram_timing->ddrphy_cfg;
+       num  = dram_timing->ddrphy_cfg_num;
+       for (i = 0; i < num; i++) {
+               /* config phy reg */
+               dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+               dram_cfg++;
+       }
+
+       /* load the frequency setpoint message block config */
+       fsp_msg = dram_timing->fsp_msg;
+       for (i = 0; i < dram_timing->fsp_msg_num; i++) {
+               debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
+               /* set dram PHY input clocks to desired frequency */
+               ddrphy_init_set_dfi_clk(fsp_msg->drate);
+
+               /* load the dram training firmware image */
+               dwc_ddrphy_apb_wr(0xd0000, 0x0);
+               ddr_load_train_firmware(fsp_msg->fw_type);
+
+               /* load the frequency set point message block parameter */
+               dram_cfg = fsp_msg->fsp_cfg;
+               num = fsp_msg->fsp_cfg_num;
+               for (j = 0; j < num; j++) {
+                       dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+                       dram_cfg++;
+               }
+
+               /*
+                * -------------------- excute the firmware --------------------
+                * Running the firmware is a simply process to taking the
+                * PMU out of reset and stall, then the firwmare will be run
+                * 1. reset the PMU;
+                * 2. begin the excution;
+                * 3. wait for the training done;
+                * 4. read the message block result.
+                * -------------------------------------------------------------
+                */
+               dwc_ddrphy_apb_wr(0xd0000, 0x1);
+               dwc_ddrphy_apb_wr(0xd0099, 0x9);
+               dwc_ddrphy_apb_wr(0xd0099, 0x1);
+               dwc_ddrphy_apb_wr(0xd0099, 0x0);
+
+               /* Wait for the training firmware to complete */
+               ret = wait_ddrphy_training_complete();
+               if (ret)
+                       return ret;
+
+               /* Halt the microcontroller. */
+               dwc_ddrphy_apb_wr(0xd0099, 0x1);
+
+               /* Read the Message Block results */
+               dwc_ddrphy_apb_wr(0xd0000, 0x0);
+
+               ddrphy_init_read_msg_block(fsp_msg->fw_type);
+
+               if(fsp_msg->fw_type != FW_2D_IMAGE)
+                       get_trained_CDD(i);
+
+               dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
+
+               fsp_msg++;
+       }
+
+       /* Load PHY Init Engine Image */
+       dram_cfg = dram_timing->ddrphy_pie;
+       num = dram_timing->ddrphy_pie_num;
+       for (i = 0; i < num; i++) {
+               dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+               dram_cfg++;
+       }
+
+       /* save the ddr PHY trained CSR in memory for low power use */
+       ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num);
+
+       return 0;
+}
diff --git a/drivers/ddr/imx/phy/ddrphy_utils.c b/drivers/ddr/imx/phy/ddrphy_utils.c
new file mode 100644 (file)
index 0000000..b852c87
--- /dev/null
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch/ddr.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/ddr.h>
+#include <asm/arch/sys_proto.h>
+
+static inline void poll_pmu_message_ready(void)
+{
+       unsigned int reg;
+
+       do {
+               reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0004));
+       } while (reg & 0x1);
+}
+
+static inline void ack_pmu_message_receive(void)
+{
+       unsigned int reg;
+
+       reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0031), 0x0);
+
+       do {
+               reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0004));
+       } while (!(reg & 0x1));
+
+       reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0031), 0x1);
+}
+
+static inline unsigned int get_mail(void)
+{
+       unsigned int reg;
+
+       poll_pmu_message_ready();
+
+       reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0032));
+
+       ack_pmu_message_receive();
+
+       return reg;
+}
+
+static inline unsigned int get_stream_message(void)
+{
+       unsigned int reg, reg2;
+
+       poll_pmu_message_ready();
+
+       reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0032));
+
+       reg2 = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0034));
+
+       reg2 = (reg2 << 16) | reg;
+
+       ack_pmu_message_receive();
+
+       return reg2;
+}
+
+static inline void decode_major_message(unsigned int mail)
+{
+       debug("[PMU Major message = 0x%08x]\n", mail);
+}
+
+static inline void decode_streaming_message(void)
+{
+       unsigned int string_index, arg __maybe_unused;
+       int i = 0;
+
+       string_index = get_stream_message();
+       debug("PMU String index = 0x%08x\n", string_index);
+       while (i < (string_index & 0xffff)) {
+               arg = get_stream_message();
+               debug("arg[%d] = 0x%08x\n", i, arg);
+               i++;
+       }
+
+       debug("\n");
+}
+
+int wait_ddrphy_training_complete(void)
+{
+       unsigned int mail;
+
+       while (1) {
+               mail = get_mail();
+               decode_major_message(mail);
+               if (mail == 0x08) {
+                       decode_streaming_message();
+               } else if (mail == 0x07) {
+                       debug("Training PASS\n");
+                       return 0;
+               } else if (mail == 0xff) {
+                       printf("Training FAILED\n");
+                       return -1;
+               }
+       }
+}
+
+void ddrphy_init_set_dfi_clk(unsigned int drate)
+{
+       switch (drate) {
+       case 4000:
+               dram_pll_init(MHZ(1000));
+               dram_disable_bypass();
+               break;
+       case 3733:
+               dram_pll_init(MHZ(933));
+               dram_disable_bypass();
+               break;
+       case 3200:
+               dram_pll_init(MHZ(800));
+               dram_disable_bypass();
+               break;
+       case 3000:
+               dram_pll_init(MHZ(750));
+               dram_disable_bypass();
+               break;
+       case 2800:
+               dram_pll_init(MHZ(700));
+               dram_disable_bypass();
+               break;
+       case 2400:
+               dram_pll_init(MHZ(600));
+               dram_disable_bypass();
+               break;
+       case 1866:
+               dram_pll_init(MHZ(466));
+               dram_disable_bypass();
+               break;
+       case 1600:
+               dram_pll_init(MHZ(400));
+               dram_disable_bypass();
+               break;
+       case 1066:
+               dram_pll_init(MHZ(266));
+               dram_disable_bypass();
+               break;
+       case 667:
+               dram_pll_init(MHZ(167));
+               dram_disable_bypass();
+               break;
+       case 400:
+               dram_enable_bypass(MHZ(400));
+               break;
+       case 333:
+               dram_enable_bypass(MHZ(333));
+               break;
+       case 200:
+               dram_enable_bypass(MHZ(200));
+               break;
+       case 100:
+               dram_enable_bypass(MHZ(100));
+               break;
+       default:
+               return;
+       }
+}
+
+void ddrphy_init_read_msg_block(enum fw_type type)
+{
+}
diff --git a/drivers/ddr/imx/phy/helper.c b/drivers/ddr/imx/phy/helper.c
new file mode 100644 (file)
index 0000000..60d650e
--- /dev/null
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/ddr.h>
+#include <asm/arch/ddr.h>
+#include <asm/sections.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define IMEM_LEN 32768 /* byte */
+#define DMEM_LEN 16384 /* byte */
+#define IMEM_2D_OFFSET 49152
+
+#define IMEM_OFFSET_ADDR 0x00050000
+#define DMEM_OFFSET_ADDR 0x00054000
+#define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0)
+
+/* We need PHY iMEM PHY is 32KB padded */
+void ddr_load_train_firmware(enum fw_type type)
+{
+       u32 tmp32, i;
+       u32 error = 0;
+       unsigned long pr_to32, pr_from32;
+       unsigned long fw_offset = type ? IMEM_2D_OFFSET : 0;
+       unsigned long imem_start = (unsigned long)&_end + fw_offset;
+       unsigned long dmem_start;
+
+#ifdef CONFIG_SPL_OF_CONTROL
+       if (gd->fdt_blob && !fdt_check_header(gd->fdt_blob)) {
+               imem_start = roundup((unsigned long)&_end +
+                                    fdt_totalsize(gd->fdt_blob), 4) +
+                       fw_offset;
+       }
+#endif
+
+       dmem_start = imem_start + IMEM_LEN;
+
+       pr_from32 = imem_start;
+       pr_to32 = IMEM_OFFSET_ADDR;
+       for (i = 0x0; i < IMEM_LEN; ) {
+               tmp32 = readl(pr_from32);
+               writew(tmp32 & 0x0000ffff, DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32));
+               pr_to32 += 1;
+               writew((tmp32 >> 16) & 0x0000ffff,
+                      DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32));
+               pr_to32 += 1;
+               pr_from32 += 4;
+               i += 4;
+       }
+
+       pr_from32 = dmem_start;
+       pr_to32 = DMEM_OFFSET_ADDR;
+       for (i = 0x0; i < DMEM_LEN; ) {
+               tmp32 = readl(pr_from32);
+               writew(tmp32 & 0x0000ffff, DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32));
+               pr_to32 += 1;
+               writew((tmp32 >> 16) & 0x0000ffff,
+                      DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32));
+               pr_to32 += 1;
+               pr_from32 += 4;
+               i += 4;
+       }
+
+       debug("check ddr_pmu_train_imem code\n");
+       pr_from32 = imem_start;
+       pr_to32 = IMEM_OFFSET_ADDR;
+       for (i = 0x0; i < IMEM_LEN; ) {
+               tmp32 = (readw(DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)) & 0x0000ffff);
+               pr_to32 += 1;
+               tmp32 += ((readw(DDR_TRAIN_CODE_BASE_ADDR +
+                         ddrphy_addr_remap(pr_to32)) & 0x0000ffff) << 16);
+
+               if (tmp32 != readl(pr_from32)) {
+                       debug("%lx %lx\n", pr_from32, pr_to32);
+                       error++;
+               }
+               pr_from32 += 4;
+               pr_to32 += 1;
+               i += 4;
+       }
+       if (error)
+               printf("check ddr_pmu_train_imem code fail=%d\n", error);
+       else
+               debug("check ddr_pmu_train_imem code pass\n");
+
+       debug("check ddr4_pmu_train_dmem code\n");
+       pr_from32 = dmem_start;
+       pr_to32 = DMEM_OFFSET_ADDR;
+       for (i = 0x0; i < DMEM_LEN;) {
+               tmp32 = (readw(DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)) & 0x0000ffff);
+               pr_to32 += 1;
+               tmp32 += ((readw(DDR_TRAIN_CODE_BASE_ADDR +
+                         ddrphy_addr_remap(pr_to32)) & 0x0000ffff) << 16);
+               if (tmp32 != readl(pr_from32)) {
+                       debug("%lx %lx\n", pr_from32, pr_to32);
+                       error++;
+               }
+               pr_from32 += 4;
+               pr_to32 += 1;
+               i += 4;
+       }
+
+       if (error)
+               printf("check ddr_pmu_train_dmem code fail=%d", error);
+       else
+               debug("check ddr_pmu_train_dmem code pass\n");
+}
+
+void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr,
+                            unsigned int num)
+{
+       int i = 0;
+
+       /* enable the ddrphy apb */
+       dwc_ddrphy_apb_wr(0xd0000, 0x0);
+       dwc_ddrphy_apb_wr(0xc0080, 0x3);
+       for (i = 0; i < num; i++) {
+               ddrphy_csr->val = dwc_ddrphy_apb_rd(ddrphy_csr->reg);
+               ddrphy_csr++;
+       }
+       /* disable the ddrphy apb */
+       dwc_ddrphy_apb_wr(0xc0080, 0x2);
+       dwc_ddrphy_apb_wr(0xd0000, 0x1);
+}
+
+void dram_config_save(struct dram_timing_info *timing_info,
+                     unsigned long saved_timing_base)
+{
+       int i = 0;
+       struct dram_timing_info *saved_timing = (struct dram_timing_info *)saved_timing_base;
+       struct dram_cfg_param *cfg;
+
+       saved_timing->ddrc_cfg_num = timing_info->ddrc_cfg_num;
+       saved_timing->ddrphy_cfg_num = timing_info->ddrphy_cfg_num;
+       saved_timing->ddrphy_trained_csr_num = ddrphy_trained_csr_num;
+       saved_timing->ddrphy_pie_num = timing_info->ddrphy_pie_num;
+
+       /* save the fsp table */
+       for (i = 0; i < 4; i++)
+               saved_timing->fsp_table[i] = timing_info->fsp_table[i];
+
+       cfg = (struct dram_cfg_param *)(saved_timing_base +
+                                       sizeof(*timing_info));
+
+       /* save ddrc config */
+       saved_timing->ddrc_cfg = cfg;
+       for (i = 0; i < timing_info->ddrc_cfg_num; i++) {
+               cfg->reg = timing_info->ddrc_cfg[i].reg;
+               cfg->val = timing_info->ddrc_cfg[i].val;
+               cfg++;
+       }
+
+       /* save ddrphy config */
+       saved_timing->ddrphy_cfg = cfg;
+       for (i = 0; i < timing_info->ddrphy_cfg_num; i++) {
+               cfg->reg = timing_info->ddrphy_cfg[i].reg;
+               cfg->val = timing_info->ddrphy_cfg[i].val;
+               cfg++;
+       }
+
+       /* save the ddrphy csr */
+       saved_timing->ddrphy_trained_csr = cfg;
+       for (i = 0; i < ddrphy_trained_csr_num; i++) {
+               cfg->reg = ddrphy_trained_csr[i].reg;
+               cfg->val = ddrphy_trained_csr[i].val;
+               cfg++;
+       }
+
+       /* save the ddrphy pie */
+       saved_timing->ddrphy_pie = cfg;
+       for (i = 0; i < timing_info->ddrphy_pie_num; i++) {
+               cfg->reg = timing_info->ddrphy_pie[i].reg;
+               cfg->val = timing_info->ddrphy_pie[i].val;
+               cfg++;
+       }
+}