]>
Commit | Line | Data |
---|---|---|
0404d53f JK |
1 | /* |
2 | * sun8i H3 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 | * (C) Copyright 2015 Jens Kuske <jenskuske@gmail.com> | |
9 | * | |
10 | * SPDX-License-Identifier: GPL-2.0+ | |
11 | */ | |
12 | #include <common.h> | |
13 | #include <asm/io.h> | |
14 | #include <asm/arch/clock.h> | |
15 | #include <asm/arch/dram.h> | |
1bc464be | 16 | #include <asm/arch/cpu.h> |
0404d53f JK |
17 | #include <linux/kconfig.h> |
18 | ||
0404d53f JK |
19 | static void mctl_phy_init(u32 val) |
20 | { | |
21 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
22 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
23 | ||
24 | writel(val | PIR_INIT, &mctl_ctl->pir); | |
25 | mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1); | |
26 | } | |
27 | ||
e013bead | 28 | static void mctl_set_bit_delays(struct dram_para *para) |
0404d53f JK |
29 | { |
30 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
31 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
32 | int i, j; | |
0404d53f JK |
33 | |
34 | clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26); | |
35 | ||
e013bead JK |
36 | for (i = 0; i < NR_OF_BYTE_LANES; i++) |
37 | for (j = 0; j < LINES_PER_BYTE_LANE; j++) | |
38 | writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) | | |
39 | DXBDLR_READ_DELAY(para->dx_read_delays[i][j]), | |
40 | &mctl_ctl->dx[i].bdlr[j]); | |
0404d53f | 41 | |
e013bead JK |
42 | for (i = 0; i < 31; i++) |
43 | writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]), | |
44 | &mctl_ctl->acbdlr[i]); | |
0404d53f | 45 | |
8201188c CYT |
46 | #ifdef CONFIG_MACH_SUN8I_R40 |
47 | /* DQSn, DMn, DQn output enable bit delay */ | |
48 | for (i = 0; i < 4; i++) | |
49 | writel(0x6 << 24, &mctl_ctl->dx[i].sdlr); | |
50 | #endif | |
51 | ||
0404d53f | 52 | setbits_le32(&mctl_ctl->pgcr[0], 1 << 26); |
0404d53f JK |
53 | } |
54 | ||
dcb50090 PT |
55 | enum { |
56 | MBUS_PORT_CPU = 0, | |
57 | MBUS_PORT_GPU = 1, | |
58 | MBUS_PORT_UNUSED = 2, | |
59 | MBUS_PORT_DMA = 3, | |
60 | MBUS_PORT_VE = 4, | |
61 | MBUS_PORT_CSI = 5, | |
62 | MBUS_PORT_NAND = 6, | |
63 | MBUS_PORT_SS = 7, | |
64 | MBUS_PORT_TS = 8, | |
65 | MBUS_PORT_DI = 9, | |
66 | MBUS_PORT_DE = 10, | |
67 | MBUS_PORT_DE_CFD = 11, | |
8201188c CYT |
68 | MBUS_PORT_UNKNOWN1 = 12, |
69 | MBUS_PORT_UNKNOWN2 = 13, | |
70 | MBUS_PORT_UNKNOWN3 = 14, | |
dcb50090 PT |
71 | }; |
72 | ||
73 | enum { | |
74 | MBUS_QOS_LOWEST = 0, | |
75 | MBUS_QOS_LOW, | |
76 | MBUS_QOS_HIGH, | |
77 | MBUS_QOS_HIGHEST | |
78 | }; | |
79 | ||
80 | inline void mbus_configure_port(u8 port, | |
81 | bool bwlimit, | |
82 | bool priority, | |
83 | u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */ | |
84 | u8 waittime, /* 0 .. 0xf */ | |
85 | u8 acs, /* 0 .. 0xff */ | |
86 | u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */ | |
87 | u16 bwl1, | |
88 | u16 bwl2) | |
89 | { | |
90 | struct sunxi_mctl_com_reg * const mctl_com = | |
91 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
92 | ||
93 | const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0) | |
94 | | (priority ? (1 << 1) : 0) | |
95 | | ((qos & 0x3) << 2) | |
96 | | ((waittime & 0xf) << 4) | |
97 | | ((acs & 0xff) << 8) | |
98 | | (bwl0 << 16) ); | |
99 | const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff); | |
100 | ||
101 | debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1); | |
102 | writel(cfg0, &mctl_com->mcr[port][0]); | |
103 | writel(cfg1, &mctl_com->mcr[port][1]); | |
104 | } | |
105 | ||
106 | #define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \ | |
107 | mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \ | |
108 | MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2) | |
109 | ||
1bc464be | 110 | static void mctl_set_master_priority_h3(void) |
0404d53f JK |
111 | { |
112 | struct sunxi_mctl_com_reg * const mctl_com = | |
113 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
114 | ||
115 | /* enable bandwidth limit windows and set windows size 1us */ | |
1bc464be | 116 | writel((1 << 16) | (400 << 0), &mctl_com->bwcr); |
0404d53f JK |
117 | |
118 | /* set cpu high priority */ | |
119 | writel(0x00000001, &mctl_com->mapr); | |
120 | ||
dcb50090 PT |
121 | MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128); |
122 | MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256); | |
123 | MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96); | |
124 | MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32); | |
125 | MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256); | |
126 | MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32); | |
127 | MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64); | |
128 | MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64); | |
129 | MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64); | |
130 | MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64); | |
131 | MBUS_CONF( DE, true, HIGHEST, 3, 8192, 6120, 1024); | |
132 | MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64); | |
0404d53f JK |
133 | } |
134 | ||
1bc464be JK |
135 | static void mctl_set_master_priority_a64(void) |
136 | { | |
137 | struct sunxi_mctl_com_reg * const mctl_com = | |
138 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
139 | ||
140 | /* enable bandwidth limit windows and set windows size 1us */ | |
141 | writel(399, &mctl_com->tmr); | |
142 | writel((1 << 16), &mctl_com->bwcr); | |
143 | ||
144 | /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they | |
145 | * initialise it */ | |
146 | MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80); | |
147 | MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256); | |
148 | MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96); | |
149 | MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100); | |
150 | MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256); | |
151 | MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0); | |
152 | MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64); | |
153 | MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64); | |
154 | MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64); | |
155 | MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64); | |
156 | MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048); | |
157 | MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64); | |
158 | ||
159 | writel(0x81000004, &mctl_com->mdfs_bwlr[2]); | |
160 | } | |
161 | ||
170817a4 AP |
162 | static void mctl_set_master_priority_h5(void) |
163 | { | |
164 | struct sunxi_mctl_com_reg * const mctl_com = | |
165 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
166 | ||
167 | /* enable bandwidth limit windows and set windows size 1us */ | |
168 | writel(399, &mctl_com->tmr); | |
169 | writel((1 << 16), &mctl_com->bwcr); | |
170 | ||
171 | /* set cpu high priority */ | |
172 | writel(0x00000001, &mctl_com->mapr); | |
173 | ||
174 | /* Port 2 is reserved per Allwinner's linux-3.10 source, yet | |
175 | * they initialise it */ | |
176 | MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150); | |
177 | MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200); | |
178 | MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96); | |
179 | MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32); | |
180 | MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000); | |
181 | MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100); | |
182 | MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64); | |
183 | MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64); | |
184 | MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64); | |
185 | MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64); | |
186 | MBUS_CONF( DE, true, HIGHEST, 3, 3400, 2400, 1024); | |
187 | MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200); | |
188 | } | |
189 | ||
8201188c CYT |
190 | static void mctl_set_master_priority_r40(void) |
191 | { | |
192 | struct sunxi_mctl_com_reg * const mctl_com = | |
193 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
194 | ||
195 | /* enable bandwidth limit windows and set windows size 1us */ | |
196 | writel(399, &mctl_com->tmr); | |
197 | writel((1 << 16), &mctl_com->bwcr); | |
198 | ||
199 | /* set cpu high priority */ | |
200 | writel(0x00000001, &mctl_com->mapr); | |
201 | ||
202 | /* Port 2 is reserved per Allwinner's linux-3.10 source, yet | |
203 | * they initialise it */ | |
204 | MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150); | |
205 | MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200); | |
206 | MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96); | |
207 | MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32); | |
208 | MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000); | |
209 | MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100); | |
210 | MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64); | |
211 | MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64); | |
212 | MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64); | |
213 | MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64); | |
214 | ||
215 | /* | |
216 | * The port names are probably wrong, but no correct sources | |
217 | * are available. | |
218 | */ | |
219 | MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0); | |
220 | MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0); | |
221 | MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256); | |
222 | MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024); | |
223 | MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64); | |
224 | } | |
225 | ||
1bc464be JK |
226 | static void mctl_set_master_priority(uint16_t socid) |
227 | { | |
228 | switch (socid) { | |
229 | case SOCID_H3: | |
230 | mctl_set_master_priority_h3(); | |
231 | return; | |
232 | case SOCID_A64: | |
233 | mctl_set_master_priority_a64(); | |
234 | return; | |
170817a4 AP |
235 | case SOCID_H5: |
236 | mctl_set_master_priority_h5(); | |
237 | return; | |
8201188c CYT |
238 | case SOCID_R40: |
239 | mctl_set_master_priority_r40(); | |
240 | return; | |
1bc464be JK |
241 | } |
242 | } | |
243 | ||
1bc464be JK |
244 | static u32 bin_to_mgray(int val) |
245 | { | |
246 | static const u8 lookup_table[32] = { | |
247 | 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, | |
248 | 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, | |
249 | 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d, | |
250 | 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11, | |
251 | }; | |
252 | ||
253 | return lookup_table[clamp(val, 0, 31)]; | |
254 | } | |
255 | ||
256 | static int mgray_to_bin(u32 val) | |
257 | { | |
258 | static const u8 lookup_table[32] = { | |
259 | 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, | |
260 | 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b, | |
261 | 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b, | |
262 | 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15, | |
263 | }; | |
264 | ||
265 | return lookup_table[val & 0x1f]; | |
266 | } | |
267 | ||
268 | static void mctl_h3_zq_calibration_quirk(struct dram_para *para) | |
0404d53f JK |
269 | { |
270 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
271 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
87098d70 IZ |
272 | int zq_count; |
273 | ||
274 | #if defined CONFIG_SUNXI_DRAM_DW_16BIT | |
275 | zq_count = 4; | |
276 | #else | |
277 | zq_count = 6; | |
278 | #endif | |
0404d53f | 279 | |
7c9454d4 JK |
280 | if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 && |
281 | (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) { | |
282 | u32 reg_val; | |
0404d53f | 283 | |
7c9454d4 JK |
284 | clrsetbits_le32(&mctl_ctl->zqcr, 0xffff, |
285 | CONFIG_DRAM_ZQ & 0xffff); | |
0404d53f JK |
286 | |
287 | writel(PIR_CLRSR, &mctl_ctl->pir); | |
288 | mctl_phy_init(PIR_ZCAL); | |
289 | ||
7c9454d4 JK |
290 | reg_val = readl(&mctl_ctl->zqdr[0]); |
291 | reg_val &= (0x1f << 16) | (0x1f << 0); | |
292 | reg_val |= reg_val << 8; | |
293 | writel(reg_val, &mctl_ctl->zqdr[0]); | |
0404d53f | 294 | |
7c9454d4 JK |
295 | reg_val = readl(&mctl_ctl->zqdr[1]); |
296 | reg_val &= (0x1f << 16) | (0x1f << 0); | |
297 | reg_val |= reg_val << 8; | |
298 | writel(reg_val, &mctl_ctl->zqdr[1]); | |
299 | writel(reg_val, &mctl_ctl->zqdr[2]); | |
300 | } else { | |
301 | int i; | |
302 | u16 zq_val[6]; | |
303 | u8 val; | |
0404d53f | 304 | |
7c9454d4 JK |
305 | writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]); |
306 | ||
87098d70 | 307 | for (i = 0; i < zq_count; i++) { |
7c9454d4 | 308 | u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf; |
0404d53f | 309 | |
7c9454d4 JK |
310 | writel((zq << 20) | (zq << 16) | (zq << 12) | |
311 | (zq << 8) | (zq << 4) | (zq << 0), | |
312 | &mctl_ctl->zqcr); | |
313 | ||
314 | writel(PIR_CLRSR, &mctl_ctl->pir); | |
315 | mctl_phy_init(PIR_ZCAL); | |
316 | ||
317 | zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff; | |
318 | writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]); | |
319 | ||
320 | writel(PIR_CLRSR, &mctl_ctl->pir); | |
321 | mctl_phy_init(PIR_ZCAL); | |
322 | ||
323 | val = readl(&mctl_ctl->zqdr[0]) >> 24; | |
324 | zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8; | |
325 | } | |
326 | ||
327 | writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]); | |
328 | writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]); | |
87098d70 IZ |
329 | if (zq_count > 4) |
330 | writel((zq_val[5] << 16) | zq_val[4], | |
331 | &mctl_ctl->zqdr[2]); | |
7c9454d4 | 332 | } |
0404d53f JK |
333 | } |
334 | ||
8201188c | 335 | static void mctl_set_cr(uint16_t socid, struct dram_para *para) |
0404d53f JK |
336 | { |
337 | struct sunxi_mctl_com_reg * const mctl_com = | |
338 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
339 | ||
f6457ce5 IZ |
340 | writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED | |
341 | #if defined CONFIG_SUNXI_DRAM_DDR3 | |
342 | MCTL_CR_DDR3 | MCTL_CR_2T | | |
67337e68 IZ |
343 | #elif defined CONFIG_SUNXI_DRAM_DDR2 |
344 | MCTL_CR_DDR2 | MCTL_CR_2T | | |
72cc9870 IZ |
345 | #elif defined CONFIG_SUNXI_DRAM_LPDDR3 |
346 | MCTL_CR_LPDDR3 | MCTL_CR_1T | | |
f6457ce5 IZ |
347 | #else |
348 | #error Unsupported DRAM type! | |
349 | #endif | |
66b12526 | 350 | (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) | |
f43a0099 | 351 | MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) | |
0404d53f JK |
352 | (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | |
353 | MCTL_CR_PAGE_SIZE(para->page_size) | | |
354 | MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr); | |
8201188c CYT |
355 | |
356 | if (socid == SOCID_R40) { | |
357 | if (para->dual_rank) | |
358 | panic("Dual rank memory not supported\n"); | |
359 | ||
360 | /* Mux pin to A15 address line for single rank memory. */ | |
361 | setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15); | |
362 | } | |
0404d53f JK |
363 | } |
364 | ||
1bc464be | 365 | static void mctl_sys_init(uint16_t socid, struct dram_para *para) |
0404d53f JK |
366 | { |
367 | struct sunxi_ccm_reg * const ccm = | |
368 | (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; | |
369 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
370 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
371 | ||
372 | clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE); | |
373 | clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET); | |
374 | clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL); | |
375 | clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); | |
376 | clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN); | |
8201188c | 377 | if (socid == SOCID_A64 || socid == SOCID_R40) |
1bc464be | 378 | clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN); |
0404d53f JK |
379 | udelay(10); |
380 | ||
381 | clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST); | |
382 | udelay(1000); | |
383 | ||
8201188c | 384 | if (socid == SOCID_A64 || socid == SOCID_R40) { |
1bc464be JK |
385 | clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false); |
386 | clrsetbits_le32(&ccm->dram_clk_cfg, | |
387 | CCM_DRAMCLK_CFG_DIV_MASK | | |
388 | CCM_DRAMCLK_CFG_SRC_MASK, | |
389 | CCM_DRAMCLK_CFG_DIV(1) | | |
390 | CCM_DRAMCLK_CFG_SRC_PLL11 | | |
391 | CCM_DRAMCLK_CFG_UPD); | |
170817a4 | 392 | } else if (socid == SOCID_H3 || socid == SOCID_H5) { |
1bc464be JK |
393 | clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false); |
394 | clrsetbits_le32(&ccm->dram_clk_cfg, | |
395 | CCM_DRAMCLK_CFG_DIV_MASK | | |
396 | CCM_DRAMCLK_CFG_SRC_MASK, | |
397 | CCM_DRAMCLK_CFG_DIV(1) | | |
398 | CCM_DRAMCLK_CFG_SRC_PLL5 | | |
399 | CCM_DRAMCLK_CFG_UPD); | |
400 | } | |
0404d53f JK |
401 | mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0); |
402 | ||
403 | setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); | |
404 | setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL); | |
405 | setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET); | |
406 | setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE); | |
407 | ||
408 | setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST); | |
409 | udelay(10); | |
410 | ||
170817a4 | 411 | writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken); |
0404d53f JK |
412 | udelay(500); |
413 | } | |
414 | ||
ed254862 AP |
415 | /* These are more guessed based on some Allwinner code. */ |
416 | #define DX_GCR_ODT_DYNAMIC (0x0 << 4) | |
417 | #define DX_GCR_ODT_ALWAYS_ON (0x1 << 4) | |
418 | #define DX_GCR_ODT_OFF (0x2 << 4) | |
419 | ||
1bc464be | 420 | static int mctl_channel_init(uint16_t socid, struct dram_para *para) |
0404d53f JK |
421 | { |
422 | struct sunxi_mctl_com_reg * const mctl_com = | |
423 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
424 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
425 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
426 | ||
427 | unsigned int i; | |
428 | ||
8201188c | 429 | mctl_set_cr(socid, para); |
1bc464be JK |
430 | mctl_set_timing_params(socid, para); |
431 | mctl_set_master_priority(socid); | |
0404d53f JK |
432 | |
433 | /* setting VTC, default disable all VT */ | |
434 | clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f); | |
170817a4 AP |
435 | if (socid == SOCID_H5) |
436 | setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26)); | |
437 | else | |
438 | clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26); | |
0404d53f JK |
439 | |
440 | /* increase DFI_PHY_UPD clock */ | |
441 | writel(PROTECT_MAGIC, &mctl_com->protect); | |
442 | udelay(100); | |
443 | clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16); | |
444 | writel(0x0, &mctl_com->protect); | |
445 | udelay(100); | |
446 | ||
447 | /* set dramc odt */ | |
170817a4 AP |
448 | for (i = 0; i < 4; i++) { |
449 | u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) | | |
450 | (0x3 << 12) | (0x3 << 14); | |
451 | u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ? | |
452 | DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF; | |
453 | ||
454 | if (socid == SOCID_H5) { | |
455 | clearmask |= 0x2 << 8; | |
456 | setmask |= 0x4 << 8; | |
457 | } | |
458 | clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask); | |
459 | } | |
0404d53f JK |
460 | |
461 | /* AC PDR should always ON */ | |
170817a4 AP |
462 | clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0, |
463 | 0x1 << 1); | |
0404d53f JK |
464 | |
465 | /* set DQS auto gating PD mode */ | |
466 | setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6); | |
467 | ||
1bc464be JK |
468 | if (socid == SOCID_H3) { |
469 | /* dx ddr_clk & hdr_clk dynamic mode */ | |
470 | clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12)); | |
471 | ||
472 | /* dphy & aphy phase select 270 degree */ | |
473 | clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), | |
474 | (0x1 << 10) | (0x2 << 8)); | |
170817a4 | 475 | } else if (socid == SOCID_A64 || socid == SOCID_H5) { |
8201188c CYT |
476 | /* dphy & aphy phase select ? */ |
477 | clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), | |
478 | (0x0 << 10) | (0x3 << 8)); | |
479 | } else if (socid == SOCID_R40) { | |
480 | /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */ | |
481 | clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12)); | |
482 | ||
1bc464be JK |
483 | /* dphy & aphy phase select ? */ |
484 | clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), | |
485 | (0x0 << 10) | (0x3 << 8)); | |
486 | } | |
0404d53f JK |
487 | |
488 | /* set half DQ */ | |
f43a0099 | 489 | if (!para->bus_full_width) { |
87098d70 | 490 | #if defined CONFIG_SUNXI_DRAM_DW_32BIT |
0eb6f9fd JK |
491 | writel(0x0, &mctl_ctl->dx[2].gcr); |
492 | writel(0x0, &mctl_ctl->dx[3].gcr); | |
87098d70 IZ |
493 | #elif defined CONFIG_SUNXI_DRAM_DW_16BIT |
494 | writel(0x0, &mctl_ctl->dx[1].gcr); | |
495 | #else | |
496 | #error Unsupported DRAM bus width! | |
497 | #endif | |
0404d53f JK |
498 | } |
499 | ||
500 | /* data training configuration */ | |
501 | clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, | |
502 | (para->dual_rank ? 0x3 : 0x1) << 24); | |
503 | ||
e013bead JK |
504 | mctl_set_bit_delays(para); |
505 | udelay(50); | |
0404d53f | 506 | |
1bc464be JK |
507 | if (socid == SOCID_H3) { |
508 | mctl_h3_zq_calibration_quirk(para); | |
0404d53f | 509 | |
1bc464be JK |
510 | mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | |
511 | PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE); | |
170817a4 | 512 | } else if (socid == SOCID_A64 || socid == SOCID_H5) { |
1bc464be JK |
513 | clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ); |
514 | ||
515 | mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | | |
516 | PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE); | |
170817a4 | 517 | /* no PIR_QSGATE for H5 ???? */ |
8201188c CYT |
518 | } else if (socid == SOCID_R40) { |
519 | clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ); | |
520 | ||
521 | mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | | |
522 | PIR_DRAMRST | PIR_DRAMINIT); | |
1bc464be | 523 | } |
0404d53f JK |
524 | |
525 | /* detect ranks and bus width */ | |
526 | if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) { | |
527 | /* only one rank */ | |
87098d70 IZ |
528 | if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) |
529 | #if defined CONFIG_SUNXI_DRAM_DW_32BIT | |
530 | || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2) | |
531 | #endif | |
532 | ) { | |
0404d53f JK |
533 | clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24); |
534 | para->dual_rank = 0; | |
535 | } | |
536 | ||
537 | /* only half DQ width */ | |
87098d70 | 538 | #if defined CONFIG_SUNXI_DRAM_DW_32BIT |
0eb6f9fd JK |
539 | if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) || |
540 | ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) { | |
541 | writel(0x0, &mctl_ctl->dx[2].gcr); | |
542 | writel(0x0, &mctl_ctl->dx[3].gcr); | |
f43a0099 | 543 | para->bus_full_width = 0; |
0404d53f | 544 | } |
87098d70 IZ |
545 | #elif defined CONFIG_SUNXI_DRAM_DW_16BIT |
546 | if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) { | |
547 | writel(0x0, &mctl_ctl->dx[1].gcr); | |
548 | para->bus_full_width = 0; | |
549 | } | |
550 | #endif | |
0404d53f | 551 | |
8201188c | 552 | mctl_set_cr(socid, para); |
0404d53f JK |
553 | udelay(20); |
554 | ||
555 | /* re-train */ | |
556 | mctl_phy_init(PIR_QSGATE); | |
557 | if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) | |
558 | return 1; | |
559 | } | |
560 | ||
561 | /* check the dramc status */ | |
562 | mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1); | |
563 | ||
564 | /* liuke added for refresh debug */ | |
565 | setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31); | |
566 | udelay(10); | |
567 | clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31); | |
568 | udelay(10); | |
569 | ||
570 | /* set PGCR3, CKE polarity */ | |
1bc464be JK |
571 | if (socid == SOCID_H3) |
572 | writel(0x00aa0060, &mctl_ctl->pgcr[3]); | |
8201188c | 573 | else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) |
1bc464be | 574 | writel(0xc0aa0060, &mctl_ctl->pgcr[3]); |
0404d53f JK |
575 | |
576 | /* power down zq calibration module for power save */ | |
577 | setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN); | |
578 | ||
579 | /* enable master access */ | |
580 | writel(0xffffffff, &mctl_com->maer); | |
581 | ||
582 | return 0; | |
583 | } | |
584 | ||
8201188c | 585 | static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para) |
0404d53f JK |
586 | { |
587 | /* detect row address bits */ | |
588 | para->page_size = 512; | |
589 | para->row_bits = 16; | |
66b12526 | 590 | para->bank_bits = 2; |
8201188c | 591 | mctl_set_cr(socid, para); |
0404d53f JK |
592 | |
593 | for (para->row_bits = 11; para->row_bits < 16; para->row_bits++) | |
66b12526 IZ |
594 | if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size)) |
595 | break; | |
596 | ||
597 | /* detect bank address bits */ | |
598 | para->bank_bits = 3; | |
599 | mctl_set_cr(socid, para); | |
600 | ||
601 | for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++) | |
602 | if (mctl_mem_matches((1 << para->bank_bits) * para->page_size)) | |
0404d53f JK |
603 | break; |
604 | ||
605 | /* detect page size */ | |
606 | para->page_size = 8192; | |
8201188c | 607 | mctl_set_cr(socid, para); |
0404d53f JK |
608 | |
609 | for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2) | |
610 | if (mctl_mem_matches(para->page_size)) | |
611 | break; | |
612 | } | |
613 | ||
e013bead JK |
614 | /* |
615 | * The actual values used here are taken from Allwinner provided boot0 | |
616 | * binaries, though they are probably board specific, so would likely benefit | |
617 | * from invidual tuning for each board. Apparently a lot of boards copy from | |
618 | * some Allwinner reference design, so we go with those generic values for now | |
619 | * in the hope that they are reasonable for most (all?) boards. | |
620 | */ | |
621 | #define SUN8I_H3_DX_READ_DELAYS \ | |
622 | {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \ | |
623 | { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ | |
624 | { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \ | |
625 | { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }} | |
626 | #define SUN8I_H3_DX_WRITE_DELAYS \ | |
627 | {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \ | |
628 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \ | |
629 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \ | |
630 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }} | |
631 | #define SUN8I_H3_AC_DELAYS \ | |
632 | { 0, 0, 0, 0, 0, 0, 0, 0, \ | |
633 | 0, 0, 0, 0, 0, 0, 0, 0, \ | |
634 | 0, 0, 0, 0, 0, 0, 0, 0, \ | |
635 | 0, 0, 0, 0, 0, 0, 0 } | |
636 | ||
8201188c CYT |
637 | #define SUN8I_R40_DX_READ_DELAYS \ |
638 | {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ | |
639 | { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ | |
640 | { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ | |
641 | { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } } | |
642 | #define SUN8I_R40_DX_WRITE_DELAYS \ | |
643 | {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \ | |
644 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \ | |
645 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \ | |
646 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } } | |
647 | #define SUN8I_R40_AC_DELAYS \ | |
648 | { 0, 0, 3, 0, 0, 0, 0, 0, \ | |
649 | 0, 0, 0, 0, 0, 0, 0, 0, \ | |
650 | 0, 0, 0, 0, 0, 0, 0, 0, \ | |
651 | 0, 0, 0, 0, 0, 0, 0 } | |
652 | ||
1bc464be JK |
653 | #define SUN50I_A64_DX_READ_DELAYS \ |
654 | {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \ | |
655 | { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \ | |
656 | { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \ | |
657 | { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }} | |
658 | #define SUN50I_A64_DX_WRITE_DELAYS \ | |
659 | {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \ | |
660 | { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \ | |
661 | { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \ | |
662 | { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }} | |
663 | #define SUN50I_A64_AC_DELAYS \ | |
664 | { 5, 5, 13, 10, 2, 5, 3, 3, \ | |
665 | 0, 3, 3, 3, 1, 0, 0, 0, \ | |
666 | 3, 4, 0, 3, 4, 1, 4, 0, \ | |
667 | 1, 1, 0, 1, 13, 5, 4 } | |
668 | ||
170817a4 AP |
669 | #define SUN8I_H5_DX_READ_DELAYS \ |
670 | {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \ | |
671 | { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \ | |
672 | { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \ | |
673 | { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } } | |
674 | #define SUN8I_H5_DX_WRITE_DELAYS \ | |
675 | {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \ | |
676 | { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \ | |
677 | { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \ | |
678 | { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } } | |
679 | #define SUN8I_H5_AC_DELAYS \ | |
680 | { 0, 0, 5, 5, 0, 0, 0, 0, \ | |
681 | 0, 0, 0, 0, 3, 3, 3, 3, \ | |
682 | 3, 3, 3, 3, 3, 3, 3, 3, \ | |
683 | 3, 3, 3, 3, 2, 0, 0 } | |
684 | ||
0404d53f JK |
685 | unsigned long sunxi_dram_init(void) |
686 | { | |
687 | struct sunxi_mctl_com_reg * const mctl_com = | |
688 | (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; | |
689 | struct sunxi_mctl_ctl_reg * const mctl_ctl = | |
690 | (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; | |
691 | ||
692 | struct dram_para para = { | |
176868bc | 693 | .dual_rank = 1, |
f43a0099 | 694 | .bus_full_width = 1, |
0404d53f | 695 | .row_bits = 15, |
66b12526 | 696 | .bank_bits = 3, |
0404d53f | 697 | .page_size = 4096, |
1bc464be JK |
698 | |
699 | #if defined(CONFIG_MACH_SUN8I_H3) | |
e013bead JK |
700 | .dx_read_delays = SUN8I_H3_DX_READ_DELAYS, |
701 | .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS, | |
702 | .ac_delays = SUN8I_H3_AC_DELAYS, | |
8201188c CYT |
703 | #elif defined(CONFIG_MACH_SUN8I_R40) |
704 | .dx_read_delays = SUN8I_R40_DX_READ_DELAYS, | |
705 | .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS, | |
706 | .ac_delays = SUN8I_R40_AC_DELAYS, | |
1bc464be JK |
707 | #elif defined(CONFIG_MACH_SUN50I) |
708 | .dx_read_delays = SUN50I_A64_DX_READ_DELAYS, | |
709 | .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS, | |
710 | .ac_delays = SUN50I_A64_AC_DELAYS, | |
170817a4 AP |
711 | #elif defined(CONFIG_MACH_SUN50I_H5) |
712 | .dx_read_delays = SUN8I_H5_DX_READ_DELAYS, | |
713 | .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS, | |
714 | .ac_delays = SUN8I_H5_AC_DELAYS, | |
1bc464be | 715 | #endif |
0404d53f | 716 | }; |
1bc464be JK |
717 | /* |
718 | * Let the compiler optimize alternatives away by passing this value into | |
719 | * the static functions. This saves us #ifdefs, but still keeps the binary | |
720 | * small. | |
721 | */ | |
722 | #if defined(CONFIG_MACH_SUN8I_H3) | |
723 | uint16_t socid = SOCID_H3; | |
8201188c CYT |
724 | #elif defined(CONFIG_MACH_SUN8I_R40) |
725 | uint16_t socid = SOCID_R40; | |
176868bc IZ |
726 | /* Currently we cannot support R40 with dual rank memory */ |
727 | para.dual_rank = 0; | |
3ec0698b IZ |
728 | #elif defined(CONFIG_MACH_SUN8I_V3S) |
729 | /* TODO: set delays and mbus priority for V3s */ | |
730 | uint16_t socid = SOCID_H3; | |
1bc464be JK |
731 | #elif defined(CONFIG_MACH_SUN50I) |
732 | uint16_t socid = SOCID_A64; | |
170817a4 AP |
733 | #elif defined(CONFIG_MACH_SUN50I_H5) |
734 | uint16_t socid = SOCID_H5; | |
1bc464be JK |
735 | #endif |
736 | ||
737 | mctl_sys_init(socid, ¶); | |
738 | if (mctl_channel_init(socid, ¶)) | |
0404d53f JK |
739 | return 0; |
740 | ||
741 | if (para.dual_rank) | |
742 | writel(0x00000303, &mctl_ctl->odtmap); | |
743 | else | |
744 | writel(0x00000201, &mctl_ctl->odtmap); | |
745 | udelay(1); | |
746 | ||
747 | /* odt delay */ | |
1bc464be JK |
748 | if (socid == SOCID_H3) |
749 | writel(0x0c000400, &mctl_ctl->odtcfg); | |
750 | ||
8201188c CYT |
751 | if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) { |
752 | /* VTF enable (tpr13[8] == 1) */ | |
170817a4 | 753 | setbits_le32(&mctl_ctl->vtfcr, |
8201188c CYT |
754 | (socid != SOCID_A64 ? 3 : 2) << 8); |
755 | /* DQ hold disable (tpr13[26] == 1) */ | |
1bc464be JK |
756 | clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13)); |
757 | } | |
0404d53f JK |
758 | |
759 | /* clear credit value */ | |
760 | setbits_le32(&mctl_com->cccr, 1 << 31); | |
761 | udelay(10); | |
762 | ||
8201188c CYT |
763 | mctl_auto_detect_dram_size(socid, ¶); |
764 | mctl_set_cr(socid, ¶); | |
0404d53f | 765 | |
66b12526 IZ |
766 | return (1UL << (para.row_bits + para.bank_bits)) * para.page_size * |
767 | (para.dual_rank ? 2 : 1); | |
0404d53f | 768 | } |