]>
Commit | Line | Data |
---|---|---|
81f50d93 | 1 | /* |
2 | * Sun8i a33 platform dram controller init. | |
3 | * | |
4 | * (C) Copyright 2007-2015 Allwinner Technology Co. | |
5 | * Jerry Wang <wangflord@allwinnertech.com> | |
6 | * (C) Copyright 2015 Vishnu Patekar <vishnupatekar0510@gmail.com> | |
7 | * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com> | |
8 | * | |
9 | * SPDX-License-Identifier: GPL-2.0+ | |
10 | */ | |
11 | #include <common.h> | |
12 | #include <errno.h> | |
13 | #include <asm/io.h> | |
14 | #include <asm/arch/clock.h> | |
15 | #include <asm/arch/dram.h> | |
16 | #include <asm/arch/prcm.h> | |
17 | ||
18 | #define DRAM_CLK_MUL 2 | |
19 | #define DRAM_CLK_DIV 1 | |
20 | ||
21 | struct dram_para { | |
22 | u8 cs1; | |
23 | u8 seq; | |
24 | u8 bank; | |
25 | u8 rank; | |
26 | u8 rows; | |
27 | u8 bus_width; | |
f5fd8caf | 28 | u8 dram_type; |
81f50d93 | 29 | u16 page_size; |
30 | }; | |
31 | ||
32 | static void mctl_set_cr(struct dram_para *para) | |
33 | { | |
34 | struct sunxi_mctl_com_reg * const mctl_com = | |
35 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
36 | ||
37 | writel(MCTL_CR_CS1_CONTROL(para->cs1) | MCTL_CR_UNKNOWN | | |
f5fd8caf | 38 | MCTL_CR_CHANNEL(1) | MCTL_CR_DRAM_TYPE(para->dram_type) | |
81f50d93 | 39 | (para->seq ? MCTL_CR_SEQUENCE : 0) | |
40 | ((para->bus_width == 16) ? MCTL_CR_BUSW16 : MCTL_CR_BUSW8) | | |
41 | MCTL_CR_PAGE_SIZE(para->page_size) | MCTL_CR_ROW(para->rows) | | |
42 | MCTL_CR_BANK(para->bank) | MCTL_CR_RANK(para->rank), | |
43 | &mctl_com->cr); | |
44 | } | |
45 | ||
46 | static void auto_detect_dram_size(struct dram_para *para) | |
47 | { | |
48 | u8 orig_rank = para->rank; | |
49 | int rows, columns; | |
50 | ||
51 | /* Row detect */ | |
52 | para->page_size = 512; | |
53 | para->seq = 1; | |
54 | para->rows = 16; | |
55 | para->rank = 1; | |
56 | mctl_set_cr(para); | |
57 | for (rows = 11 ; rows < 16 ; rows++) { | |
58 | if (mctl_mem_matches(1 << (rows + 9))) /* row-column */ | |
59 | break; | |
60 | } | |
61 | ||
62 | /* Column (page size) detect */ | |
63 | para->rows = 11; | |
64 | para->page_size = 8192; | |
65 | mctl_set_cr(para); | |
66 | for (columns = 9 ; columns < 13 ; columns++) { | |
67 | if (mctl_mem_matches(1 << columns)) | |
68 | break; | |
69 | } | |
70 | ||
71 | para->seq = 0; | |
72 | para->rank = orig_rank; | |
73 | para->rows = rows; | |
74 | para->page_size = 1 << columns; | |
75 | mctl_set_cr(para); | |
76 | } | |
77 | ||
78 | static inline int ns_to_t(int nanoseconds) | |
79 | { | |
80 | const unsigned int ctrl_freq = | |
81 | CONFIG_DRAM_CLK * DRAM_CLK_MUL / DRAM_CLK_DIV; | |
82 | ||
83 | return (ctrl_freq * nanoseconds + 999) / 1000; | |
84 | } | |
85 | ||
86 | static void auto_set_timing_para(struct dram_para *para) | |
87 | { | |
88 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
89 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
f5fd8caf | 90 | |
81f50d93 | 91 | u32 reg_val; |
92 | ||
93 | u8 tccd = 2; | |
94 | u8 tfaw = ns_to_t(50); | |
95 | u8 trrd = max(ns_to_t(10), 4); | |
96 | u8 trcd = ns_to_t(15); | |
97 | u8 trc = ns_to_t(53); | |
98 | u8 txp = max(ns_to_t(8), 3); | |
99 | u8 twtr = max(ns_to_t(8), 4); | |
100 | u8 trtp = max(ns_to_t(8), 4); | |
101 | u8 twr = max(ns_to_t(15), 3); | |
102 | u8 trp = ns_to_t(15); | |
103 | u8 tras = ns_to_t(38); | |
104 | ||
105 | u16 trefi = ns_to_t(7800) / 32; | |
106 | u16 trfc = ns_to_t(350); | |
107 | ||
108 | /* Fixed timing parameters */ | |
109 | u8 tmrw = 0; | |
110 | u8 tmrd = 4; | |
111 | u8 tmod = 12; | |
112 | u8 tcke = 3; | |
113 | u8 tcksrx = 5; | |
114 | u8 tcksre = 5; | |
115 | u8 tckesr = 4; | |
116 | u8 trasmax = 24; | |
117 | u8 tcl = 6; /* CL 12 */ | |
118 | u8 tcwl = 4; /* CWL 8 */ | |
119 | u8 t_rdata_en = 4; | |
120 | u8 wr_latency = 2; | |
121 | ||
122 | u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */ | |
123 | u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */ | |
124 | u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ | |
125 | u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */ | |
126 | ||
127 | u8 twtp = tcwl + 2 + twr; /* WL + BL / 2 + tWR */ | |
128 | u8 twr2rd = tcwl + 2 + twtr; /* WL + BL / 2 + tWTR */ | |
129 | u8 trd2wr = tcl + 2 + 1 - tcwl; /* RL + BL / 2 + 2 - WL */ | |
130 | ||
131 | /* Set work mode register */ | |
132 | mctl_set_cr(para); | |
133 | /* Set mode register */ | |
f3ad64c8 VP |
134 | if (para->dram_type == DRAM_TYPE_DDR3) { |
135 | writel(MCTL_MR0, &mctl_ctl->mr0); | |
136 | writel(MCTL_MR1, &mctl_ctl->mr1); | |
137 | writel(MCTL_MR2, &mctl_ctl->mr2); | |
138 | writel(MCTL_MR3, &mctl_ctl->mr3); | |
139 | } else if (para->dram_type == DRAM_TYPE_LPDDR3) { | |
140 | writel(MCTL_LPDDR3_MR0, &mctl_ctl->mr0); | |
141 | writel(MCTL_LPDDR3_MR1, &mctl_ctl->mr1); | |
142 | writel(MCTL_LPDDR3_MR2, &mctl_ctl->mr2); | |
143 | writel(MCTL_LPDDR3_MR3, &mctl_ctl->mr3); | |
144 | ||
145 | /* timing parameters for LPDDR3 */ | |
146 | tfaw = max(ns_to_t(50), 4); | |
147 | trrd = max(ns_to_t(10), 2); | |
148 | trcd = max(ns_to_t(24), 2); | |
149 | trc = ns_to_t(70); | |
150 | txp = max(ns_to_t(8), 2); | |
151 | twtr = max(ns_to_t(8), 2); | |
152 | trtp = max(ns_to_t(8), 2); | |
153 | trp = max(ns_to_t(27), 2); | |
154 | tras = ns_to_t(42); | |
155 | trefi = ns_to_t(3900) / 32; | |
156 | trfc = ns_to_t(210); | |
157 | tmrw = 5; | |
158 | tmrd = 5; | |
159 | tckesr = 5; | |
160 | tcwl = 3; /* CWL 8 */ | |
161 | t_rdata_en = 5; | |
162 | tdinit0 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ | |
163 | tdinit1 = (100 * CONFIG_DRAM_CLK) / 1000 + 1; /* 100ns */ | |
164 | tdinit2 = (11 * CONFIG_DRAM_CLK) + 1; /* 200us */ | |
165 | tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */ | |
166 | twtp = tcwl + 4 + twr + 1; /* CWL + BL/2 + tWR */ | |
167 | twr2rd = tcwl + 4 + 1 + twtr; /* WL + BL / 2 + tWTR */ | |
168 | trd2wr = tcl + 4 + 5 - tcwl + 1; /* RL + BL / 2 + 2 - WL */ | |
169 | } | |
81f50d93 | 170 | /* Set dram timing */ |
171 | reg_val = (twtp << 24) | (tfaw << 16) | (trasmax << 8) | (tras << 0); | |
172 | writel(reg_val, &mctl_ctl->dramtmg0); | |
173 | reg_val = (txp << 16) | (trtp << 8) | (trc << 0); | |
174 | writel(reg_val, &mctl_ctl->dramtmg1); | |
175 | reg_val = (tcwl << 24) | (tcl << 16) | (trd2wr << 8) | (twr2rd << 0); | |
176 | writel(reg_val, &mctl_ctl->dramtmg2); | |
177 | reg_val = (tmrw << 16) | (tmrd << 12) | (tmod << 0); | |
178 | writel(reg_val, &mctl_ctl->dramtmg3); | |
179 | reg_val = (trcd << 24) | (tccd << 16) | (trrd << 8) | (trp << 0); | |
180 | writel(reg_val, &mctl_ctl->dramtmg4); | |
181 | reg_val = (tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | (tcke << 0); | |
182 | writel(reg_val, &mctl_ctl->dramtmg5); | |
183 | /* Set two rank timing and exit self-refresh timing */ | |
184 | reg_val = readl(&mctl_ctl->dramtmg8); | |
185 | reg_val &= ~(0xff << 8); | |
186 | reg_val &= ~(0xff << 0); | |
187 | reg_val |= (0x33 << 8); | |
188 | reg_val |= (0x8 << 0); | |
189 | writel(reg_val, &mctl_ctl->dramtmg8); | |
190 | /* Set phy interface time */ | |
191 | reg_val = (0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) | |
192 | | (wr_latency << 0); | |
193 | /* PHY interface write latency and read latency configure */ | |
194 | writel(reg_val, &mctl_ctl->pitmg0); | |
195 | /* Set phy time PTR0-2 use default */ | |
196 | writel(((tdinit0 << 0) | (tdinit1 << 20)), &mctl_ctl->ptr3); | |
197 | writel(((tdinit2 << 0) | (tdinit3 << 20)), &mctl_ctl->ptr4); | |
198 | /* Set refresh timing */ | |
199 | reg_val = (trefi << 16) | (trfc << 0); | |
200 | writel(reg_val, &mctl_ctl->rfshtmg); | |
201 | } | |
202 | ||
203 | static void mctl_set_pir(u32 val) | |
204 | { | |
205 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
206 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
207 | ||
208 | writel(val, &mctl_ctl->pir); | |
209 | mctl_await_completion(&mctl_ctl->pgsr0, 0x1, 0x1); | |
210 | } | |
211 | ||
212 | static void mctl_data_train_cfg(struct dram_para *para) | |
213 | { | |
214 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
215 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
216 | ||
217 | if (para->rank == 2) | |
218 | clrsetbits_le32(&mctl_ctl->dtcr, 0x3 << 24, 0x3 << 24); | |
219 | else | |
220 | clrsetbits_le32(&mctl_ctl->dtcr, 0x3 << 24, 0x1 << 24); | |
221 | } | |
222 | ||
223 | static int mctl_train_dram(struct dram_para *para) | |
224 | { | |
225 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
226 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
227 | ||
228 | mctl_data_train_cfg(para); | |
229 | mctl_set_pir(0x5f3); | |
230 | ||
231 | return ((readl(&mctl_ctl->pgsr0) >> 20) & 0xff) ? -EIO : 0; | |
232 | } | |
233 | ||
234 | static void set_master_priority(void) | |
235 | { | |
236 | writel(0x00a0000d, MCTL_MASTER_CFG0(0)); | |
237 | writel(0x00500064, MCTL_MASTER_CFG1(0)); | |
238 | writel(0x07000009, MCTL_MASTER_CFG0(1)); | |
239 | writel(0x00000600, MCTL_MASTER_CFG1(1)); | |
240 | writel(0x01000009, MCTL_MASTER_CFG0(3)); | |
241 | writel(0x00000064, MCTL_MASTER_CFG1(3)); | |
242 | writel(0x08000009, MCTL_MASTER_CFG0(4)); | |
243 | writel(0x00000640, MCTL_MASTER_CFG1(4)); | |
244 | writel(0x20000308, MCTL_MASTER_CFG0(8)); | |
245 | writel(0x00001000, MCTL_MASTER_CFG1(8)); | |
246 | writel(0x02800009, MCTL_MASTER_CFG0(9)); | |
247 | writel(0x00000100, MCTL_MASTER_CFG1(9)); | |
248 | writel(0x01800009, MCTL_MASTER_CFG0(5)); | |
249 | writel(0x00000100, MCTL_MASTER_CFG1(5)); | |
250 | writel(0x01800009, MCTL_MASTER_CFG0(7)); | |
251 | writel(0x00000100, MCTL_MASTER_CFG1(7)); | |
252 | writel(0x00640009, MCTL_MASTER_CFG0(6)); | |
253 | writel(0x00000032, MCTL_MASTER_CFG1(6)); | |
254 | writel(0x0100000d, MCTL_MASTER_CFG0(2)); | |
255 | writel(0x00500080, MCTL_MASTER_CFG1(2)); | |
256 | } | |
257 | ||
258 | static int mctl_channel_init(struct dram_para *para) | |
259 | { | |
260 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
261 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
262 | struct sunxi_mctl_com_reg * const mctl_com = | |
263 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
264 | u32 low_data_lines_status; /* Training status of datalines 0 - 7 */ | |
265 | u32 high_data_lines_status; /* Training status of datalines 8 - 15 */ | |
266 | u32 i, rval; | |
267 | ||
268 | auto_set_timing_para(para); | |
269 | ||
270 | /* Set dram master access priority */ | |
271 | writel(0x000101a0, &mctl_com->bwcr); | |
272 | /* set cpu high priority */ | |
273 | writel(0x1, &mctl_com->mapr); | |
274 | set_master_priority(); | |
275 | udelay(250); | |
276 | ||
277 | /* Disable dram VTC */ | |
278 | clrbits_le32(&mctl_ctl->pgcr0, 0x3f << 0 | 0x1 << 30); | |
279 | clrsetbits_le32(&mctl_ctl->pgcr1, 0x1 << 24, 0x1 << 26); | |
280 | ||
281 | writel(0x94be6fa3, MCTL_PROTECT); | |
282 | udelay(100); | |
e449e840 | 283 | clrsetbits_le32(MX_UPD2, 0xfff << 16, 0x50 << 16); |
81f50d93 | 284 | writel(0x0, MCTL_PROTECT); |
285 | udelay(100); | |
286 | ||
287 | ||
288 | /* Set ODT */ | |
289 | if (IS_ENABLED(CONFIG_DRAM_ODT_EN)) | |
290 | rval = 0x0; | |
291 | else | |
292 | rval = 0x2; | |
293 | ||
294 | for (i = 0 ; i < 11 ; i++) { | |
295 | clrsetbits_le32(DATX0IOCR(i), (0x3 << 24) | (0x3 << 16), | |
296 | rval << 24); | |
297 | clrsetbits_le32(DATX1IOCR(i), (0x3 << 24) | (0x3 << 16), | |
298 | rval << 24); | |
299 | clrsetbits_le32(DATX2IOCR(i), (0x3 << 24) | (0x3 << 16), | |
300 | rval << 24); | |
301 | clrsetbits_le32(DATX3IOCR(i), (0x3 << 24) | (0x3 << 16), | |
302 | rval << 24); | |
303 | } | |
304 | ||
305 | for (i = 0; i < 31; i++) | |
306 | clrsetbits_le32(CAIOCR(i), 0x3 << 26 | 0x3 << 16, 0x2 << 26); | |
307 | ||
308 | /* set PLL configuration */ | |
309 | if (CONFIG_DRAM_CLK >= 480) | |
310 | setbits_le32(&mctl_ctl->pllgcr, 0x1 << 19); | |
311 | else | |
312 | setbits_le32(&mctl_ctl->pllgcr, 0x3 << 19); | |
313 | ||
314 | /* Auto detect dram config, set 2 rank and 16bit bus-width */ | |
315 | para->cs1 = 0; | |
316 | para->rank = 2; | |
317 | para->bus_width = 16; | |
318 | mctl_set_cr(para); | |
319 | ||
320 | /* Open DQS gating */ | |
321 | clrbits_le32(&mctl_ctl->pgcr2, (0x3 << 6)); | |
322 | clrbits_le32(&mctl_ctl->dqsgmr, (0x1 << 8) | (0x7)); | |
323 | ||
f3ad64c8 VP |
324 | if (para->dram_type == DRAM_TYPE_LPDDR3) |
325 | clrsetbits_le32(&mctl_ctl->dxccr, (0x1 << 27) | (0x3<<6) , | |
326 | 0x1 << 31); | |
81f50d93 | 327 | if (readl(&mctl_com->cr) & 0x1) |
328 | writel(0x00000303, &mctl_ctl->odtmap); | |
329 | else | |
330 | writel(0x00000201, &mctl_ctl->odtmap); | |
331 | ||
332 | mctl_data_train_cfg(para); | |
333 | /* ZQ calibration */ | |
334 | clrsetbits_le32(ZQnPR(0), 0x000000ff, CONFIG_DRAM_ZQ & 0xff); | |
335 | clrsetbits_le32(ZQnPR(1), 0x000000ff, (CONFIG_DRAM_ZQ >> 8) & 0xff); | |
336 | /* CA calibration */ | |
f3ad64c8 VP |
337 | |
338 | if (para->dram_type == DRAM_TYPE_DDR3) | |
339 | mctl_set_pir(0x0201f3 | 0x1<<10); | |
340 | else | |
341 | mctl_set_pir(0x020173 | 0x1<<10); | |
81f50d93 | 342 | |
343 | /* DQS gate training */ | |
344 | if (mctl_train_dram(para) != 0) { | |
345 | low_data_lines_status = (readl(DXnGSR0(0)) >> 24) & 0x03; | |
346 | high_data_lines_status = (readl(DXnGSR0(1)) >> 24) & 0x03; | |
347 | ||
348 | if (low_data_lines_status == 0x3) | |
349 | return -EIO; | |
350 | ||
351 | /* DRAM has only one rank */ | |
352 | para->rank = 1; | |
353 | mctl_set_cr(para); | |
354 | ||
355 | if (low_data_lines_status == high_data_lines_status) | |
356 | goto done; /* 16 bit bus, 1 rank */ | |
357 | ||
358 | if (!(low_data_lines_status & high_data_lines_status)) { | |
359 | /* Retry 16 bit bus-width with CS1 set */ | |
360 | para->cs1 = 1; | |
361 | mctl_set_cr(para); | |
362 | if (mctl_train_dram(para) == 0) | |
363 | goto done; | |
364 | } | |
365 | ||
366 | /* Try 8 bit bus-width */ | |
367 | writel(0x0, DXnGCR0(1)); /* Disable high DQ */ | |
368 | para->cs1 = 0; | |
369 | para->bus_width = 8; | |
370 | mctl_set_cr(para); | |
371 | if (mctl_train_dram(para) != 0) | |
372 | return -EIO; | |
373 | } | |
374 | done: | |
375 | /* Check the dramc status */ | |
376 | mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1); | |
377 | ||
378 | /* Close DQS gating */ | |
379 | setbits_le32(&mctl_ctl->pgcr2, 0x3 << 6); | |
380 | ||
381 | /* set PGCR3,CKE polarity */ | |
382 | writel(0x00aa0060, &mctl_ctl->pgcr3); | |
383 | /* Enable master access */ | |
384 | writel(0xffffffff, &mctl_com->maer); | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | static void mctl_sys_init(struct dram_para *para) | |
390 | { | |
391 | struct sunxi_ccm_reg * const ccm = | |
392 | (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; | |
393 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
394 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
395 | ||
396 | clrbits_le32(&ccm->mbus_clk_cfg, MBUS_CLK_GATE); | |
397 | clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET); | |
398 | clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL); | |
399 | clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); | |
400 | clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN); | |
f3ad64c8 | 401 | udelay(1000); |
81f50d93 | 402 | clrbits_le32(&ccm->dram_clk_cfg, 0x01<<31); |
403 | ||
404 | clock_set_pll5(CONFIG_DRAM_CLK * 1000000 * DRAM_CLK_MUL); | |
405 | ||
406 | clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV_MASK, | |
407 | CCM_DRAMCLK_CFG_DIV(DRAM_CLK_DIV) | | |
408 | CCM_DRAMCLK_CFG_RST | CCM_DRAMCLK_CFG_UPD); | |
409 | mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0); | |
410 | ||
81f50d93 | 411 | setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); |
412 | setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL); | |
413 | setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET); | |
414 | setbits_le32(&ccm->mbus_clk_cfg, MBUS_CLK_GATE); | |
415 | ||
f3ad64c8 VP |
416 | para->rank = 2; |
417 | para->bus_width = 16; | |
418 | mctl_set_cr(para); | |
419 | ||
81f50d93 | 420 | /* Set dram master access priority */ |
421 | writel(0x0000e00f, &mctl_ctl->clken); /* normal */ | |
422 | ||
423 | udelay(250); | |
424 | } | |
425 | ||
426 | unsigned long sunxi_dram_init(void) | |
427 | { | |
428 | struct sunxi_mctl_com_reg * const mctl_com = | |
429 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
430 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
431 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
432 | ||
433 | struct dram_para para = { | |
434 | .cs1 = 0, | |
435 | .bank = 1, | |
436 | .rank = 1, | |
437 | .rows = 15, | |
438 | .bus_width = 16, | |
439 | .page_size = 2048, | |
440 | }; | |
441 | ||
f5fd8caf VP |
442 | #if defined(CONFIG_MACH_SUN8I_A83T) |
443 | #if (CONFIG_DRAM_TYPE == 3) || (CONFIG_DRAM_TYPE == 7) | |
444 | para.dram_type = CONFIG_DRAM_TYPE; | |
445 | #else | |
446 | #error Unsupported DRAM type, Please set DRAM type (3:DDR3, 7:LPDDR3) | |
447 | #endif | |
448 | #endif | |
81f50d93 | 449 | setbits_le32(SUNXI_PRCM_BASE + 0x1e0, 0x1 << 8); |
450 | ||
451 | writel(0, (SUNXI_PRCM_BASE + 0x1e8)); | |
452 | udelay(10); | |
453 | ||
454 | mctl_sys_init(¶); | |
455 | ||
456 | if (mctl_channel_init(¶) != 0) | |
457 | return 0; | |
458 | ||
459 | auto_detect_dram_size(¶); | |
460 | ||
461 | /* Enable master software clk */ | |
462 | writel(readl(&mctl_com->swonr) | 0x3ffff, &mctl_com->swonr); | |
463 | ||
464 | /* Set DRAM ODT MAP */ | |
465 | if (para.rank == 2) | |
466 | writel(0x00000303, &mctl_ctl->odtmap); | |
467 | else | |
468 | writel(0x00000201, &mctl_ctl->odtmap); | |
469 | ||
470 | return para.page_size * (para.bus_width / 8) * | |
471 | (1 << (para.bank + para.rank + para.rows)); | |
472 | } |