summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/mx7/ddr.c
blob: d1e10a678870ef7a61d81533a0c7b553eb166f3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// SPDX-License-Identifier: GPL-2.0+
/*
 * 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>
 */

#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>
#include <linux/delay.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;

	/*
	 * iMX7D RM 9.2.4.9.3 Power removal flow Table 9-11. Re-enabling power
	 * row 2 says "Reset controller / PHY by driving core_ddrc_rst = 0 ,
	 * aresetn_n = 0, presetn = 0. That means reset everything.
	 */
	writel(SRC_DDRC_RCR_DDRC_CORE_RST_MASK | SRC_DDRC_RCR_DDRC_PRST_MASK,
	       &src_regs->ddrc_rcr);

	/*
	 * iMX7D RM 6.2.7.26 SRC_DDRC_RCR says wait 30 cycles (of unknown).
	 * If we assume this is 30 cycles at 100 MHz (about the rate of a
	 * DRAM bus), that's 300 nS, so waiting 10 uS is more then plenty.
	 */
	udelay(10);

	/* De-assert DDR Controller 'preset' and DDR PHY reset */
	clrbits_le32(&src_regs->ddrc_rcr, SRC_DDRC_RCR_DDRC_PRST_MASK);

	/* 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 'core_ddrc_rstn' and 'aresetn' */
	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++;

	/* cap to max 2 GB */
	if (bits > 31)
		bits = 31;

	return 1 << bits;
}