blob: daef051d0c8ee436571d3722d38b1a1111c2d851 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jens Kuske53f018e2015-11-17 15:12:59 +01002/*
3 * sun8i H3 platform dram controller init
4 *
5 * (C) Copyright 2007-2015 Allwinner Technology Co.
6 * Jerry Wang <wangflord@allwinnertech.com>
7 * (C) Copyright 2015 Vishnu Patekar <vishnupatekar0510@gmail.com>
8 * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
9 * (C) Copyright 2015 Jens Kuske <jenskuske@gmail.com>
Jens Kuske53f018e2015-11-17 15:12:59 +010010 */
11#include <common.h>
Simon Glass97589732020-05-10 11:40:02 -060012#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Jens Kuske53f018e2015-11-17 15:12:59 +010014#include <asm/io.h>
15#include <asm/arch/clock.h>
16#include <asm/arch/dram.h>
Jens Kuskef6138172017-01-02 11:48:42 +000017#include <asm/arch/cpu.h>
Simon Glassdbd79542020-05-10 11:40:11 -060018#include <linux/delay.h>
Jens Kuske53f018e2015-11-17 15:12:59 +010019
Jens Kuske53f018e2015-11-17 15:12:59 +010020static void mctl_phy_init(u32 val)
21{
22 struct sunxi_mctl_ctl_reg * const mctl_ctl =
23 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
24
25 writel(val | PIR_INIT, &mctl_ctl->pir);
26 mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
27}
28
Jens Kuske8bbadc82017-01-02 11:48:40 +000029static void mctl_set_bit_delays(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +010030{
31 struct sunxi_mctl_ctl_reg * const mctl_ctl =
32 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
33 int i, j;
Jens Kuske53f018e2015-11-17 15:12:59 +010034
35 clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
36
Jens Kuske8bbadc82017-01-02 11:48:40 +000037 for (i = 0; i < NR_OF_BYTE_LANES; i++)
38 for (j = 0; j < LINES_PER_BYTE_LANE; j++)
39 writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
40 DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
41 &mctl_ctl->dx[i].bdlr[j]);
Jens Kuske53f018e2015-11-17 15:12:59 +010042
Jens Kuske8bbadc82017-01-02 11:48:40 +000043 for (i = 0; i < 31; i++)
44 writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
45 &mctl_ctl->acbdlr[i]);
Jens Kuske53f018e2015-11-17 15:12:59 +010046
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080047#ifdef CONFIG_MACH_SUN8I_R40
48 /* DQSn, DMn, DQn output enable bit delay */
49 for (i = 0; i < 4; i++)
50 writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
51#endif
52
Jens Kuske53f018e2015-11-17 15:12:59 +010053 setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +010054}
55
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000056enum {
57 MBUS_PORT_CPU = 0,
58 MBUS_PORT_GPU = 1,
59 MBUS_PORT_UNUSED = 2,
60 MBUS_PORT_DMA = 3,
61 MBUS_PORT_VE = 4,
62 MBUS_PORT_CSI = 5,
63 MBUS_PORT_NAND = 6,
64 MBUS_PORT_SS = 7,
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +080065 MBUS_PORT_DE_V3S = 8,
66 MBUS_PORT_DE_CFD_V3S = 9,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000067 MBUS_PORT_TS = 8,
68 MBUS_PORT_DI = 9,
69 MBUS_PORT_DE = 10,
70 MBUS_PORT_DE_CFD = 11,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080071 MBUS_PORT_UNKNOWN1 = 12,
72 MBUS_PORT_UNKNOWN2 = 13,
73 MBUS_PORT_UNKNOWN3 = 14,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000074};
75
76enum {
77 MBUS_QOS_LOWEST = 0,
78 MBUS_QOS_LOW,
79 MBUS_QOS_HIGH,
80 MBUS_QOS_HIGHEST
81};
82
Andre Przywara16f6f792023-06-07 01:07:41 +010083static void mbus_configure_port(u8 port,
84 bool bwlimit,
85 bool priority,
86 u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
87 u8 waittime, /* 0 .. 0xf */
88 u8 acs, /* 0 .. 0xff */
89 u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */
90 u16 bwl1,
91 u16 bwl2)
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000092{
93 struct sunxi_mctl_com_reg * const mctl_com =
94 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
95
96 const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
97 | (priority ? (1 << 1) : 0)
98 | ((qos & 0x3) << 2)
99 | ((waittime & 0xf) << 4)
100 | ((acs & 0xff) << 8)
101 | (bwl0 << 16) );
102 const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
103
104 debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
105 writel(cfg0, &mctl_com->mcr[port][0]);
106 writel(cfg1, &mctl_com->mcr[port][1]);
107}
108
109#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \
110 mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
111 MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
112
Jens Kuskef6138172017-01-02 11:48:42 +0000113static void mctl_set_master_priority_h3(void)
Jens Kuske53f018e2015-11-17 15:12:59 +0100114{
115 struct sunxi_mctl_com_reg * const mctl_com =
116 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
117
118 /* enable bandwidth limit windows and set windows size 1us */
Jens Kuskef6138172017-01-02 11:48:42 +0000119 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
Jens Kuske53f018e2015-11-17 15:12:59 +0100120
121 /* set cpu high priority */
122 writel(0x00000001, &mctl_com->mapr);
123
Philipp Tomsich3c31ba92017-01-02 11:48:38 +0000124 MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128);
125 MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256);
126 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
127 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
128 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
129 MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32);
130 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
131 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
132 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
133 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
134 MBUS_CONF( DE, true, HIGHEST, 3, 8192, 6120, 1024);
135 MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64);
Jens Kuske53f018e2015-11-17 15:12:59 +0100136}
137
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800138static void mctl_set_master_priority_v3s(void)
139{
140 struct sunxi_mctl_com_reg * const mctl_com =
141 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
142
143 /* enable bandwidth limit windows and set windows size 1us */
144 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
145
146 /* set cpu high priority */
147 writel(0x00000001, &mctl_com->mapr);
148
149 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
150 MBUS_CONF( GPU, true, HIGH, 0, 1792, 1536, 0);
151 MBUS_CONF( UNUSED, true, HIGHEST, 0, 256, 128, 80);
152 MBUS_CONF( DMA, true, HIGH, 0, 256, 100, 0);
153 MBUS_CONF( VE, true, HIGH, 0, 2048, 1600, 0);
154 MBUS_CONF( CSI, true, HIGHEST, 0, 384, 256, 0);
155 MBUS_CONF( NAND, true, HIGH, 0, 100, 50, 0);
156 MBUS_CONF( SS, true, HIGH, 0, 384, 256, 0);
157 MBUS_CONF( DE_V3S, false, HIGH, 0, 8192, 4096, 0);
158 MBUS_CONF(DE_CFD_V3S, true, HIGH, 0, 640, 256, 0);
159}
160
Jens Kuskef6138172017-01-02 11:48:42 +0000161static void mctl_set_master_priority_a64(void)
162{
163 struct sunxi_mctl_com_reg * const mctl_com =
164 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
165
166 /* enable bandwidth limit windows and set windows size 1us */
167 writel(399, &mctl_com->tmr);
168 writel((1 << 16), &mctl_com->bwcr);
169
170 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
171 * initialise it */
172 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
173 MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256);
174 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
175 MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100);
176 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
177 MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0);
178 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
179 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
180 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
181 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
182 MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048);
183 MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64);
184
185 writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
186}
187
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000188static void mctl_set_master_priority_h5(void)
189{
190 struct sunxi_mctl_com_reg * const mctl_com =
191 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
192
193 /* enable bandwidth limit windows and set windows size 1us */
194 writel(399, &mctl_com->tmr);
195 writel((1 << 16), &mctl_com->bwcr);
196
197 /* set cpu high priority */
198 writel(0x00000001, &mctl_com->mapr);
199
200 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
201 * they initialise it */
202 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
203 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
204 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
205 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
206 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
207 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
208 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
209 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
210 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
211 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
212 MBUS_CONF( DE, true, HIGHEST, 3, 3400, 2400, 1024);
213 MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200);
214}
215
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800216static void mctl_set_master_priority_r40(void)
217{
218 struct sunxi_mctl_com_reg * const mctl_com =
219 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
220
221 /* enable bandwidth limit windows and set windows size 1us */
222 writel(399, &mctl_com->tmr);
223 writel((1 << 16), &mctl_com->bwcr);
224
225 /* set cpu high priority */
226 writel(0x00000001, &mctl_com->mapr);
227
228 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
229 * they initialise it */
230 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
231 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
232 MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96);
233 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
234 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
235 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
236 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
237 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
238 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
239 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
240
241 /*
242 * The port names are probably wrong, but no correct sources
243 * are available.
244 */
245 MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0);
246 MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0);
247 MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256);
248 MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
249 MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64);
250}
251
Jens Kuskef6138172017-01-02 11:48:42 +0000252static void mctl_set_master_priority(uint16_t socid)
253{
254 switch (socid) {
255 case SOCID_H3:
256 mctl_set_master_priority_h3();
257 return;
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800258 case SOCID_V3S:
259 mctl_set_master_priority_v3s();
260 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000261 case SOCID_A64:
262 mctl_set_master_priority_a64();
263 return;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000264 case SOCID_H5:
265 mctl_set_master_priority_h5();
266 return;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800267 case SOCID_R40:
268 mctl_set_master_priority_r40();
269 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000270 }
271}
272
Jens Kuskef6138172017-01-02 11:48:42 +0000273static u32 bin_to_mgray(int val)
274{
275 static const u8 lookup_table[32] = {
276 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
277 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
278 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
279 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
280 };
281
282 return lookup_table[clamp(val, 0, 31)];
283}
284
285static int mgray_to_bin(u32 val)
286{
287 static const u8 lookup_table[32] = {
288 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
289 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
290 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
291 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
292 };
293
294 return lookup_table[val & 0x1f];
295}
296
297static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100298{
299 struct sunxi_mctl_ctl_reg * const mctl_ctl =
300 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
Icenowy Zhengb2607512017-06-03 17:10:16 +0800301 int zq_count;
302
303#if defined CONFIG_SUNXI_DRAM_DW_16BIT
304 zq_count = 4;
305#else
306 zq_count = 6;
307#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100308
Jens Kusked8b95932016-09-21 20:08:30 +0200309 if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
310 (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
311 u32 reg_val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100312
Jens Kusked8b95932016-09-21 20:08:30 +0200313 clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
314 CONFIG_DRAM_ZQ & 0xffff);
Jens Kuske53f018e2015-11-17 15:12:59 +0100315
316 writel(PIR_CLRSR, &mctl_ctl->pir);
317 mctl_phy_init(PIR_ZCAL);
318
Jens Kusked8b95932016-09-21 20:08:30 +0200319 reg_val = readl(&mctl_ctl->zqdr[0]);
320 reg_val &= (0x1f << 16) | (0x1f << 0);
321 reg_val |= reg_val << 8;
322 writel(reg_val, &mctl_ctl->zqdr[0]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100323
Jens Kusked8b95932016-09-21 20:08:30 +0200324 reg_val = readl(&mctl_ctl->zqdr[1]);
325 reg_val &= (0x1f << 16) | (0x1f << 0);
326 reg_val |= reg_val << 8;
327 writel(reg_val, &mctl_ctl->zqdr[1]);
328 writel(reg_val, &mctl_ctl->zqdr[2]);
329 } else {
330 int i;
331 u16 zq_val[6];
332 u8 val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100333
Jens Kusked8b95932016-09-21 20:08:30 +0200334 writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
335
Icenowy Zhengb2607512017-06-03 17:10:16 +0800336 for (i = 0; i < zq_count; i++) {
Jens Kusked8b95932016-09-21 20:08:30 +0200337 u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
Jens Kuske53f018e2015-11-17 15:12:59 +0100338
Jens Kusked8b95932016-09-21 20:08:30 +0200339 writel((zq << 20) | (zq << 16) | (zq << 12) |
340 (zq << 8) | (zq << 4) | (zq << 0),
341 &mctl_ctl->zqcr);
342
343 writel(PIR_CLRSR, &mctl_ctl->pir);
344 mctl_phy_init(PIR_ZCAL);
345
346 zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
347 writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
348
349 writel(PIR_CLRSR, &mctl_ctl->pir);
350 mctl_phy_init(PIR_ZCAL);
351
352 val = readl(&mctl_ctl->zqdr[0]) >> 24;
353 zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
354 }
355
356 writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
357 writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800358 if (zq_count > 4)
359 writel((zq_val[5] << 16) | zq_val[4],
360 &mctl_ctl->zqdr[2]);
Jens Kusked8b95932016-09-21 20:08:30 +0200361 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100362}
363
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800364static void mctl_v3s_zq_calibration_quirk(struct dram_para *para)
365{
366 struct sunxi_mctl_ctl_reg * const mctl_ctl =
367 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
368
369 u32 reg_val;
370
371 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff,
372 CONFIG_DRAM_ZQ & 0xffffff);
373 mctl_phy_init(PIR_ZCAL);
374
375 reg_val = readl(&mctl_ctl->zqdr[0]);
376 reg_val &= (0x1f << 16) | (0x1f << 0);
377 reg_val |= reg_val << 8;
378 writel(reg_val, &mctl_ctl->zqdr[0]);
379
380 reg_val = readl(&mctl_ctl->zqdr[1]);
381 reg_val &= (0x1f << 16) | (0x1f << 0);
382 reg_val |= reg_val << 8;
383 writel(reg_val, &mctl_ctl->zqdr[1]);
384}
385
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800386static void mctl_set_cr(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100387{
388 struct sunxi_mctl_com_reg * const mctl_com =
389 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
390
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800391 writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
392#if defined CONFIG_SUNXI_DRAM_DDR3
393 MCTL_CR_DDR3 | MCTL_CR_2T |
Icenowy Zhenge270a582017-06-03 17:10:20 +0800394#elif defined CONFIG_SUNXI_DRAM_DDR2
395 MCTL_CR_DDR2 | MCTL_CR_2T |
Icenowy Zheng3c1b9f12017-06-03 17:10:23 +0800396#elif defined CONFIG_SUNXI_DRAM_LPDDR3
397 MCTL_CR_LPDDR3 | MCTL_CR_1T |
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800398#else
399#error Unsupported DRAM type!
400#endif
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800401 (para->ranks[0].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800402 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
Jens Kuske53f018e2015-11-17 15:12:59 +0100403 (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800404 MCTL_CR_PAGE_SIZE(para->ranks[0].page_size) |
405 MCTL_CR_ROW_BITS(para->ranks[0].row_bits), &mctl_com->cr);
406
407 if (para->dual_rank && (socid == SOCID_A64 || socid == SOCID_R40)) {
408 writel((para->ranks[1].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
409 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
410 MCTL_CR_DUAL_RANK |
411 MCTL_CR_PAGE_SIZE(para->ranks[1].page_size) |
412 MCTL_CR_ROW_BITS(para->ranks[1].row_bits), &mctl_com->cr_r1);
413 }
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800414
415 if (socid == SOCID_R40) {
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800416 /* Mux pin to A15 address line for single rank memory. */
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800417 if (!para->dual_rank)
418 setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800419 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100420}
421
Jens Kuskef6138172017-01-02 11:48:42 +0000422static void mctl_sys_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100423{
424 struct sunxi_ccm_reg * const ccm =
425 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
426 struct sunxi_mctl_ctl_reg * const mctl_ctl =
427 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
428
429 clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
430 clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
431 clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
432 clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
433 clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800434 if (socid == SOCID_A64 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000435 clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
Jens Kuske53f018e2015-11-17 15:12:59 +0100436 udelay(10);
437
438 clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
439 udelay(1000);
440
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800441 if (socid == SOCID_A64 || socid == SOCID_R40) {
Jens Kuskef6138172017-01-02 11:48:42 +0000442 clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
443 clrsetbits_le32(&ccm->dram_clk_cfg,
444 CCM_DRAMCLK_CFG_DIV_MASK |
445 CCM_DRAMCLK_CFG_SRC_MASK,
446 CCM_DRAMCLK_CFG_DIV(1) |
447 CCM_DRAMCLK_CFG_SRC_PLL11 |
448 CCM_DRAMCLK_CFG_UPD);
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800449 } else if (socid == SOCID_H3 || socid == SOCID_H5 || socid == SOCID_V3S) {
Jens Kuskef6138172017-01-02 11:48:42 +0000450 clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
451 clrsetbits_le32(&ccm->dram_clk_cfg,
452 CCM_DRAMCLK_CFG_DIV_MASK |
453 CCM_DRAMCLK_CFG_SRC_MASK,
454 CCM_DRAMCLK_CFG_DIV(1) |
455 CCM_DRAMCLK_CFG_SRC_PLL5 |
456 CCM_DRAMCLK_CFG_UPD);
457 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100458 mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
459
460 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
461 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
462 setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
463 setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
464
465 setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
466 udelay(10);
467
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000468 writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
Jens Kuske53f018e2015-11-17 15:12:59 +0100469 udelay(500);
470}
471
Andre Przywarac98f5cc2017-01-02 11:48:43 +0000472/* These are more guessed based on some Allwinner code. */
473#define DX_GCR_ODT_DYNAMIC (0x0 << 4)
474#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4)
475#define DX_GCR_ODT_OFF (0x2 << 4)
476
Jens Kuskef6138172017-01-02 11:48:42 +0000477static int mctl_channel_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100478{
479 struct sunxi_mctl_com_reg * const mctl_com =
480 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
481 struct sunxi_mctl_ctl_reg * const mctl_ctl =
482 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
483
484 unsigned int i;
485
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800486 mctl_set_cr(socid, para);
Jens Kuskef6138172017-01-02 11:48:42 +0000487 mctl_set_timing_params(socid, para);
488 mctl_set_master_priority(socid);
Jens Kuske53f018e2015-11-17 15:12:59 +0100489
490 /* setting VTC, default disable all VT */
491 clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000492 if (socid == SOCID_H5)
493 setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
494 else
495 clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +0100496
497 /* increase DFI_PHY_UPD clock */
498 writel(PROTECT_MAGIC, &mctl_com->protect);
499 udelay(100);
500 clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
501 writel(0x0, &mctl_com->protect);
502 udelay(100);
503
504 /* set dramc odt */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000505 for (i = 0; i < 4; i++) {
506 u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
507 (0x3 << 12) | (0x3 << 14);
508 u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
509 DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
510
511 if (socid == SOCID_H5) {
512 clearmask |= 0x2 << 8;
513 setmask |= 0x4 << 8;
514 }
515 clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
516 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100517
518 /* AC PDR should always ON */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000519 clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
520 0x1 << 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100521
522 /* set DQS auto gating PD mode */
523 setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
524
Jens Kuskef6138172017-01-02 11:48:42 +0000525 if (socid == SOCID_H3) {
526 /* dx ddr_clk & hdr_clk dynamic mode */
527 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
Jens Kuske53f018e2015-11-17 15:12:59 +0100528
Jens Kuskef6138172017-01-02 11:48:42 +0000529 /* dphy & aphy phase select 270 degree */
530 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
531 (0x1 << 10) | (0x2 << 8));
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800532 } else if (socid == SOCID_V3S) {
533 /* dx ddr_clk & hdr_clk dynamic mode */
534 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
535
536 /* dphy & aphy phase select 270 degree */
537 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
538 (0x1 << 10) | (0x1 << 8));
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000539 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000540 /* dphy & aphy phase select ? */
541 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
542 (0x0 << 10) | (0x3 << 8));
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800543 } else if (socid == SOCID_R40) {
544 /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
545 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
546
547 /* dphy & aphy phase select ? */
548 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
549 (0x0 << 10) | (0x3 << 8));
Jens Kuskef6138172017-01-02 11:48:42 +0000550 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100551
552 /* set half DQ */
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800553 if (!para->bus_full_width) {
Icenowy Zhengb2607512017-06-03 17:10:16 +0800554#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000555 writel(0x0, &mctl_ctl->dx[2].gcr);
556 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800557#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
558 writel(0x0, &mctl_ctl->dx[1].gcr);
559#else
560#error Unsupported DRAM bus width!
561#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100562 }
563
564 /* data training configuration */
565 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
566 (para->dual_rank ? 0x3 : 0x1) << 24);
567
Jens Kuske8bbadc82017-01-02 11:48:40 +0000568 mctl_set_bit_delays(para);
569 udelay(50);
Jens Kuske53f018e2015-11-17 15:12:59 +0100570
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800571 if (socid == SOCID_V3S) {
572 mctl_v3s_zq_calibration_quirk(para);
573
574 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
575 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
576 } else if (socid == SOCID_H3) {
Jens Kuskef6138172017-01-02 11:48:42 +0000577 mctl_h3_zq_calibration_quirk(para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100578
Jens Kuskef6138172017-01-02 11:48:42 +0000579 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
580 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000581 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000582 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
583
584 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
585 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000586 /* no PIR_QSGATE for H5 ???? */
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800587 } else if (socid == SOCID_R40) {
588 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
589
590 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
591 PIR_DRAMRST | PIR_DRAMINIT);
Jens Kuskef6138172017-01-02 11:48:42 +0000592 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100593
594 /* detect ranks and bus width */
595 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
596 /* only one rank */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800597 if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
598#if defined CONFIG_SUNXI_DRAM_DW_32BIT
599 || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
600#endif
601 ) {
Jens Kuske53f018e2015-11-17 15:12:59 +0100602 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
603 para->dual_rank = 0;
604 }
605
606 /* only half DQ width */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800607#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000608 if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
609 ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
610 writel(0x0, &mctl_ctl->dx[2].gcr);
611 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800612 para->bus_full_width = 0;
Jens Kuske53f018e2015-11-17 15:12:59 +0100613 }
Icenowy Zhengb2607512017-06-03 17:10:16 +0800614#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
615 if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
616 writel(0x0, &mctl_ctl->dx[1].gcr);
617 para->bus_full_width = 0;
618 }
619#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100620
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800621 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100622 udelay(20);
623
624 /* re-train */
625 mctl_phy_init(PIR_QSGATE);
626 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
627 return 1;
628 }
629
630 /* check the dramc status */
631 mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
632
633 /* liuke added for refresh debug */
634 setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
635 udelay(10);
636 clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
637 udelay(10);
638
639 /* set PGCR3, CKE polarity */
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800640 if (socid == SOCID_H3 || socid == SOCID_V3S)
Jens Kuskef6138172017-01-02 11:48:42 +0000641 writel(0x00aa0060, &mctl_ctl->pgcr[3]);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800642 else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000643 writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100644
645 /* power down zq calibration module for power save */
646 setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
647
648 /* enable master access */
649 writel(0xffffffff, &mctl_com->maer);
650
651 return 0;
652}
653
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800654/*
655 * Test if memory at offset offset matches memory at a certain base
656 */
657static bool mctl_mem_matches_base(u32 offset, ulong base)
658{
659 /* Try to write different values to RAM at two addresses */
660 writel(0, base);
661 writel(0xaa55aa55, base + offset);
662 dsb();
663 /* Check if the same value is actually observed when reading back */
664 return readl(base) ==
665 readl(base + offset);
666}
667
668static void mctl_auto_detect_dram_size_rank(uint16_t socid, struct dram_para *para, ulong base, struct rank_para *rank)
Jens Kuske53f018e2015-11-17 15:12:59 +0100669{
670 /* detect row address bits */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800671 rank->page_size = 512;
672 rank->row_bits = 16;
673 rank->bank_bits = 2;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800674 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100675
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800676 for (rank->row_bits = 11; rank->row_bits < 16; rank->row_bits++)
677 if (mctl_mem_matches_base((1 << (rank->row_bits + rank->bank_bits)) * rank->page_size, base))
Jens Kuske53f018e2015-11-17 15:12:59 +0100678 break;
679
Icenowy Zheng20020352017-06-03 17:10:17 +0800680 /* detect bank address bits */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800681 rank->bank_bits = 3;
Icenowy Zheng20020352017-06-03 17:10:17 +0800682 mctl_set_cr(socid, para);
683
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800684 for (rank->bank_bits = 2; rank->bank_bits < 3; rank->bank_bits++)
685 if (mctl_mem_matches_base((1 << rank->bank_bits) * rank->page_size, base))
Icenowy Zheng20020352017-06-03 17:10:17 +0800686 break;
687
Jens Kuske53f018e2015-11-17 15:12:59 +0100688 /* detect page size */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800689 rank->page_size = 8192;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800690 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100691
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800692 for (rank->page_size = 512; rank->page_size < 8192; rank->page_size *= 2)
693 if (mctl_mem_matches_base(rank->page_size, base))
Jens Kuske53f018e2015-11-17 15:12:59 +0100694 break;
695}
696
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800697static unsigned long mctl_calc_rank_size(struct rank_para *rank)
698{
699 return (1UL << (rank->row_bits + rank->bank_bits)) * rank->page_size;
700}
701
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800702/*
703 * Because we cannot do mctl_phy_init(PIR_QSGATE) on R40 now (which leads
704 * to failure), it's needed to detect the rank count of R40 in another way.
705 *
706 * The code here is modelled after time_out_detect() in BSP, which tries to
707 * access the memory and check for error code.
708 *
709 * TODO: auto detect half DQ width here
710 */
711static void mctl_r40_detect_rank_count(struct dram_para *para)
712{
Tom Rinibb4dd962022-11-16 13:10:37 -0500713 ulong rank1_base = (ulong) CFG_SYS_SDRAM_BASE +
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800714 mctl_calc_rank_size(&para->ranks[0]);
715 struct sunxi_mctl_ctl_reg * const mctl_ctl =
716 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
717
718 /* Enable read time out */
719 setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
720
721 (void) readl((void *) rank1_base);
722 udelay(10);
723
724 if (readl(&mctl_ctl->pgsr[0]) & (0x1 << 13)) {
725 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
726 para->dual_rank = 0;
727 }
728
729 /* Reset PHY FIFO to clear it */
730 clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
731 udelay(100);
732 setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
733
734 /* Clear error status */
735 setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 24);
736
737 /* Clear time out flag */
738 clrbits_le32(&mctl_ctl->pgsr[0], 0x1 << 13);
739
740 /* Disable read time out */
741 clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
742}
743
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800744static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
745{
Tom Rinibb4dd962022-11-16 13:10:37 -0500746 mctl_auto_detect_dram_size_rank(socid, para, (ulong)CFG_SYS_SDRAM_BASE, &para->ranks[0]);
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800747
748 if ((socid == SOCID_A64 || socid == SOCID_R40) && para->dual_rank) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500749 mctl_auto_detect_dram_size_rank(socid, para, (ulong)CFG_SYS_SDRAM_BASE + mctl_calc_rank_size(&para->ranks[0]), &para->ranks[1]);
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800750 }
751}
752
Jens Kuske8bbadc82017-01-02 11:48:40 +0000753/*
754 * The actual values used here are taken from Allwinner provided boot0
755 * binaries, though they are probably board specific, so would likely benefit
756 * from invidual tuning for each board. Apparently a lot of boards copy from
757 * some Allwinner reference design, so we go with those generic values for now
758 * in the hope that they are reasonable for most (all?) boards.
759 */
760#define SUN8I_H3_DX_READ_DELAYS \
761 {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
762 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
763 { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
764 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }}
765#define SUN8I_H3_DX_WRITE_DELAYS \
766 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
767 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
768 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
769 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }}
770#define SUN8I_H3_AC_DELAYS \
771 { 0, 0, 0, 0, 0, 0, 0, 0, \
772 0, 0, 0, 0, 0, 0, 0, 0, \
773 0, 0, 0, 0, 0, 0, 0, 0, \
774 0, 0, 0, 0, 0, 0, 0 }
775
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800776#define SUN8I_V3S_DX_READ_DELAYS \
777 {{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0 }, \
778 { 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0 }, \
779 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
780 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
781#define SUN8I_V3S_DX_WRITE_DELAYS \
782 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4 }, \
783 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, \
784 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
785 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
786#define SUN8I_V3S_AC_DELAYS \
787 { 0, 0, 0, 0, 0, 0, 0, 0, \
788 0, 0, 0, 0, 0, 0, 0, 0, \
789 0, 0, 0, 0, 0, 0, 0, 0, \
790 0, 0, 0, 0, 0, 0, 0 }
791
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800792#define SUN8I_R40_DX_READ_DELAYS \
793 {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
794 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
795 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
796 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } }
797#define SUN8I_R40_DX_WRITE_DELAYS \
798 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
799 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
800 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
801 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } }
802#define SUN8I_R40_AC_DELAYS \
803 { 0, 0, 3, 0, 0, 0, 0, 0, \
804 0, 0, 0, 0, 0, 0, 0, 0, \
805 0, 0, 0, 0, 0, 0, 0, 0, \
806 0, 0, 0, 0, 0, 0, 0 }
807
Jens Kuskef6138172017-01-02 11:48:42 +0000808#define SUN50I_A64_DX_READ_DELAYS \
809 {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \
810 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \
811 { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \
812 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}
813#define SUN50I_A64_DX_WRITE_DELAYS \
814 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \
815 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \
816 { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \
817 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}
818#define SUN50I_A64_AC_DELAYS \
819 { 5, 5, 13, 10, 2, 5, 3, 3, \
820 0, 3, 3, 3, 1, 0, 0, 0, \
821 3, 4, 0, 3, 4, 1, 4, 0, \
822 1, 1, 0, 1, 13, 5, 4 }
823
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000824#define SUN8I_H5_DX_READ_DELAYS \
825 {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \
826 { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \
827 { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \
828 { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } }
829#define SUN8I_H5_DX_WRITE_DELAYS \
830 {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \
831 { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \
832 { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \
833 { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } }
834#define SUN8I_H5_AC_DELAYS \
835 { 0, 0, 5, 5, 0, 0, 0, 0, \
836 0, 0, 0, 0, 3, 3, 3, 3, \
837 3, 3, 3, 3, 3, 3, 3, 3, \
838 3, 3, 3, 3, 2, 0, 0 }
839
Jens Kuske53f018e2015-11-17 15:12:59 +0100840unsigned long sunxi_dram_init(void)
841{
842 struct sunxi_mctl_com_reg * const mctl_com =
843 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
844 struct sunxi_mctl_ctl_reg * const mctl_ctl =
845 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
846
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800847 unsigned long size;
848
Jens Kuske53f018e2015-11-17 15:12:59 +0100849 struct dram_para para = {
Icenowy Zheng88048772017-06-03 17:10:19 +0800850 .dual_rank = 1,
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800851 .bus_full_width = 1,
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800852 .ranks = {
853 {
854 .row_bits = 15,
855 .bank_bits = 3,
856 .page_size = 4096,
857 },
858 {
859 .row_bits = 15,
860 .bank_bits = 3,
861 .page_size = 4096,
862 }
863 },
Jens Kuskef6138172017-01-02 11:48:42 +0000864
865#if defined(CONFIG_MACH_SUN8I_H3)
Jens Kuske8bbadc82017-01-02 11:48:40 +0000866 .dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
867 .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
868 .ac_delays = SUN8I_H3_AC_DELAYS,
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800869#elif defined(CONFIG_MACH_SUN8I_V3S)
870 .dx_read_delays = SUN8I_V3S_DX_READ_DELAYS,
871 .dx_write_delays = SUN8I_V3S_DX_WRITE_DELAYS,
872 .ac_delays = SUN8I_V3S_AC_DELAYS,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800873#elif defined(CONFIG_MACH_SUN8I_R40)
874 .dx_read_delays = SUN8I_R40_DX_READ_DELAYS,
875 .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
876 .ac_delays = SUN8I_R40_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000877#elif defined(CONFIG_MACH_SUN50I)
878 .dx_read_delays = SUN50I_A64_DX_READ_DELAYS,
879 .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
880 .ac_delays = SUN50I_A64_AC_DELAYS,
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000881#elif defined(CONFIG_MACH_SUN50I_H5)
882 .dx_read_delays = SUN8I_H5_DX_READ_DELAYS,
883 .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
884 .ac_delays = SUN8I_H5_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000885#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100886 };
Jens Kuskef6138172017-01-02 11:48:42 +0000887/*
888 * Let the compiler optimize alternatives away by passing this value into
889 * the static functions. This saves us #ifdefs, but still keeps the binary
890 * small.
891 */
892#if defined(CONFIG_MACH_SUN8I_H3)
893 uint16_t socid = SOCID_H3;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800894#elif defined(CONFIG_MACH_SUN8I_R40)
895 uint16_t socid = SOCID_R40;
Icenowy Zhengfe052172017-06-03 17:10:21 +0800896#elif defined(CONFIG_MACH_SUN8I_V3S)
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800897 uint16_t socid = SOCID_V3S;
Jens Kuskef6138172017-01-02 11:48:42 +0000898#elif defined(CONFIG_MACH_SUN50I)
899 uint16_t socid = SOCID_A64;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000900#elif defined(CONFIG_MACH_SUN50I_H5)
901 uint16_t socid = SOCID_H5;
Jens Kuskef6138172017-01-02 11:48:42 +0000902#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100903
Jens Kuskef6138172017-01-02 11:48:42 +0000904 mctl_sys_init(socid, &para);
905 if (mctl_channel_init(socid, &para))
Jens Kuske53f018e2015-11-17 15:12:59 +0100906 return 0;
907
908 if (para.dual_rank)
909 writel(0x00000303, &mctl_ctl->odtmap);
910 else
911 writel(0x00000201, &mctl_ctl->odtmap);
912 udelay(1);
913
914 /* odt delay */
Jens Kuskef6138172017-01-02 11:48:42 +0000915 if (socid == SOCID_H3)
916 writel(0x0c000400, &mctl_ctl->odtcfg);
917
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800918 if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
919 /* VTF enable (tpr13[8] == 1) */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000920 setbits_le32(&mctl_ctl->vtfcr,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800921 (socid != SOCID_A64 ? 3 : 2) << 8);
922 /* DQ hold disable (tpr13[26] == 1) */
Jens Kuskef6138172017-01-02 11:48:42 +0000923 clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
924 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100925
926 /* clear credit value */
927 setbits_le32(&mctl_com->cccr, 1 << 31);
928 udelay(10);
929
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800930 if (socid == SOCID_R40) {
931 mctl_r40_detect_rank_count(&para);
932 mctl_set_cr(SOCID_R40, &para);
933 }
934
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800935 mctl_auto_detect_dram_size(socid, &para);
936 mctl_set_cr(socid, &para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100937
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800938 size = mctl_calc_rank_size(&para.ranks[0]);
939 if (socid == SOCID_A64 || socid == SOCID_R40) {
940 if (para.dual_rank)
941 size += mctl_calc_rank_size(&para.ranks[1]);
942 } else if (para.dual_rank) {
943 size *= 2;
944 }
945
946 return size;
Jens Kuske53f018e2015-11-17 15:12:59 +0100947}