blob: 20c3055b7a5bf6d790fcbd235b44b325e822c5d6 [file] [log] [blame]
Jens Kuske53f018e2015-11-17 15:12:59 +01001/*
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>
Jens Kuskef6138172017-01-02 11:48:42 +000016#include <asm/arch/cpu.h>
Jens Kuske53f018e2015-11-17 15:12:59 +010017#include <linux/kconfig.h>
18
Jens Kuske53f018e2015-11-17 15:12:59 +010019static 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
Jens Kuske8bbadc82017-01-02 11:48:40 +000028static void mctl_set_bit_delays(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +010029{
30 struct sunxi_mctl_ctl_reg * const mctl_ctl =
31 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
32 int i, j;
Jens Kuske53f018e2015-11-17 15:12:59 +010033
34 clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
35
Jens Kuske8bbadc82017-01-02 11:48:40 +000036 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]);
Jens Kuske53f018e2015-11-17 15:12:59 +010041
Jens Kuske8bbadc82017-01-02 11:48:40 +000042 for (i = 0; i < 31; i++)
43 writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
44 &mctl_ctl->acbdlr[i]);
Jens Kuske53f018e2015-11-17 15:12:59 +010045
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080046#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
Jens Kuske53f018e2015-11-17 15:12:59 +010052 setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +010053}
54
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000055enum {
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,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080068 MBUS_PORT_UNKNOWN1 = 12,
69 MBUS_PORT_UNKNOWN2 = 13,
70 MBUS_PORT_UNKNOWN3 = 14,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000071};
72
73enum {
74 MBUS_QOS_LOWEST = 0,
75 MBUS_QOS_LOW,
76 MBUS_QOS_HIGH,
77 MBUS_QOS_HIGHEST
78};
79
80inline 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
Jens Kuskef6138172017-01-02 11:48:42 +0000110static void mctl_set_master_priority_h3(void)
Jens Kuske53f018e2015-11-17 15:12:59 +0100111{
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 */
Jens Kuskef6138172017-01-02 11:48:42 +0000116 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
Jens Kuske53f018e2015-11-17 15:12:59 +0100117
118 /* set cpu high priority */
119 writel(0x00000001, &mctl_com->mapr);
120
Philipp Tomsich3c31ba92017-01-02 11:48:38 +0000121 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);
Jens Kuske53f018e2015-11-17 15:12:59 +0100133}
134
Jens Kuskef6138172017-01-02 11:48:42 +0000135static 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
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000162static 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
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800190static 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
Jens Kuskef6138172017-01-02 11:48:42 +0000226static 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;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000235 case SOCID_H5:
236 mctl_set_master_priority_h5();
237 return;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800238 case SOCID_R40:
239 mctl_set_master_priority_r40();
240 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000241 }
242}
243
Jens Kuskef6138172017-01-02 11:48:42 +0000244static 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
256static 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
268static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100269{
270 struct sunxi_mctl_ctl_reg * const mctl_ctl =
271 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
Icenowy Zhengb2607512017-06-03 17:10:16 +0800272 int zq_count;
273
274#if defined CONFIG_SUNXI_DRAM_DW_16BIT
275 zq_count = 4;
276#else
277 zq_count = 6;
278#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100279
Jens Kusked8b95932016-09-21 20:08:30 +0200280 if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
281 (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
282 u32 reg_val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100283
Jens Kusked8b95932016-09-21 20:08:30 +0200284 clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
285 CONFIG_DRAM_ZQ & 0xffff);
Jens Kuske53f018e2015-11-17 15:12:59 +0100286
287 writel(PIR_CLRSR, &mctl_ctl->pir);
288 mctl_phy_init(PIR_ZCAL);
289
Jens Kusked8b95932016-09-21 20:08:30 +0200290 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]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100294
Jens Kusked8b95932016-09-21 20:08:30 +0200295 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;
Jens Kuske53f018e2015-11-17 15:12:59 +0100304
Jens Kusked8b95932016-09-21 20:08:30 +0200305 writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
306
Icenowy Zhengb2607512017-06-03 17:10:16 +0800307 for (i = 0; i < zq_count; i++) {
Jens Kusked8b95932016-09-21 20:08:30 +0200308 u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
Jens Kuske53f018e2015-11-17 15:12:59 +0100309
Jens Kusked8b95932016-09-21 20:08:30 +0200310 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]);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800329 if (zq_count > 4)
330 writel((zq_val[5] << 16) | zq_val[4],
331 &mctl_ctl->zqdr[2]);
Jens Kusked8b95932016-09-21 20:08:30 +0200332 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100333}
334
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800335static void mctl_set_cr(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100336{
337 struct sunxi_mctl_com_reg * const mctl_com =
338 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
339
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800340 writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
341#if defined CONFIG_SUNXI_DRAM_DDR3
342 MCTL_CR_DDR3 | MCTL_CR_2T |
Icenowy Zhenge270a582017-06-03 17:10:20 +0800343#elif defined CONFIG_SUNXI_DRAM_DDR2
344 MCTL_CR_DDR2 | MCTL_CR_2T |
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800345#else
346#error Unsupported DRAM type!
347#endif
Icenowy Zheng20020352017-06-03 17:10:17 +0800348 (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800349 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
Jens Kuske53f018e2015-11-17 15:12:59 +0100350 (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
351 MCTL_CR_PAGE_SIZE(para->page_size) |
352 MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800353
354 if (socid == SOCID_R40) {
355 if (para->dual_rank)
356 panic("Dual rank memory not supported\n");
357
358 /* Mux pin to A15 address line for single rank memory. */
359 setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
360 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100361}
362
Jens Kuskef6138172017-01-02 11:48:42 +0000363static void mctl_sys_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100364{
365 struct sunxi_ccm_reg * const ccm =
366 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
367 struct sunxi_mctl_ctl_reg * const mctl_ctl =
368 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
369
370 clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
371 clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
372 clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
373 clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
374 clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800375 if (socid == SOCID_A64 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000376 clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
Jens Kuske53f018e2015-11-17 15:12:59 +0100377 udelay(10);
378
379 clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
380 udelay(1000);
381
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800382 if (socid == SOCID_A64 || socid == SOCID_R40) {
Jens Kuskef6138172017-01-02 11:48:42 +0000383 clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
384 clrsetbits_le32(&ccm->dram_clk_cfg,
385 CCM_DRAMCLK_CFG_DIV_MASK |
386 CCM_DRAMCLK_CFG_SRC_MASK,
387 CCM_DRAMCLK_CFG_DIV(1) |
388 CCM_DRAMCLK_CFG_SRC_PLL11 |
389 CCM_DRAMCLK_CFG_UPD);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000390 } else if (socid == SOCID_H3 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000391 clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
392 clrsetbits_le32(&ccm->dram_clk_cfg,
393 CCM_DRAMCLK_CFG_DIV_MASK |
394 CCM_DRAMCLK_CFG_SRC_MASK,
395 CCM_DRAMCLK_CFG_DIV(1) |
396 CCM_DRAMCLK_CFG_SRC_PLL5 |
397 CCM_DRAMCLK_CFG_UPD);
398 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100399 mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
400
401 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
402 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
403 setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
404 setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
405
406 setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
407 udelay(10);
408
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000409 writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
Jens Kuske53f018e2015-11-17 15:12:59 +0100410 udelay(500);
411}
412
Andre Przywarac98f5cc2017-01-02 11:48:43 +0000413/* These are more guessed based on some Allwinner code. */
414#define DX_GCR_ODT_DYNAMIC (0x0 << 4)
415#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4)
416#define DX_GCR_ODT_OFF (0x2 << 4)
417
Jens Kuskef6138172017-01-02 11:48:42 +0000418static int mctl_channel_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100419{
420 struct sunxi_mctl_com_reg * const mctl_com =
421 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
422 struct sunxi_mctl_ctl_reg * const mctl_ctl =
423 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
424
425 unsigned int i;
426
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800427 mctl_set_cr(socid, para);
Jens Kuskef6138172017-01-02 11:48:42 +0000428 mctl_set_timing_params(socid, para);
429 mctl_set_master_priority(socid);
Jens Kuske53f018e2015-11-17 15:12:59 +0100430
431 /* setting VTC, default disable all VT */
432 clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000433 if (socid == SOCID_H5)
434 setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
435 else
436 clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +0100437
438 /* increase DFI_PHY_UPD clock */
439 writel(PROTECT_MAGIC, &mctl_com->protect);
440 udelay(100);
441 clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
442 writel(0x0, &mctl_com->protect);
443 udelay(100);
444
445 /* set dramc odt */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000446 for (i = 0; i < 4; i++) {
447 u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
448 (0x3 << 12) | (0x3 << 14);
449 u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
450 DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
451
452 if (socid == SOCID_H5) {
453 clearmask |= 0x2 << 8;
454 setmask |= 0x4 << 8;
455 }
456 clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
457 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100458
459 /* AC PDR should always ON */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000460 clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
461 0x1 << 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100462
463 /* set DQS auto gating PD mode */
464 setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
465
Jens Kuskef6138172017-01-02 11:48:42 +0000466 if (socid == SOCID_H3) {
467 /* dx ddr_clk & hdr_clk dynamic mode */
468 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
Jens Kuske53f018e2015-11-17 15:12:59 +0100469
Jens Kuskef6138172017-01-02 11:48:42 +0000470 /* dphy & aphy phase select 270 degree */
471 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
472 (0x1 << 10) | (0x2 << 8));
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000473 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000474 /* dphy & aphy phase select ? */
475 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
476 (0x0 << 10) | (0x3 << 8));
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800477 } else if (socid == SOCID_R40) {
478 /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
479 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
480
481 /* dphy & aphy phase select ? */
482 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
483 (0x0 << 10) | (0x3 << 8));
Jens Kuskef6138172017-01-02 11:48:42 +0000484 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100485
486 /* set half DQ */
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800487 if (!para->bus_full_width) {
Icenowy Zhengb2607512017-06-03 17:10:16 +0800488#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000489 writel(0x0, &mctl_ctl->dx[2].gcr);
490 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800491#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
492 writel(0x0, &mctl_ctl->dx[1].gcr);
493#else
494#error Unsupported DRAM bus width!
495#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100496 }
497
498 /* data training configuration */
499 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
500 (para->dual_rank ? 0x3 : 0x1) << 24);
501
Jens Kuske8bbadc82017-01-02 11:48:40 +0000502 mctl_set_bit_delays(para);
503 udelay(50);
Jens Kuske53f018e2015-11-17 15:12:59 +0100504
Jens Kuskef6138172017-01-02 11:48:42 +0000505 if (socid == SOCID_H3) {
506 mctl_h3_zq_calibration_quirk(para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100507
Jens Kuskef6138172017-01-02 11:48:42 +0000508 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
509 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000510 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000511 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
512
513 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
514 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000515 /* no PIR_QSGATE for H5 ???? */
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800516 } else if (socid == SOCID_R40) {
517 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
518
519 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
520 PIR_DRAMRST | PIR_DRAMINIT);
Jens Kuskef6138172017-01-02 11:48:42 +0000521 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100522
523 /* detect ranks and bus width */
524 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
525 /* only one rank */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800526 if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
527#if defined CONFIG_SUNXI_DRAM_DW_32BIT
528 || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
529#endif
530 ) {
Jens Kuske53f018e2015-11-17 15:12:59 +0100531 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
532 para->dual_rank = 0;
533 }
534
535 /* only half DQ width */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800536#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000537 if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
538 ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
539 writel(0x0, &mctl_ctl->dx[2].gcr);
540 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800541 para->bus_full_width = 0;
Jens Kuske53f018e2015-11-17 15:12:59 +0100542 }
Icenowy Zhengb2607512017-06-03 17:10:16 +0800543#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
544 if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
545 writel(0x0, &mctl_ctl->dx[1].gcr);
546 para->bus_full_width = 0;
547 }
548#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100549
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800550 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100551 udelay(20);
552
553 /* re-train */
554 mctl_phy_init(PIR_QSGATE);
555 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
556 return 1;
557 }
558
559 /* check the dramc status */
560 mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
561
562 /* liuke added for refresh debug */
563 setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
564 udelay(10);
565 clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
566 udelay(10);
567
568 /* set PGCR3, CKE polarity */
Jens Kuskef6138172017-01-02 11:48:42 +0000569 if (socid == SOCID_H3)
570 writel(0x00aa0060, &mctl_ctl->pgcr[3]);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800571 else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000572 writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100573
574 /* power down zq calibration module for power save */
575 setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
576
577 /* enable master access */
578 writel(0xffffffff, &mctl_com->maer);
579
580 return 0;
581}
582
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800583static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100584{
585 /* detect row address bits */
586 para->page_size = 512;
587 para->row_bits = 16;
Icenowy Zheng20020352017-06-03 17:10:17 +0800588 para->bank_bits = 2;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800589 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100590
591 for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
Icenowy Zheng20020352017-06-03 17:10:17 +0800592 if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
Jens Kuske53f018e2015-11-17 15:12:59 +0100593 break;
594
Icenowy Zheng20020352017-06-03 17:10:17 +0800595 /* detect bank address bits */
596 para->bank_bits = 3;
597 mctl_set_cr(socid, para);
598
599 for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
600 if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
601 break;
602
Jens Kuske53f018e2015-11-17 15:12:59 +0100603 /* detect page size */
604 para->page_size = 8192;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800605 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100606
607 for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
608 if (mctl_mem_matches(para->page_size))
609 break;
610}
611
Jens Kuske8bbadc82017-01-02 11:48:40 +0000612/*
613 * The actual values used here are taken from Allwinner provided boot0
614 * binaries, though they are probably board specific, so would likely benefit
615 * from invidual tuning for each board. Apparently a lot of boards copy from
616 * some Allwinner reference design, so we go with those generic values for now
617 * in the hope that they are reasonable for most (all?) boards.
618 */
619#define SUN8I_H3_DX_READ_DELAYS \
620 {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
621 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
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#define SUN8I_H3_DX_WRITE_DELAYS \
625 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
626 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
627 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
628 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }}
629#define SUN8I_H3_AC_DELAYS \
630 { 0, 0, 0, 0, 0, 0, 0, 0, \
631 0, 0, 0, 0, 0, 0, 0, 0, \
632 0, 0, 0, 0, 0, 0, 0, 0, \
633 0, 0, 0, 0, 0, 0, 0 }
634
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800635#define SUN8I_R40_DX_READ_DELAYS \
636 {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
637 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
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#define SUN8I_R40_DX_WRITE_DELAYS \
641 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
642 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
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#define SUN8I_R40_AC_DELAYS \
646 { 0, 0, 3, 0, 0, 0, 0, 0, \
647 0, 0, 0, 0, 0, 0, 0, 0, \
648 0, 0, 0, 0, 0, 0, 0, 0, \
649 0, 0, 0, 0, 0, 0, 0 }
650
Jens Kuskef6138172017-01-02 11:48:42 +0000651#define SUN50I_A64_DX_READ_DELAYS \
652 {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \
653 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \
654 { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \
655 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}
656#define SUN50I_A64_DX_WRITE_DELAYS \
657 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \
658 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \
659 { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \
660 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}
661#define SUN50I_A64_AC_DELAYS \
662 { 5, 5, 13, 10, 2, 5, 3, 3, \
663 0, 3, 3, 3, 1, 0, 0, 0, \
664 3, 4, 0, 3, 4, 1, 4, 0, \
665 1, 1, 0, 1, 13, 5, 4 }
666
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000667#define SUN8I_H5_DX_READ_DELAYS \
668 {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \
669 { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \
670 { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \
671 { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } }
672#define SUN8I_H5_DX_WRITE_DELAYS \
673 {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \
674 { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \
675 { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \
676 { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } }
677#define SUN8I_H5_AC_DELAYS \
678 { 0, 0, 5, 5, 0, 0, 0, 0, \
679 0, 0, 0, 0, 3, 3, 3, 3, \
680 3, 3, 3, 3, 3, 3, 3, 3, \
681 3, 3, 3, 3, 2, 0, 0 }
682
Jens Kuske53f018e2015-11-17 15:12:59 +0100683unsigned long sunxi_dram_init(void)
684{
685 struct sunxi_mctl_com_reg * const mctl_com =
686 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
687 struct sunxi_mctl_ctl_reg * const mctl_ctl =
688 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
689
690 struct dram_para para = {
Icenowy Zheng88048772017-06-03 17:10:19 +0800691 .dual_rank = 1,
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800692 .bus_full_width = 1,
Jens Kuske53f018e2015-11-17 15:12:59 +0100693 .row_bits = 15,
Icenowy Zheng20020352017-06-03 17:10:17 +0800694 .bank_bits = 3,
Jens Kuske53f018e2015-11-17 15:12:59 +0100695 .page_size = 4096,
Jens Kuskef6138172017-01-02 11:48:42 +0000696
697#if defined(CONFIG_MACH_SUN8I_H3)
Jens Kuske8bbadc82017-01-02 11:48:40 +0000698 .dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
699 .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
700 .ac_delays = SUN8I_H3_AC_DELAYS,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800701#elif defined(CONFIG_MACH_SUN8I_R40)
702 .dx_read_delays = SUN8I_R40_DX_READ_DELAYS,
703 .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
704 .ac_delays = SUN8I_R40_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000705#elif defined(CONFIG_MACH_SUN50I)
706 .dx_read_delays = SUN50I_A64_DX_READ_DELAYS,
707 .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
708 .ac_delays = SUN50I_A64_AC_DELAYS,
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000709#elif defined(CONFIG_MACH_SUN50I_H5)
710 .dx_read_delays = SUN8I_H5_DX_READ_DELAYS,
711 .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
712 .ac_delays = SUN8I_H5_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000713#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100714 };
Jens Kuskef6138172017-01-02 11:48:42 +0000715/*
716 * Let the compiler optimize alternatives away by passing this value into
717 * the static functions. This saves us #ifdefs, but still keeps the binary
718 * small.
719 */
720#if defined(CONFIG_MACH_SUN8I_H3)
721 uint16_t socid = SOCID_H3;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800722#elif defined(CONFIG_MACH_SUN8I_R40)
723 uint16_t socid = SOCID_R40;
Icenowy Zheng88048772017-06-03 17:10:19 +0800724 /* Currently we cannot support R40 with dual rank memory */
725 para.dual_rank = 0;
Icenowy Zhengfe052172017-06-03 17:10:21 +0800726#elif defined(CONFIG_MACH_SUN8I_V3S)
727 /* TODO: set delays and mbus priority for V3s */
728 uint16_t socid = SOCID_H3;
Jens Kuskef6138172017-01-02 11:48:42 +0000729#elif defined(CONFIG_MACH_SUN50I)
730 uint16_t socid = SOCID_A64;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000731#elif defined(CONFIG_MACH_SUN50I_H5)
732 uint16_t socid = SOCID_H5;
Jens Kuskef6138172017-01-02 11:48:42 +0000733#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100734
Jens Kuskef6138172017-01-02 11:48:42 +0000735 mctl_sys_init(socid, &para);
736 if (mctl_channel_init(socid, &para))
Jens Kuske53f018e2015-11-17 15:12:59 +0100737 return 0;
738
739 if (para.dual_rank)
740 writel(0x00000303, &mctl_ctl->odtmap);
741 else
742 writel(0x00000201, &mctl_ctl->odtmap);
743 udelay(1);
744
745 /* odt delay */
Jens Kuskef6138172017-01-02 11:48:42 +0000746 if (socid == SOCID_H3)
747 writel(0x0c000400, &mctl_ctl->odtcfg);
748
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800749 if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
750 /* VTF enable (tpr13[8] == 1) */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000751 setbits_le32(&mctl_ctl->vtfcr,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800752 (socid != SOCID_A64 ? 3 : 2) << 8);
753 /* DQ hold disable (tpr13[26] == 1) */
Jens Kuskef6138172017-01-02 11:48:42 +0000754 clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
755 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100756
757 /* clear credit value */
758 setbits_le32(&mctl_com->cccr, 1 << 31);
759 udelay(10);
760
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800761 mctl_auto_detect_dram_size(socid, &para);
762 mctl_set_cr(socid, &para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100763
Icenowy Zheng20020352017-06-03 17:10:17 +0800764 return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
765 (para.dual_rank ? 2 : 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100766}