xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-sunxi/dram_sunxi_dw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * sun8i H3 platform dram controller init
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 2007-2015 Allwinner Technology Co.
5*4882a593Smuzhiyun  *                         Jerry Wang <wangflord@allwinnertech.com>
6*4882a593Smuzhiyun  * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
7*4882a593Smuzhiyun  * (C) Copyright 2015      Hans de Goede <hdegoede@redhat.com>
8*4882a593Smuzhiyun  * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun #include <asm/arch/clock.h>
15*4882a593Smuzhiyun #include <asm/arch/dram.h>
16*4882a593Smuzhiyun #include <asm/arch/cpu.h>
17*4882a593Smuzhiyun #include <linux/kconfig.h>
18*4882a593Smuzhiyun 
mctl_phy_init(u32 val)19*4882a593Smuzhiyun static void mctl_phy_init(u32 val)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
22*4882a593Smuzhiyun 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	writel(val | PIR_INIT, &mctl_ctl->pir);
25*4882a593Smuzhiyun 	mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun 
mctl_set_bit_delays(struct dram_para * para)28*4882a593Smuzhiyun static void mctl_set_bit_delays(struct dram_para *para)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
31*4882a593Smuzhiyun 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
32*4882a593Smuzhiyun 	int i, j;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	for (i = 0; i < NR_OF_BYTE_LANES; i++)
37*4882a593Smuzhiyun 		for (j = 0; j < LINES_PER_BYTE_LANE; j++)
38*4882a593Smuzhiyun 			writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
39*4882a593Smuzhiyun 			       DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
40*4882a593Smuzhiyun 			       &mctl_ctl->dx[i].bdlr[j]);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	for (i = 0; i < 31; i++)
43*4882a593Smuzhiyun 		writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
44*4882a593Smuzhiyun 		       &mctl_ctl->acbdlr[i]);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #ifdef CONFIG_MACH_SUN8I_R40
47*4882a593Smuzhiyun 	/* DQSn, DMn, DQn output enable bit delay */
48*4882a593Smuzhiyun 	for (i = 0; i < 4; i++)
49*4882a593Smuzhiyun 		writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun enum {
56*4882a593Smuzhiyun 	MBUS_PORT_CPU           = 0,
57*4882a593Smuzhiyun 	MBUS_PORT_GPU           = 1,
58*4882a593Smuzhiyun 	MBUS_PORT_UNUSED	= 2,
59*4882a593Smuzhiyun 	MBUS_PORT_DMA           = 3,
60*4882a593Smuzhiyun 	MBUS_PORT_VE            = 4,
61*4882a593Smuzhiyun 	MBUS_PORT_CSI           = 5,
62*4882a593Smuzhiyun 	MBUS_PORT_NAND          = 6,
63*4882a593Smuzhiyun 	MBUS_PORT_SS            = 7,
64*4882a593Smuzhiyun 	MBUS_PORT_TS            = 8,
65*4882a593Smuzhiyun 	MBUS_PORT_DI            = 9,
66*4882a593Smuzhiyun 	MBUS_PORT_DE            = 10,
67*4882a593Smuzhiyun 	MBUS_PORT_DE_CFD        = 11,
68*4882a593Smuzhiyun 	MBUS_PORT_UNKNOWN1	= 12,
69*4882a593Smuzhiyun 	MBUS_PORT_UNKNOWN2	= 13,
70*4882a593Smuzhiyun 	MBUS_PORT_UNKNOWN3	= 14,
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun enum {
74*4882a593Smuzhiyun 	MBUS_QOS_LOWEST = 0,
75*4882a593Smuzhiyun 	MBUS_QOS_LOW,
76*4882a593Smuzhiyun 	MBUS_QOS_HIGH,
77*4882a593Smuzhiyun 	MBUS_QOS_HIGHEST
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun 
mbus_configure_port(u8 port,bool bwlimit,bool priority,u8 qos,u8 waittime,u8 acs,u16 bwl0,u16 bwl1,u16 bwl2)80*4882a593Smuzhiyun inline void mbus_configure_port(u8 port,
81*4882a593Smuzhiyun 				bool bwlimit,
82*4882a593Smuzhiyun 				bool priority,
83*4882a593Smuzhiyun 				u8 qos,         /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
84*4882a593Smuzhiyun 				u8 waittime,    /* 0 .. 0xf */
85*4882a593Smuzhiyun 				u8 acs,         /* 0 .. 0xff */
86*4882a593Smuzhiyun 				u16 bwl0,       /* 0 .. 0xffff, bandwidth limit in MB/s */
87*4882a593Smuzhiyun 				u16 bwl1,
88*4882a593Smuzhiyun 				u16 bwl2)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
91*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
94*4882a593Smuzhiyun 			   | (priority ? (1 << 1) : 0)
95*4882a593Smuzhiyun 			   | ((qos & 0x3) << 2)
96*4882a593Smuzhiyun 			   | ((waittime & 0xf) << 4)
97*4882a593Smuzhiyun 			   | ((acs & 0xff) << 8)
98*4882a593Smuzhiyun 			   | (bwl0 << 16) );
99*4882a593Smuzhiyun 	const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
102*4882a593Smuzhiyun 	writel(cfg0, &mctl_com->mcr[port][0]);
103*4882a593Smuzhiyun 	writel(cfg1, &mctl_com->mcr[port][1]);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)	\
107*4882a593Smuzhiyun 	mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
108*4882a593Smuzhiyun 			    MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
109*4882a593Smuzhiyun 
mctl_set_master_priority_h3(void)110*4882a593Smuzhiyun static void mctl_set_master_priority_h3(void)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
113*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	/* enable bandwidth limit windows and set windows size 1us */
116*4882a593Smuzhiyun 	writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	/* set cpu high priority */
119*4882a593Smuzhiyun 	writel(0x00000001, &mctl_com->mapr);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	MBUS_CONF(   CPU,  true, HIGHEST, 0,  512,  256,  128);
122*4882a593Smuzhiyun 	MBUS_CONF(   GPU,  true,    HIGH, 0, 1536, 1024,  256);
123*4882a593Smuzhiyun 	MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
124*4882a593Smuzhiyun 	MBUS_CONF(   DMA,  true, HIGHEST, 0,  256,  128,   32);
125*4882a593Smuzhiyun 	MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
126*4882a593Smuzhiyun 	MBUS_CONF(   CSI,  true, HIGHEST, 0,  256,  128,   32);
127*4882a593Smuzhiyun 	MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
128*4882a593Smuzhiyun 	MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
129*4882a593Smuzhiyun 	MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
130*4882a593Smuzhiyun 	MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
131*4882a593Smuzhiyun 	MBUS_CONF(    DE,  true, HIGHEST, 3, 8192, 6120, 1024);
132*4882a593Smuzhiyun 	MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1024,  288,   64);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
mctl_set_master_priority_a64(void)135*4882a593Smuzhiyun static void mctl_set_master_priority_a64(void)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
138*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* enable bandwidth limit windows and set windows size 1us */
141*4882a593Smuzhiyun 	writel(399, &mctl_com->tmr);
142*4882a593Smuzhiyun 	writel((1 << 16), &mctl_com->bwcr);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
145*4882a593Smuzhiyun 	 * initialise it */
146*4882a593Smuzhiyun 	MBUS_CONF(   CPU,  true, HIGHEST, 0,  160,  100,   80);
147*4882a593Smuzhiyun 	MBUS_CONF(   GPU, false,    HIGH, 0, 1536, 1400,  256);
148*4882a593Smuzhiyun 	MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
149*4882a593Smuzhiyun 	MBUS_CONF(   DMA,  true,    HIGH, 0,  256,   80,  100);
150*4882a593Smuzhiyun 	MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
151*4882a593Smuzhiyun 	MBUS_CONF(   CSI,  true,    HIGH, 0,  256,  128,    0);
152*4882a593Smuzhiyun 	MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
153*4882a593Smuzhiyun 	MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
154*4882a593Smuzhiyun 	MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
155*4882a593Smuzhiyun 	MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
156*4882a593Smuzhiyun 	MBUS_CONF(    DE,  true,    HIGH, 2, 8192, 6144, 2048);
157*4882a593Smuzhiyun 	MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1280,  144,   64);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
mctl_set_master_priority_h5(void)162*4882a593Smuzhiyun static void mctl_set_master_priority_h5(void)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
165*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/* enable bandwidth limit windows and set windows size 1us */
168*4882a593Smuzhiyun 	writel(399, &mctl_com->tmr);
169*4882a593Smuzhiyun 	writel((1 << 16), &mctl_com->bwcr);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	/* set cpu high priority */
172*4882a593Smuzhiyun 	writel(0x00000001, &mctl_com->mapr);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet
175*4882a593Smuzhiyun 	 * they initialise it */
176*4882a593Smuzhiyun 	MBUS_CONF(   CPU, true, HIGHEST, 0,  300,  260,  150);
177*4882a593Smuzhiyun 	MBUS_CONF(   GPU, true, HIGHEST, 0,  600,  400,  200);
178*4882a593Smuzhiyun 	MBUS_CONF(UNUSED, true, HIGHEST, 0,  512,  256,   96);
179*4882a593Smuzhiyun 	MBUS_CONF(   DMA, true, HIGHEST, 0,  256,  128,   32);
180*4882a593Smuzhiyun 	MBUS_CONF(    VE, true, HIGHEST, 0, 1900, 1500, 1000);
181*4882a593Smuzhiyun 	MBUS_CONF(   CSI, true, HIGHEST, 0,  150,  120,  100);
182*4882a593Smuzhiyun 	MBUS_CONF(  NAND, true,    HIGH, 0,  256,  128,   64);
183*4882a593Smuzhiyun 	MBUS_CONF(    SS, true, HIGHEST, 0,  256,  128,   64);
184*4882a593Smuzhiyun 	MBUS_CONF(    TS, true, HIGHEST, 0,  256,  128,   64);
185*4882a593Smuzhiyun 	MBUS_CONF(    DI, true,    HIGH, 0, 1024,  256,   64);
186*4882a593Smuzhiyun 	MBUS_CONF(    DE, true, HIGHEST, 3, 3400, 2400, 1024);
187*4882a593Smuzhiyun 	MBUS_CONF(DE_CFD, true, HIGHEST, 0,  600,  400,  200);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
mctl_set_master_priority_r40(void)190*4882a593Smuzhiyun static void mctl_set_master_priority_r40(void)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
193*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/* enable bandwidth limit windows and set windows size 1us */
196*4882a593Smuzhiyun 	writel(399, &mctl_com->tmr);
197*4882a593Smuzhiyun 	writel((1 << 16), &mctl_com->bwcr);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* set cpu high priority */
200*4882a593Smuzhiyun 	writel(0x00000001, &mctl_com->mapr);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet
203*4882a593Smuzhiyun 	 * they initialise it */
204*4882a593Smuzhiyun 	MBUS_CONF(     CPU, true, HIGHEST, 0,  300,  260,  150);
205*4882a593Smuzhiyun 	MBUS_CONF(     GPU, true, HIGHEST, 0,  600,  400,  200);
206*4882a593Smuzhiyun 	MBUS_CONF(  UNUSED, true, HIGHEST, 0,  512,  256,   96);
207*4882a593Smuzhiyun 	MBUS_CONF(     DMA, true, HIGHEST, 0,  256,  128,   32);
208*4882a593Smuzhiyun 	MBUS_CONF(      VE, true, HIGHEST, 0, 1900, 1500, 1000);
209*4882a593Smuzhiyun 	MBUS_CONF(     CSI, true, HIGHEST, 0,  150,  120,  100);
210*4882a593Smuzhiyun 	MBUS_CONF(    NAND, true,    HIGH, 0,  256,  128,   64);
211*4882a593Smuzhiyun 	MBUS_CONF(      SS, true, HIGHEST, 0,  256,  128,   64);
212*4882a593Smuzhiyun 	MBUS_CONF(      TS, true, HIGHEST, 0,  256,  128,   64);
213*4882a593Smuzhiyun 	MBUS_CONF(      DI, true,    HIGH, 0, 1024,  256,   64);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	/*
216*4882a593Smuzhiyun 	 * The port names are probably wrong, but no correct sources
217*4882a593Smuzhiyun 	 * are available.
218*4882a593Smuzhiyun 	 */
219*4882a593Smuzhiyun 	MBUS_CONF(      DE, true,    HIGH, 0,  128,   48,    0);
220*4882a593Smuzhiyun 	MBUS_CONF(  DE_CFD, true,    HIGH, 0,  384,  256,    0);
221*4882a593Smuzhiyun 	MBUS_CONF(UNKNOWN1, true, HIGHEST, 0,  512,  384,  256);
222*4882a593Smuzhiyun 	MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
223*4882a593Smuzhiyun 	MBUS_CONF(UNKNOWN3, true,    HIGH, 0, 1280,  144,   64);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
mctl_set_master_priority(uint16_t socid)226*4882a593Smuzhiyun static void mctl_set_master_priority(uint16_t socid)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	switch (socid) {
229*4882a593Smuzhiyun 	case SOCID_H3:
230*4882a593Smuzhiyun 		mctl_set_master_priority_h3();
231*4882a593Smuzhiyun 		return;
232*4882a593Smuzhiyun 	case SOCID_A64:
233*4882a593Smuzhiyun 		mctl_set_master_priority_a64();
234*4882a593Smuzhiyun 		return;
235*4882a593Smuzhiyun 	case SOCID_H5:
236*4882a593Smuzhiyun 		mctl_set_master_priority_h5();
237*4882a593Smuzhiyun 		return;
238*4882a593Smuzhiyun 	case SOCID_R40:
239*4882a593Smuzhiyun 		mctl_set_master_priority_r40();
240*4882a593Smuzhiyun 		return;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
bin_to_mgray(int val)244*4882a593Smuzhiyun static u32 bin_to_mgray(int val)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	static const u8 lookup_table[32] = {
247*4882a593Smuzhiyun 		0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
248*4882a593Smuzhiyun 		0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
249*4882a593Smuzhiyun 		0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
250*4882a593Smuzhiyun 		0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
251*4882a593Smuzhiyun 	};
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	return lookup_table[clamp(val, 0, 31)];
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
mgray_to_bin(u32 val)256*4882a593Smuzhiyun static int mgray_to_bin(u32 val)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	static const u8 lookup_table[32] = {
259*4882a593Smuzhiyun 		0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
260*4882a593Smuzhiyun 		0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
261*4882a593Smuzhiyun 		0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
262*4882a593Smuzhiyun 		0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
263*4882a593Smuzhiyun 	};
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	return lookup_table[val & 0x1f];
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
mctl_h3_zq_calibration_quirk(struct dram_para * para)268*4882a593Smuzhiyun static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
271*4882a593Smuzhiyun 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
272*4882a593Smuzhiyun 	int zq_count;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun #if defined CONFIG_SUNXI_DRAM_DW_16BIT
275*4882a593Smuzhiyun 	zq_count = 4;
276*4882a593Smuzhiyun #else
277*4882a593Smuzhiyun 	zq_count = 6;
278*4882a593Smuzhiyun #endif
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
281*4882a593Smuzhiyun 	    (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
282*4882a593Smuzhiyun 		u32 reg_val;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
285*4882a593Smuzhiyun 				CONFIG_DRAM_ZQ & 0xffff);
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 		writel(PIR_CLRSR, &mctl_ctl->pir);
288*4882a593Smuzhiyun 		mctl_phy_init(PIR_ZCAL);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		reg_val = readl(&mctl_ctl->zqdr[0]);
291*4882a593Smuzhiyun 		reg_val &= (0x1f << 16) | (0x1f << 0);
292*4882a593Smuzhiyun 		reg_val |= reg_val << 8;
293*4882a593Smuzhiyun 		writel(reg_val, &mctl_ctl->zqdr[0]);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		reg_val = readl(&mctl_ctl->zqdr[1]);
296*4882a593Smuzhiyun 		reg_val &= (0x1f << 16) | (0x1f << 0);
297*4882a593Smuzhiyun 		reg_val |= reg_val << 8;
298*4882a593Smuzhiyun 		writel(reg_val, &mctl_ctl->zqdr[1]);
299*4882a593Smuzhiyun 		writel(reg_val, &mctl_ctl->zqdr[2]);
300*4882a593Smuzhiyun 	} else {
301*4882a593Smuzhiyun 		int i;
302*4882a593Smuzhiyun 		u16 zq_val[6];
303*4882a593Smuzhiyun 		u8 val;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 		writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		for (i = 0; i < zq_count; i++) {
308*4882a593Smuzhiyun 			u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 			writel((zq << 20) | (zq << 16) | (zq << 12) |
311*4882a593Smuzhiyun 					(zq << 8) | (zq << 4) | (zq << 0),
312*4882a593Smuzhiyun 					&mctl_ctl->zqcr);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 			writel(PIR_CLRSR, &mctl_ctl->pir);
315*4882a593Smuzhiyun 			mctl_phy_init(PIR_ZCAL);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 			zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
318*4882a593Smuzhiyun 			writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 			writel(PIR_CLRSR, &mctl_ctl->pir);
321*4882a593Smuzhiyun 			mctl_phy_init(PIR_ZCAL);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 			val = readl(&mctl_ctl->zqdr[0]) >> 24;
324*4882a593Smuzhiyun 			zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
325*4882a593Smuzhiyun 		}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 		writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
328*4882a593Smuzhiyun 		writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
329*4882a593Smuzhiyun 		if (zq_count > 4)
330*4882a593Smuzhiyun 			writel((zq_val[5] << 16) | zq_val[4],
331*4882a593Smuzhiyun 			       &mctl_ctl->zqdr[2]);
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
mctl_set_cr(uint16_t socid,struct dram_para * para)335*4882a593Smuzhiyun static void mctl_set_cr(uint16_t socid, struct dram_para *para)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
338*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
341*4882a593Smuzhiyun #if defined CONFIG_SUNXI_DRAM_DDR3
342*4882a593Smuzhiyun 	       MCTL_CR_DDR3 | MCTL_CR_2T |
343*4882a593Smuzhiyun #elif defined CONFIG_SUNXI_DRAM_DDR2
344*4882a593Smuzhiyun 	       MCTL_CR_DDR2 | MCTL_CR_2T |
345*4882a593Smuzhiyun #elif defined CONFIG_SUNXI_DRAM_LPDDR3
346*4882a593Smuzhiyun 	       MCTL_CR_LPDDR3 | MCTL_CR_1T |
347*4882a593Smuzhiyun #else
348*4882a593Smuzhiyun #error Unsupported DRAM type!
349*4882a593Smuzhiyun #endif
350*4882a593Smuzhiyun 	       (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
351*4882a593Smuzhiyun 	       MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
352*4882a593Smuzhiyun 	       (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
353*4882a593Smuzhiyun 	       MCTL_CR_PAGE_SIZE(para->page_size) |
354*4882a593Smuzhiyun 	       MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (socid == SOCID_R40) {
357*4882a593Smuzhiyun 		if (para->dual_rank)
358*4882a593Smuzhiyun 			panic("Dual rank memory not supported\n");
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 		/* Mux pin to A15 address line for single rank memory. */
361*4882a593Smuzhiyun 		setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
mctl_sys_init(uint16_t socid,struct dram_para * para)365*4882a593Smuzhiyun static void mctl_sys_init(uint16_t socid, struct dram_para *para)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	struct sunxi_ccm_reg * const ccm =
368*4882a593Smuzhiyun 			(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
369*4882a593Smuzhiyun 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
370*4882a593Smuzhiyun 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
373*4882a593Smuzhiyun 	clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
374*4882a593Smuzhiyun 	clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
375*4882a593Smuzhiyun 	clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
376*4882a593Smuzhiyun 	clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
377*4882a593Smuzhiyun 	if (socid == SOCID_A64 || socid == SOCID_R40)
378*4882a593Smuzhiyun 		clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
379*4882a593Smuzhiyun 	udelay(10);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
382*4882a593Smuzhiyun 	udelay(1000);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (socid == SOCID_A64 || socid == SOCID_R40) {
385*4882a593Smuzhiyun 		clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
386*4882a593Smuzhiyun 		clrsetbits_le32(&ccm->dram_clk_cfg,
387*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_DIV_MASK |
388*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_SRC_MASK,
389*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_DIV(1) |
390*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_SRC_PLL11 |
391*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_UPD);
392*4882a593Smuzhiyun 	} else if (socid == SOCID_H3 || socid == SOCID_H5) {
393*4882a593Smuzhiyun 		clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
394*4882a593Smuzhiyun 		clrsetbits_le32(&ccm->dram_clk_cfg,
395*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_DIV_MASK |
396*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_SRC_MASK,
397*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_DIV(1) |
398*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_SRC_PLL5 |
399*4882a593Smuzhiyun 				CCM_DRAMCLK_CFG_UPD);
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun 	mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
404*4882a593Smuzhiyun 	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
405*4882a593Smuzhiyun 	setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
406*4882a593Smuzhiyun 	setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
409*4882a593Smuzhiyun 	udelay(10);
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
412*4882a593Smuzhiyun 	udelay(500);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun /* These are more guessed based on some Allwinner code. */
416*4882a593Smuzhiyun #define DX_GCR_ODT_DYNAMIC	(0x0 << 4)
417*4882a593Smuzhiyun #define DX_GCR_ODT_ALWAYS_ON	(0x1 << 4)
418*4882a593Smuzhiyun #define DX_GCR_ODT_OFF		(0x2 << 4)
419*4882a593Smuzhiyun 
mctl_channel_init(uint16_t socid,struct dram_para * para)420*4882a593Smuzhiyun static int mctl_channel_init(uint16_t socid, struct dram_para *para)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
423*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
424*4882a593Smuzhiyun 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
425*4882a593Smuzhiyun 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	unsigned int i;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	mctl_set_cr(socid, para);
430*4882a593Smuzhiyun 	mctl_set_timing_params(socid, para);
431*4882a593Smuzhiyun 	mctl_set_master_priority(socid);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	/* setting VTC, default disable all VT */
434*4882a593Smuzhiyun 	clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
435*4882a593Smuzhiyun 	if (socid == SOCID_H5)
436*4882a593Smuzhiyun 		setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
437*4882a593Smuzhiyun 	else
438*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/* increase DFI_PHY_UPD clock */
441*4882a593Smuzhiyun 	writel(PROTECT_MAGIC, &mctl_com->protect);
442*4882a593Smuzhiyun 	udelay(100);
443*4882a593Smuzhiyun 	clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
444*4882a593Smuzhiyun 	writel(0x0, &mctl_com->protect);
445*4882a593Smuzhiyun 	udelay(100);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	/* set dramc odt */
448*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
449*4882a593Smuzhiyun 		u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
450*4882a593Smuzhiyun 				(0x3 << 12) | (0x3 << 14);
451*4882a593Smuzhiyun 		u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
452*4882a593Smuzhiyun 				DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 		if (socid == SOCID_H5) {
455*4882a593Smuzhiyun 			clearmask |= 0x2 << 8;
456*4882a593Smuzhiyun 			setmask |= 0x4 << 8;
457*4882a593Smuzhiyun 		}
458*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	/* AC PDR should always ON */
462*4882a593Smuzhiyun 	clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
463*4882a593Smuzhiyun 			0x1 << 1);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	/* set DQS auto gating PD mode */
466*4882a593Smuzhiyun 	setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (socid == SOCID_H3) {
469*4882a593Smuzhiyun 		/* dx ddr_clk & hdr_clk dynamic mode */
470*4882a593Smuzhiyun 		clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		/* dphy & aphy phase select 270 degree */
473*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
474*4882a593Smuzhiyun 				(0x1 << 10) | (0x2 << 8));
475*4882a593Smuzhiyun 	} else if (socid == SOCID_A64 || socid == SOCID_H5) {
476*4882a593Smuzhiyun 		/* dphy & aphy phase select ? */
477*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
478*4882a593Smuzhiyun 				(0x0 << 10) | (0x3 << 8));
479*4882a593Smuzhiyun 	} else if (socid == SOCID_R40) {
480*4882a593Smuzhiyun 		/* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
481*4882a593Smuzhiyun 		clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 		/* dphy & aphy phase select ? */
484*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
485*4882a593Smuzhiyun 				(0x0 << 10) | (0x3 << 8));
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	/* set half DQ */
489*4882a593Smuzhiyun 	if (!para->bus_full_width) {
490*4882a593Smuzhiyun #if defined CONFIG_SUNXI_DRAM_DW_32BIT
491*4882a593Smuzhiyun 		writel(0x0, &mctl_ctl->dx[2].gcr);
492*4882a593Smuzhiyun 		writel(0x0, &mctl_ctl->dx[3].gcr);
493*4882a593Smuzhiyun #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
494*4882a593Smuzhiyun 		writel(0x0, &mctl_ctl->dx[1].gcr);
495*4882a593Smuzhiyun #else
496*4882a593Smuzhiyun #error Unsupported DRAM bus width!
497*4882a593Smuzhiyun #endif
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	/* data training configuration */
501*4882a593Smuzhiyun 	clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
502*4882a593Smuzhiyun 			(para->dual_rank ? 0x3 : 0x1) << 24);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	mctl_set_bit_delays(para);
505*4882a593Smuzhiyun 	udelay(50);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	if (socid == SOCID_H3) {
508*4882a593Smuzhiyun 		mctl_h3_zq_calibration_quirk(para);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 		mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
511*4882a593Smuzhiyun 			      PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
512*4882a593Smuzhiyun 	} else if (socid == SOCID_A64 || socid == SOCID_H5) {
513*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 		mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
516*4882a593Smuzhiyun 			      PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
517*4882a593Smuzhiyun 		/* no PIR_QSGATE for H5 ???? */
518*4882a593Smuzhiyun 	} else if (socid == SOCID_R40) {
519*4882a593Smuzhiyun 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 		mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
522*4882a593Smuzhiyun 			      PIR_DRAMRST | PIR_DRAMINIT);
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	/* detect ranks and bus width */
526*4882a593Smuzhiyun 	if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
527*4882a593Smuzhiyun 		/* only one rank */
528*4882a593Smuzhiyun 		if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
529*4882a593Smuzhiyun #if defined CONFIG_SUNXI_DRAM_DW_32BIT
530*4882a593Smuzhiyun 		    || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
531*4882a593Smuzhiyun #endif
532*4882a593Smuzhiyun 		    ) {
533*4882a593Smuzhiyun 			clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
534*4882a593Smuzhiyun 			para->dual_rank = 0;
535*4882a593Smuzhiyun 		}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 		/* only half DQ width */
538*4882a593Smuzhiyun #if defined CONFIG_SUNXI_DRAM_DW_32BIT
539*4882a593Smuzhiyun 		if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
540*4882a593Smuzhiyun 		    ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
541*4882a593Smuzhiyun 			writel(0x0, &mctl_ctl->dx[2].gcr);
542*4882a593Smuzhiyun 			writel(0x0, &mctl_ctl->dx[3].gcr);
543*4882a593Smuzhiyun 			para->bus_full_width = 0;
544*4882a593Smuzhiyun 		}
545*4882a593Smuzhiyun #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
546*4882a593Smuzhiyun 		if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
547*4882a593Smuzhiyun 			writel(0x0, &mctl_ctl->dx[1].gcr);
548*4882a593Smuzhiyun 			para->bus_full_width = 0;
549*4882a593Smuzhiyun 		}
550*4882a593Smuzhiyun #endif
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		mctl_set_cr(socid, para);
553*4882a593Smuzhiyun 		udelay(20);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 		/* re-train */
556*4882a593Smuzhiyun 		mctl_phy_init(PIR_QSGATE);
557*4882a593Smuzhiyun 		if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
558*4882a593Smuzhiyun 			return 1;
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	/* check the dramc status */
562*4882a593Smuzhiyun 	mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	/* liuke added for refresh debug */
565*4882a593Smuzhiyun 	setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
566*4882a593Smuzhiyun 	udelay(10);
567*4882a593Smuzhiyun 	clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
568*4882a593Smuzhiyun 	udelay(10);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* set PGCR3, CKE polarity */
571*4882a593Smuzhiyun 	if (socid == SOCID_H3)
572*4882a593Smuzhiyun 		writel(0x00aa0060, &mctl_ctl->pgcr[3]);
573*4882a593Smuzhiyun 	else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
574*4882a593Smuzhiyun 		writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	/* power down zq calibration module for power save */
577*4882a593Smuzhiyun 	setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* enable master access */
580*4882a593Smuzhiyun 	writel(0xffffffff, &mctl_com->maer);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	return 0;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
mctl_auto_detect_dram_size(uint16_t socid,struct dram_para * para)585*4882a593Smuzhiyun static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	/* detect row address bits */
588*4882a593Smuzhiyun 	para->page_size = 512;
589*4882a593Smuzhiyun 	para->row_bits = 16;
590*4882a593Smuzhiyun 	para->bank_bits = 2;
591*4882a593Smuzhiyun 	mctl_set_cr(socid, para);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
594*4882a593Smuzhiyun 		if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
595*4882a593Smuzhiyun 			break;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* detect bank address bits */
598*4882a593Smuzhiyun 	para->bank_bits = 3;
599*4882a593Smuzhiyun 	mctl_set_cr(socid, para);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
602*4882a593Smuzhiyun 		if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
603*4882a593Smuzhiyun 			break;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	/* detect page size */
606*4882a593Smuzhiyun 	para->page_size = 8192;
607*4882a593Smuzhiyun 	mctl_set_cr(socid, para);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
610*4882a593Smuzhiyun 		if (mctl_mem_matches(para->page_size))
611*4882a593Smuzhiyun 			break;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun /*
615*4882a593Smuzhiyun  * The actual values used here are taken from Allwinner provided boot0
616*4882a593Smuzhiyun  * binaries, though they are probably board specific, so would likely benefit
617*4882a593Smuzhiyun  * from invidual tuning for each board. Apparently a lot of boards copy from
618*4882a593Smuzhiyun  * some Allwinner reference design, so we go with those generic values for now
619*4882a593Smuzhiyun  * in the hope that they are reasonable for most (all?) boards.
620*4882a593Smuzhiyun  */
621*4882a593Smuzhiyun #define SUN8I_H3_DX_READ_DELAYS					\
622*4882a593Smuzhiyun 	{{ 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
623*4882a593Smuzhiyun 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
624*4882a593Smuzhiyun 	 { 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
625*4882a593Smuzhiyun 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 }}
626*4882a593Smuzhiyun #define SUN8I_H3_DX_WRITE_DELAYS				\
627*4882a593Smuzhiyun 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
628*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
629*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
630*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  6 }}
631*4882a593Smuzhiyun #define SUN8I_H3_AC_DELAYS					\
632*4882a593Smuzhiyun 	{  0,  0,  0,  0,  0,  0,  0,  0,			\
633*4882a593Smuzhiyun 	   0,  0,  0,  0,  0,  0,  0,  0,			\
634*4882a593Smuzhiyun 	   0,  0,  0,  0,  0,  0,  0,  0,			\
635*4882a593Smuzhiyun 	   0,  0,  0,  0,  0,  0,  0      }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun #define SUN8I_R40_DX_READ_DELAYS				\
638*4882a593Smuzhiyun 	{{ 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
639*4882a593Smuzhiyun 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
640*4882a593Smuzhiyun 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
641*4882a593Smuzhiyun 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 } }
642*4882a593Smuzhiyun #define SUN8I_R40_DX_WRITE_DELAYS				\
643*4882a593Smuzhiyun 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
644*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
645*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
646*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 } }
647*4882a593Smuzhiyun #define SUN8I_R40_AC_DELAYS					\
648*4882a593Smuzhiyun 	{  0,  0,  3,  0,  0,  0,  0,  0,			\
649*4882a593Smuzhiyun 	   0,  0,  0,  0,  0,  0,  0,  0,			\
650*4882a593Smuzhiyun 	   0,  0,  0,  0,  0,  0,  0,  0,			\
651*4882a593Smuzhiyun 	   0,  0,  0,  0,  0,  0,  0      }
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun #define SUN50I_A64_DX_READ_DELAYS				\
654*4882a593Smuzhiyun 	{{ 16, 16, 16, 16, 17, 16, 16, 17, 16,  1,  0 },	\
655*4882a593Smuzhiyun 	 { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 },	\
656*4882a593Smuzhiyun 	 { 16, 17, 17, 16, 16, 16, 16, 16, 16,  0,  0 },	\
657*4882a593Smuzhiyun 	 { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 }}
658*4882a593Smuzhiyun #define SUN50I_A64_DX_WRITE_DELAYS				\
659*4882a593Smuzhiyun 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15 },	\
660*4882a593Smuzhiyun 	 {  0,  0,  0,  0,  1,  1,  1,  1,  0, 10, 10 },	\
661*4882a593Smuzhiyun 	 {  1,  0,  1,  1,  1,  1,  1,  1,  0, 11, 11 },	\
662*4882a593Smuzhiyun 	 {  1,  0,  0,  1,  1,  1,  1,  1,  0, 12, 12 }}
663*4882a593Smuzhiyun #define SUN50I_A64_AC_DELAYS					\
664*4882a593Smuzhiyun 	{  5,  5, 13, 10,  2,  5,  3,  3,			\
665*4882a593Smuzhiyun 	   0,  3,  3,  3,  1,  0,  0,  0,			\
666*4882a593Smuzhiyun 	   3,  4,  0,  3,  4,  1,  4,  0,			\
667*4882a593Smuzhiyun 	   1,  1,  0,  1, 13,  5,  4      }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun #define SUN8I_H5_DX_READ_DELAYS					\
670*4882a593Smuzhiyun 	{{ 14, 15, 17, 17, 17, 17, 17, 18, 17,  3,  3 },	\
671*4882a593Smuzhiyun 	 { 21, 21, 12, 22, 21, 21, 21, 21, 21,  3,  3 },	\
672*4882a593Smuzhiyun 	 { 16, 19, 19, 17, 22, 22, 21, 22, 19,  3,  3 },	\
673*4882a593Smuzhiyun 	 { 21, 21, 22, 22, 20, 21, 19, 19, 19,  3,  3 } }
674*4882a593Smuzhiyun #define SUN8I_H5_DX_WRITE_DELAYS				\
675*4882a593Smuzhiyun 	{{  1,  2,  3,  4,  3,  4,  4,  4,  6,  6,  6 },	\
676*4882a593Smuzhiyun 	 {  6,  6,  6,  5,  5,  5,  5,  5,  6,  6,  6 },	\
677*4882a593Smuzhiyun 	 {  0,  2,  4,  2,  6,  5,  5,  5,  6,  6,  6 },	\
678*4882a593Smuzhiyun 	 {  3,  3,  3,  2,  2,  1,  1,  1,  4,  4,  4 } }
679*4882a593Smuzhiyun #define SUN8I_H5_AC_DELAYS					\
680*4882a593Smuzhiyun 	{  0,  0,  5,  5,  0,  0,  0,  0,			\
681*4882a593Smuzhiyun 	   0,  0,  0,  0,  3,  3,  3,  3,			\
682*4882a593Smuzhiyun 	   3,  3,  3,  3,  3,  3,  3,  3,			\
683*4882a593Smuzhiyun 	   3,  3,  3,  3,  2,  0,  0      }
684*4882a593Smuzhiyun 
sunxi_dram_init(void)685*4882a593Smuzhiyun unsigned long sunxi_dram_init(void)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	struct sunxi_mctl_com_reg * const mctl_com =
688*4882a593Smuzhiyun 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
689*4882a593Smuzhiyun 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
690*4882a593Smuzhiyun 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	struct dram_para para = {
693*4882a593Smuzhiyun 		.dual_rank = 1,
694*4882a593Smuzhiyun 		.bus_full_width = 1,
695*4882a593Smuzhiyun 		.row_bits = 15,
696*4882a593Smuzhiyun 		.bank_bits = 3,
697*4882a593Smuzhiyun 		.page_size = 4096,
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun #if defined(CONFIG_MACH_SUN8I_H3)
700*4882a593Smuzhiyun 		.dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
701*4882a593Smuzhiyun 		.dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
702*4882a593Smuzhiyun 		.ac_delays	 = SUN8I_H3_AC_DELAYS,
703*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN8I_R40)
704*4882a593Smuzhiyun 		.dx_read_delays  = SUN8I_R40_DX_READ_DELAYS,
705*4882a593Smuzhiyun 		.dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
706*4882a593Smuzhiyun 		.ac_delays	 = SUN8I_R40_AC_DELAYS,
707*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN50I)
708*4882a593Smuzhiyun 		.dx_read_delays  = SUN50I_A64_DX_READ_DELAYS,
709*4882a593Smuzhiyun 		.dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
710*4882a593Smuzhiyun 		.ac_delays	 = SUN50I_A64_AC_DELAYS,
711*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN50I_H5)
712*4882a593Smuzhiyun 		.dx_read_delays  = SUN8I_H5_DX_READ_DELAYS,
713*4882a593Smuzhiyun 		.dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
714*4882a593Smuzhiyun 		.ac_delays	 = SUN8I_H5_AC_DELAYS,
715*4882a593Smuzhiyun #endif
716*4882a593Smuzhiyun 	};
717*4882a593Smuzhiyun /*
718*4882a593Smuzhiyun  * Let the compiler optimize alternatives away by passing this value into
719*4882a593Smuzhiyun  * the static functions. This saves us #ifdefs, but still keeps the binary
720*4882a593Smuzhiyun  * small.
721*4882a593Smuzhiyun  */
722*4882a593Smuzhiyun #if defined(CONFIG_MACH_SUN8I_H3)
723*4882a593Smuzhiyun 	uint16_t socid = SOCID_H3;
724*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN8I_R40)
725*4882a593Smuzhiyun 	uint16_t socid = SOCID_R40;
726*4882a593Smuzhiyun 	/* Currently we cannot support R40 with dual rank memory */
727*4882a593Smuzhiyun 	para.dual_rank = 0;
728*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN8I_V3S)
729*4882a593Smuzhiyun 	/* TODO: set delays and mbus priority for V3s */
730*4882a593Smuzhiyun 	uint16_t socid = SOCID_H3;
731*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN50I)
732*4882a593Smuzhiyun 	uint16_t socid = SOCID_A64;
733*4882a593Smuzhiyun #elif defined(CONFIG_MACH_SUN50I_H5)
734*4882a593Smuzhiyun 	uint16_t socid = SOCID_H5;
735*4882a593Smuzhiyun #endif
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	mctl_sys_init(socid, &para);
738*4882a593Smuzhiyun 	if (mctl_channel_init(socid, &para))
739*4882a593Smuzhiyun 		return 0;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if (para.dual_rank)
742*4882a593Smuzhiyun 		writel(0x00000303, &mctl_ctl->odtmap);
743*4882a593Smuzhiyun 	else
744*4882a593Smuzhiyun 		writel(0x00000201, &mctl_ctl->odtmap);
745*4882a593Smuzhiyun 	udelay(1);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	/* odt delay */
748*4882a593Smuzhiyun 	if (socid == SOCID_H3)
749*4882a593Smuzhiyun 		writel(0x0c000400, &mctl_ctl->odtcfg);
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
752*4882a593Smuzhiyun 		/* VTF enable (tpr13[8] == 1) */
753*4882a593Smuzhiyun 		setbits_le32(&mctl_ctl->vtfcr,
754*4882a593Smuzhiyun 			     (socid != SOCID_A64 ? 3 : 2) << 8);
755*4882a593Smuzhiyun 		/* DQ hold disable (tpr13[26] == 1) */
756*4882a593Smuzhiyun 		clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	/* clear credit value */
760*4882a593Smuzhiyun 	setbits_le32(&mctl_com->cccr, 1 << 31);
761*4882a593Smuzhiyun 	udelay(10);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	mctl_auto_detect_dram_size(socid, &para);
764*4882a593Smuzhiyun 	mctl_set_cr(socid, &para);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
767*4882a593Smuzhiyun 	       (para.dual_rank ? 2 : 1);
768*4882a593Smuzhiyun }
769