]>
Commit | Line | Data |
---|---|---|
7ff02556 | 1 | // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
53c45f0c | 2 | /* |
7ff02556 | 3 | * (C) Copyright 2015 Rockchip Electronics Co., Ltd |
53c45f0c | 4 | */ |
d678a59d | 5 | #include <common.h> |
691d719d | 6 | #include <init.h> |
53c45f0c | 7 | #include <asm/types.h> |
15f09a1a KY |
8 | #include <asm/arch-rockchip/cru_rk3036.h> |
9 | #include <asm/arch-rockchip/grf_rk3036.h> | |
10 | #include <asm/arch-rockchip/hardware.h> | |
11 | #include <asm/arch-rockchip/sdram_rk3036.h> | |
15f09a1a | 12 | #include <asm/arch-rockchip/uart.h> |
c05ed00a | 13 | #include <linux/delay.h> |
53c45f0c | 14 | |
15 | /* | |
16 | * we can not fit the code to access the device tree in SPL | |
17 | * (due to 4K SRAM size limits), so these are hard-coded | |
18 | */ | |
19 | #define CRU_BASE 0x20000000 | |
20 | #define GRF_BASE 0x20008000 | |
21 | #define DDR_PHY_BASE 0x2000a000 | |
22 | #define DDR_PCTL_BASE 0x20004000 | |
23 | #define CPU_AXI_BUS_BASE 0x10128000 | |
24 | ||
25 | struct rk3036_sdram_priv { | |
26 | struct rk3036_cru *cru; | |
27 | struct rk3036_grf *grf; | |
28 | struct rk3036_ddr_phy *phy; | |
29 | struct rk3036_ddr_pctl *pctl; | |
30 | struct rk3036_service_sys *axi_bus; | |
31 | ||
32 | /* ddr die config */ | |
33 | struct rk3036_ddr_config ddr_config; | |
34 | }; | |
35 | ||
faa75ad9 KY |
36 | /* |
37 | * use integer mode, dpll output 792MHz and ddr get 396MHz | |
53c45f0c | 38 | * refdiv, fbdiv, postdiv1, postdiv2 |
39 | */ | |
faa75ad9 | 40 | const struct pll_div dpll_init_cfg = {1, 66, 2, 1}; |
53c45f0c | 41 | |
42 | /* 396Mhz ddr timing */ | |
43 | const struct rk3036_ddr_timing ddr_timing = {0x18c, | |
44 | {0x18c, 0xc8, 0x1f4, 0x27, 0x4e, | |
45 | 0x4, 0x8b, 0x06, 0x03, 0x0, 0x06, 0x05, 0x0f, 0x15, 0x06, 0x04, 0x04, | |
46 | 0x06, 0x04, 0x200, 0x03, 0x0a, 0x40, 0x2710, 0x01, 0x05, 0x05, 0x03, | |
47 | 0x0c, 0x28, 0x100, 0x0, 0x04, 0x0}, | |
48 | {{0x420, 0x42, 0x0, 0x0}, 0x01, 0x60}, | |
49 | {0x24717315} }; | |
50 | ||
51 | /* | |
52 | * [7:6] bank(n:n bit bank) | |
53 | * [5:4] row(13+n) | |
54 | * [3] cs(0:1 cs, 1:2 cs) | |
55 | * [2:1] bank(n:n bit bank) | |
56 | * [0] col(10+n) | |
57 | */ | |
58 | const char ddr_cfg_2_rbc[] = { | |
59 | ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 1), | |
60 | ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 0), | |
61 | ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 0), | |
62 | ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 0), | |
63 | ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 1), | |
64 | ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 1), | |
65 | ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 1), | |
66 | ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 0), | |
67 | ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 1), | |
68 | ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 0), | |
69 | ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 1), | |
70 | ((1 << 6) | (2 << 4) | (0 << 3) | (2 << 1) | 0), | |
71 | ((3 << 6) | (2 << 4) | (0 << 3) | (0 << 1) | 1), | |
72 | ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 0), | |
73 | }; | |
74 | ||
75 | /* DDRPHY REG */ | |
76 | enum { | |
77 | /* DDRPHY_REG1 */ | |
78 | SOFT_RESET_MASK = 3, | |
79 | SOFT_RESET_SHIFT = 2, | |
80 | ||
81 | /* DDRPHY_REG2 */ | |
82 | MEMORY_SELECT_DDR3 = 0 << 6, | |
83 | DQS_SQU_CAL_NORMAL_MODE = 0 << 1, | |
84 | DQS_SQU_CAL_START = 1 << 0, | |
85 | DQS_SQU_NO_CAL = 0 << 0, | |
86 | ||
87 | /* DDRPHY_REG2A */ | |
88 | CMD_DLL_BYPASS = 1 << 4, | |
89 | CMD_DLL_BYPASS_DISABLE = 0 << 4, | |
90 | HIGH_8BIT_DLL_BYPASS = 1 << 3, | |
91 | HIGH_8BIT_DLL_BYPASS_DISABLE = 0 << 3, | |
92 | LOW_8BIT_DLL_BYPASS = 1 << 2, | |
93 | LOW_8BIT_DLL_BYPASS_DISABLE = 0 << 2, | |
94 | ||
95 | /* DDRPHY_REG19 */ | |
96 | CMD_FEEDBACK_ENABLE = 1 << 5, | |
97 | CMD_SLAVE_DLL_INVERSE_MODE = 1 << 4, | |
98 | CMD_SLAVE_DLL_NO_INVERSE_MODE = 0 << 4, | |
99 | CMD_SLAVE_DLL_ENALBE = 1 << 3, | |
100 | CMD_TX_SLAVE_DLL_DELAY_MASK = 7, | |
101 | CMD_TX_SLAVE_DLL_DELAY_SHIFT = 0, | |
102 | ||
103 | /* DDRPHY_REG6 */ | |
104 | LEFT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4, | |
105 | LEFT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4, | |
106 | LEFT_CHN_TX_DQ_DLL_ENABLE = 1 << 3, | |
107 | LEFT_CHN_TX_DQ_DLL_DELAY_MASK = 7, | |
108 | LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0, | |
109 | ||
110 | /* DDRPHY_REG8 */ | |
111 | LEFT_CHN_RX_DQS_DELAY_TAP_MASK = 3, | |
112 | LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0, | |
113 | ||
114 | /* DDRPHY_REG9 */ | |
115 | RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4, | |
116 | RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4, | |
117 | RIGHT_CHN_TX_DQ_DLL_ENABLE = 1 << 3, | |
118 | RIGHT_CHN_TX_DQ_DLL_DELAY_MASK = 7, | |
119 | RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0, | |
120 | ||
121 | /* DDRPHY_REG11 */ | |
122 | RIGHT_CHN_RX_DQS_DELAY_TAP_MASK = 3, | |
123 | RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0, | |
124 | ||
125 | /* DDRPHY_REG62 */ | |
126 | CAL_DONE_MASK = 3, | |
127 | HIGH_8BIT_CAL_DONE = 1 << 1, | |
128 | LOW_8BIT_CAL_DONE = 1 << 0, | |
129 | }; | |
130 | ||
131 | /* PTCL */ | |
132 | enum { | |
133 | /* PCTL_DFISTCFG0 */ | |
134 | DFI_INIT_START = 1 << 0, | |
135 | DFI_DATA_BYTE_DISABLE_EN = 1 << 2, | |
136 | ||
137 | /* PCTL_DFISTCFG1 */ | |
138 | DFI_DRAM_CLK_SR_EN = 1 << 0, | |
139 | DFI_DRAM_CLK_DPD_EN = 1 << 1, | |
140 | ||
141 | /* PCTL_DFISTCFG2 */ | |
142 | DFI_PARITY_INTR_EN = 1 << 0, | |
143 | DFI_PARITY_EN = 1 << 1, | |
144 | ||
145 | /* PCTL_DFILPCFG0 */ | |
146 | TLP_RESP_TIME_SHIFT = 16, | |
147 | LP_SR_EN = 1 << 8, | |
148 | LP_PD_EN = 1 << 0, | |
149 | ||
150 | /* PCTL_DFIODTCFG */ | |
151 | RANK0_ODT_WRITE_SEL = 1 << 3, | |
152 | RANK1_ODT_WRITE_SEL = 1 << 11, | |
153 | ||
154 | /* PCTL_DFIODTCFG1 */ | |
155 | ODT_LEN_BL8_W_SHIFT = 16, | |
156 | ||
157 | /* PCTL_MCFG */ | |
158 | TFAW_CFG_MASK = 3, | |
159 | TFAW_CFG_SHIFT = 18, | |
160 | PD_EXIT_SLOW_MODE = 0 << 17, | |
161 | PD_ACTIVE_POWER_DOWN = 1 << 16, | |
162 | PD_IDLE_MASK = 0xff, | |
163 | PD_IDLE_SHIFT = 8, | |
164 | MEM_BL4 = 0 << 0, | |
165 | MEM_BL8 = 1 << 0, | |
166 | ||
167 | /* PCTL_MCFG1 */ | |
168 | HW_EXIT_IDLE_EN_MASK = 1, | |
169 | HW_EXIT_IDLE_EN_SHIFT = 31, | |
170 | SR_IDLE_MASK = 0x1ff, | |
171 | SR_IDLE_SHIFT = 0, | |
172 | ||
173 | /* PCTL_SCFG */ | |
174 | HW_LOW_POWER_EN = 1 << 0, | |
175 | ||
176 | /* PCTL_POWCTL */ | |
177 | POWER_UP_START = 1 << 0, | |
178 | ||
179 | /* PCTL_POWSTAT */ | |
180 | POWER_UP_DONE = 1 << 0, | |
181 | ||
182 | /* PCTL_MCMD */ | |
183 | START_CMD = 1 << 31, | |
184 | BANK_ADDR_MASK = 7, | |
185 | BANK_ADDR_SHIFT = 17, | |
186 | CMD_ADDR_MASK = 0x1fff, | |
187 | CMD_ADDR_SHIFT = 4, | |
188 | DESELECT_CMD = 0, | |
189 | PREA_CMD, | |
190 | REF_CMD, | |
191 | MRS_CMD, | |
192 | ZQCS_CMD, | |
193 | ZQCL_CMD, | |
194 | RSTL_CMD, | |
195 | MRR_CMD = 8, | |
196 | ||
197 | /* PCTL_STAT */ | |
198 | INIT_MEM = 0, | |
199 | CONFIG, | |
6e7df1d1 | 200 | CFG_REQ, |
53c45f0c | 201 | ACCESS, |
202 | ACCESS_REQ, | |
203 | LOW_POWER, | |
204 | LOW_POWER_ENTRY_REQ, | |
205 | LOW_POWER_EXIT_REQ, | |
206 | PCTL_STAT_MASK = 7, | |
207 | ||
208 | /* PCTL_SCTL */ | |
209 | INIT_STATE = 0, | |
210 | CFG_STATE = 1, | |
211 | GO_STATE = 2, | |
212 | SLEEP_STATE = 3, | |
213 | WAKEUP_STATE = 4, | |
214 | }; | |
215 | ||
216 | /* GRF_SOC_CON2 */ | |
217 | #define MSCH4_MAINDDR3 (1 << 7) | |
218 | #define PHY_DRV_ODT_SET(n) ((n << 4) | n) | |
219 | #define DDR3_DLL_RESET (1 << 8) | |
220 | ||
221 | /* CK pull up/down driver strength control */ | |
222 | enum { | |
223 | PHY_RON_DISABLE = 0, | |
224 | PHY_RON_309OHM = 1, | |
225 | PHY_RON_155OHM, | |
226 | PHY_RON_103OHM = 3, | |
227 | PHY_RON_63OHM = 5, | |
228 | PHY_RON_45OHM = 7, | |
229 | PHY_RON_77OHM, | |
230 | PHY_RON_62OHM, | |
231 | PHY_RON_52OHM, | |
232 | PHY_RON_44OHM, | |
233 | PHY_RON_39OHM, | |
234 | PHY_RON_34OHM, | |
235 | PHY_RON_31OHM, | |
236 | PHY_RON_28OHM, | |
237 | }; | |
238 | ||
239 | /* DQ pull up/down control */ | |
240 | enum { | |
241 | PHY_RTT_DISABLE = 0, | |
242 | PHY_RTT_861OHM = 1, | |
243 | PHY_RTT_431OHM, | |
244 | PHY_RTT_287OHM, | |
245 | PHY_RTT_216OHM, | |
246 | PHY_RTT_172OHM, | |
247 | PHY_RTT_145OHM, | |
248 | PHY_RTT_124OHM, | |
249 | PHY_RTT_215OHM, | |
250 | PHY_RTT_144OHM = 0xa, | |
251 | PHY_RTT_123OHM, | |
252 | PHY_RTT_108OHM, | |
253 | PHY_RTT_96OHM, | |
254 | PHY_RTT_86OHM, | |
255 | PHY_RTT_78OHM, | |
256 | }; | |
257 | ||
258 | /* DQS squelch DLL delay */ | |
259 | enum { | |
260 | DQS_DLL_NO_DELAY = 0, | |
261 | DQS_DLL_22P5_DELAY, | |
262 | DQS_DLL_45_DELAY, | |
263 | DQS_DLL_67P5_DELAY, | |
264 | DQS_DLL_90_DELAY, | |
265 | DQS_DLL_112P5_DELAY, | |
266 | DQS_DLL_135_DELAY, | |
267 | DQS_DLL_157P5_DELAY, | |
268 | }; | |
269 | ||
270 | /* GRF_OS_REG1 */ | |
271 | enum { | |
272 | /* | |
273 | * 000: lpddr | |
274 | * 001: ddr | |
275 | * 010: ddr2 | |
276 | * 011: ddr3 | |
277 | * 100: lpddr2-s2 | |
278 | * 101: lpddr2-s4 | |
279 | * 110: lpddr3 | |
280 | */ | |
281 | DDR_TYPE_MASK = 7, | |
282 | DDR_TYPE_SHIFT = 13, | |
283 | ||
284 | /* 0: 1 chn, 1: 2 chn */ | |
285 | DDR_CHN_CNT_SHIFT = 12, | |
286 | ||
287 | /* 0: 1 rank, 1: 2 rank */ | |
288 | DDR_RANK_CNT_MASK = 1, | |
289 | DDR_RANK_CNT_SHIFT = 11, | |
290 | ||
291 | /* | |
292 | * 00: 9col | |
293 | * 01: 10col | |
294 | * 10: 11col | |
295 | * 11: 12col | |
296 | */ | |
297 | DDR_COL_MASK = 3, | |
298 | DDR_COL_SHIFT = 9, | |
299 | ||
300 | /* 0: 8 bank, 1: 4 bank*/ | |
301 | DDR_BANK_MASK = 1, | |
302 | DDR_BANK_SHIFT = 8, | |
303 | ||
304 | /* | |
305 | * 00: 13 row | |
306 | * 01: 14 row | |
307 | * 10: 15 row | |
308 | * 11: 16 row | |
309 | */ | |
310 | DDR_CS0_ROW_MASK = 3, | |
311 | DDR_CS0_ROW_SHIFT = 6, | |
312 | DDR_CS1_ROW_MASK = 3, | |
313 | DDR_CS1_ROW_SHIFT = 4, | |
314 | ||
315 | /* | |
316 | * 00: 32 bit | |
317 | * 01: 16 bit | |
318 | * 10: 8 bit | |
319 | * rk3036 only support 16bit | |
320 | */ | |
321 | DDR_BW_MASK = 3, | |
322 | DDR_BW_SHIFT = 2, | |
323 | DDR_DIE_BW_MASK = 3, | |
324 | DDR_DIE_BW_SHIFT = 0, | |
325 | }; | |
326 | ||
327 | static void rkdclk_init(struct rk3036_sdram_priv *priv) | |
328 | { | |
329 | struct rk3036_pll *pll = &priv->cru->pll[1]; | |
330 | ||
331 | /* pll enter slow-mode */ | |
731cafec | 332 | rk_clrsetreg(&priv->cru->cru_mode_con, DPLL_MODE_MASK, |
53c45f0c | 333 | DPLL_MODE_SLOW << DPLL_MODE_SHIFT); |
334 | ||
335 | /* use integer mode */ | |
fd1f80aa | 336 | rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); |
53c45f0c | 337 | |
338 | rk_clrsetreg(&pll->con0, | |
731cafec | 339 | PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, |
53c45f0c | 340 | (dpll_init_cfg.postdiv1 << PLL_POSTDIV1_SHIFT) | |
341 | dpll_init_cfg.fbdiv); | |
731cafec KY |
342 | rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, |
343 | (dpll_init_cfg.postdiv2 << PLL_POSTDIV2_SHIFT | | |
344 | dpll_init_cfg.refdiv << PLL_REFDIV_SHIFT)); | |
53c45f0c | 345 | |
346 | /* waiting for pll lock */ | |
347 | while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) | |
19d0de3e | 348 | udelay(1); |
53c45f0c | 349 | |
350 | /* PLL enter normal-mode */ | |
731cafec | 351 | rk_clrsetreg(&priv->cru->cru_mode_con, DPLL_MODE_MASK, |
53c45f0c | 352 | DPLL_MODE_NORM << DPLL_MODE_SHIFT); |
353 | } | |
354 | ||
355 | static void copy_to_reg(u32 *dest, const u32 *src, u32 n) | |
356 | { | |
357 | int i; | |
358 | ||
359 | for (i = 0; i < n / sizeof(u32); i++) { | |
360 | writel(*src, dest); | |
361 | src++; | |
362 | dest++; | |
363 | } | |
364 | } | |
365 | ||
366 | void phy_pctrl_reset(struct rk3036_sdram_priv *priv) | |
367 | { | |
368 | struct rk3036_ddr_phy *ddr_phy = priv->phy; | |
369 | ||
370 | rk_clrsetreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | | |
371 | 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT | | |
372 | 1 << DDRPHY_SRST_SHIFT, | |
373 | 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT | | |
374 | 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT); | |
375 | ||
19d0de3e | 376 | udelay(10); |
53c45f0c | 377 | |
378 | rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT | | |
379 | 1 << DDRPHY_SRST_SHIFT); | |
19d0de3e | 380 | udelay(10); |
53c45f0c | 381 | |
382 | rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | | |
383 | 1 << DDRCTRL_SRST_SHIFT); | |
19d0de3e | 384 | udelay(10); |
53c45f0c | 385 | |
386 | clrsetbits_le32(&ddr_phy->ddrphy_reg1, | |
387 | SOFT_RESET_MASK << SOFT_RESET_SHIFT, | |
388 | 0 << SOFT_RESET_SHIFT); | |
19d0de3e | 389 | udelay(10); |
53c45f0c | 390 | clrsetbits_le32(&ddr_phy->ddrphy_reg1, |
391 | SOFT_RESET_MASK << SOFT_RESET_SHIFT, | |
392 | 3 << SOFT_RESET_SHIFT); | |
393 | ||
19d0de3e | 394 | udelay(1); |
53c45f0c | 395 | } |
396 | ||
397 | void phy_dll_bypass_set(struct rk3036_sdram_priv *priv, unsigned int freq) | |
398 | { | |
399 | struct rk3036_ddr_phy *ddr_phy = priv->phy; | |
400 | ||
401 | if (freq < ddr_timing.freq) { | |
402 | writel(CMD_DLL_BYPASS | HIGH_8BIT_DLL_BYPASS | | |
403 | LOW_8BIT_DLL_BYPASS, &ddr_phy->ddrphy_reg2a); | |
404 | ||
405 | writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_90 | | |
406 | LEFT_CHN_TX_DQ_DLL_ENABLE | | |
407 | (0 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) << | |
408 | LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg6); | |
409 | ||
410 | writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 | | |
411 | RIGHT_CHN_TX_DQ_DLL_ENABLE | | |
412 | (0 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) << | |
413 | RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT, | |
414 | &ddr_phy->ddrphy_reg9); | |
415 | } else { | |
416 | writel(CMD_DLL_BYPASS_DISABLE | HIGH_8BIT_DLL_BYPASS_DISABLE | | |
417 | LOW_8BIT_DLL_BYPASS_DISABLE, &ddr_phy->ddrphy_reg2a); | |
418 | ||
419 | writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_0 | | |
420 | LEFT_CHN_TX_DQ_DLL_ENABLE | | |
421 | (4 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) << | |
422 | LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, | |
423 | &ddr_phy->ddrphy_reg6); | |
424 | ||
425 | writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 | | |
426 | RIGHT_CHN_TX_DQ_DLL_ENABLE | | |
427 | (4 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) << | |
428 | RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT, | |
429 | &ddr_phy->ddrphy_reg9); | |
430 | } | |
431 | ||
432 | writel(CMD_SLAVE_DLL_NO_INVERSE_MODE | CMD_SLAVE_DLL_ENALBE | | |
433 | (0 & CMD_TX_SLAVE_DLL_DELAY_MASK) << | |
434 | CMD_TX_SLAVE_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg19); | |
435 | ||
436 | /* 45 degree delay */ | |
437 | writel((DQS_DLL_45_DELAY & LEFT_CHN_RX_DQS_DELAY_TAP_MASK) << | |
438 | LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg8); | |
439 | writel((DQS_DLL_45_DELAY & RIGHT_CHN_RX_DQS_DELAY_TAP_MASK) << | |
440 | RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg11); | |
441 | } | |
442 | ||
443 | static void send_command(struct rk3036_ddr_pctl *pctl, | |
444 | u32 rank, u32 cmd, u32 arg) | |
445 | { | |
446 | writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); | |
19d0de3e | 447 | udelay(1); |
53c45f0c | 448 | while (readl(&pctl->mcmd) & START_CMD) |
449 | ; | |
450 | } | |
451 | ||
452 | static void memory_init(struct rk3036_sdram_priv *priv) | |
453 | { | |
454 | struct rk3036_ddr_pctl *pctl = priv->pctl; | |
455 | ||
456 | send_command(pctl, 3, DESELECT_CMD, 0); | |
19d0de3e | 457 | udelay(1); |
53c45f0c | 458 | send_command(pctl, 3, PREA_CMD, 0); |
459 | send_command(pctl, 3, MRS_CMD, | |
460 | (0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | | |
461 | (ddr_timing.phy_timing.mr[2] & CMD_ADDR_MASK) << | |
462 | CMD_ADDR_SHIFT); | |
463 | ||
464 | send_command(pctl, 3, MRS_CMD, | |
465 | (0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | | |
466 | (ddr_timing.phy_timing.mr[3] & CMD_ADDR_MASK) << | |
467 | CMD_ADDR_SHIFT); | |
468 | ||
469 | send_command(pctl, 3, MRS_CMD, | |
470 | (0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | | |
471 | (ddr_timing.phy_timing.mr[1] & CMD_ADDR_MASK) << | |
472 | CMD_ADDR_SHIFT); | |
473 | ||
474 | send_command(pctl, 3, MRS_CMD, | |
475 | (0x00 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | | |
476 | (ddr_timing.phy_timing.mr[0] & CMD_ADDR_MASK) << | |
477 | CMD_ADDR_SHIFT | DDR3_DLL_RESET); | |
478 | ||
479 | send_command(pctl, 3, ZQCL_CMD, 0); | |
480 | } | |
481 | ||
482 | static void data_training(struct rk3036_sdram_priv *priv) | |
483 | { | |
484 | struct rk3036_ddr_phy *ddr_phy = priv->phy; | |
485 | struct rk3036_ddr_pctl *pctl = priv->pctl; | |
486 | u32 value; | |
487 | ||
488 | /* disable auto refresh */ | |
489 | value = readl(&pctl->trefi), | |
490 | writel(0, &pctl->trefi); | |
491 | ||
492 | clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03, | |
493 | DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_CAL_START); | |
494 | ||
19d0de3e | 495 | udelay(1); |
53c45f0c | 496 | while ((readl(&ddr_phy->ddrphy_reg62) & CAL_DONE_MASK) != |
497 | (HIGH_8BIT_CAL_DONE | LOW_8BIT_CAL_DONE)) { | |
498 | ; | |
499 | } | |
500 | ||
501 | clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03, | |
502 | DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_NO_CAL); | |
503 | ||
504 | /* | |
505 | * since data training will take about 20us, so send some auto | |
506 | * refresh(about 7.8us) to complement the lost time | |
507 | */ | |
508 | send_command(pctl, 3, REF_CMD, 0); | |
509 | send_command(pctl, 3, REF_CMD, 0); | |
510 | send_command(pctl, 3, REF_CMD, 0); | |
511 | ||
512 | writel(value, &pctl->trefi); | |
513 | } | |
514 | ||
515 | static void move_to_config_state(struct rk3036_sdram_priv *priv) | |
516 | { | |
517 | unsigned int state; | |
518 | struct rk3036_ddr_pctl *pctl = priv->pctl; | |
519 | ||
520 | while (1) { | |
521 | state = readl(&pctl->stat) & PCTL_STAT_MASK; | |
522 | switch (state) { | |
523 | case LOW_POWER: | |
524 | writel(WAKEUP_STATE, &pctl->sctl); | |
525 | while ((readl(&pctl->stat) & PCTL_STAT_MASK) | |
526 | != ACCESS) | |
527 | ; | |
528 | /* | |
529 | * If at low power state, need wakeup first, and then | |
530 | * enter the config, so fallthrough | |
531 | */ | |
532 | case ACCESS: | |
533 | /* fallthrough */ | |
534 | case INIT_MEM: | |
535 | writel(CFG_STATE, &pctl->sctl); | |
536 | while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) | |
537 | ; | |
538 | break; | |
539 | case CONFIG: | |
540 | return; | |
541 | default: | |
542 | break; | |
543 | } | |
544 | } | |
545 | } | |
546 | ||
547 | static void move_to_access_state(struct rk3036_sdram_priv *priv) | |
548 | { | |
549 | unsigned int state; | |
550 | struct rk3036_ddr_pctl *pctl = priv->pctl; | |
551 | ||
552 | while (1) { | |
553 | state = readl(&pctl->stat) & PCTL_STAT_MASK; | |
554 | switch (state) { | |
555 | case LOW_POWER: | |
556 | writel(WAKEUP_STATE, &pctl->sctl); | |
557 | while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) | |
558 | ; | |
559 | break; | |
560 | case INIT_MEM: | |
561 | writel(CFG_STATE, &pctl->sctl); | |
562 | while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) | |
563 | ; | |
564 | /* fallthrough */ | |
565 | case CONFIG: | |
566 | writel(GO_STATE, &pctl->sctl); | |
567 | while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) | |
568 | ; | |
569 | break; | |
570 | case ACCESS: | |
571 | return; | |
572 | default: | |
573 | break; | |
574 | } | |
575 | } | |
576 | } | |
577 | ||
578 | static void pctl_cfg(struct rk3036_sdram_priv *priv) | |
579 | { | |
580 | struct rk3036_ddr_pctl *pctl = priv->pctl; | |
581 | u32 burst_len; | |
582 | u32 reg; | |
583 | ||
584 | writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0); | |
585 | writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1); | |
586 | writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); | |
587 | writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN, | |
588 | &pctl->dfilpcfg0); | |
589 | ||
590 | writel(1, &pctl->dfitphyupdtype0); | |
591 | writel(0x0d, &pctl->dfitphyrdlat); | |
592 | ||
593 | /* cs0 and cs1 write odt enable */ | |
594 | writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL), | |
595 | &pctl->dfiodtcfg); | |
596 | ||
597 | /* odt write length */ | |
598 | writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); | |
599 | ||
600 | /* phyupd and ctrlupd disabled */ | |
601 | writel(0, &pctl->dfiupdcfg); | |
602 | ||
603 | if ((ddr_timing.noc_timing.burstlen << 1) == 4) | |
604 | burst_len = MEM_BL4; | |
605 | else | |
606 | burst_len = MEM_BL8; | |
607 | ||
608 | copy_to_reg(&pctl->togcnt1u, &ddr_timing.pctl_timing.togcnt1u, | |
609 | sizeof(struct rk3036_pctl_timing)); | |
610 | reg = readl(&pctl->tcl); | |
611 | writel(reg - 3, &pctl->dfitrddataen); | |
612 | reg = readl(&pctl->tcwl); | |
613 | writel(reg - 1, &pctl->dfitphywrlat); | |
614 | ||
615 | writel(burst_len | (1 & TFAW_CFG_MASK) << TFAW_CFG_SHIFT | | |
616 | PD_EXIT_SLOW_MODE | PD_ACTIVE_POWER_DOWN | | |
617 | (0 & PD_IDLE_MASK) << PD_IDLE_SHIFT, | |
618 | &pctl->mcfg); | |
619 | ||
620 | writel(RK_SETBITS(MSCH4_MAINDDR3), &priv->grf->soc_con2); | |
621 | setbits_le32(&pctl->scfg, HW_LOW_POWER_EN); | |
622 | } | |
623 | ||
624 | static void phy_cfg(struct rk3036_sdram_priv *priv) | |
625 | { | |
626 | struct rk3036_ddr_phy *ddr_phy = priv->phy; | |
627 | struct rk3036_service_sys *axi_bus = priv->axi_bus; | |
628 | ||
629 | writel(ddr_timing.noc_timing.noc_timing, &axi_bus->ddrtiming); | |
630 | writel(0x3f, &axi_bus->readlatency); | |
631 | ||
632 | writel(MEMORY_SELECT_DDR3 | DQS_SQU_CAL_NORMAL_MODE, | |
633 | &ddr_phy->ddrphy_reg2); | |
634 | ||
635 | clrsetbits_le32(&ddr_phy->ddrphy_reg3, 1, ddr_timing.phy_timing.bl); | |
636 | writel(ddr_timing.phy_timing.cl_al, &ddr_phy->ddrphy_reg4a); | |
637 | writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg16); | |
638 | writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg22); | |
639 | writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg25); | |
640 | writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg26); | |
641 | writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg27); | |
642 | writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg28); | |
643 | } | |
644 | ||
645 | void dram_cfg_rbc(struct rk3036_sdram_priv *priv) | |
646 | { | |
647 | char noc_config; | |
648 | int i = 0; | |
649 | struct rk3036_ddr_config config = priv->ddr_config; | |
650 | struct rk3036_service_sys *axi_bus = priv->axi_bus; | |
651 | ||
652 | move_to_config_state(priv); | |
653 | ||
654 | /* 2bit in BIT1, 2 */ | |
655 | if (config.rank == 2) { | |
656 | noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 | | |
657 | 1 << 3 | (config.col - 10); | |
658 | if (noc_config == ddr_cfg_2_rbc[9]) { | |
659 | i = 9; | |
660 | goto finish; | |
661 | } else if (noc_config == ddr_cfg_2_rbc[10]) { | |
662 | i = 10; | |
663 | goto finish; | |
664 | } | |
665 | } | |
666 | ||
667 | noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 | | |
668 | (config.col - 10); | |
669 | ||
670 | for (i = 0; i < sizeof(ddr_cfg_2_rbc); i++) { | |
671 | if (noc_config == ddr_cfg_2_rbc[i]) | |
672 | goto finish; | |
673 | } | |
674 | ||
675 | /* bank: 1 bit in BIT6,7, 1bit in BIT1, 2 */ | |
676 | noc_config = 1 << 6 | (config.cs0_row - 13) << 4 | | |
677 | 2 << 1 | (config.col - 10); | |
678 | if (noc_config == ddr_cfg_2_rbc[11]) { | |
679 | i = 11; | |
680 | goto finish; | |
681 | } | |
682 | ||
683 | /* bank: 2bit in BIT6,7 */ | |
684 | noc_config = (config.bank << 6) | (config.cs0_row - 13) << 4 | | |
685 | (config.col - 10); | |
686 | ||
687 | if (noc_config == ddr_cfg_2_rbc[0]) | |
688 | i = 0; | |
689 | else if (noc_config == ddr_cfg_2_rbc[12]) | |
690 | i = 12; | |
691 | else if (noc_config == ddr_cfg_2_rbc[13]) | |
692 | i = 13; | |
693 | finish: | |
694 | writel(i, &axi_bus->ddrconf); | |
695 | move_to_access_state(priv); | |
696 | } | |
697 | ||
698 | static void sdram_all_config(struct rk3036_sdram_priv *priv) | |
699 | { | |
700 | u32 os_reg = 0; | |
e3906800 | 701 | u32 cs1_row = 0; |
53c45f0c | 702 | struct rk3036_ddr_config config = priv->ddr_config; |
703 | ||
e3906800 | 704 | if (config.rank > 1) |
705 | cs1_row = config.cs1_row - 13; | |
706 | ||
53c45f0c | 707 | os_reg = config.ddr_type << DDR_TYPE_SHIFT | |
708 | 0 << DDR_CHN_CNT_SHIFT | | |
709 | (config.rank - 1) << DDR_RANK_CNT_SHIFT | | |
64a524b0 | 710 | (config.col - 9) << DDR_COL_SHIFT | |
53c45f0c | 711 | (config.bank == 3 ? 0 : 1) << DDR_BANK_SHIFT | |
712 | (config.cs0_row - 13) << DDR_CS0_ROW_SHIFT | | |
e3906800 | 713 | cs1_row << DDR_CS1_ROW_SHIFT | |
64a524b0 KY |
714 | 1 << DDR_BW_SHIFT | |
715 | (2 >> config.bw) << DDR_DIE_BW_SHIFT; | |
53c45f0c | 716 | writel(os_reg, &priv->grf->os_reg[1]); |
717 | } | |
718 | ||
719 | size_t sdram_size(void) | |
720 | { | |
721 | u32 size, os_reg, cs0_row, cs1_row, col, bank, rank; | |
722 | struct rk3036_grf *grf = (void *)GRF_BASE; | |
723 | ||
724 | os_reg = readl(&grf->os_reg[1]); | |
725 | ||
726 | cs0_row = 13 + ((os_reg >> DDR_CS0_ROW_SHIFT) & DDR_CS0_ROW_MASK); | |
727 | cs1_row = 13 + ((os_reg >> DDR_CS1_ROW_SHIFT) & DDR_CS1_ROW_MASK); | |
728 | col = 9 + ((os_reg >> DDR_COL_SHIFT) & DDR_COL_MASK); | |
729 | bank = 3 - ((os_reg >> DDR_BANK_SHIFT) & DDR_BANK_MASK); | |
730 | rank = 1 + ((os_reg >> DDR_RANK_CNT_SHIFT) & DDR_RANK_CNT_MASK); | |
731 | ||
732 | /* row + col + bank + bw(rk3036 only support 16bit, so fix in 1) */ | |
733 | size = 1 << (cs0_row + col + bank + 1); | |
734 | ||
735 | if (rank > 1) | |
736 | size += size >> (cs0_row - cs1_row); | |
737 | ||
738 | return size; | |
739 | } | |
740 | ||
741 | void sdram_init(void) | |
742 | { | |
743 | struct rk3036_sdram_priv sdram_priv; | |
744 | ||
745 | sdram_priv.cru = (void *)CRU_BASE; | |
746 | sdram_priv.grf = (void *)GRF_BASE; | |
747 | sdram_priv.phy = (void *)DDR_PHY_BASE; | |
748 | sdram_priv.pctl = (void *)DDR_PCTL_BASE; | |
749 | sdram_priv.axi_bus = (void *)CPU_AXI_BUS_BASE; | |
750 | ||
751 | get_ddr_config(&sdram_priv.ddr_config); | |
752 | sdram_all_config(&sdram_priv); | |
753 | rkdclk_init(&sdram_priv); | |
754 | phy_pctrl_reset(&sdram_priv); | |
755 | phy_dll_bypass_set(&sdram_priv, ddr_timing.freq); | |
756 | pctl_cfg(&sdram_priv); | |
757 | phy_cfg(&sdram_priv); | |
758 | writel(POWER_UP_START, &sdram_priv.pctl->powctl); | |
759 | while (!(readl(&sdram_priv.pctl->powstat) & POWER_UP_DONE)) | |
760 | ; | |
761 | memory_init(&sdram_priv); | |
762 | move_to_config_state(&sdram_priv); | |
763 | data_training(&sdram_priv); | |
764 | move_to_access_state(&sdram_priv); | |
765 | dram_cfg_rbc(&sdram_priv); | |
766 | } |