blob: 4ed295909cebfd9bbbe39490a2c85369eccb5d90 [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 */
Simon Glass97589732020-05-10 11:40:02 -060011#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Jens Kuske53f018e2015-11-17 15:12:59 +010013#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>
Simon Glassdbd79542020-05-10 11:40:11 -060017#include <linux/delay.h>
Jens Kuske53f018e2015-11-17 15:12:59 +010018
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,
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +080064 MBUS_PORT_DE_V3S = 8,
65 MBUS_PORT_DE_CFD_V3S = 9,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000066 MBUS_PORT_TS = 8,
67 MBUS_PORT_DI = 9,
68 MBUS_PORT_DE = 10,
69 MBUS_PORT_DE_CFD = 11,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080070 MBUS_PORT_UNKNOWN1 = 12,
71 MBUS_PORT_UNKNOWN2 = 13,
72 MBUS_PORT_UNKNOWN3 = 14,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000073};
74
75enum {
76 MBUS_QOS_LOWEST = 0,
77 MBUS_QOS_LOW,
78 MBUS_QOS_HIGH,
79 MBUS_QOS_HIGHEST
80};
81
Andre Przywara16f6f792023-06-07 01:07:41 +010082static void mbus_configure_port(u8 port,
83 bool bwlimit,
84 bool priority,
85 u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
86 u8 waittime, /* 0 .. 0xf */
87 u8 acs, /* 0 .. 0xff */
88 u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */
89 u16 bwl1,
90 u16 bwl2)
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000091{
92 struct sunxi_mctl_com_reg * const mctl_com =
93 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
94
95 const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
96 | (priority ? (1 << 1) : 0)
97 | ((qos & 0x3) << 2)
98 | ((waittime & 0xf) << 4)
99 | ((acs & 0xff) << 8)
100 | (bwl0 << 16) );
101 const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
102
103 debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
104 writel(cfg0, &mctl_com->mcr[port][0]);
105 writel(cfg1, &mctl_com->mcr[port][1]);
106}
107
108#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \
109 mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
110 MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
111
Jens Kuskef6138172017-01-02 11:48:42 +0000112static void mctl_set_master_priority_h3(void)
Jens Kuske53f018e2015-11-17 15:12:59 +0100113{
114 struct sunxi_mctl_com_reg * const mctl_com =
115 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
116
117 /* enable bandwidth limit windows and set windows size 1us */
Jens Kuskef6138172017-01-02 11:48:42 +0000118 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
Jens Kuske53f018e2015-11-17 15:12:59 +0100119
120 /* set cpu high priority */
121 writel(0x00000001, &mctl_com->mapr);
122
Philipp Tomsich3c31ba92017-01-02 11:48:38 +0000123 MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128);
124 MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256);
125 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
126 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
127 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
128 MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32);
129 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
130 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
131 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
132 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
133 MBUS_CONF( DE, true, HIGHEST, 3, 8192, 6120, 1024);
134 MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64);
Jens Kuske53f018e2015-11-17 15:12:59 +0100135}
136
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800137static void mctl_set_master_priority_v3s(void)
138{
139 struct sunxi_mctl_com_reg * const mctl_com =
140 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
141
142 /* enable bandwidth limit windows and set windows size 1us */
143 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
144
145 /* set cpu high priority */
146 writel(0x00000001, &mctl_com->mapr);
147
148 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
149 MBUS_CONF( GPU, true, HIGH, 0, 1792, 1536, 0);
150 MBUS_CONF( UNUSED, true, HIGHEST, 0, 256, 128, 80);
151 MBUS_CONF( DMA, true, HIGH, 0, 256, 100, 0);
152 MBUS_CONF( VE, true, HIGH, 0, 2048, 1600, 0);
153 MBUS_CONF( CSI, true, HIGHEST, 0, 384, 256, 0);
154 MBUS_CONF( NAND, true, HIGH, 0, 100, 50, 0);
155 MBUS_CONF( SS, true, HIGH, 0, 384, 256, 0);
156 MBUS_CONF( DE_V3S, false, HIGH, 0, 8192, 4096, 0);
157 MBUS_CONF(DE_CFD_V3S, true, HIGH, 0, 640, 256, 0);
158}
159
Jens Kuskef6138172017-01-02 11:48:42 +0000160static void mctl_set_master_priority_a64(void)
161{
162 struct sunxi_mctl_com_reg * const mctl_com =
163 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
164
165 /* enable bandwidth limit windows and set windows size 1us */
166 writel(399, &mctl_com->tmr);
167 writel((1 << 16), &mctl_com->bwcr);
168
169 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
170 * initialise it */
171 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
172 MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256);
173 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
174 MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100);
175 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
176 MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0);
177 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
178 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
179 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
180 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
181 MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048);
182 MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64);
183
184 writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
185}
186
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000187static void mctl_set_master_priority_h5(void)
188{
189 struct sunxi_mctl_com_reg * const mctl_com =
190 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
191
192 /* enable bandwidth limit windows and set windows size 1us */
193 writel(399, &mctl_com->tmr);
194 writel((1 << 16), &mctl_com->bwcr);
195
196 /* set cpu high priority */
197 writel(0x00000001, &mctl_com->mapr);
198
199 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
200 * they initialise it */
201 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
202 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
203 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
204 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
205 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
206 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
207 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
208 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
209 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
210 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
211 MBUS_CONF( DE, true, HIGHEST, 3, 3400, 2400, 1024);
212 MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200);
213}
214
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800215static void mctl_set_master_priority_r40(void)
216{
217 struct sunxi_mctl_com_reg * const mctl_com =
218 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
219
220 /* enable bandwidth limit windows and set windows size 1us */
221 writel(399, &mctl_com->tmr);
222 writel((1 << 16), &mctl_com->bwcr);
223
224 /* set cpu high priority */
225 writel(0x00000001, &mctl_com->mapr);
226
227 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
228 * they initialise it */
229 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
230 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
231 MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96);
232 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
233 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
234 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
235 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
236 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
237 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
238 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
239
240 /*
241 * The port names are probably wrong, but no correct sources
242 * are available.
243 */
244 MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0);
245 MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0);
246 MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256);
247 MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
248 MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64);
249}
250
Jens Kuskef6138172017-01-02 11:48:42 +0000251static void mctl_set_master_priority(uint16_t socid)
252{
253 switch (socid) {
254 case SOCID_H3:
255 mctl_set_master_priority_h3();
256 return;
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800257 case SOCID_V3S:
258 mctl_set_master_priority_v3s();
259 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000260 case SOCID_A64:
261 mctl_set_master_priority_a64();
262 return;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000263 case SOCID_H5:
264 mctl_set_master_priority_h5();
265 return;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800266 case SOCID_R40:
267 mctl_set_master_priority_r40();
268 return;
Jens Kuskef6138172017-01-02 11:48:42 +0000269 }
270}
271
Jens Kuskef6138172017-01-02 11:48:42 +0000272static u32 bin_to_mgray(int val)
273{
274 static const u8 lookup_table[32] = {
275 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
276 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
277 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
278 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
279 };
280
281 return lookup_table[clamp(val, 0, 31)];
282}
283
284static int mgray_to_bin(u32 val)
285{
286 static const u8 lookup_table[32] = {
287 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
288 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
289 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
290 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
291 };
292
293 return lookup_table[val & 0x1f];
294}
295
296static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100297{
298 struct sunxi_mctl_ctl_reg * const mctl_ctl =
299 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
Icenowy Zhengb2607512017-06-03 17:10:16 +0800300 int zq_count;
301
302#if defined CONFIG_SUNXI_DRAM_DW_16BIT
303 zq_count = 4;
304#else
305 zq_count = 6;
306#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100307
Jens Kusked8b95932016-09-21 20:08:30 +0200308 if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
309 (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
310 u32 reg_val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100311
Jens Kusked8b95932016-09-21 20:08:30 +0200312 clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
313 CONFIG_DRAM_ZQ & 0xffff);
Jens Kuske53f018e2015-11-17 15:12:59 +0100314
315 writel(PIR_CLRSR, &mctl_ctl->pir);
316 mctl_phy_init(PIR_ZCAL);
317
Jens Kusked8b95932016-09-21 20:08:30 +0200318 reg_val = readl(&mctl_ctl->zqdr[0]);
319 reg_val &= (0x1f << 16) | (0x1f << 0);
320 reg_val |= reg_val << 8;
321 writel(reg_val, &mctl_ctl->zqdr[0]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100322
Jens Kusked8b95932016-09-21 20:08:30 +0200323 reg_val = readl(&mctl_ctl->zqdr[1]);
324 reg_val &= (0x1f << 16) | (0x1f << 0);
325 reg_val |= reg_val << 8;
326 writel(reg_val, &mctl_ctl->zqdr[1]);
327 writel(reg_val, &mctl_ctl->zqdr[2]);
328 } else {
329 int i;
330 u16 zq_val[6];
331 u8 val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100332
Jens Kusked8b95932016-09-21 20:08:30 +0200333 writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
334
Icenowy Zhengb2607512017-06-03 17:10:16 +0800335 for (i = 0; i < zq_count; i++) {
Jens Kusked8b95932016-09-21 20:08:30 +0200336 u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
Jens Kuske53f018e2015-11-17 15:12:59 +0100337
Jens Kusked8b95932016-09-21 20:08:30 +0200338 writel((zq << 20) | (zq << 16) | (zq << 12) |
339 (zq << 8) | (zq << 4) | (zq << 0),
340 &mctl_ctl->zqcr);
341
342 writel(PIR_CLRSR, &mctl_ctl->pir);
343 mctl_phy_init(PIR_ZCAL);
344
345 zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
346 writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
347
348 writel(PIR_CLRSR, &mctl_ctl->pir);
349 mctl_phy_init(PIR_ZCAL);
350
351 val = readl(&mctl_ctl->zqdr[0]) >> 24;
352 zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
353 }
354
355 writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
356 writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800357 if (zq_count > 4)
358 writel((zq_val[5] << 16) | zq_val[4],
359 &mctl_ctl->zqdr[2]);
Jens Kusked8b95932016-09-21 20:08:30 +0200360 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100361}
362
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800363static void mctl_v3s_zq_calibration_quirk(struct dram_para *para)
364{
365 struct sunxi_mctl_ctl_reg * const mctl_ctl =
366 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
367
368 u32 reg_val;
369
370 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff,
371 CONFIG_DRAM_ZQ & 0xffffff);
372 mctl_phy_init(PIR_ZCAL);
373
374 reg_val = readl(&mctl_ctl->zqdr[0]);
375 reg_val &= (0x1f << 16) | (0x1f << 0);
376 reg_val |= reg_val << 8;
377 writel(reg_val, &mctl_ctl->zqdr[0]);
378
379 reg_val = readl(&mctl_ctl->zqdr[1]);
380 reg_val &= (0x1f << 16) | (0x1f << 0);
381 reg_val |= reg_val << 8;
382 writel(reg_val, &mctl_ctl->zqdr[1]);
383}
384
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800385static void mctl_set_cr(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100386{
387 struct sunxi_mctl_com_reg * const mctl_com =
388 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
389
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800390 writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
391#if defined CONFIG_SUNXI_DRAM_DDR3
392 MCTL_CR_DDR3 | MCTL_CR_2T |
Icenowy Zhenge270a582017-06-03 17:10:20 +0800393#elif defined CONFIG_SUNXI_DRAM_DDR2
394 MCTL_CR_DDR2 | MCTL_CR_2T |
Icenowy Zheng3c1b9f12017-06-03 17:10:23 +0800395#elif defined CONFIG_SUNXI_DRAM_LPDDR3
396 MCTL_CR_LPDDR3 | MCTL_CR_1T |
Icenowy Zhengf09b48e2017-06-03 17:10:18 +0800397#else
398#error Unsupported DRAM type!
399#endif
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800400 (para->ranks[0].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800401 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
Jens Kuske53f018e2015-11-17 15:12:59 +0100402 (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800403 MCTL_CR_PAGE_SIZE(para->ranks[0].page_size) |
404 MCTL_CR_ROW_BITS(para->ranks[0].row_bits), &mctl_com->cr);
405
406 if (para->dual_rank && (socid == SOCID_A64 || socid == SOCID_R40)) {
407 writel((para->ranks[1].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
408 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
409 MCTL_CR_DUAL_RANK |
410 MCTL_CR_PAGE_SIZE(para->ranks[1].page_size) |
411 MCTL_CR_ROW_BITS(para->ranks[1].row_bits), &mctl_com->cr_r1);
412 }
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800413
414 if (socid == SOCID_R40) {
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800415 /* Mux pin to A15 address line for single rank memory. */
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800416 if (!para->dual_rank)
417 setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800418 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100419}
420
Jens Kuskef6138172017-01-02 11:48:42 +0000421static void mctl_sys_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100422{
423 struct sunxi_ccm_reg * const ccm =
424 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
425 struct sunxi_mctl_ctl_reg * const mctl_ctl =
426 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
427
428 clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
429 clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
430 clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
431 clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
432 clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800433 if (socid == SOCID_A64 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000434 clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
Jens Kuske53f018e2015-11-17 15:12:59 +0100435 udelay(10);
436
437 clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
438 udelay(1000);
439
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800440 if (socid == SOCID_A64 || socid == SOCID_R40) {
Jens Kuskef6138172017-01-02 11:48:42 +0000441 clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
442 clrsetbits_le32(&ccm->dram_clk_cfg,
443 CCM_DRAMCLK_CFG_DIV_MASK |
444 CCM_DRAMCLK_CFG_SRC_MASK,
445 CCM_DRAMCLK_CFG_DIV(1) |
446 CCM_DRAMCLK_CFG_SRC_PLL11 |
447 CCM_DRAMCLK_CFG_UPD);
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800448 } else if (socid == SOCID_H3 || socid == SOCID_H5 || socid == SOCID_V3S) {
Jens Kuskef6138172017-01-02 11:48:42 +0000449 clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
450 clrsetbits_le32(&ccm->dram_clk_cfg,
451 CCM_DRAMCLK_CFG_DIV_MASK |
452 CCM_DRAMCLK_CFG_SRC_MASK,
453 CCM_DRAMCLK_CFG_DIV(1) |
454 CCM_DRAMCLK_CFG_SRC_PLL5 |
455 CCM_DRAMCLK_CFG_UPD);
456 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100457 mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
458
459 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
460 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
461 setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
462 setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
463
464 setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
465 udelay(10);
466
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000467 writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
Jens Kuske53f018e2015-11-17 15:12:59 +0100468 udelay(500);
469}
470
Andre Przywarac98f5cc2017-01-02 11:48:43 +0000471/* These are more guessed based on some Allwinner code. */
472#define DX_GCR_ODT_DYNAMIC (0x0 << 4)
473#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4)
474#define DX_GCR_ODT_OFF (0x2 << 4)
475
Jens Kuskef6138172017-01-02 11:48:42 +0000476static int mctl_channel_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100477{
478 struct sunxi_mctl_com_reg * const mctl_com =
479 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
480 struct sunxi_mctl_ctl_reg * const mctl_ctl =
481 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
482
483 unsigned int i;
484
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800485 mctl_set_cr(socid, para);
Jens Kuskef6138172017-01-02 11:48:42 +0000486 mctl_set_timing_params(socid, para);
487 mctl_set_master_priority(socid);
Jens Kuske53f018e2015-11-17 15:12:59 +0100488
489 /* setting VTC, default disable all VT */
490 clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000491 if (socid == SOCID_H5)
492 setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
493 else
494 clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +0100495
496 /* increase DFI_PHY_UPD clock */
497 writel(PROTECT_MAGIC, &mctl_com->protect);
498 udelay(100);
499 clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
500 writel(0x0, &mctl_com->protect);
501 udelay(100);
502
503 /* set dramc odt */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000504 for (i = 0; i < 4; i++) {
505 u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
506 (0x3 << 12) | (0x3 << 14);
507 u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
508 DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
509
510 if (socid == SOCID_H5) {
511 clearmask |= 0x2 << 8;
512 setmask |= 0x4 << 8;
513 }
514 clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
515 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100516
517 /* AC PDR should always ON */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000518 clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
519 0x1 << 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100520
521 /* set DQS auto gating PD mode */
522 setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
523
Jens Kuskef6138172017-01-02 11:48:42 +0000524 if (socid == SOCID_H3) {
525 /* dx ddr_clk & hdr_clk dynamic mode */
526 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
Jens Kuske53f018e2015-11-17 15:12:59 +0100527
Jens Kuskef6138172017-01-02 11:48:42 +0000528 /* dphy & aphy phase select 270 degree */
529 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
530 (0x1 << 10) | (0x2 << 8));
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800531 } else if (socid == SOCID_V3S) {
532 /* dx ddr_clk & hdr_clk dynamic mode */
533 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
534
535 /* dphy & aphy phase select 270 degree */
536 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
537 (0x1 << 10) | (0x1 << 8));
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000538 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000539 /* dphy & aphy phase select ? */
540 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
541 (0x0 << 10) | (0x3 << 8));
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800542 } else if (socid == SOCID_R40) {
543 /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
544 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
545
546 /* dphy & aphy phase select ? */
547 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
548 (0x0 << 10) | (0x3 << 8));
Jens Kuskef6138172017-01-02 11:48:42 +0000549 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100550
551 /* set half DQ */
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800552 if (!para->bus_full_width) {
Icenowy Zhengb2607512017-06-03 17:10:16 +0800553#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000554 writel(0x0, &mctl_ctl->dx[2].gcr);
555 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800556#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
557 writel(0x0, &mctl_ctl->dx[1].gcr);
558#else
559#error Unsupported DRAM bus width!
560#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100561 }
562
563 /* data training configuration */
564 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
565 (para->dual_rank ? 0x3 : 0x1) << 24);
566
Jens Kuske8bbadc82017-01-02 11:48:40 +0000567 mctl_set_bit_delays(para);
568 udelay(50);
Jens Kuske53f018e2015-11-17 15:12:59 +0100569
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800570 if (socid == SOCID_V3S) {
571 mctl_v3s_zq_calibration_quirk(para);
572
573 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
574 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
575 } else if (socid == SOCID_H3) {
Jens Kuskef6138172017-01-02 11:48:42 +0000576 mctl_h3_zq_calibration_quirk(para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100577
Jens Kuskef6138172017-01-02 11:48:42 +0000578 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
579 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000580 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000581 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
582
583 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
584 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000585 /* no PIR_QSGATE for H5 ???? */
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800586 } else if (socid == SOCID_R40) {
587 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
588
589 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
590 PIR_DRAMRST | PIR_DRAMINIT);
Jens Kuskef6138172017-01-02 11:48:42 +0000591 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100592
593 /* detect ranks and bus width */
594 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
595 /* only one rank */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800596 if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
597#if defined CONFIG_SUNXI_DRAM_DW_32BIT
598 || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
599#endif
600 ) {
Jens Kuske53f018e2015-11-17 15:12:59 +0100601 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
602 para->dual_rank = 0;
603 }
604
605 /* only half DQ width */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800606#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000607 if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
608 ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
609 writel(0x0, &mctl_ctl->dx[2].gcr);
610 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800611 para->bus_full_width = 0;
Jens Kuske53f018e2015-11-17 15:12:59 +0100612 }
Icenowy Zhengb2607512017-06-03 17:10:16 +0800613#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
614 if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
615 writel(0x0, &mctl_ctl->dx[1].gcr);
616 para->bus_full_width = 0;
617 }
618#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100619
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800620 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100621 udelay(20);
622
623 /* re-train */
624 mctl_phy_init(PIR_QSGATE);
625 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
626 return 1;
627 }
628
629 /* check the dramc status */
630 mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
631
632 /* liuke added for refresh debug */
633 setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
634 udelay(10);
635 clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
636 udelay(10);
637
638 /* set PGCR3, CKE polarity */
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800639 if (socid == SOCID_H3 || socid == SOCID_V3S)
Jens Kuskef6138172017-01-02 11:48:42 +0000640 writel(0x00aa0060, &mctl_ctl->pgcr[3]);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800641 else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000642 writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100643
644 /* power down zq calibration module for power save */
645 setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
646
647 /* enable master access */
648 writel(0xffffffff, &mctl_com->maer);
649
650 return 0;
651}
652
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800653static 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 +0100654{
655 /* detect row address bits */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800656 rank->page_size = 512;
657 rank->row_bits = 16;
658 rank->bank_bits = 2;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800659 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100660
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800661 for (rank->row_bits = 11; rank->row_bits < 16; rank->row_bits++)
662 if (mctl_mem_matches_base((1 << (rank->row_bits + rank->bank_bits)) * rank->page_size, base))
Jens Kuske53f018e2015-11-17 15:12:59 +0100663 break;
664
Icenowy Zheng20020352017-06-03 17:10:17 +0800665 /* detect bank address bits */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800666 rank->bank_bits = 3;
Icenowy Zheng20020352017-06-03 17:10:17 +0800667 mctl_set_cr(socid, para);
668
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800669 for (rank->bank_bits = 2; rank->bank_bits < 3; rank->bank_bits++)
670 if (mctl_mem_matches_base((1 << rank->bank_bits) * rank->page_size, base))
Icenowy Zheng20020352017-06-03 17:10:17 +0800671 break;
672
Jens Kuske53f018e2015-11-17 15:12:59 +0100673 /* detect page size */
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800674 rank->page_size = 8192;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800675 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100676
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800677 for (rank->page_size = 512; rank->page_size < 8192; rank->page_size *= 2)
678 if (mctl_mem_matches_base(rank->page_size, base))
Jens Kuske53f018e2015-11-17 15:12:59 +0100679 break;
680}
681
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800682static unsigned long mctl_calc_rank_size(struct rank_para *rank)
683{
684 return (1UL << (rank->row_bits + rank->bank_bits)) * rank->page_size;
685}
686
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800687/*
688 * Because we cannot do mctl_phy_init(PIR_QSGATE) on R40 now (which leads
689 * to failure), it's needed to detect the rank count of R40 in another way.
690 *
691 * The code here is modelled after time_out_detect() in BSP, which tries to
692 * access the memory and check for error code.
693 *
694 * TODO: auto detect half DQ width here
695 */
696static void mctl_r40_detect_rank_count(struct dram_para *para)
697{
Tom Rinibb4dd962022-11-16 13:10:37 -0500698 ulong rank1_base = (ulong) CFG_SYS_SDRAM_BASE +
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800699 mctl_calc_rank_size(&para->ranks[0]);
700 struct sunxi_mctl_ctl_reg * const mctl_ctl =
701 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
702
703 /* Enable read time out */
704 setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
705
706 (void) readl((void *) rank1_base);
707 udelay(10);
708
709 if (readl(&mctl_ctl->pgsr[0]) & (0x1 << 13)) {
710 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
711 para->dual_rank = 0;
712 }
713
714 /* Reset PHY FIFO to clear it */
715 clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
716 udelay(100);
717 setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
718
719 /* Clear error status */
720 setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 24);
721
722 /* Clear time out flag */
723 clrbits_le32(&mctl_ctl->pgsr[0], 0x1 << 13);
724
725 /* Disable read time out */
726 clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
727}
728
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800729static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
730{
Tom Rinibb4dd962022-11-16 13:10:37 -0500731 mctl_auto_detect_dram_size_rank(socid, para, (ulong)CFG_SYS_SDRAM_BASE, &para->ranks[0]);
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800732
733 if ((socid == SOCID_A64 || socid == SOCID_R40) && para->dual_rank) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500734 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 +0800735 }
736}
737
Jens Kuske8bbadc82017-01-02 11:48:40 +0000738/*
739 * The actual values used here are taken from Allwinner provided boot0
740 * binaries, though they are probably board specific, so would likely benefit
741 * from invidual tuning for each board. Apparently a lot of boards copy from
742 * some Allwinner reference design, so we go with those generic values for now
743 * in the hope that they are reasonable for most (all?) boards.
744 */
745#define SUN8I_H3_DX_READ_DELAYS \
746 {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
747 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
748 { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
749 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }}
750#define SUN8I_H3_DX_WRITE_DELAYS \
751 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
752 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
753 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
754 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }}
755#define SUN8I_H3_AC_DELAYS \
756 { 0, 0, 0, 0, 0, 0, 0, 0, \
757 0, 0, 0, 0, 0, 0, 0, 0, \
758 0, 0, 0, 0, 0, 0, 0, 0, \
759 0, 0, 0, 0, 0, 0, 0 }
760
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800761#define SUN8I_V3S_DX_READ_DELAYS \
762 {{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0 }, \
763 { 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0 }, \
764 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
765 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
766#define SUN8I_V3S_DX_WRITE_DELAYS \
767 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4 }, \
768 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, \
769 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
770 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
771#define SUN8I_V3S_AC_DELAYS \
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, 0, \
775 0, 0, 0, 0, 0, 0, 0 }
776
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800777#define SUN8I_R40_DX_READ_DELAYS \
778 {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
779 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
780 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
781 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } }
782#define SUN8I_R40_DX_WRITE_DELAYS \
783 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
784 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
785 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
786 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } }
787#define SUN8I_R40_AC_DELAYS \
788 { 0, 0, 3, 0, 0, 0, 0, 0, \
789 0, 0, 0, 0, 0, 0, 0, 0, \
790 0, 0, 0, 0, 0, 0, 0, 0, \
791 0, 0, 0, 0, 0, 0, 0 }
792
Jens Kuskef6138172017-01-02 11:48:42 +0000793#define SUN50I_A64_DX_READ_DELAYS \
794 {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \
795 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \
796 { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \
797 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}
798#define SUN50I_A64_DX_WRITE_DELAYS \
799 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \
800 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \
801 { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \
802 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}
803#define SUN50I_A64_AC_DELAYS \
804 { 5, 5, 13, 10, 2, 5, 3, 3, \
805 0, 3, 3, 3, 1, 0, 0, 0, \
806 3, 4, 0, 3, 4, 1, 4, 0, \
807 1, 1, 0, 1, 13, 5, 4 }
808
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000809#define SUN8I_H5_DX_READ_DELAYS \
810 {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \
811 { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \
812 { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \
813 { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } }
814#define SUN8I_H5_DX_WRITE_DELAYS \
815 {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \
816 { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \
817 { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \
818 { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } }
819#define SUN8I_H5_AC_DELAYS \
820 { 0, 0, 5, 5, 0, 0, 0, 0, \
821 0, 0, 0, 0, 3, 3, 3, 3, \
822 3, 3, 3, 3, 3, 3, 3, 3, \
823 3, 3, 3, 3, 2, 0, 0 }
824
Jens Kuske53f018e2015-11-17 15:12:59 +0100825unsigned long sunxi_dram_init(void)
826{
827 struct sunxi_mctl_com_reg * const mctl_com =
828 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
829 struct sunxi_mctl_ctl_reg * const mctl_ctl =
830 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
831
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800832 unsigned long size;
833
Jens Kuske53f018e2015-11-17 15:12:59 +0100834 struct dram_para para = {
Icenowy Zheng88048772017-06-03 17:10:19 +0800835 .dual_rank = 1,
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800836 .bus_full_width = 1,
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800837 .ranks = {
838 {
839 .row_bits = 15,
840 .bank_bits = 3,
841 .page_size = 4096,
842 },
843 {
844 .row_bits = 15,
845 .bank_bits = 3,
846 .page_size = 4096,
847 }
848 },
Jens Kuskef6138172017-01-02 11:48:42 +0000849
850#if defined(CONFIG_MACH_SUN8I_H3)
Jens Kuske8bbadc82017-01-02 11:48:40 +0000851 .dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
852 .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
853 .ac_delays = SUN8I_H3_AC_DELAYS,
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800854#elif defined(CONFIG_MACH_SUN8I_V3S)
855 .dx_read_delays = SUN8I_V3S_DX_READ_DELAYS,
856 .dx_write_delays = SUN8I_V3S_DX_WRITE_DELAYS,
857 .ac_delays = SUN8I_V3S_AC_DELAYS,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800858#elif defined(CONFIG_MACH_SUN8I_R40)
859 .dx_read_delays = SUN8I_R40_DX_READ_DELAYS,
860 .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
861 .ac_delays = SUN8I_R40_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000862#elif defined(CONFIG_MACH_SUN50I)
863 .dx_read_delays = SUN50I_A64_DX_READ_DELAYS,
864 .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
865 .ac_delays = SUN50I_A64_AC_DELAYS,
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000866#elif defined(CONFIG_MACH_SUN50I_H5)
867 .dx_read_delays = SUN8I_H5_DX_READ_DELAYS,
868 .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
869 .ac_delays = SUN8I_H5_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000870#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100871 };
Jens Kuskef6138172017-01-02 11:48:42 +0000872/*
873 * Let the compiler optimize alternatives away by passing this value into
874 * the static functions. This saves us #ifdefs, but still keeps the binary
875 * small.
876 */
877#if defined(CONFIG_MACH_SUN8I_H3)
878 uint16_t socid = SOCID_H3;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800879#elif defined(CONFIG_MACH_SUN8I_R40)
880 uint16_t socid = SOCID_R40;
Icenowy Zhengfe052172017-06-03 17:10:21 +0800881#elif defined(CONFIG_MACH_SUN8I_V3S)
Icenowy Zhengaff2d3a2020-10-16 17:33:08 +0800882 uint16_t socid = SOCID_V3S;
Jens Kuskef6138172017-01-02 11:48:42 +0000883#elif defined(CONFIG_MACH_SUN50I)
884 uint16_t socid = SOCID_A64;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000885#elif defined(CONFIG_MACH_SUN50I_H5)
886 uint16_t socid = SOCID_H5;
Jens Kuskef6138172017-01-02 11:48:42 +0000887#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100888
Jens Kuskef6138172017-01-02 11:48:42 +0000889 mctl_sys_init(socid, &para);
890 if (mctl_channel_init(socid, &para))
Jens Kuske53f018e2015-11-17 15:12:59 +0100891 return 0;
892
893 if (para.dual_rank)
894 writel(0x00000303, &mctl_ctl->odtmap);
895 else
896 writel(0x00000201, &mctl_ctl->odtmap);
897 udelay(1);
898
899 /* odt delay */
Jens Kuskef6138172017-01-02 11:48:42 +0000900 if (socid == SOCID_H3)
901 writel(0x0c000400, &mctl_ctl->odtcfg);
902
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800903 if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
904 /* VTF enable (tpr13[8] == 1) */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000905 setbits_le32(&mctl_ctl->vtfcr,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800906 (socid != SOCID_A64 ? 3 : 2) << 8);
907 /* DQ hold disable (tpr13[26] == 1) */
Jens Kuskef6138172017-01-02 11:48:42 +0000908 clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
909 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100910
911 /* clear credit value */
912 setbits_le32(&mctl_com->cccr, 1 << 31);
913 udelay(10);
914
Icenowy Zhengc3391f62021-02-26 00:13:25 +0800915 if (socid == SOCID_R40) {
916 mctl_r40_detect_rank_count(&para);
917 mctl_set_cr(SOCID_R40, &para);
918 }
919
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800920 mctl_auto_detect_dram_size(socid, &para);
921 mctl_set_cr(socid, &para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100922
Icenowy Zheng9e9b0732021-02-26 00:13:24 +0800923 size = mctl_calc_rank_size(&para.ranks[0]);
924 if (socid == SOCID_A64 || socid == SOCID_R40) {
925 if (para.dual_rank)
926 size += mctl_calc_rank_size(&para.ranks[1]);
927 } else if (para.dual_rank) {
928 size *= 2;
929 }
930
931 return size;
Jens Kuske53f018e2015-11-17 15:12:59 +0100932}