imx: mx7: DDR controller configuration for the i.MX7 architecture
authorUri Mashiach <uri.mashiach@compulab.co.il>
Sun, 24 Sep 2017 06:00:23 +0000 (09:00 +0300)
committerStefano Babic <sbabic@denx.de>
Thu, 12 Oct 2017 15:31:16 +0000 (17:31 +0200)
The configuration files imximage.cfg are used for the DDR controller
configuration.
Add DDR configuration function to replace the DDR controller
configuration in the imximage.cfg file. The function can be used for
DDR size detection.

Signed-off-by: Uri Mashiach <uri.mashiach@compulab.co.il>
arch/arm/include/asm/arch-mx7/crm_regs.h
arch/arm/include/asm/arch-mx7/imx-regs.h
arch/arm/include/asm/arch-mx7/mx7-ddr.h [new file with mode: 0644]
arch/arm/mach-imx/mx7/Makefile
arch/arm/mach-imx/mx7/ddr.c [new file with mode: 0644]

index e54a254259508edfa0adbe4855217fa7a6dd9127..611190eee73cc89c07c650a5bd19298e231e5237 100644 (file)
@@ -2055,6 +2055,11 @@ struct mxc_ccm_anatop_reg {
 #define HW_CCM_ROOT_TARGET_TOGGLE(i, v)        writel((v), CCM_ROOT_TARGET_TOGGLE(i))
 
 #define CCM_CLK_ON_MSK 0x03
+#define CCM_CLK_ON_N_N 0x00 /* Domain clocks not needed */
+#define CCM_CLK_ON_R_W 0x02 /* Domain clocks needed when in RUN and WAIT */
+
+/* CCGR Mapping */
+#define CCGR_IDX_DDR 19 /* CCM_CCGR19 */
 
 #define CCM_ROOT_TGT_POST_DIV_SHIFT    0
 #define CCM_ROOT_TGT_PRE_DIV_SHIFT     15
index aab3a9a7a6c8a3b29913d95e907367363cd96bbe..f0693f90286e3089ecae383cd1683cd9b5b03e0b 100644 (file)
@@ -268,6 +268,8 @@ struct src {
 #define SRC_M4RCR_M4C_NON_SCLR_RST_MASK                (1 << 0)
 #define SRC_M4RCR_ENABLE_M4_OFFSET             3
 #define SRC_M4RCR_ENABLE_M4_MASK               (1 << 3)
+#define SRC_DDRC_RCR_DDRC_CORE_RST_OFFSET      1
+#define SRC_DDRC_RCR_DDRC_CORE_RST_MASK                (1 << 1)
 
 /* GPR0 Bit Fields */
 #define IOMUXC_GPR_GPR0_DMAREQ_MUX_SEL0_MASK     0x1u
diff --git a/arch/arm/include/asm/arch-mx7/mx7-ddr.h b/arch/arm/include/asm/arch-mx7/mx7-ddr.h
new file mode 100644 (file)
index 0000000..3a4841c
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * DDR controller registers of the i.MX7 architecture
+ *
+ * (C) Copyright 2017 CompuLab, Ltd. http://www.compulab.com
+ *
+ * Author: Uri Mashiach <uri.mashiach@compulab.co.il>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_MX7_DDR_H__
+#define __ASM_ARCH_MX7_DDR_H__
+
+/* DDRC Registers (DDRC_IPS_BASE_ADDR) */
+struct ddrc {
+       u32 mstr;               /* 0x0000 */
+       u32 reserved1[0x18];
+       u32 rfshtmg;            /* 0x0064 */
+       u32 reserved2[0x1a];
+       u32 init0;              /* 0x00d0 */
+       u32 init1;              /* 0x00d4 */
+       u32 reserved3;
+       u32 init3;              /* 0x00dc */
+       u32 init4;              /* 0x00e0 */
+       u32 init5;              /* 0x00e4 */
+       u32 reserved4[0x03];
+       u32 rankctl;            /* 0x00f4 */
+       u32 reserved5[0x02];
+       u32 dramtmg0;           /* 0x0100 */
+       u32 dramtmg1;           /* 0x0104 */
+       u32 dramtmg2;           /* 0x0108 */
+       u32 dramtmg3;           /* 0x010c */
+       u32 dramtmg4;           /* 0x0110 */
+       u32 dramtmg5;           /* 0x0114 */
+       u32 reserved6[0x02];
+       u32 dramtmg8;           /* 0x0120 */
+       u32 reserved7[0x17];
+       u32 zqctl0;             /* 0x0180 */
+       u32 reserved8[0x03];
+       u32 dfitmg0;            /* 0x0190 */
+       u32 dfitmg1;            /* 0x0194 */
+       u32 reserved9[0x02];
+       u32 dfiupd0;            /* 0x01a0 */
+       u32 dfiupd1;            /* 0x01a4 */
+       u32 dfiupd2;            /* 0x01a8 */
+       u32 reserved10[0x15];
+       u32 addrmap0;           /* 0x0200 */
+       u32 addrmap1;           /* 0x0204 */
+       u32 addrmap2;           /* 0x0208 */
+       u32 addrmap3;           /* 0x020c */
+       u32 addrmap4;           /* 0x0210 */
+       u32 addrmap5;           /* 0x0214 */
+       u32 addrmap6;           /* 0x0218 */
+       u32 reserved12[0x09];
+       u32 odtcfg;             /* 0x0240 */
+       u32 odtmap;             /* 0x0244 */
+};
+
+/* DDRC_MSTR fields */
+#define MSTR_DATA_BUS_WIDTH_MASK       0x3 << 12
+#define MSTR_DATA_BUS_WIDTH_SHIFT      12
+#define MSTR_DATA_ACTIVE_RANKS_MASK    0xf << 24
+#define MSTR_DATA_ACTIVE_RANKS_SHIFT   24
+/* DDRC_ADDRMAP1 fields */
+#define ADDRMAP1_BANK_B0_MASK          0x1f << 0
+#define ADDRMAP1_BANK_B0_SHIFT         0
+#define ADDRMAP1_BANK_B1_MASK          0x1f << 8
+#define ADDRMAP1_BANK_B1_SHIFT         8
+#define ADDRMAP1_BANK_B2_MASK          0x1f << 16
+#define ADDRMAP1_BANK_B2_SHIFT         16
+/* DDRC_ADDRMAP2 fields */
+#define ADDRMAP2_COL_B2_MASK           0xF << 0
+#define ADDRMAP2_COL_B2_SHIFT          0
+#define ADDRMAP2_COL_B3_MASK           0xF << 8
+#define ADDRMAP2_COL_B3_SHIFT          8
+#define ADDRMAP2_COL_B4_MASK           0xF << 16
+#define ADDRMAP2_COL_B4_SHIFT          16
+#define ADDRMAP2_COL_B5_MASK           0xF << 24
+#define ADDRMAP2_COL_B5_SHIFT          24
+/* DDRC_ADDRMAP3 fields */
+#define ADDRMAP3_COL_B6_MASK           0xF << 0
+#define ADDRMAP3_COL_B6_SHIFT          0
+#define ADDRMAP3_COL_B7_MASK           0xF << 8
+#define ADDRMAP3_COL_B7_SHIFT          8
+#define ADDRMAP3_COL_B8_MASK           0xF << 16
+#define ADDRMAP3_COL_B8_SHIFT          16
+#define ADDRMAP3_COL_B9_MASK           0xF << 24
+#define ADDRMAP3_COL_B9_SHIFT          24
+/* DDRC_ADDRMAP4 fields */
+#define ADDRMAP4_COL_B10_MASK          0xF << 0
+#define ADDRMAP4_COL_B10_SHIFT         0
+#define ADDRMAP4_COL_B11_MASK          0xF << 8
+#define ADDRMAP4_COL_B11_SHIFT         8
+/* DDRC_ADDRMAP5 fields */
+#define ADDRMAP5_ROW_B0_MASK           0xF << 0
+#define ADDRMAP5_ROW_B0_SHIFT          0
+#define ADDRMAP5_ROW_B1_MASK           0xF << 8
+#define ADDRMAP5_ROW_B1_SHIFT          8
+#define ADDRMAP5_ROW_B2_10_MASK                0xF << 16
+#define ADDRMAP5_ROW_B2_10_SHIFT       16
+#define ADDRMAP5_ROW_B11_MASK          0xF << 24
+#define ADDRMAP5_ROW_B11_SHIFT         24
+/* DDRC_ADDRMAP6 fields */
+#define ADDRMAP6_ROW_B12_MASK          0xF << 0
+#define ADDRMAP6_ROW_B12_SHIFT         0
+#define ADDRMAP6_ROW_B13_MASK          0xF << 8
+#define ADDRMAP6_ROW_B13_SHIFT         8
+#define ADDRMAP6_ROW_B14_MASK          0xF << 16
+#define ADDRMAP6_ROW_B14_SHIFT         16
+#define ADDRMAP6_ROW_B15_MASK          0xF << 24
+#define ADDRMAP6_ROW_B15_SHIFT         24
+
+/* DDRC_MP Registers */
+#define DDRC_MP_BASE_ADDR (DDRC_IPS_BASE_ADDR + 0x03fc)
+struct ddrc_mp {
+       u32 reserved1[0x25];
+       u32 pctrl_0;            /* 0x0094 */
+};
+
+/* DDR_PHY registers */
+struct ddr_phy {
+       u32 phy_con0;           /* 0x0000 */
+       u32 phy_con1;           /* 0x0004 */
+       u32 reserved1[0x02];
+       u32 phy_con4;           /* 0x0010 */
+       u32 reserved2;
+       u32 offset_lp_con0;     /* 0x0018 */
+       u32 reserved3;
+       u32 offset_rd_con0;     /* 0x0020 */
+       u32 reserved4[0x03];
+       u32 offset_wr_con0;     /* 0x0030 */
+       u32 reserved5[0x07];
+       u32 cmd_sdll_con0;      /* 0x0050 */
+       u32 reserved6[0x12];
+       u32 drvds_con0;         /* 0x009c */
+       u32 reserved7[0x04];
+       u32 mdll_con0;          /* 0x00b0 */
+       u32 reserved8[0x03];
+       u32 zq_con0;            /* 0x00c0 */
+};
+
+#define DDR_PHY_CMD_SDLL_CON0_CTRL_RESYNC_MASK BIT(24)
+
+#define MX7_CAL_VAL_MAX 5
+/* Calibration parameters */
+struct mx7_calibration {
+       int num_val;                    /* Number of calibration values */
+       u32 values[MX7_CAL_VAL_MAX];    /* calibration values */
+};
+
+void mx7_dram_cfg(struct ddrc *ddrc_regs_val, struct ddrc_mp *ddrc_mp_val,
+                 struct ddr_phy *ddr_phy_regs_val,
+                 struct mx7_calibration *calib_param);
+
+#endif /*__ASM_ARCH_MX7_DDR_H__ */
index d21f87f18cb2a919d33ae440996ec3a074ba64f8..ce289c1415a1a4fe24aa1cde64eec90e292ea654 100644 (file)
@@ -5,7 +5,7 @@
 #
 #
 
-obj-y  := soc.o clock.o clock_slice.o
+obj-y  := soc.o clock.o clock_slice.o ddr.o
 
 ifdef CONFIG_ARMV7_PSCI
 obj-y  += psci-mx7.o psci.o
diff --git a/arch/arm/mach-imx/mx7/ddr.c b/arch/arm/mach-imx/mx7/ddr.c
new file mode 100644 (file)
index 0000000..9268ad9
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * DDR controller configuration for the i.MX7 architecture
+ *
+ * (C) Copyright 2017 CompuLab, Ltd. http://www.compulab.com
+ *
+ * Author: Uri Mashiach <uri.mashiach@compulab.co.il>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/mx7-ddr.h>
+#include <common.h>
+
+/*
+ * Routine: mx7_dram_cfg
+ * Description: DDR controller configuration
+ *
+ * @ddrc_regs_val: DDRC registers value
+ * @ddrc_mp_val: DDRC_MP registers value
+ * @ddr_phy_regs_val: DDR_PHY registers value
+ * @calib_param: calibration parameters
+ *
+ */
+void mx7_dram_cfg(struct ddrc *ddrc_regs_val, struct ddrc_mp *ddrc_mp_val,
+                 struct ddr_phy *ddr_phy_regs_val,
+                 struct mx7_calibration *calib_param)
+{
+       struct src *const src_regs = (struct src *)SRC_BASE_ADDR;
+       struct ddrc *const ddrc_regs = (struct ddrc *)DDRC_IPS_BASE_ADDR;
+       struct ddrc_mp *const ddrc_mp_reg = (struct ddrc_mp *)DDRC_MP_BASE_ADDR;
+       struct ddr_phy *const ddr_phy_regs =
+               (struct ddr_phy *)DDRPHY_IPS_BASE_ADDR;
+       struct iomuxc_gpr_base_regs *const iomuxc_gpr_regs =
+               (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
+       int i;
+
+       /* Assert DDR Controller preset and DDR PHY reset */
+       writel(SRC_DDRC_RCR_DDRC_CORE_RST_MASK, &src_regs->ddrc_rcr);
+
+       /* DDR controller configuration */
+       writel(ddrc_regs_val->mstr, &ddrc_regs->mstr);
+       writel(ddrc_regs_val->rfshtmg, &ddrc_regs->rfshtmg);
+       writel(ddrc_mp_val->pctrl_0, &ddrc_mp_reg->pctrl_0);
+       writel(ddrc_regs_val->init1, &ddrc_regs->init1);
+       writel(ddrc_regs_val->init0, &ddrc_regs->init0);
+       writel(ddrc_regs_val->init3, &ddrc_regs->init3);
+       writel(ddrc_regs_val->init4, &ddrc_regs->init4);
+       writel(ddrc_regs_val->init5, &ddrc_regs->init5);
+       writel(ddrc_regs_val->rankctl, &ddrc_regs->rankctl);
+       writel(ddrc_regs_val->dramtmg0, &ddrc_regs->dramtmg0);
+       writel(ddrc_regs_val->dramtmg1, &ddrc_regs->dramtmg1);
+       writel(ddrc_regs_val->dramtmg2, &ddrc_regs->dramtmg2);
+       writel(ddrc_regs_val->dramtmg3, &ddrc_regs->dramtmg3);
+       writel(ddrc_regs_val->dramtmg4, &ddrc_regs->dramtmg4);
+       writel(ddrc_regs_val->dramtmg5, &ddrc_regs->dramtmg5);
+       writel(ddrc_regs_val->dramtmg8, &ddrc_regs->dramtmg8);
+       writel(ddrc_regs_val->zqctl0, &ddrc_regs->zqctl0);
+       writel(ddrc_regs_val->dfitmg0, &ddrc_regs->dfitmg0);
+       writel(ddrc_regs_val->dfitmg1, &ddrc_regs->dfitmg1);
+       writel(ddrc_regs_val->dfiupd0, &ddrc_regs->dfiupd0);
+       writel(ddrc_regs_val->dfiupd1, &ddrc_regs->dfiupd1);
+       writel(ddrc_regs_val->dfiupd2, &ddrc_regs->dfiupd2);
+       writel(ddrc_regs_val->addrmap0, &ddrc_regs->addrmap0);
+       writel(ddrc_regs_val->addrmap1, &ddrc_regs->addrmap1);
+       writel(ddrc_regs_val->addrmap4, &ddrc_regs->addrmap4);
+       writel(ddrc_regs_val->addrmap5, &ddrc_regs->addrmap5);
+       writel(ddrc_regs_val->addrmap6, &ddrc_regs->addrmap6);
+       writel(ddrc_regs_val->odtcfg, &ddrc_regs->odtcfg);
+       writel(ddrc_regs_val->odtmap, &ddrc_regs->odtmap);
+
+       /* De-assert DDR Controller preset and DDR PHY reset */
+       clrbits_le32(&src_regs->ddrc_rcr, SRC_DDRC_RCR_DDRC_CORE_RST_MASK);
+
+       /* PHY configuration */
+       writel(ddr_phy_regs_val->phy_con0, &ddr_phy_regs->phy_con0);
+       writel(ddr_phy_regs_val->phy_con1, &ddr_phy_regs->phy_con1);
+       writel(ddr_phy_regs_val->phy_con4, &ddr_phy_regs->phy_con4);
+       writel(ddr_phy_regs_val->mdll_con0, &ddr_phy_regs->mdll_con0);
+       writel(ddr_phy_regs_val->drvds_con0, &ddr_phy_regs->drvds_con0);
+       writel(ddr_phy_regs_val->offset_wr_con0, &ddr_phy_regs->offset_wr_con0);
+       writel(ddr_phy_regs_val->offset_rd_con0, &ddr_phy_regs->offset_rd_con0);
+       writel(ddr_phy_regs_val->cmd_sdll_con0 |
+              DDR_PHY_CMD_SDLL_CON0_CTRL_RESYNC_MASK,
+              &ddr_phy_regs->cmd_sdll_con0);
+       writel(ddr_phy_regs_val->cmd_sdll_con0 &
+              ~DDR_PHY_CMD_SDLL_CON0_CTRL_RESYNC_MASK,
+              &ddr_phy_regs->cmd_sdll_con0);
+       writel(ddr_phy_regs_val->offset_lp_con0, &ddr_phy_regs->offset_lp_con0);
+
+       /* calibration */
+       for (i = 0; i < calib_param->num_val; i++)
+               writel(calib_param->values[i], &ddr_phy_regs->zq_con0);
+
+       /* Wake_up DDR PHY */
+       HW_CCM_CCGR_WR(CCGR_IDX_DDR, CCM_CLK_ON_N_N);
+       writel(IOMUXC_GPR_GPR8_ddr_phy_ctrl_wake_up(0xf) |
+              IOMUXC_GPR_GPR8_ddr_phy_dfi_init_start_MASK,
+              &iomuxc_gpr_regs->gpr[8]);
+       HW_CCM_CCGR_WR(CCGR_IDX_DDR, CCM_CLK_ON_R_W);
+}
+
+/*
+ * Routine: imx_ddr_size
+ * Description: extract the current DRAM size from the DDRC registers
+ *
+ * @return: DRAM size
+ */
+unsigned int imx_ddr_size(void)
+{
+       struct ddrc *const ddrc_regs = (struct ddrc *)DDRC_IPS_BASE_ADDR;
+       u32 reg_val, field_val;
+       int bits = 0;/* Number of address bits */
+
+       /* Count data bus width bits */
+       reg_val = readl(&ddrc_regs->mstr);
+       field_val = (reg_val & MSTR_DATA_BUS_WIDTH_MASK) >> MSTR_DATA_BUS_WIDTH_SHIFT;
+       bits += 2 - field_val;
+       /* Count rank address bits */
+       field_val = (reg_val & MSTR_DATA_ACTIVE_RANKS_MASK) >> MSTR_DATA_ACTIVE_RANKS_SHIFT;
+       if (field_val > 1)
+               bits += field_val - 1;
+       /* Count column address bits */
+       bits += 2;/* Column address 0 and 1 are fixed mapped */
+       reg_val = readl(&ddrc_regs->addrmap2);
+       field_val = (reg_val & ADDRMAP2_COL_B2_MASK) >> ADDRMAP2_COL_B2_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP2_COL_B3_MASK) >> ADDRMAP2_COL_B3_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP2_COL_B4_MASK) >> ADDRMAP2_COL_B4_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP2_COL_B5_MASK) >> ADDRMAP2_COL_B5_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       reg_val = readl(&ddrc_regs->addrmap3);
+       field_val = (reg_val & ADDRMAP3_COL_B6_MASK) >> ADDRMAP3_COL_B6_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP3_COL_B7_MASK) >> ADDRMAP3_COL_B7_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP3_COL_B8_MASK) >> ADDRMAP3_COL_B8_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP3_COL_B9_MASK) >> ADDRMAP3_COL_B9_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       reg_val = readl(&ddrc_regs->addrmap4);
+       field_val = (reg_val & ADDRMAP4_COL_B10_MASK) >> ADDRMAP4_COL_B10_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       field_val = (reg_val & ADDRMAP4_COL_B11_MASK) >> ADDRMAP4_COL_B11_SHIFT;
+       if (field_val <= 7)
+               bits++;
+       /* Count row address bits */
+       reg_val = readl(&ddrc_regs->addrmap5);
+       field_val = (reg_val & ADDRMAP5_ROW_B0_MASK) >> ADDRMAP5_ROW_B0_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       field_val = (reg_val & ADDRMAP5_ROW_B1_MASK) >> ADDRMAP5_ROW_B1_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       field_val = (reg_val & ADDRMAP5_ROW_B2_10_MASK) >> ADDRMAP5_ROW_B2_10_SHIFT;
+       if (field_val <= 11)
+               bits += 9;
+       field_val = (reg_val & ADDRMAP5_ROW_B11_MASK) >> ADDRMAP5_ROW_B11_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       reg_val = readl(&ddrc_regs->addrmap6);
+       field_val = (reg_val & ADDRMAP6_ROW_B12_MASK) >> ADDRMAP6_ROW_B12_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       field_val = (reg_val & ADDRMAP6_ROW_B13_MASK) >> ADDRMAP6_ROW_B13_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       field_val = (reg_val & ADDRMAP6_ROW_B14_MASK) >> ADDRMAP6_ROW_B14_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       field_val = (reg_val & ADDRMAP6_ROW_B15_MASK) >> ADDRMAP6_ROW_B15_SHIFT;
+       if (field_val <= 11)
+               bits++;
+       /* Count bank bits */
+       reg_val = readl(&ddrc_regs->addrmap1);
+       field_val = (reg_val & ADDRMAP1_BANK_B0_MASK) >> ADDRMAP1_BANK_B0_SHIFT;
+       if (field_val <= 30)
+               bits++;
+       field_val = (reg_val & ADDRMAP1_BANK_B1_MASK) >> ADDRMAP1_BANK_B1_SHIFT;
+       if (field_val <= 30)
+               bits++;
+       field_val = (reg_val & ADDRMAP1_BANK_B2_MASK) >> ADDRMAP1_BANK_B2_SHIFT;
+       if (field_val <= 29)
+               bits++;
+
+       return 1 << bits;
+}