imx: mx7: DDR controller configuration for the i.MX7 architecture

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>
diff --git a/arch/arm/include/asm/arch-mx7/crm_regs.h b/arch/arm/include/asm/arch-mx7/crm_regs.h
index e54a254..611190e 100644
--- a/arch/arm/include/asm/arch-mx7/crm_regs.h
+++ b/arch/arm/include/asm/arch-mx7/crm_regs.h
@@ -2055,6 +2055,11 @@
 #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
diff --git a/arch/arm/include/asm/arch-mx7/imx-regs.h b/arch/arm/include/asm/arch-mx7/imx-regs.h
index aab3a9a..f0693f9 100644
--- a/arch/arm/include/asm/arch-mx7/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx7/imx-regs.h
@@ -268,6 +268,8 @@
 #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
index 0000000..3a4841c
--- /dev/null
+++ b/arch/arm/include/asm/arch-mx7/mx7-ddr.h
@@ -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__ */
diff --git a/arch/arm/mach-imx/mx7/Makefile b/arch/arm/mach-imx/mx7/Makefile
index d21f87f..ce289c1 100644
--- a/arch/arm/mach-imx/mx7/Makefile
+++ b/arch/arm/mach-imx/mx7/Makefile
@@ -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
index 0000000..9268ad9
--- /dev/null
+++ b/arch/arm/mach-imx/mx7/ddr.c
@@ -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;
+}