blob: 2b9d631d49b0169de47f461dde2e16a45248bb32 [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#include <linux/kconfig.h>
20
Jens Kuske53f018e2015-11-17 15:12:59 +010021static void mctl_phy_init(u32 val)
22{
23 struct sunxi_mctl_ctl_reg * const mctl_ctl =
24 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
25
26 writel(val | PIR_INIT, &mctl_ctl->pir);
27 mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
28}
29
Jens Kuske8bbadc82017-01-02 11:48:40 +000030static void mctl_set_bit_delays(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +010031{
32 struct sunxi_mctl_ctl_reg * const mctl_ctl =
33 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
34 int i, j;
Jens Kuske53f018e2015-11-17 15:12:59 +010035
36 clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
37
Jens Kuske8bbadc82017-01-02 11:48:40 +000038 for (i = 0; i < NR_OF_BYTE_LANES; i++)
39 for (j = 0; j < LINES_PER_BYTE_LANE; j++)
40 writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
41 DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
42 &mctl_ctl->dx[i].bdlr[j]);
Jens Kuske53f018e2015-11-17 15:12:59 +010043
Jens Kuske8bbadc82017-01-02 11:48:40 +000044 for (i = 0; i < 31; i++)
45 writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
46 &mctl_ctl->acbdlr[i]);
Jens Kuske53f018e2015-11-17 15:12:59 +010047
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080048#ifdef CONFIG_MACH_SUN8I_R40
49 /* DQSn, DMn, DQn output enable bit delay */
50 for (i = 0; i < 4; i++)
51 writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
52#endif
53
Jens Kuske53f018e2015-11-17 15:12:59 +010054 setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +010055}
56
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000057enum {
58 MBUS_PORT_CPU = 0,
59 MBUS_PORT_GPU = 1,
60 MBUS_PORT_UNUSED = 2,
61 MBUS_PORT_DMA = 3,
62 MBUS_PORT_VE = 4,
63 MBUS_PORT_CSI = 5,
64 MBUS_PORT_NAND = 6,
65 MBUS_PORT_SS = 7,
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +080066 MBUS_PORT_DE_V3S = 8,
67 MBUS_PORT_DE_CFD_V3S = 9,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000068 MBUS_PORT_TS = 8,
69 MBUS_PORT_DI = 9,
70 MBUS_PORT_DE = 10,
71 MBUS_PORT_DE_CFD = 11,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080072 MBUS_PORT_UNKNOWN1 = 12,
73 MBUS_PORT_UNKNOWN2 = 13,
74 MBUS_PORT_UNKNOWN3 = 14,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000075};
76
77enum {
78 MBUS_QOS_LOWEST = 0,
79 MBUS_QOS_LOW,
80 MBUS_QOS_HIGH,
81 MBUS_QOS_HIGHEST
82};
83
Samuel Hollanda1dba892020-05-07 18:02:33 -050084static inline void mbus_configure_port(u8 port,
85 bool bwlimit,
86 bool priority,
87 u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
88 u8 waittime, /* 0 .. 0xf */
89 u8 acs, /* 0 .. 0xff */
90 u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */
91 u16 bwl1,
92 u16 bwl2)
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000093{
94 struct sunxi_mctl_com_reg * const mctl_com =
95 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
96
97 const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
98 | (priority ? (1 << 1) : 0)
99 | ((qos & 0x3) << 2)
100 | ((waittime & 0xf) << 4)
101 | ((acs & 0xff) << 8)
102 | (bwl0 << 16) );
103 const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
104
105 debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
106 writel(cfg0, &mctl_com->mcr[port][0]);
107 writel(cfg1, &mctl_com->mcr[port][1]);
108}
109
110#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \
111 mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
112 MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
113
Jens Kuskef6138172017-01-02 11:48:42 +0000114static void mctl_set_master_priority_h3(void)
Jens Kuske53f018e2015-11-17 15:12:59 +0100115{
116 struct sunxi_mctl_com_reg * const mctl_com =
117 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
118
119 /* enable bandwidth limit windows and set windows size 1us */
Jens Kuskef6138172017-01-02 11:48:42 +0000120 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
Jens Kuske53f018e2015-11-17 15:12:59 +0100121
122 /* set cpu high priority */
123 writel(0x00000001, &mctl_com->mapr);
124
Philipp Tomsich3c31ba92017-01-02 11:48:38 +0000125 MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128);
126 MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256);
127 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
128 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
129 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
130 MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32);
131 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
132 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
133 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
134 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
135 MBUS_CONF( DE, true, HIGHEST, 3, 8192, 6120, 1024);
136 MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64);
Jens Kuske53f018e2015-11-17 15:12:59 +0100137}
138
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800139static void mctl_set_master_priority_v3s(void)
140{
141 struct sunxi_mctl_com_reg * const mctl_com =
142 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
143
144 /* enable bandwidth limit windows and set windows size 1us */
145 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
146
147 /* set cpu high priority */
148 writel(0x00000001, &mctl_com->mapr);
149
150 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
151 MBUS_CONF( GPU, true, HIGH, 0, 1792, 1536, 0);
152 MBUS_CONF( UNUSED, true, HIGHEST, 0, 256, 128, 80);
153 MBUS_CONF( DMA, true, HIGH, 0, 256, 100, 0);
154 MBUS_CONF( VE, true, HIGH, 0, 2048, 1600, 0);
155 MBUS_CONF( CSI, true, HIGHEST, 0, 384, 256, 0);
156 MBUS_CONF( NAND, true, HIGH, 0, 100, 50, 0);
157 MBUS_CONF( SS, true, HIGH, 0, 384, 256, 0);
158 MBUS_CONF( DE_V3S, false, HIGH, 0, 8192, 4096, 0);
159 MBUS_CONF(DE_CFD_V3S, true, HIGH, 0, 640, 256, 0);
160}
161
Jens Kuskef6138172017-01-02 11:48:42 +0000162static void mctl_set_master_priority_a64(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 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
172 * initialise it */
173 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
174 MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256);
175 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
176 MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100);
177 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
178 MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0);
179 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
180 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
181 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
182 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
183 MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048);
184 MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64);
185
186 writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
187}
188
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000189static void mctl_set_master_priority_h5(void)
190{
191 struct sunxi_mctl_com_reg * const mctl_com =
192 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
193
194 /* enable bandwidth limit windows and set windows size 1us */
195 writel(399, &mctl_com->tmr);
196 writel((1 << 16), &mctl_com->bwcr);
197
198 /* set cpu high priority */
199 writel(0x00000001, &mctl_com->mapr);
200
201 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
202 * they initialise it */
203 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
204 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
205 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
206 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
207 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
208 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
209 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
210 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
211 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
212 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
213 MBUS_CONF( DE, true, HIGHEST, 3, 3400, 2400, 1024);
214 MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200);
215}
216
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800217static void mctl_set_master_priority_r40(void)
218{
219 struct sunxi_mctl_com_reg * const mctl_com =
220 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
221
222 /* enable bandwidth limit windows and set windows size 1us */
223 writel(399, &mctl_com->tmr);
224 writel((1 << 16), &mctl_com->bwcr);
225
226 /* set cpu high priority */
227 writel(0x00000001, &mctl_com->mapr);
228
229 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
230 * they initialise it */
231 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
232 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
233 MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96);
234 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
235 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
236 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
237 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
238 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
239 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
240 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
241
242 /*
243 * The port names are probably wrong, but no correct sources
244 * are available.
245 */
246 MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0);
247 MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0);
248 MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256);
249 MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
250 MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64);
251}
252
Jens Kuskef6138172017-01-02 11:48:42 +0000253static void mctl_set_master_priority(uint16_t socid)
254{
255 switch (socid) {
256 case SOCID_H3:
257 mctl_set_master_priority_h3();
258 return;
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800259 case SOCID_V3S:
260 mctl_set_master_priority_v3s();
261 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000262 case SOCID_A64:
263 mctl_set_master_priority_a64();
264 return;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000265 case SOCID_H5:
266 mctl_set_master_priority_h5();
267 return;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800268 case SOCID_R40:
269 mctl_set_master_priority_r40();
270 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000271 }
272}
273
Jens Kuskef6138172017-01-02 11:48:42 +0000274static u32 bin_to_mgray(int val)
275{
276 static const u8 lookup_table[32] = {
277 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
278 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
279 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
280 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
281 };
282
283 return lookup_table[clamp(val, 0, 31)];
284}
285
286static int mgray_to_bin(u32 val)
287{
288 static const u8 lookup_table[32] = {
289 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
290 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
291 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
292 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
293 };
294
295 return lookup_table[val & 0x1f];
296}
297
298static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100299{
300 struct sunxi_mctl_ctl_reg * const mctl_ctl =
301 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
Icenowy Zhengb2607512017-06-03 17:10:16 +0800302 int zq_count;
303
304#if defined CONFIG_SUNXI_DRAM_DW_16BIT
305 zq_count = 4;
306#else
307 zq_count = 6;
308#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100309
Jens Kusked8b95932016-09-21 20:08:30 +0200310 if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
311 (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
312 u32 reg_val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100313
Jens Kusked8b95932016-09-21 20:08:30 +0200314 clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
315 CONFIG_DRAM_ZQ & 0xffff);
Jens Kuske53f018e2015-11-17 15:12:59 +0100316
317 writel(PIR_CLRSR, &mctl_ctl->pir);
318 mctl_phy_init(PIR_ZCAL);
319
Jens Kusked8b95932016-09-21 20:08:30 +0200320 reg_val = readl(&mctl_ctl->zqdr[0]);
321 reg_val &= (0x1f << 16) | (0x1f << 0);
322 reg_val |= reg_val << 8;
323 writel(reg_val, &mctl_ctl->zqdr[0]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100324
Jens Kusked8b95932016-09-21 20:08:30 +0200325 reg_val = readl(&mctl_ctl->zqdr[1]);
326 reg_val &= (0x1f << 16) | (0x1f << 0);
327 reg_val |= reg_val << 8;
328 writel(reg_val, &mctl_ctl->zqdr[1]);
329 writel(reg_val, &mctl_ctl->zqdr[2]);
330 } else {
331 int i;
332 u16 zq_val[6];
333 u8 val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100334
Jens Kusked8b95932016-09-21 20:08:30 +0200335 writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
336
Icenowy Zhengb2607512017-06-03 17:10:16 +0800337 for (i = 0; i < zq_count; i++) {
Jens Kusked8b95932016-09-21 20:08:30 +0200338 u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
Jens Kuske53f018e2015-11-17 15:12:59 +0100339
Jens Kusked8b95932016-09-21 20:08:30 +0200340 writel((zq << 20) | (zq << 16) | (zq << 12) |
341 (zq << 8) | (zq << 4) | (zq << 0),
342 &mctl_ctl->zqcr);
343
344 writel(PIR_CLRSR, &mctl_ctl->pir);
345 mctl_phy_init(PIR_ZCAL);
346
347 zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
348 writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
349
350 writel(PIR_CLRSR, &mctl_ctl->pir);
351 mctl_phy_init(PIR_ZCAL);
352
353 val = readl(&mctl_ctl->zqdr[0]) >> 24;
354 zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
355 }
356
357 writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
358 writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800359 if (zq_count > 4)
360 writel((zq_val[5] << 16) | zq_val[4],
361 &mctl_ctl->zqdr[2]);
Jens Kusked8b95932016-09-21 20:08:30 +0200362 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100363}
364
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800365static void mctl_v3s_zq_calibration_quirk(struct dram_para *para)
366{
367 struct sunxi_mctl_ctl_reg * const mctl_ctl =
368 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
369
370 u32 reg_val;
371
372 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff,
373 CONFIG_DRAM_ZQ & 0xffffff);
374 mctl_phy_init(PIR_ZCAL);
375
376 reg_val = readl(&mctl_ctl->zqdr[0]);
377 reg_val &= (0x1f << 16) | (0x1f << 0);
378 reg_val |= reg_val << 8;
379 writel(reg_val, &mctl_ctl->zqdr[0]);
380
381 reg_val = readl(&mctl_ctl->zqdr[1]);
382 reg_val &= (0x1f << 16) | (0x1f << 0);
383 reg_val |= reg_val << 8;
384 writel(reg_val, &mctl_ctl->zqdr[1]);
385}
386
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800387static void mctl_set_cr(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100388{
389 struct sunxi_mctl_com_reg * const mctl_com =
390 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
391
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800392 writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
393#if defined CONFIG_SUNXI_DRAM_DDR3
394 MCTL_CR_DDR3 | MCTL_CR_2T |
Icenowy Zhenge270a582017-06-03 17:10:20 +0800395#elif defined CONFIG_SUNXI_DRAM_DDR2
396 MCTL_CR_DDR2 | MCTL_CR_2T |
Icenowy Zheng3c1b9f12017-06-03 17:10:23 +0800397#elif defined CONFIG_SUNXI_DRAM_LPDDR3
398 MCTL_CR_LPDDR3 | MCTL_CR_1T |
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800399#else
400#error Unsupported DRAM type!
401#endif
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800402 (para->ranks[0].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800403 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
Jens Kuske53f018e2015-11-17 15:12:59 +0100404 (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800405 MCTL_CR_PAGE_SIZE(para->ranks[0].page_size) |
406 MCTL_CR_ROW_BITS(para->ranks[0].row_bits), &mctl_com->cr);
407
408 if (para->dual_rank && (socid == SOCID_A64 || socid == SOCID_R40)) {
409 writel((para->ranks[1].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
410 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
411 MCTL_CR_DUAL_RANK |
412 MCTL_CR_PAGE_SIZE(para->ranks[1].page_size) |
413 MCTL_CR_ROW_BITS(para->ranks[1].row_bits), &mctl_com->cr_r1);
414 }
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800415
416 if (socid == SOCID_R40) {
417 if (para->dual_rank)
418 panic("Dual rank memory not supported\n");
419
420 /* Mux pin to A15 address line for single rank memory. */
421 setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
422 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100423}
424
Jens Kuskef6138172017-01-02 11:48:42 +0000425static void mctl_sys_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100426{
427 struct sunxi_ccm_reg * const ccm =
428 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
429 struct sunxi_mctl_ctl_reg * const mctl_ctl =
430 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
431
432 clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
433 clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
434 clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
435 clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
436 clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800437 if (socid == SOCID_A64 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000438 clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
Jens Kuske53f018e2015-11-17 15:12:59 +0100439 udelay(10);
440
441 clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
442 udelay(1000);
443
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800444 if (socid == SOCID_A64 || socid == SOCID_R40) {
Jens Kuskef6138172017-01-02 11:48:42 +0000445 clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
446 clrsetbits_le32(&ccm->dram_clk_cfg,
447 CCM_DRAMCLK_CFG_DIV_MASK |
448 CCM_DRAMCLK_CFG_SRC_MASK,
449 CCM_DRAMCLK_CFG_DIV(1) |
450 CCM_DRAMCLK_CFG_SRC_PLL11 |
451 CCM_DRAMCLK_CFG_UPD);
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800452 } else if (socid == SOCID_H3 || socid == SOCID_H5 || socid == SOCID_V3S) {
Jens Kuskef6138172017-01-02 11:48:42 +0000453 clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
454 clrsetbits_le32(&ccm->dram_clk_cfg,
455 CCM_DRAMCLK_CFG_DIV_MASK |
456 CCM_DRAMCLK_CFG_SRC_MASK,
457 CCM_DRAMCLK_CFG_DIV(1) |
458 CCM_DRAMCLK_CFG_SRC_PLL5 |
459 CCM_DRAMCLK_CFG_UPD);
460 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100461 mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
462
463 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
464 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
465 setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
466 setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
467
468 setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
469 udelay(10);
470
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000471 writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
Jens Kuske53f018e2015-11-17 15:12:59 +0100472 udelay(500);
473}
474
Andre Przywarac98f5cc2017-01-02 11:48:43 +0000475/* These are more guessed based on some Allwinner code. */
476#define DX_GCR_ODT_DYNAMIC (0x0 << 4)
477#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4)
478#define DX_GCR_ODT_OFF (0x2 << 4)
479
Jens Kuskef6138172017-01-02 11:48:42 +0000480static int mctl_channel_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100481{
482 struct sunxi_mctl_com_reg * const mctl_com =
483 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
484 struct sunxi_mctl_ctl_reg * const mctl_ctl =
485 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
486
487 unsigned int i;
488
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800489 mctl_set_cr(socid, para);
Jens Kuskef6138172017-01-02 11:48:42 +0000490 mctl_set_timing_params(socid, para);
491 mctl_set_master_priority(socid);
Jens Kuske53f018e2015-11-17 15:12:59 +0100492
493 /* setting VTC, default disable all VT */
494 clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000495 if (socid == SOCID_H5)
496 setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
497 else
498 clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +0100499
500 /* increase DFI_PHY_UPD clock */
501 writel(PROTECT_MAGIC, &mctl_com->protect);
502 udelay(100);
503 clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
504 writel(0x0, &mctl_com->protect);
505 udelay(100);
506
507 /* set dramc odt */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000508 for (i = 0; i < 4; i++) {
509 u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
510 (0x3 << 12) | (0x3 << 14);
511 u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
512 DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
513
514 if (socid == SOCID_H5) {
515 clearmask |= 0x2 << 8;
516 setmask |= 0x4 << 8;
517 }
518 clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
519 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100520
521 /* AC PDR should always ON */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000522 clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
523 0x1 << 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100524
525 /* set DQS auto gating PD mode */
526 setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
527
Jens Kuskef6138172017-01-02 11:48:42 +0000528 if (socid == SOCID_H3) {
529 /* dx ddr_clk & hdr_clk dynamic mode */
530 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
Jens Kuske53f018e2015-11-17 15:12:59 +0100531
Jens Kuskef6138172017-01-02 11:48:42 +0000532 /* dphy & aphy phase select 270 degree */
533 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
534 (0x1 << 10) | (0x2 << 8));
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800535 } else if (socid == SOCID_V3S) {
536 /* dx ddr_clk & hdr_clk dynamic mode */
537 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
538
539 /* dphy & aphy phase select 270 degree */
540 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
541 (0x1 << 10) | (0x1 << 8));
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000542 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000543 /* dphy & aphy phase select ? */
544 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
545 (0x0 << 10) | (0x3 << 8));
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800546 } else if (socid == SOCID_R40) {
547 /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
548 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
549
550 /* dphy & aphy phase select ? */
551 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
552 (0x0 << 10) | (0x3 << 8));
Jens Kuskef6138172017-01-02 11:48:42 +0000553 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100554
555 /* set half DQ */
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800556 if (!para->bus_full_width) {
Icenowy Zhengb2607512017-06-03 17:10:16 +0800557#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000558 writel(0x0, &mctl_ctl->dx[2].gcr);
559 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800560#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
561 writel(0x0, &mctl_ctl->dx[1].gcr);
562#else
563#error Unsupported DRAM bus width!
564#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100565 }
566
567 /* data training configuration */
568 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
569 (para->dual_rank ? 0x3 : 0x1) << 24);
570
Jens Kuske8bbadc82017-01-02 11:48:40 +0000571 mctl_set_bit_delays(para);
572 udelay(50);
Jens Kuske53f018e2015-11-17 15:12:59 +0100573
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800574 if (socid == SOCID_V3S) {
575 mctl_v3s_zq_calibration_quirk(para);
576
577 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
578 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
579 } else if (socid == SOCID_H3) {
Jens Kuskef6138172017-01-02 11:48:42 +0000580 mctl_h3_zq_calibration_quirk(para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100581
Jens Kuskef6138172017-01-02 11:48:42 +0000582 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
583 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000584 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000585 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
586
587 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
588 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000589 /* no PIR_QSGATE for H5 ???? */
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800590 } else if (socid == SOCID_R40) {
591 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
592
593 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
594 PIR_DRAMRST | PIR_DRAMINIT);
Jens Kuskef6138172017-01-02 11:48:42 +0000595 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100596
597 /* detect ranks and bus width */
598 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
599 /* only one rank */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800600 if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
601#if defined CONFIG_SUNXI_DRAM_DW_32BIT
602 || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
603#endif
604 ) {
Jens Kuske53f018e2015-11-17 15:12:59 +0100605 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
606 para->dual_rank = 0;
607 }
608
609 /* only half DQ width */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800610#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000611 if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
612 ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
613 writel(0x0, &mctl_ctl->dx[2].gcr);
614 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800615 para->bus_full_width = 0;
Jens Kuske53f018e2015-11-17 15:12:59 +0100616 }
Icenowy Zhengb2607512017-06-03 17:10:16 +0800617#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
618 if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
619 writel(0x0, &mctl_ctl->dx[1].gcr);
620 para->bus_full_width = 0;
621 }
622#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100623
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800624 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100625 udelay(20);
626
627 /* re-train */
628 mctl_phy_init(PIR_QSGATE);
629 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
630 return 1;
631 }
632
633 /* check the dramc status */
634 mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
635
636 /* liuke added for refresh debug */
637 setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
638 udelay(10);
639 clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
640 udelay(10);
641
642 /* set PGCR3, CKE polarity */
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800643 if (socid == SOCID_H3 || socid == SOCID_V3S)
Jens Kuskef6138172017-01-02 11:48:42 +0000644 writel(0x00aa0060, &mctl_ctl->pgcr[3]);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800645 else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000646 writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100647
648 /* power down zq calibration module for power save */
649 setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
650
651 /* enable master access */
652 writel(0xffffffff, &mctl_com->maer);
653
654 return 0;
655}
656
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800657/*
658 * Test if memory at offset offset matches memory at a certain base
659 */
660static bool mctl_mem_matches_base(u32 offset, ulong base)
661{
662 /* Try to write different values to RAM at two addresses */
663 writel(0, base);
664 writel(0xaa55aa55, base + offset);
665 dsb();
666 /* Check if the same value is actually observed when reading back */
667 return readl(base) ==
668 readl(base + offset);
669}
670
671static 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 +0100672{
673 /* detect row address bits */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800674 rank->page_size = 512;
675 rank->row_bits = 16;
676 rank->bank_bits = 2;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800677 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100678
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800679 for (rank->row_bits = 11; rank->row_bits < 16; rank->row_bits++)
680 if (mctl_mem_matches_base((1 << (rank->row_bits + rank->bank_bits)) * rank->page_size, base))
Jens Kuske53f018e2015-11-17 15:12:59 +0100681 break;
682
Icenowy Zheng20020352017-06-03 17:10:17 +0800683 /* detect bank address bits */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800684 rank->bank_bits = 3;
Icenowy Zheng20020352017-06-03 17:10:17 +0800685 mctl_set_cr(socid, para);
686
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800687 for (rank->bank_bits = 2; rank->bank_bits < 3; rank->bank_bits++)
688 if (mctl_mem_matches_base((1 << rank->bank_bits) * rank->page_size, base))
Icenowy Zheng20020352017-06-03 17:10:17 +0800689 break;
690
Jens Kuske53f018e2015-11-17 15:12:59 +0100691 /* detect page size */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800692 rank->page_size = 8192;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800693 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100694
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800695 for (rank->page_size = 512; rank->page_size < 8192; rank->page_size *= 2)
696 if (mctl_mem_matches_base(rank->page_size, base))
Jens Kuske53f018e2015-11-17 15:12:59 +0100697 break;
698}
699
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800700static unsigned long mctl_calc_rank_size(struct rank_para *rank)
701{
702 return (1UL << (rank->row_bits + rank->bank_bits)) * rank->page_size;
703}
704
705static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
706{
707 mctl_auto_detect_dram_size_rank(socid, para, (ulong)CONFIG_SYS_SDRAM_BASE, &para->ranks[0]);
708
709 if ((socid == SOCID_A64 || socid == SOCID_R40) && para->dual_rank) {
710 mctl_auto_detect_dram_size_rank(socid, para, (ulong)CONFIG_SYS_SDRAM_BASE + mctl_calc_rank_size(&para->ranks[0]), &para->ranks[1]);
711 }
712}
713
Jens Kuske8bbadc82017-01-02 11:48:40 +0000714/*
715 * The actual values used here are taken from Allwinner provided boot0
716 * binaries, though they are probably board specific, so would likely benefit
717 * from invidual tuning for each board. Apparently a lot of boards copy from
718 * some Allwinner reference design, so we go with those generic values for now
719 * in the hope that they are reasonable for most (all?) boards.
720 */
721#define SUN8I_H3_DX_READ_DELAYS \
722 {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
723 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
724 { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
725 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }}
726#define SUN8I_H3_DX_WRITE_DELAYS \
727 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
728 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
729 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
730 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }}
731#define SUN8I_H3_AC_DELAYS \
732 { 0, 0, 0, 0, 0, 0, 0, 0, \
733 0, 0, 0, 0, 0, 0, 0, 0, \
734 0, 0, 0, 0, 0, 0, 0, 0, \
735 0, 0, 0, 0, 0, 0, 0 }
736
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800737#define SUN8I_V3S_DX_READ_DELAYS \
738 {{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0 }, \
739 { 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0 }, \
740 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
741 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
742#define SUN8I_V3S_DX_WRITE_DELAYS \
743 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4 }, \
744 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, \
745 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
746 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
747#define SUN8I_V3S_AC_DELAYS \
748 { 0, 0, 0, 0, 0, 0, 0, 0, \
749 0, 0, 0, 0, 0, 0, 0, 0, \
750 0, 0, 0, 0, 0, 0, 0, 0, \
751 0, 0, 0, 0, 0, 0, 0 }
752
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800753#define SUN8I_R40_DX_READ_DELAYS \
754 {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
755 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
756 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
757 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } }
758#define SUN8I_R40_DX_WRITE_DELAYS \
759 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
760 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
761 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
762 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } }
763#define SUN8I_R40_AC_DELAYS \
764 { 0, 0, 3, 0, 0, 0, 0, 0, \
765 0, 0, 0, 0, 0, 0, 0, 0, \
766 0, 0, 0, 0, 0, 0, 0, 0, \
767 0, 0, 0, 0, 0, 0, 0 }
768
Jens Kuskef6138172017-01-02 11:48:42 +0000769#define SUN50I_A64_DX_READ_DELAYS \
770 {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \
771 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \
772 { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \
773 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}
774#define SUN50I_A64_DX_WRITE_DELAYS \
775 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \
776 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \
777 { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \
778 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}
779#define SUN50I_A64_AC_DELAYS \
780 { 5, 5, 13, 10, 2, 5, 3, 3, \
781 0, 3, 3, 3, 1, 0, 0, 0, \
782 3, 4, 0, 3, 4, 1, 4, 0, \
783 1, 1, 0, 1, 13, 5, 4 }
784
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000785#define SUN8I_H5_DX_READ_DELAYS \
786 {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \
787 { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \
788 { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \
789 { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } }
790#define SUN8I_H5_DX_WRITE_DELAYS \
791 {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \
792 { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \
793 { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \
794 { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } }
795#define SUN8I_H5_AC_DELAYS \
796 { 0, 0, 5, 5, 0, 0, 0, 0, \
797 0, 0, 0, 0, 3, 3, 3, 3, \
798 3, 3, 3, 3, 3, 3, 3, 3, \
799 3, 3, 3, 3, 2, 0, 0 }
800
Jens Kuske53f018e2015-11-17 15:12:59 +0100801unsigned long sunxi_dram_init(void)
802{
803 struct sunxi_mctl_com_reg * const mctl_com =
804 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
805 struct sunxi_mctl_ctl_reg * const mctl_ctl =
806 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
807
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800808 unsigned long size;
809
Jens Kuske53f018e2015-11-17 15:12:59 +0100810 struct dram_para para = {
Icenowy Zheng88048772017-06-03 17:10:19 +0800811 .dual_rank = 1,
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800812 .bus_full_width = 1,
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800813 .ranks = {
814 {
815 .row_bits = 15,
816 .bank_bits = 3,
817 .page_size = 4096,
818 },
819 {
820 .row_bits = 15,
821 .bank_bits = 3,
822 .page_size = 4096,
823 }
824 },
Jens Kuskef6138172017-01-02 11:48:42 +0000825
826#if defined(CONFIG_MACH_SUN8I_H3)
Jens Kuske8bbadc82017-01-02 11:48:40 +0000827 .dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
828 .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
829 .ac_delays = SUN8I_H3_AC_DELAYS,
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800830#elif defined(CONFIG_MACH_SUN8I_V3S)
831 .dx_read_delays = SUN8I_V3S_DX_READ_DELAYS,
832 .dx_write_delays = SUN8I_V3S_DX_WRITE_DELAYS,
833 .ac_delays = SUN8I_V3S_AC_DELAYS,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800834#elif defined(CONFIG_MACH_SUN8I_R40)
835 .dx_read_delays = SUN8I_R40_DX_READ_DELAYS,
836 .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
837 .ac_delays = SUN8I_R40_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000838#elif defined(CONFIG_MACH_SUN50I)
839 .dx_read_delays = SUN50I_A64_DX_READ_DELAYS,
840 .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
841 .ac_delays = SUN50I_A64_AC_DELAYS,
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000842#elif defined(CONFIG_MACH_SUN50I_H5)
843 .dx_read_delays = SUN8I_H5_DX_READ_DELAYS,
844 .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
845 .ac_delays = SUN8I_H5_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000846#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100847 };
Jens Kuskef6138172017-01-02 11:48:42 +0000848/*
849 * Let the compiler optimize alternatives away by passing this value into
850 * the static functions. This saves us #ifdefs, but still keeps the binary
851 * small.
852 */
853#if defined(CONFIG_MACH_SUN8I_H3)
854 uint16_t socid = SOCID_H3;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800855#elif defined(CONFIG_MACH_SUN8I_R40)
856 uint16_t socid = SOCID_R40;
Icenowy Zheng88048772017-06-03 17:10:19 +0800857 /* Currently we cannot support R40 with dual rank memory */
858 para.dual_rank = 0;
Icenowy Zhengfe052172017-06-03 17:10:21 +0800859#elif defined(CONFIG_MACH_SUN8I_V3S)
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800860 uint16_t socid = SOCID_V3S;
Jens Kuskef6138172017-01-02 11:48:42 +0000861#elif defined(CONFIG_MACH_SUN50I)
862 uint16_t socid = SOCID_A64;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000863#elif defined(CONFIG_MACH_SUN50I_H5)
864 uint16_t socid = SOCID_H5;
Jens Kuskef6138172017-01-02 11:48:42 +0000865#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100866
Jens Kuskef6138172017-01-02 11:48:42 +0000867 mctl_sys_init(socid, &para);
868 if (mctl_channel_init(socid, &para))
Jens Kuske53f018e2015-11-17 15:12:59 +0100869 return 0;
870
871 if (para.dual_rank)
872 writel(0x00000303, &mctl_ctl->odtmap);
873 else
874 writel(0x00000201, &mctl_ctl->odtmap);
875 udelay(1);
876
877 /* odt delay */
Jens Kuskef6138172017-01-02 11:48:42 +0000878 if (socid == SOCID_H3)
879 writel(0x0c000400, &mctl_ctl->odtcfg);
880
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800881 if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
882 /* VTF enable (tpr13[8] == 1) */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000883 setbits_le32(&mctl_ctl->vtfcr,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800884 (socid != SOCID_A64 ? 3 : 2) << 8);
885 /* DQ hold disable (tpr13[26] == 1) */
Jens Kuskef6138172017-01-02 11:48:42 +0000886 clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
887 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100888
889 /* clear credit value */
890 setbits_le32(&mctl_com->cccr, 1 << 31);
891 udelay(10);
892
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800893 mctl_auto_detect_dram_size(socid, &para);
894 mctl_set_cr(socid, &para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100895
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800896 size = mctl_calc_rank_size(&para.ranks[0]);
897 if (socid == SOCID_A64 || socid == SOCID_R40) {
898 if (para.dual_rank)
899 size += mctl_calc_rank_size(&para.ranks[1]);
900 } else if (para.dual_rank) {
901 size *= 2;
902 }
903
904 return size;
Jens Kuske53f018e2015-11-17 15:12:59 +0100905}