blob: 3f54c8ee09af165a493a2fa71ba47bea10949d08 [file] [log] [blame]
Jens Kuske53f018e2015-11-17 15:12:59 +01001/*
2 * sun8i H3 platform dram controller init
3 *
4 * (C) Copyright 2007-2015 Allwinner Technology Co.
5 * Jerry Wang <wangflord@allwinnertech.com>
6 * (C) Copyright 2015 Vishnu Patekar <vishnupatekar0510@gmail.com>
7 * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
8 * (C) Copyright 2015 Jens Kuske <jenskuske@gmail.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0+
11 */
12#include <common.h>
13#include <asm/io.h>
14#include <asm/arch/clock.h>
15#include <asm/arch/dram.h>
Jens Kuskef6138172017-01-02 11:48:42 +000016#include <asm/arch/cpu.h>
Jens Kuske53f018e2015-11-17 15:12:59 +010017#include <linux/kconfig.h>
18
Jens Kuske8bbadc82017-01-02 11:48:40 +000019/*
20 * The delay parameters below allow to allegedly specify delay times of some
21 * unknown unit for each individual bit trace in each of the four data bytes
22 * the 32-bit wide access consists of. Also three control signals can be
23 * adjusted individually.
24 */
25#define BITS_PER_BYTE 8
26#define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE)
27/* The eight data lines (DQn) plus DM, DQS and DQSN */
28#define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3)
Jens Kuske53f018e2015-11-17 15:12:59 +010029struct dram_para {
Jens Kuske53f018e2015-11-17 15:12:59 +010030 u16 page_size;
Icenowy Zheng4323a8f2017-06-03 17:10:15 +080031 u8 bus_full_width;
Jens Kuske53f018e2015-11-17 15:12:59 +010032 u8 dual_rank;
33 u8 row_bits;
Icenowy Zheng20020352017-06-03 17:10:17 +080034 u8 bank_bits;
Jens Kuske8bbadc82017-01-02 11:48:40 +000035 const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
36 const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
37 const u8 ac_delays[31];
Jens Kuske53f018e2015-11-17 15:12:59 +010038};
39
40static inline int ns_to_t(int nanoseconds)
41{
42 const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
43
44 return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
45}
46
Jens Kuske53f018e2015-11-17 15:12:59 +010047static void mctl_phy_init(u32 val)
48{
49 struct sunxi_mctl_ctl_reg * const mctl_ctl =
50 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
51
52 writel(val | PIR_INIT, &mctl_ctl->pir);
53 mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
54}
55
Jens Kuske8bbadc82017-01-02 11:48:40 +000056static void mctl_set_bit_delays(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +010057{
58 struct sunxi_mctl_ctl_reg * const mctl_ctl =
59 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
60 int i, j;
Jens Kuske53f018e2015-11-17 15:12:59 +010061
62 clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
63
Jens Kuske8bbadc82017-01-02 11:48:40 +000064 for (i = 0; i < NR_OF_BYTE_LANES; i++)
65 for (j = 0; j < LINES_PER_BYTE_LANE; j++)
66 writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
67 DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
68 &mctl_ctl->dx[i].bdlr[j]);
Jens Kuske53f018e2015-11-17 15:12:59 +010069
Jens Kuske8bbadc82017-01-02 11:48:40 +000070 for (i = 0; i < 31; i++)
71 writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
72 &mctl_ctl->acbdlr[i]);
Jens Kuske53f018e2015-11-17 15:12:59 +010073
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080074#ifdef CONFIG_MACH_SUN8I_R40
75 /* DQSn, DMn, DQn output enable bit delay */
76 for (i = 0; i < 4; i++)
77 writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
78#endif
79
Jens Kuske53f018e2015-11-17 15:12:59 +010080 setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +010081}
82
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000083enum {
84 MBUS_PORT_CPU = 0,
85 MBUS_PORT_GPU = 1,
86 MBUS_PORT_UNUSED = 2,
87 MBUS_PORT_DMA = 3,
88 MBUS_PORT_VE = 4,
89 MBUS_PORT_CSI = 5,
90 MBUS_PORT_NAND = 6,
91 MBUS_PORT_SS = 7,
92 MBUS_PORT_TS = 8,
93 MBUS_PORT_DI = 9,
94 MBUS_PORT_DE = 10,
95 MBUS_PORT_DE_CFD = 11,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +080096 MBUS_PORT_UNKNOWN1 = 12,
97 MBUS_PORT_UNKNOWN2 = 13,
98 MBUS_PORT_UNKNOWN3 = 14,
Philipp Tomsich3c31ba92017-01-02 11:48:38 +000099};
100
101enum {
102 MBUS_QOS_LOWEST = 0,
103 MBUS_QOS_LOW,
104 MBUS_QOS_HIGH,
105 MBUS_QOS_HIGHEST
106};
107
108inline void mbus_configure_port(u8 port,
109 bool bwlimit,
110 bool priority,
111 u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
112 u8 waittime, /* 0 .. 0xf */
113 u8 acs, /* 0 .. 0xff */
114 u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */
115 u16 bwl1,
116 u16 bwl2)
117{
118 struct sunxi_mctl_com_reg * const mctl_com =
119 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
120
121 const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
122 | (priority ? (1 << 1) : 0)
123 | ((qos & 0x3) << 2)
124 | ((waittime & 0xf) << 4)
125 | ((acs & 0xff) << 8)
126 | (bwl0 << 16) );
127 const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
128
129 debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
130 writel(cfg0, &mctl_com->mcr[port][0]);
131 writel(cfg1, &mctl_com->mcr[port][1]);
132}
133
134#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \
135 mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
136 MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
137
Jens Kuskef6138172017-01-02 11:48:42 +0000138static void mctl_set_master_priority_h3(void)
Jens Kuske53f018e2015-11-17 15:12:59 +0100139{
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 */
Jens Kuskef6138172017-01-02 11:48:42 +0000144 writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
Jens Kuske53f018e2015-11-17 15:12:59 +0100145
146 /* set cpu high priority */
147 writel(0x00000001, &mctl_com->mapr);
148
Philipp Tomsich3c31ba92017-01-02 11:48:38 +0000149 MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128);
150 MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256);
151 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
152 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
153 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
154 MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32);
155 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
156 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
157 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
158 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
159 MBUS_CONF( DE, true, HIGHEST, 3, 8192, 6120, 1024);
160 MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64);
Jens Kuske53f018e2015-11-17 15:12:59 +0100161}
162
Jens Kuskef6138172017-01-02 11:48:42 +0000163static void mctl_set_master_priority_a64(void)
164{
165 struct sunxi_mctl_com_reg * const mctl_com =
166 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
167
168 /* enable bandwidth limit windows and set windows size 1us */
169 writel(399, &mctl_com->tmr);
170 writel((1 << 16), &mctl_com->bwcr);
171
172 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
173 * initialise it */
174 MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
175 MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256);
176 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
177 MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100);
178 MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
179 MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0);
180 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
181 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
182 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
183 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
184 MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048);
185 MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64);
186
187 writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
188}
189
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000190static void mctl_set_master_priority_h5(void)
191{
192 struct sunxi_mctl_com_reg * const mctl_com =
193 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
194
195 /* enable bandwidth limit windows and set windows size 1us */
196 writel(399, &mctl_com->tmr);
197 writel((1 << 16), &mctl_com->bwcr);
198
199 /* set cpu high priority */
200 writel(0x00000001, &mctl_com->mapr);
201
202 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
203 * they initialise it */
204 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
205 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
206 MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
207 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
208 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
209 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
210 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
211 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
212 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
213 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
214 MBUS_CONF( DE, true, HIGHEST, 3, 3400, 2400, 1024);
215 MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200);
216}
217
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800218static void mctl_set_master_priority_r40(void)
219{
220 struct sunxi_mctl_com_reg * const mctl_com =
221 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
222
223 /* enable bandwidth limit windows and set windows size 1us */
224 writel(399, &mctl_com->tmr);
225 writel((1 << 16), &mctl_com->bwcr);
226
227 /* set cpu high priority */
228 writel(0x00000001, &mctl_com->mapr);
229
230 /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
231 * they initialise it */
232 MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
233 MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
234 MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96);
235 MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
236 MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
237 MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
238 MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
239 MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
240 MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
241 MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
242
243 /*
244 * The port names are probably wrong, but no correct sources
245 * are available.
246 */
247 MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0);
248 MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0);
249 MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256);
250 MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
251 MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64);
252}
253
Jens Kuskef6138172017-01-02 11:48:42 +0000254static void mctl_set_master_priority(uint16_t socid)
255{
256 switch (socid) {
257 case SOCID_H3:
258 mctl_set_master_priority_h3();
259 return;
260 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
272static void mctl_set_timing_params(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100273{
274 struct sunxi_mctl_ctl_reg * const mctl_ctl =
275 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
276
277 u8 tccd = 2;
278 u8 tfaw = ns_to_t(50);
279 u8 trrd = max(ns_to_t(10), 4);
280 u8 trcd = ns_to_t(15);
281 u8 trc = ns_to_t(53);
282 u8 txp = max(ns_to_t(8), 3);
283 u8 twtr = max(ns_to_t(8), 4);
284 u8 trtp = max(ns_to_t(8), 4);
285 u8 twr = max(ns_to_t(15), 3);
286 u8 trp = ns_to_t(15);
287 u8 tras = ns_to_t(38);
288 u16 trefi = ns_to_t(7800) / 32;
289 u16 trfc = ns_to_t(350);
290
291 u8 tmrw = 0;
292 u8 tmrd = 4;
293 u8 tmod = 12;
294 u8 tcke = 3;
295 u8 tcksrx = 5;
296 u8 tcksre = 5;
297 u8 tckesr = 4;
298 u8 trasmax = 24;
299
300 u8 tcl = 6; /* CL 12 */
301 u8 tcwl = 4; /* CWL 8 */
302 u8 t_rdata_en = 4;
303 u8 wr_latency = 2;
304
305 u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */
306 u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */
307 u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */
308 u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */
309
310 u8 twtp = tcwl + 2 + twr; /* WL + BL / 2 + tWR */
311 u8 twr2rd = tcwl + 2 + twtr; /* WL + BL / 2 + tWTR */
312 u8 trd2wr = tcl + 2 + 1 - tcwl; /* RL + BL / 2 + 2 - WL */
313
314 /* set mode register */
315 writel(0x1c70, &mctl_ctl->mr[0]); /* CL=11, WR=12 */
316 writel(0x40, &mctl_ctl->mr[1]);
317 writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */
318 writel(0x0, &mctl_ctl->mr[3]);
319
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800320 if (socid == SOCID_R40)
321 writel(0x3, &mctl_ctl->lp3mr11); /* odt_en[7:4] */
322
Jens Kuske53f018e2015-11-17 15:12:59 +0100323 /* set DRAM timing */
324 writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) |
325 DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras),
326 &mctl_ctl->dramtmg[0]);
327 writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc),
328 &mctl_ctl->dramtmg[1]);
329 writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) |
330 DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd),
331 &mctl_ctl->dramtmg[2]);
332 writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod),
333 &mctl_ctl->dramtmg[3]);
334 writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) |
335 DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]);
336 writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) |
337 DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke),
338 &mctl_ctl->dramtmg[5]);
339
340 /* set two rank timing */
341 clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xff << 8) | (0xff << 0),
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000342 ((socid == SOCID_H5 ? 0x33 : 0x66) << 8) | (0x10 << 0));
Jens Kuske53f018e2015-11-17 15:12:59 +0100343
344 /* set PHY interface timing, write latency and read latency configure */
345 writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) |
346 (wr_latency << 0), &mctl_ctl->pitmg[0]);
347
348 /* set PHY timing, PTR0-2 use default */
349 writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]);
350 writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]);
351
352 /* set refresh timing */
353 writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg);
354}
355
Jens Kuskef6138172017-01-02 11:48:42 +0000356static u32 bin_to_mgray(int val)
357{
358 static const u8 lookup_table[32] = {
359 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
360 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
361 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
362 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
363 };
364
365 return lookup_table[clamp(val, 0, 31)];
366}
367
368static int mgray_to_bin(u32 val)
369{
370 static const u8 lookup_table[32] = {
371 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
372 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
373 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
374 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
375 };
376
377 return lookup_table[val & 0x1f];
378}
379
380static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100381{
382 struct sunxi_mctl_ctl_reg * const mctl_ctl =
383 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
Icenowy Zhengb2607512017-06-03 17:10:16 +0800384 int zq_count;
385
386#if defined CONFIG_SUNXI_DRAM_DW_16BIT
387 zq_count = 4;
388#else
389 zq_count = 6;
390#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100391
Jens Kusked8b95932016-09-21 20:08:30 +0200392 if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
393 (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
394 u32 reg_val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100395
Jens Kusked8b95932016-09-21 20:08:30 +0200396 clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
397 CONFIG_DRAM_ZQ & 0xffff);
Jens Kuske53f018e2015-11-17 15:12:59 +0100398
399 writel(PIR_CLRSR, &mctl_ctl->pir);
400 mctl_phy_init(PIR_ZCAL);
401
Jens Kusked8b95932016-09-21 20:08:30 +0200402 reg_val = readl(&mctl_ctl->zqdr[0]);
403 reg_val &= (0x1f << 16) | (0x1f << 0);
404 reg_val |= reg_val << 8;
405 writel(reg_val, &mctl_ctl->zqdr[0]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100406
Jens Kusked8b95932016-09-21 20:08:30 +0200407 reg_val = readl(&mctl_ctl->zqdr[1]);
408 reg_val &= (0x1f << 16) | (0x1f << 0);
409 reg_val |= reg_val << 8;
410 writel(reg_val, &mctl_ctl->zqdr[1]);
411 writel(reg_val, &mctl_ctl->zqdr[2]);
412 } else {
413 int i;
414 u16 zq_val[6];
415 u8 val;
Jens Kuske53f018e2015-11-17 15:12:59 +0100416
Jens Kusked8b95932016-09-21 20:08:30 +0200417 writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
418
Icenowy Zhengb2607512017-06-03 17:10:16 +0800419 for (i = 0; i < zq_count; i++) {
Jens Kusked8b95932016-09-21 20:08:30 +0200420 u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
Jens Kuske53f018e2015-11-17 15:12:59 +0100421
Jens Kusked8b95932016-09-21 20:08:30 +0200422 writel((zq << 20) | (zq << 16) | (zq << 12) |
423 (zq << 8) | (zq << 4) | (zq << 0),
424 &mctl_ctl->zqcr);
425
426 writel(PIR_CLRSR, &mctl_ctl->pir);
427 mctl_phy_init(PIR_ZCAL);
428
429 zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
430 writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
431
432 writel(PIR_CLRSR, &mctl_ctl->pir);
433 mctl_phy_init(PIR_ZCAL);
434
435 val = readl(&mctl_ctl->zqdr[0]) >> 24;
436 zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
437 }
438
439 writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
440 writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800441 if (zq_count > 4)
442 writel((zq_val[5] << 16) | zq_val[4],
443 &mctl_ctl->zqdr[2]);
Jens Kusked8b95932016-09-21 20:08:30 +0200444 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100445}
446
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800447static void mctl_set_cr(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100448{
449 struct sunxi_mctl_com_reg * const mctl_com =
450 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
451
452 writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED |
Icenowy Zheng20020352017-06-03 17:10:17 +0800453 (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800454 MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
Jens Kuske53f018e2015-11-17 15:12:59 +0100455 (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
456 MCTL_CR_PAGE_SIZE(para->page_size) |
457 MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800458
459 if (socid == SOCID_R40) {
460 if (para->dual_rank)
461 panic("Dual rank memory not supported\n");
462
463 /* Mux pin to A15 address line for single rank memory. */
464 setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
465 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100466}
467
Jens Kuskef6138172017-01-02 11:48:42 +0000468static void mctl_sys_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100469{
470 struct sunxi_ccm_reg * const ccm =
471 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
472 struct sunxi_mctl_ctl_reg * const mctl_ctl =
473 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
474
475 clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
476 clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
477 clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
478 clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
479 clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800480 if (socid == SOCID_A64 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000481 clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
Jens Kuske53f018e2015-11-17 15:12:59 +0100482 udelay(10);
483
484 clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
485 udelay(1000);
486
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800487 if (socid == SOCID_A64 || socid == SOCID_R40) {
Jens Kuskef6138172017-01-02 11:48:42 +0000488 clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
489 clrsetbits_le32(&ccm->dram_clk_cfg,
490 CCM_DRAMCLK_CFG_DIV_MASK |
491 CCM_DRAMCLK_CFG_SRC_MASK,
492 CCM_DRAMCLK_CFG_DIV(1) |
493 CCM_DRAMCLK_CFG_SRC_PLL11 |
494 CCM_DRAMCLK_CFG_UPD);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000495 } else if (socid == SOCID_H3 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000496 clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
497 clrsetbits_le32(&ccm->dram_clk_cfg,
498 CCM_DRAMCLK_CFG_DIV_MASK |
499 CCM_DRAMCLK_CFG_SRC_MASK,
500 CCM_DRAMCLK_CFG_DIV(1) |
501 CCM_DRAMCLK_CFG_SRC_PLL5 |
502 CCM_DRAMCLK_CFG_UPD);
503 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100504 mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
505
506 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
507 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
508 setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
509 setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
510
511 setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
512 udelay(10);
513
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000514 writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
Jens Kuske53f018e2015-11-17 15:12:59 +0100515 udelay(500);
516}
517
Andre Przywarac98f5cc2017-01-02 11:48:43 +0000518/* These are more guessed based on some Allwinner code. */
519#define DX_GCR_ODT_DYNAMIC (0x0 << 4)
520#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4)
521#define DX_GCR_ODT_OFF (0x2 << 4)
522
Jens Kuskef6138172017-01-02 11:48:42 +0000523static int mctl_channel_init(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100524{
525 struct sunxi_mctl_com_reg * const mctl_com =
526 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
527 struct sunxi_mctl_ctl_reg * const mctl_ctl =
528 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
529
530 unsigned int i;
531
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800532 mctl_set_cr(socid, para);
Jens Kuskef6138172017-01-02 11:48:42 +0000533 mctl_set_timing_params(socid, para);
534 mctl_set_master_priority(socid);
Jens Kuske53f018e2015-11-17 15:12:59 +0100535
536 /* setting VTC, default disable all VT */
537 clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000538 if (socid == SOCID_H5)
539 setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
540 else
541 clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
Jens Kuske53f018e2015-11-17 15:12:59 +0100542
543 /* increase DFI_PHY_UPD clock */
544 writel(PROTECT_MAGIC, &mctl_com->protect);
545 udelay(100);
546 clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
547 writel(0x0, &mctl_com->protect);
548 udelay(100);
549
550 /* set dramc odt */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000551 for (i = 0; i < 4; i++) {
552 u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
553 (0x3 << 12) | (0x3 << 14);
554 u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
555 DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
556
557 if (socid == SOCID_H5) {
558 clearmask |= 0x2 << 8;
559 setmask |= 0x4 << 8;
560 }
561 clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
562 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100563
564 /* AC PDR should always ON */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000565 clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
566 0x1 << 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100567
568 /* set DQS auto gating PD mode */
569 setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
570
Jens Kuskef6138172017-01-02 11:48:42 +0000571 if (socid == SOCID_H3) {
572 /* dx ddr_clk & hdr_clk dynamic mode */
573 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
Jens Kuske53f018e2015-11-17 15:12:59 +0100574
Jens Kuskef6138172017-01-02 11:48:42 +0000575 /* dphy & aphy phase select 270 degree */
576 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
577 (0x1 << 10) | (0x2 << 8));
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000578 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000579 /* dphy & aphy phase select ? */
580 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
581 (0x0 << 10) | (0x3 << 8));
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800582 } else if (socid == SOCID_R40) {
583 /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
584 clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
585
586 /* dphy & aphy phase select ? */
587 clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
588 (0x0 << 10) | (0x3 << 8));
Jens Kuskef6138172017-01-02 11:48:42 +0000589 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100590
591 /* set half DQ */
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800592 if (!para->bus_full_width) {
Icenowy Zhengb2607512017-06-03 17:10:16 +0800593#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000594 writel(0x0, &mctl_ctl->dx[2].gcr);
595 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zhengb2607512017-06-03 17:10:16 +0800596#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
597 writel(0x0, &mctl_ctl->dx[1].gcr);
598#else
599#error Unsupported DRAM bus width!
600#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100601 }
602
603 /* data training configuration */
604 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
605 (para->dual_rank ? 0x3 : 0x1) << 24);
606
Jens Kuske8bbadc82017-01-02 11:48:40 +0000607 mctl_set_bit_delays(para);
608 udelay(50);
Jens Kuske53f018e2015-11-17 15:12:59 +0100609
Jens Kuskef6138172017-01-02 11:48:42 +0000610 if (socid == SOCID_H3) {
611 mctl_h3_zq_calibration_quirk(para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100612
Jens Kuskef6138172017-01-02 11:48:42 +0000613 mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
614 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000615 } else if (socid == SOCID_A64 || socid == SOCID_H5) {
Jens Kuskef6138172017-01-02 11:48:42 +0000616 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
617
618 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
619 PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000620 /* no PIR_QSGATE for H5 ???? */
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800621 } else if (socid == SOCID_R40) {
622 clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
623
624 mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
625 PIR_DRAMRST | PIR_DRAMINIT);
Jens Kuskef6138172017-01-02 11:48:42 +0000626 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100627
628 /* detect ranks and bus width */
629 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
630 /* only one rank */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800631 if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
632#if defined CONFIG_SUNXI_DRAM_DW_32BIT
633 || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
634#endif
635 ) {
Jens Kuske53f018e2015-11-17 15:12:59 +0100636 clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
637 para->dual_rank = 0;
638 }
639
640 /* only half DQ width */
Icenowy Zhengb2607512017-06-03 17:10:16 +0800641#if defined CONFIG_SUNXI_DRAM_DW_32BIT
Jens Kuske3e797582017-01-02 11:48:39 +0000642 if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
643 ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
644 writel(0x0, &mctl_ctl->dx[2].gcr);
645 writel(0x0, &mctl_ctl->dx[3].gcr);
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800646 para->bus_full_width = 0;
Jens Kuske53f018e2015-11-17 15:12:59 +0100647 }
Icenowy Zhengb2607512017-06-03 17:10:16 +0800648#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
649 if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
650 writel(0x0, &mctl_ctl->dx[1].gcr);
651 para->bus_full_width = 0;
652 }
653#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100654
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800655 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100656 udelay(20);
657
658 /* re-train */
659 mctl_phy_init(PIR_QSGATE);
660 if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
661 return 1;
662 }
663
664 /* check the dramc status */
665 mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
666
667 /* liuke added for refresh debug */
668 setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
669 udelay(10);
670 clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
671 udelay(10);
672
673 /* set PGCR3, CKE polarity */
Jens Kuskef6138172017-01-02 11:48:42 +0000674 if (socid == SOCID_H3)
675 writel(0x00aa0060, &mctl_ctl->pgcr[3]);
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800676 else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
Jens Kuskef6138172017-01-02 11:48:42 +0000677 writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
Jens Kuske53f018e2015-11-17 15:12:59 +0100678
679 /* power down zq calibration module for power save */
680 setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
681
682 /* enable master access */
683 writel(0xffffffff, &mctl_com->maer);
684
685 return 0;
686}
687
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800688static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
Jens Kuske53f018e2015-11-17 15:12:59 +0100689{
690 /* detect row address bits */
691 para->page_size = 512;
692 para->row_bits = 16;
Icenowy Zheng20020352017-06-03 17:10:17 +0800693 para->bank_bits = 2;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800694 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100695
696 for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
Icenowy Zheng20020352017-06-03 17:10:17 +0800697 if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
Jens Kuske53f018e2015-11-17 15:12:59 +0100698 break;
699
Icenowy Zheng20020352017-06-03 17:10:17 +0800700 /* detect bank address bits */
701 para->bank_bits = 3;
702 mctl_set_cr(socid, para);
703
704 for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
705 if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
706 break;
707
Jens Kuske53f018e2015-11-17 15:12:59 +0100708 /* detect page size */
709 para->page_size = 8192;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800710 mctl_set_cr(socid, para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100711
712 for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
713 if (mctl_mem_matches(para->page_size))
714 break;
715}
716
Jens Kuske8bbadc82017-01-02 11:48:40 +0000717/*
718 * The actual values used here are taken from Allwinner provided boot0
719 * binaries, though they are probably board specific, so would likely benefit
720 * from invidual tuning for each board. Apparently a lot of boards copy from
721 * some Allwinner reference design, so we go with those generic values for now
722 * in the hope that they are reasonable for most (all?) boards.
723 */
724#define SUN8I_H3_DX_READ_DELAYS \
725 {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
726 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
727 { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
728 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }}
729#define SUN8I_H3_DX_WRITE_DELAYS \
730 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
731 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
732 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
733 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }}
734#define SUN8I_H3_AC_DELAYS \
735 { 0, 0, 0, 0, 0, 0, 0, 0, \
736 0, 0, 0, 0, 0, 0, 0, 0, \
737 0, 0, 0, 0, 0, 0, 0, 0, \
738 0, 0, 0, 0, 0, 0, 0 }
739
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800740#define SUN8I_R40_DX_READ_DELAYS \
741 {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
742 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
743 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
744 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } }
745#define SUN8I_R40_DX_WRITE_DELAYS \
746 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
747 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
748 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
749 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } }
750#define SUN8I_R40_AC_DELAYS \
751 { 0, 0, 3, 0, 0, 0, 0, 0, \
752 0, 0, 0, 0, 0, 0, 0, 0, \
753 0, 0, 0, 0, 0, 0, 0, 0, \
754 0, 0, 0, 0, 0, 0, 0 }
755
Jens Kuskef6138172017-01-02 11:48:42 +0000756#define SUN50I_A64_DX_READ_DELAYS \
757 {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \
758 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \
759 { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \
760 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}
761#define SUN50I_A64_DX_WRITE_DELAYS \
762 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \
763 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \
764 { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \
765 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}
766#define SUN50I_A64_AC_DELAYS \
767 { 5, 5, 13, 10, 2, 5, 3, 3, \
768 0, 3, 3, 3, 1, 0, 0, 0, \
769 3, 4, 0, 3, 4, 1, 4, 0, \
770 1, 1, 0, 1, 13, 5, 4 }
771
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000772#define SUN8I_H5_DX_READ_DELAYS \
773 {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \
774 { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \
775 { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \
776 { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } }
777#define SUN8I_H5_DX_WRITE_DELAYS \
778 {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \
779 { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \
780 { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \
781 { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } }
782#define SUN8I_H5_AC_DELAYS \
783 { 0, 0, 5, 5, 0, 0, 0, 0, \
784 0, 0, 0, 0, 3, 3, 3, 3, \
785 3, 3, 3, 3, 3, 3, 3, 3, \
786 3, 3, 3, 3, 2, 0, 0 }
787
Jens Kuske53f018e2015-11-17 15:12:59 +0100788unsigned long sunxi_dram_init(void)
789{
790 struct sunxi_mctl_com_reg * const mctl_com =
791 (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
792 struct sunxi_mctl_ctl_reg * const mctl_ctl =
793 (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
794
795 struct dram_para para = {
Jens Kuske53f018e2015-11-17 15:12:59 +0100796 .dual_rank = 0,
Icenowy Zheng4323a8f2017-06-03 17:10:15 +0800797 .bus_full_width = 1,
Jens Kuske53f018e2015-11-17 15:12:59 +0100798 .row_bits = 15,
Icenowy Zheng20020352017-06-03 17:10:17 +0800799 .bank_bits = 3,
Jens Kuske53f018e2015-11-17 15:12:59 +0100800 .page_size = 4096,
Jens Kuskef6138172017-01-02 11:48:42 +0000801
802#if defined(CONFIG_MACH_SUN8I_H3)
Jens Kuske8bbadc82017-01-02 11:48:40 +0000803 .dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
804 .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
805 .ac_delays = SUN8I_H3_AC_DELAYS,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800806#elif defined(CONFIG_MACH_SUN8I_R40)
807 .dx_read_delays = SUN8I_R40_DX_READ_DELAYS,
808 .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
809 .ac_delays = SUN8I_R40_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000810#elif defined(CONFIG_MACH_SUN50I)
811 .dx_read_delays = SUN50I_A64_DX_READ_DELAYS,
812 .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
813 .ac_delays = SUN50I_A64_AC_DELAYS,
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000814#elif defined(CONFIG_MACH_SUN50I_H5)
815 .dx_read_delays = SUN8I_H5_DX_READ_DELAYS,
816 .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
817 .ac_delays = SUN8I_H5_AC_DELAYS,
Jens Kuskef6138172017-01-02 11:48:42 +0000818#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100819 };
Jens Kuskef6138172017-01-02 11:48:42 +0000820/*
821 * Let the compiler optimize alternatives away by passing this value into
822 * the static functions. This saves us #ifdefs, but still keeps the binary
823 * small.
824 */
825#if defined(CONFIG_MACH_SUN8I_H3)
826 uint16_t socid = SOCID_H3;
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800827#elif defined(CONFIG_MACH_SUN8I_R40)
828 uint16_t socid = SOCID_R40;
Jens Kuskef6138172017-01-02 11:48:42 +0000829#elif defined(CONFIG_MACH_SUN50I)
830 uint16_t socid = SOCID_A64;
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000831#elif defined(CONFIG_MACH_SUN50I_H5)
832 uint16_t socid = SOCID_H5;
Jens Kuskef6138172017-01-02 11:48:42 +0000833#endif
Jens Kuske53f018e2015-11-17 15:12:59 +0100834
Jens Kuskef6138172017-01-02 11:48:42 +0000835 mctl_sys_init(socid, &para);
836 if (mctl_channel_init(socid, &para))
Jens Kuske53f018e2015-11-17 15:12:59 +0100837 return 0;
838
839 if (para.dual_rank)
840 writel(0x00000303, &mctl_ctl->odtmap);
841 else
842 writel(0x00000201, &mctl_ctl->odtmap);
843 udelay(1);
844
845 /* odt delay */
Jens Kuskef6138172017-01-02 11:48:42 +0000846 if (socid == SOCID_H3)
847 writel(0x0c000400, &mctl_ctl->odtcfg);
848
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800849 if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
850 /* VTF enable (tpr13[8] == 1) */
Andre Przywara5d0d28f2017-02-16 01:20:26 +0000851 setbits_le32(&mctl_ctl->vtfcr,
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800852 (socid != SOCID_A64 ? 3 : 2) << 8);
853 /* DQ hold disable (tpr13[26] == 1) */
Jens Kuskef6138172017-01-02 11:48:42 +0000854 clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
855 }
Jens Kuske53f018e2015-11-17 15:12:59 +0100856
857 /* clear credit value */
858 setbits_le32(&mctl_com->cccr, 1 << 31);
859 udelay(10);
860
Chen-Yu Tsai143ef792016-12-01 19:09:57 +0800861 mctl_auto_detect_dram_size(socid, &para);
862 mctl_set_cr(socid, &para);
Jens Kuske53f018e2015-11-17 15:12:59 +0100863
Icenowy Zheng20020352017-06-03 17:10:17 +0800864 return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
865 (para.dual_rank ? 2 : 1);
Jens Kuske53f018e2015-11-17 15:12:59 +0100866}