19934aba4SIcenowy Zheng /*
29934aba4SIcenowy Zheng  * sun8i H3 platform dram controller init
39934aba4SIcenowy Zheng  *
49934aba4SIcenowy Zheng  * (C) Copyright 2007-2015 Allwinner Technology Co.
59934aba4SIcenowy Zheng  *                         Jerry Wang <wangflord@allwinnertech.com>
69934aba4SIcenowy Zheng  * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
79934aba4SIcenowy Zheng  * (C) Copyright 2015      Hans de Goede <hdegoede@redhat.com>
89934aba4SIcenowy Zheng  * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
99934aba4SIcenowy Zheng  *
109934aba4SIcenowy Zheng  * SPDX-License-Identifier:	GPL-2.0+
119934aba4SIcenowy Zheng  */
129934aba4SIcenowy Zheng #include <common.h>
139934aba4SIcenowy Zheng #include <asm/io.h>
149934aba4SIcenowy Zheng #include <asm/arch/clock.h>
159934aba4SIcenowy Zheng #include <asm/arch/dram.h>
169934aba4SIcenowy Zheng #include <asm/arch/cpu.h>
179934aba4SIcenowy Zheng #include <linux/kconfig.h>
189934aba4SIcenowy Zheng 
199934aba4SIcenowy Zheng /*
209934aba4SIcenowy Zheng  * The delay parameters below allow to allegedly specify delay times of some
219934aba4SIcenowy Zheng  * unknown unit for each individual bit trace in each of the four data bytes
229934aba4SIcenowy Zheng  * the 32-bit wide access consists of. Also three control signals can be
239934aba4SIcenowy Zheng  * adjusted individually.
249934aba4SIcenowy Zheng  */
259934aba4SIcenowy Zheng #define BITS_PER_BYTE		8
269934aba4SIcenowy Zheng #define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
279934aba4SIcenowy Zheng /* The eight data lines (DQn) plus DM, DQS and DQSN */
289934aba4SIcenowy Zheng #define LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 3)
299934aba4SIcenowy Zheng struct dram_para {
309934aba4SIcenowy Zheng 	u16 page_size;
31f43a0099SIcenowy Zheng 	u8 bus_full_width;
329934aba4SIcenowy Zheng 	u8 dual_rank;
339934aba4SIcenowy Zheng 	u8 row_bits;
34*66b12526SIcenowy Zheng 	u8 bank_bits;
359934aba4SIcenowy Zheng 	const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
369934aba4SIcenowy Zheng 	const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
379934aba4SIcenowy Zheng 	const u8 ac_delays[31];
389934aba4SIcenowy Zheng };
399934aba4SIcenowy Zheng 
409934aba4SIcenowy Zheng static inline int ns_to_t(int nanoseconds)
419934aba4SIcenowy Zheng {
429934aba4SIcenowy Zheng 	const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
439934aba4SIcenowy Zheng 
449934aba4SIcenowy Zheng 	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
459934aba4SIcenowy Zheng }
469934aba4SIcenowy Zheng 
479934aba4SIcenowy Zheng static void mctl_phy_init(u32 val)
489934aba4SIcenowy Zheng {
499934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
509934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
519934aba4SIcenowy Zheng 
529934aba4SIcenowy Zheng 	writel(val | PIR_INIT, &mctl_ctl->pir);
539934aba4SIcenowy Zheng 	mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
549934aba4SIcenowy Zheng }
559934aba4SIcenowy Zheng 
569934aba4SIcenowy Zheng static void mctl_set_bit_delays(struct dram_para *para)
579934aba4SIcenowy Zheng {
589934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
599934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
609934aba4SIcenowy Zheng 	int i, j;
619934aba4SIcenowy Zheng 
629934aba4SIcenowy Zheng 	clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
639934aba4SIcenowy Zheng 
649934aba4SIcenowy Zheng 	for (i = 0; i < NR_OF_BYTE_LANES; i++)
659934aba4SIcenowy Zheng 		for (j = 0; j < LINES_PER_BYTE_LANE; j++)
669934aba4SIcenowy Zheng 			writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
679934aba4SIcenowy Zheng 			       DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
689934aba4SIcenowy Zheng 			       &mctl_ctl->dx[i].bdlr[j]);
699934aba4SIcenowy Zheng 
709934aba4SIcenowy Zheng 	for (i = 0; i < 31; i++)
719934aba4SIcenowy Zheng 		writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
729934aba4SIcenowy Zheng 		       &mctl_ctl->acbdlr[i]);
739934aba4SIcenowy Zheng 
749934aba4SIcenowy Zheng #ifdef CONFIG_MACH_SUN8I_R40
759934aba4SIcenowy Zheng 	/* DQSn, DMn, DQn output enable bit delay */
769934aba4SIcenowy Zheng 	for (i = 0; i < 4; i++)
779934aba4SIcenowy Zheng 		writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
789934aba4SIcenowy Zheng #endif
799934aba4SIcenowy Zheng 
809934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
819934aba4SIcenowy Zheng }
829934aba4SIcenowy Zheng 
839934aba4SIcenowy Zheng enum {
849934aba4SIcenowy Zheng 	MBUS_PORT_CPU           = 0,
859934aba4SIcenowy Zheng 	MBUS_PORT_GPU           = 1,
869934aba4SIcenowy Zheng 	MBUS_PORT_UNUSED	= 2,
879934aba4SIcenowy Zheng 	MBUS_PORT_DMA           = 3,
889934aba4SIcenowy Zheng 	MBUS_PORT_VE            = 4,
899934aba4SIcenowy Zheng 	MBUS_PORT_CSI           = 5,
909934aba4SIcenowy Zheng 	MBUS_PORT_NAND          = 6,
919934aba4SIcenowy Zheng 	MBUS_PORT_SS            = 7,
929934aba4SIcenowy Zheng 	MBUS_PORT_TS            = 8,
939934aba4SIcenowy Zheng 	MBUS_PORT_DI            = 9,
949934aba4SIcenowy Zheng 	MBUS_PORT_DE            = 10,
959934aba4SIcenowy Zheng 	MBUS_PORT_DE_CFD        = 11,
969934aba4SIcenowy Zheng 	MBUS_PORT_UNKNOWN1	= 12,
979934aba4SIcenowy Zheng 	MBUS_PORT_UNKNOWN2	= 13,
989934aba4SIcenowy Zheng 	MBUS_PORT_UNKNOWN3	= 14,
999934aba4SIcenowy Zheng };
1009934aba4SIcenowy Zheng 
1019934aba4SIcenowy Zheng enum {
1029934aba4SIcenowy Zheng 	MBUS_QOS_LOWEST = 0,
1039934aba4SIcenowy Zheng 	MBUS_QOS_LOW,
1049934aba4SIcenowy Zheng 	MBUS_QOS_HIGH,
1059934aba4SIcenowy Zheng 	MBUS_QOS_HIGHEST
1069934aba4SIcenowy Zheng };
1079934aba4SIcenowy Zheng 
1089934aba4SIcenowy Zheng inline void mbus_configure_port(u8 port,
1099934aba4SIcenowy Zheng 				bool bwlimit,
1109934aba4SIcenowy Zheng 				bool priority,
1119934aba4SIcenowy Zheng 				u8 qos,         /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
1129934aba4SIcenowy Zheng 				u8 waittime,    /* 0 .. 0xf */
1139934aba4SIcenowy Zheng 				u8 acs,         /* 0 .. 0xff */
1149934aba4SIcenowy Zheng 				u16 bwl0,       /* 0 .. 0xffff, bandwidth limit in MB/s */
1159934aba4SIcenowy Zheng 				u16 bwl1,
1169934aba4SIcenowy Zheng 				u16 bwl2)
1179934aba4SIcenowy Zheng {
1189934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1199934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1209934aba4SIcenowy Zheng 
1219934aba4SIcenowy Zheng 	const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
1229934aba4SIcenowy Zheng 			   | (priority ? (1 << 1) : 0)
1239934aba4SIcenowy Zheng 			   | ((qos & 0x3) << 2)
1249934aba4SIcenowy Zheng 			   | ((waittime & 0xf) << 4)
1259934aba4SIcenowy Zheng 			   | ((acs & 0xff) << 8)
1269934aba4SIcenowy Zheng 			   | (bwl0 << 16) );
1279934aba4SIcenowy Zheng 	const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
1289934aba4SIcenowy Zheng 
1299934aba4SIcenowy Zheng 	debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
1309934aba4SIcenowy Zheng 	writel(cfg0, &mctl_com->mcr[port][0]);
1319934aba4SIcenowy Zheng 	writel(cfg1, &mctl_com->mcr[port][1]);
1329934aba4SIcenowy Zheng }
1339934aba4SIcenowy Zheng 
1349934aba4SIcenowy Zheng #define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)	\
1359934aba4SIcenowy Zheng 	mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
1369934aba4SIcenowy Zheng 			    MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
1379934aba4SIcenowy Zheng 
1389934aba4SIcenowy Zheng static void mctl_set_master_priority_h3(void)
1399934aba4SIcenowy Zheng {
1409934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1419934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1429934aba4SIcenowy Zheng 
1439934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1449934aba4SIcenowy Zheng 	writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
1459934aba4SIcenowy Zheng 
1469934aba4SIcenowy Zheng 	/* set cpu high priority */
1479934aba4SIcenowy Zheng 	writel(0x00000001, &mctl_com->mapr);
1489934aba4SIcenowy Zheng 
1499934aba4SIcenowy Zheng 	MBUS_CONF(   CPU,  true, HIGHEST, 0,  512,  256,  128);
1509934aba4SIcenowy Zheng 	MBUS_CONF(   GPU,  true,    HIGH, 0, 1536, 1024,  256);
1519934aba4SIcenowy Zheng 	MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
1529934aba4SIcenowy Zheng 	MBUS_CONF(   DMA,  true, HIGHEST, 0,  256,  128,   32);
1539934aba4SIcenowy Zheng 	MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
1549934aba4SIcenowy Zheng 	MBUS_CONF(   CSI,  true, HIGHEST, 0,  256,  128,   32);
1559934aba4SIcenowy Zheng 	MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
1569934aba4SIcenowy Zheng 	MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
1579934aba4SIcenowy Zheng 	MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
1589934aba4SIcenowy Zheng 	MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
1599934aba4SIcenowy Zheng 	MBUS_CONF(    DE,  true, HIGHEST, 3, 8192, 6120, 1024);
1609934aba4SIcenowy Zheng 	MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1024,  288,   64);
1619934aba4SIcenowy Zheng }
1629934aba4SIcenowy Zheng 
1639934aba4SIcenowy Zheng static void mctl_set_master_priority_a64(void)
1649934aba4SIcenowy Zheng {
1659934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1669934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1679934aba4SIcenowy Zheng 
1689934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1699934aba4SIcenowy Zheng 	writel(399, &mctl_com->tmr);
1709934aba4SIcenowy Zheng 	writel((1 << 16), &mctl_com->bwcr);
1719934aba4SIcenowy Zheng 
1729934aba4SIcenowy Zheng 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
1739934aba4SIcenowy Zheng 	 * initialise it */
1749934aba4SIcenowy Zheng 	MBUS_CONF(   CPU,  true, HIGHEST, 0,  160,  100,   80);
1759934aba4SIcenowy Zheng 	MBUS_CONF(   GPU, false,    HIGH, 0, 1536, 1400,  256);
1769934aba4SIcenowy Zheng 	MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
1779934aba4SIcenowy Zheng 	MBUS_CONF(   DMA,  true,    HIGH, 0,  256,   80,  100);
1789934aba4SIcenowy Zheng 	MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
1799934aba4SIcenowy Zheng 	MBUS_CONF(   CSI,  true,    HIGH, 0,  256,  128,    0);
1809934aba4SIcenowy Zheng 	MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
1819934aba4SIcenowy Zheng 	MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
1829934aba4SIcenowy Zheng 	MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
1839934aba4SIcenowy Zheng 	MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
1849934aba4SIcenowy Zheng 	MBUS_CONF(    DE,  true,    HIGH, 2, 8192, 6144, 2048);
1859934aba4SIcenowy Zheng 	MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1280,  144,   64);
1869934aba4SIcenowy Zheng 
1879934aba4SIcenowy Zheng 	writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
1889934aba4SIcenowy Zheng }
1899934aba4SIcenowy Zheng 
1909934aba4SIcenowy Zheng static void mctl_set_master_priority_h5(void)
1919934aba4SIcenowy Zheng {
1929934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1939934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1949934aba4SIcenowy Zheng 
1959934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1969934aba4SIcenowy Zheng 	writel(399, &mctl_com->tmr);
1979934aba4SIcenowy Zheng 	writel((1 << 16), &mctl_com->bwcr);
1989934aba4SIcenowy Zheng 
1999934aba4SIcenowy Zheng 	/* set cpu high priority */
2009934aba4SIcenowy Zheng 	writel(0x00000001, &mctl_com->mapr);
2019934aba4SIcenowy Zheng 
2029934aba4SIcenowy Zheng 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet
2039934aba4SIcenowy Zheng 	 * they initialise it */
2049934aba4SIcenowy Zheng 	MBUS_CONF(   CPU, true, HIGHEST, 0,  300,  260,  150);
2059934aba4SIcenowy Zheng 	MBUS_CONF(   GPU, true, HIGHEST, 0,  600,  400,  200);
2069934aba4SIcenowy Zheng 	MBUS_CONF(UNUSED, true, HIGHEST, 0,  512,  256,   96);
2079934aba4SIcenowy Zheng 	MBUS_CONF(   DMA, true, HIGHEST, 0,  256,  128,   32);
2089934aba4SIcenowy Zheng 	MBUS_CONF(    VE, true, HIGHEST, 0, 1900, 1500, 1000);
2099934aba4SIcenowy Zheng 	MBUS_CONF(   CSI, true, HIGHEST, 0,  150,  120,  100);
2109934aba4SIcenowy Zheng 	MBUS_CONF(  NAND, true,    HIGH, 0,  256,  128,   64);
2119934aba4SIcenowy Zheng 	MBUS_CONF(    SS, true, HIGHEST, 0,  256,  128,   64);
2129934aba4SIcenowy Zheng 	MBUS_CONF(    TS, true, HIGHEST, 0,  256,  128,   64);
2139934aba4SIcenowy Zheng 	MBUS_CONF(    DI, true,    HIGH, 0, 1024,  256,   64);
2149934aba4SIcenowy Zheng 	MBUS_CONF(    DE, true, HIGHEST, 3, 3400, 2400, 1024);
2159934aba4SIcenowy Zheng 	MBUS_CONF(DE_CFD, true, HIGHEST, 0,  600,  400,  200);
2169934aba4SIcenowy Zheng }
2179934aba4SIcenowy Zheng 
2189934aba4SIcenowy Zheng static void mctl_set_master_priority_r40(void)
2199934aba4SIcenowy Zheng {
2209934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
2219934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
2229934aba4SIcenowy Zheng 
2239934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
2249934aba4SIcenowy Zheng 	writel(399, &mctl_com->tmr);
2259934aba4SIcenowy Zheng 	writel((1 << 16), &mctl_com->bwcr);
2269934aba4SIcenowy Zheng 
2279934aba4SIcenowy Zheng 	/* set cpu high priority */
2289934aba4SIcenowy Zheng 	writel(0x00000001, &mctl_com->mapr);
2299934aba4SIcenowy Zheng 
2309934aba4SIcenowy Zheng 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet
2319934aba4SIcenowy Zheng 	 * they initialise it */
2329934aba4SIcenowy Zheng 	MBUS_CONF(     CPU, true, HIGHEST, 0,  300,  260,  150);
2339934aba4SIcenowy Zheng 	MBUS_CONF(     GPU, true, HIGHEST, 0,  600,  400,  200);
2349934aba4SIcenowy Zheng 	MBUS_CONF(  UNUSED, true, HIGHEST, 0,  512,  256,   96);
2359934aba4SIcenowy Zheng 	MBUS_CONF(     DMA, true, HIGHEST, 0,  256,  128,   32);
2369934aba4SIcenowy Zheng 	MBUS_CONF(      VE, true, HIGHEST, 0, 1900, 1500, 1000);
2379934aba4SIcenowy Zheng 	MBUS_CONF(     CSI, true, HIGHEST, 0,  150,  120,  100);
2389934aba4SIcenowy Zheng 	MBUS_CONF(    NAND, true,    HIGH, 0,  256,  128,   64);
2399934aba4SIcenowy Zheng 	MBUS_CONF(      SS, true, HIGHEST, 0,  256,  128,   64);
2409934aba4SIcenowy Zheng 	MBUS_CONF(      TS, true, HIGHEST, 0,  256,  128,   64);
2419934aba4SIcenowy Zheng 	MBUS_CONF(      DI, true,    HIGH, 0, 1024,  256,   64);
2429934aba4SIcenowy Zheng 
2439934aba4SIcenowy Zheng 	/*
2449934aba4SIcenowy Zheng 	 * The port names are probably wrong, but no correct sources
2459934aba4SIcenowy Zheng 	 * are available.
2469934aba4SIcenowy Zheng 	 */
2479934aba4SIcenowy Zheng 	MBUS_CONF(      DE, true,    HIGH, 0,  128,   48,    0);
2489934aba4SIcenowy Zheng 	MBUS_CONF(  DE_CFD, true,    HIGH, 0,  384,  256,    0);
2499934aba4SIcenowy Zheng 	MBUS_CONF(UNKNOWN1, true, HIGHEST, 0,  512,  384,  256);
2509934aba4SIcenowy Zheng 	MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
2519934aba4SIcenowy Zheng 	MBUS_CONF(UNKNOWN3, true,    HIGH, 0, 1280,  144,   64);
2529934aba4SIcenowy Zheng }
2539934aba4SIcenowy Zheng 
2549934aba4SIcenowy Zheng static void mctl_set_master_priority(uint16_t socid)
2559934aba4SIcenowy Zheng {
2569934aba4SIcenowy Zheng 	switch (socid) {
2579934aba4SIcenowy Zheng 	case SOCID_H3:
2589934aba4SIcenowy Zheng 		mctl_set_master_priority_h3();
2599934aba4SIcenowy Zheng 		return;
2609934aba4SIcenowy Zheng 	case SOCID_A64:
2619934aba4SIcenowy Zheng 		mctl_set_master_priority_a64();
2629934aba4SIcenowy Zheng 		return;
2639934aba4SIcenowy Zheng 	case SOCID_H5:
2649934aba4SIcenowy Zheng 		mctl_set_master_priority_h5();
2659934aba4SIcenowy Zheng 		return;
2669934aba4SIcenowy Zheng 	case SOCID_R40:
2679934aba4SIcenowy Zheng 		mctl_set_master_priority_r40();
2689934aba4SIcenowy Zheng 		return;
2699934aba4SIcenowy Zheng 	}
2709934aba4SIcenowy Zheng }
2719934aba4SIcenowy Zheng 
2729934aba4SIcenowy Zheng static void mctl_set_timing_params(uint16_t socid, struct dram_para *para)
2739934aba4SIcenowy Zheng {
2749934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
2759934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
2769934aba4SIcenowy Zheng 
2779934aba4SIcenowy Zheng 	u8 tccd		= 2;
2789934aba4SIcenowy Zheng 	u8 tfaw		= ns_to_t(50);
2799934aba4SIcenowy Zheng 	u8 trrd		= max(ns_to_t(10), 4);
2809934aba4SIcenowy Zheng 	u8 trcd		= ns_to_t(15);
2819934aba4SIcenowy Zheng 	u8 trc		= ns_to_t(53);
2829934aba4SIcenowy Zheng 	u8 txp		= max(ns_to_t(8), 3);
2839934aba4SIcenowy Zheng 	u8 twtr		= max(ns_to_t(8), 4);
2849934aba4SIcenowy Zheng 	u8 trtp		= max(ns_to_t(8), 4);
2859934aba4SIcenowy Zheng 	u8 twr		= max(ns_to_t(15), 3);
2869934aba4SIcenowy Zheng 	u8 trp		= ns_to_t(15);
2879934aba4SIcenowy Zheng 	u8 tras		= ns_to_t(38);
2889934aba4SIcenowy Zheng 	u16 trefi	= ns_to_t(7800) / 32;
2899934aba4SIcenowy Zheng 	u16 trfc	= ns_to_t(350);
2909934aba4SIcenowy Zheng 
2919934aba4SIcenowy Zheng 	u8 tmrw		= 0;
2929934aba4SIcenowy Zheng 	u8 tmrd		= 4;
2939934aba4SIcenowy Zheng 	u8 tmod		= 12;
2949934aba4SIcenowy Zheng 	u8 tcke		= 3;
2959934aba4SIcenowy Zheng 	u8 tcksrx	= 5;
2969934aba4SIcenowy Zheng 	u8 tcksre	= 5;
2979934aba4SIcenowy Zheng 	u8 tckesr	= 4;
2989934aba4SIcenowy Zheng 	u8 trasmax	= 24;
2999934aba4SIcenowy Zheng 
3009934aba4SIcenowy Zheng 	u8 tcl		= 6; /* CL 12 */
3019934aba4SIcenowy Zheng 	u8 tcwl		= 4; /* CWL 8 */
3029934aba4SIcenowy Zheng 	u8 t_rdata_en	= 4;
3039934aba4SIcenowy Zheng 	u8 wr_latency	= 2;
3049934aba4SIcenowy Zheng 
3059934aba4SIcenowy Zheng 	u32 tdinit0	= (500 * CONFIG_DRAM_CLK) + 1;		/* 500us */
3069934aba4SIcenowy Zheng 	u32 tdinit1	= (360 * CONFIG_DRAM_CLK) / 1000 + 1;	/* 360ns */
3079934aba4SIcenowy Zheng 	u32 tdinit2	= (200 * CONFIG_DRAM_CLK) + 1;		/* 200us */
3089934aba4SIcenowy Zheng 	u32 tdinit3	= (1 * CONFIG_DRAM_CLK) + 1;		/* 1us */
3099934aba4SIcenowy Zheng 
3109934aba4SIcenowy Zheng 	u8 twtp		= tcwl + 2 + twr;	/* WL + BL / 2 + tWR */
3119934aba4SIcenowy Zheng 	u8 twr2rd	= tcwl + 2 + twtr;	/* WL + BL / 2 + tWTR */
3129934aba4SIcenowy Zheng 	u8 trd2wr	= tcl + 2 + 1 - tcwl;	/* RL + BL / 2 + 2 - WL */
3139934aba4SIcenowy Zheng 
3149934aba4SIcenowy Zheng 	/* set mode register */
3159934aba4SIcenowy Zheng 	writel(0x1c70, &mctl_ctl->mr[0]);	/* CL=11, WR=12 */
3169934aba4SIcenowy Zheng 	writel(0x40, &mctl_ctl->mr[1]);
3179934aba4SIcenowy Zheng 	writel(0x18, &mctl_ctl->mr[2]);		/* CWL=8 */
3189934aba4SIcenowy Zheng 	writel(0x0, &mctl_ctl->mr[3]);
3199934aba4SIcenowy Zheng 
3209934aba4SIcenowy Zheng 	if (socid == SOCID_R40)
3219934aba4SIcenowy Zheng 		writel(0x3, &mctl_ctl->lp3mr11);	/* odt_en[7:4] */
3229934aba4SIcenowy Zheng 
3239934aba4SIcenowy Zheng 	/* set DRAM timing */
3249934aba4SIcenowy Zheng 	writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) |
3259934aba4SIcenowy Zheng 	       DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras),
3269934aba4SIcenowy Zheng 	       &mctl_ctl->dramtmg[0]);
3279934aba4SIcenowy Zheng 	writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc),
3289934aba4SIcenowy Zheng 	       &mctl_ctl->dramtmg[1]);
3299934aba4SIcenowy Zheng 	writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) |
3309934aba4SIcenowy Zheng 	       DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd),
3319934aba4SIcenowy Zheng 	       &mctl_ctl->dramtmg[2]);
3329934aba4SIcenowy Zheng 	writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod),
3339934aba4SIcenowy Zheng 	       &mctl_ctl->dramtmg[3]);
3349934aba4SIcenowy Zheng 	writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) |
3359934aba4SIcenowy Zheng 	       DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]);
3369934aba4SIcenowy Zheng 	writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) |
3379934aba4SIcenowy Zheng 	       DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke),
3389934aba4SIcenowy Zheng 	       &mctl_ctl->dramtmg[5]);
3399934aba4SIcenowy Zheng 
3409934aba4SIcenowy Zheng 	/* set two rank timing */
3419934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xff << 8) | (0xff << 0),
3429934aba4SIcenowy Zheng 			((socid == SOCID_H5 ? 0x33 : 0x66) << 8) | (0x10 << 0));
3439934aba4SIcenowy Zheng 
3449934aba4SIcenowy Zheng 	/* set PHY interface timing, write latency and read latency configure */
3459934aba4SIcenowy Zheng 	writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) |
3469934aba4SIcenowy Zheng 	       (wr_latency << 0), &mctl_ctl->pitmg[0]);
3479934aba4SIcenowy Zheng 
3489934aba4SIcenowy Zheng 	/* set PHY timing, PTR0-2 use default */
3499934aba4SIcenowy Zheng 	writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]);
3509934aba4SIcenowy Zheng 	writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]);
3519934aba4SIcenowy Zheng 
3529934aba4SIcenowy Zheng 	/* set refresh timing */
3539934aba4SIcenowy Zheng 	writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg);
3549934aba4SIcenowy Zheng }
3559934aba4SIcenowy Zheng 
3569934aba4SIcenowy Zheng static u32 bin_to_mgray(int val)
3579934aba4SIcenowy Zheng {
3589934aba4SIcenowy Zheng 	static const u8 lookup_table[32] = {
3599934aba4SIcenowy Zheng 		0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
3609934aba4SIcenowy Zheng 		0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
3619934aba4SIcenowy Zheng 		0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
3629934aba4SIcenowy Zheng 		0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
3639934aba4SIcenowy Zheng 	};
3649934aba4SIcenowy Zheng 
3659934aba4SIcenowy Zheng 	return lookup_table[clamp(val, 0, 31)];
3669934aba4SIcenowy Zheng }
3679934aba4SIcenowy Zheng 
3689934aba4SIcenowy Zheng static int mgray_to_bin(u32 val)
3699934aba4SIcenowy Zheng {
3709934aba4SIcenowy Zheng 	static const u8 lookup_table[32] = {
3719934aba4SIcenowy Zheng 		0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
3729934aba4SIcenowy Zheng 		0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
3739934aba4SIcenowy Zheng 		0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
3749934aba4SIcenowy Zheng 		0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
3759934aba4SIcenowy Zheng 	};
3769934aba4SIcenowy Zheng 
3779934aba4SIcenowy Zheng 	return lookup_table[val & 0x1f];
3789934aba4SIcenowy Zheng }
3799934aba4SIcenowy Zheng 
3809934aba4SIcenowy Zheng static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
3819934aba4SIcenowy Zheng {
3829934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
3839934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
38487098d70SIcenowy Zheng 	int zq_count;
38587098d70SIcenowy Zheng 
38687098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_16BIT
38787098d70SIcenowy Zheng 	zq_count = 4;
38887098d70SIcenowy Zheng #else
38987098d70SIcenowy Zheng 	zq_count = 6;
39087098d70SIcenowy Zheng #endif
3919934aba4SIcenowy Zheng 
3929934aba4SIcenowy Zheng 	if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
3939934aba4SIcenowy Zheng 	    (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
3949934aba4SIcenowy Zheng 		u32 reg_val;
3959934aba4SIcenowy Zheng 
3969934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
3979934aba4SIcenowy Zheng 				CONFIG_DRAM_ZQ & 0xffff);
3989934aba4SIcenowy Zheng 
3999934aba4SIcenowy Zheng 		writel(PIR_CLRSR, &mctl_ctl->pir);
4009934aba4SIcenowy Zheng 		mctl_phy_init(PIR_ZCAL);
4019934aba4SIcenowy Zheng 
4029934aba4SIcenowy Zheng 		reg_val = readl(&mctl_ctl->zqdr[0]);
4039934aba4SIcenowy Zheng 		reg_val &= (0x1f << 16) | (0x1f << 0);
4049934aba4SIcenowy Zheng 		reg_val |= reg_val << 8;
4059934aba4SIcenowy Zheng 		writel(reg_val, &mctl_ctl->zqdr[0]);
4069934aba4SIcenowy Zheng 
4079934aba4SIcenowy Zheng 		reg_val = readl(&mctl_ctl->zqdr[1]);
4089934aba4SIcenowy Zheng 		reg_val &= (0x1f << 16) | (0x1f << 0);
4099934aba4SIcenowy Zheng 		reg_val |= reg_val << 8;
4109934aba4SIcenowy Zheng 		writel(reg_val, &mctl_ctl->zqdr[1]);
4119934aba4SIcenowy Zheng 		writel(reg_val, &mctl_ctl->zqdr[2]);
4129934aba4SIcenowy Zheng 	} else {
4139934aba4SIcenowy Zheng 		int i;
4149934aba4SIcenowy Zheng 		u16 zq_val[6];
4159934aba4SIcenowy Zheng 		u8 val;
4169934aba4SIcenowy Zheng 
4179934aba4SIcenowy Zheng 		writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
4189934aba4SIcenowy Zheng 
41987098d70SIcenowy Zheng 		for (i = 0; i < zq_count; i++) {
4209934aba4SIcenowy Zheng 			u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
4219934aba4SIcenowy Zheng 
4229934aba4SIcenowy Zheng 			writel((zq << 20) | (zq << 16) | (zq << 12) |
4239934aba4SIcenowy Zheng 					(zq << 8) | (zq << 4) | (zq << 0),
4249934aba4SIcenowy Zheng 					&mctl_ctl->zqcr);
4259934aba4SIcenowy Zheng 
4269934aba4SIcenowy Zheng 			writel(PIR_CLRSR, &mctl_ctl->pir);
4279934aba4SIcenowy Zheng 			mctl_phy_init(PIR_ZCAL);
4289934aba4SIcenowy Zheng 
4299934aba4SIcenowy Zheng 			zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
4309934aba4SIcenowy Zheng 			writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
4319934aba4SIcenowy Zheng 
4329934aba4SIcenowy Zheng 			writel(PIR_CLRSR, &mctl_ctl->pir);
4339934aba4SIcenowy Zheng 			mctl_phy_init(PIR_ZCAL);
4349934aba4SIcenowy Zheng 
4359934aba4SIcenowy Zheng 			val = readl(&mctl_ctl->zqdr[0]) >> 24;
4369934aba4SIcenowy Zheng 			zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
4379934aba4SIcenowy Zheng 		}
4389934aba4SIcenowy Zheng 
4399934aba4SIcenowy Zheng 		writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
4409934aba4SIcenowy Zheng 		writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
44187098d70SIcenowy Zheng 		if (zq_count > 4)
44287098d70SIcenowy Zheng 			writel((zq_val[5] << 16) | zq_val[4],
44387098d70SIcenowy Zheng 			       &mctl_ctl->zqdr[2]);
4449934aba4SIcenowy Zheng 	}
4459934aba4SIcenowy Zheng }
4469934aba4SIcenowy Zheng 
4479934aba4SIcenowy Zheng static void mctl_set_cr(uint16_t socid, struct dram_para *para)
4489934aba4SIcenowy Zheng {
4499934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
4509934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
4519934aba4SIcenowy Zheng 
4529934aba4SIcenowy Zheng 	writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED |
453*66b12526SIcenowy Zheng 	       (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
454f43a0099SIcenowy Zheng 	       MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
4559934aba4SIcenowy Zheng 	       (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
4569934aba4SIcenowy Zheng 	       MCTL_CR_PAGE_SIZE(para->page_size) |
4579934aba4SIcenowy Zheng 	       MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
4589934aba4SIcenowy Zheng 
4599934aba4SIcenowy Zheng 	if (socid == SOCID_R40) {
4609934aba4SIcenowy Zheng 		if (para->dual_rank)
4619934aba4SIcenowy Zheng 			panic("Dual rank memory not supported\n");
4629934aba4SIcenowy Zheng 
4639934aba4SIcenowy Zheng 		/* Mux pin to A15 address line for single rank memory. */
4649934aba4SIcenowy Zheng 		setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
4659934aba4SIcenowy Zheng 	}
4669934aba4SIcenowy Zheng }
4679934aba4SIcenowy Zheng 
4689934aba4SIcenowy Zheng static void mctl_sys_init(uint16_t socid, struct dram_para *para)
4699934aba4SIcenowy Zheng {
4709934aba4SIcenowy Zheng 	struct sunxi_ccm_reg * const ccm =
4719934aba4SIcenowy Zheng 			(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
4729934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
4739934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
4749934aba4SIcenowy Zheng 
4759934aba4SIcenowy Zheng 	clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
4769934aba4SIcenowy Zheng 	clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
4779934aba4SIcenowy Zheng 	clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
4789934aba4SIcenowy Zheng 	clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
4799934aba4SIcenowy Zheng 	clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
4809934aba4SIcenowy Zheng 	if (socid == SOCID_A64 || socid == SOCID_R40)
4819934aba4SIcenowy Zheng 		clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
4829934aba4SIcenowy Zheng 	udelay(10);
4839934aba4SIcenowy Zheng 
4849934aba4SIcenowy Zheng 	clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
4859934aba4SIcenowy Zheng 	udelay(1000);
4869934aba4SIcenowy Zheng 
4879934aba4SIcenowy Zheng 	if (socid == SOCID_A64 || socid == SOCID_R40) {
4889934aba4SIcenowy Zheng 		clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
4899934aba4SIcenowy Zheng 		clrsetbits_le32(&ccm->dram_clk_cfg,
4909934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV_MASK |
4919934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_MASK,
4929934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV(1) |
4939934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_PLL11 |
4949934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_UPD);
4959934aba4SIcenowy Zheng 	} else if (socid == SOCID_H3 || socid == SOCID_H5) {
4969934aba4SIcenowy Zheng 		clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
4979934aba4SIcenowy Zheng 		clrsetbits_le32(&ccm->dram_clk_cfg,
4989934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV_MASK |
4999934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_MASK,
5009934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV(1) |
5019934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_PLL5 |
5029934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_UPD);
5039934aba4SIcenowy Zheng 	}
5049934aba4SIcenowy Zheng 	mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
5059934aba4SIcenowy Zheng 
5069934aba4SIcenowy Zheng 	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
5079934aba4SIcenowy Zheng 	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
5089934aba4SIcenowy Zheng 	setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
5099934aba4SIcenowy Zheng 	setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
5109934aba4SIcenowy Zheng 
5119934aba4SIcenowy Zheng 	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
5129934aba4SIcenowy Zheng 	udelay(10);
5139934aba4SIcenowy Zheng 
5149934aba4SIcenowy Zheng 	writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
5159934aba4SIcenowy Zheng 	udelay(500);
5169934aba4SIcenowy Zheng }
5179934aba4SIcenowy Zheng 
5189934aba4SIcenowy Zheng /* These are more guessed based on some Allwinner code. */
5199934aba4SIcenowy Zheng #define DX_GCR_ODT_DYNAMIC	(0x0 << 4)
5209934aba4SIcenowy Zheng #define DX_GCR_ODT_ALWAYS_ON	(0x1 << 4)
5219934aba4SIcenowy Zheng #define DX_GCR_ODT_OFF		(0x2 << 4)
5229934aba4SIcenowy Zheng 
5239934aba4SIcenowy Zheng static int mctl_channel_init(uint16_t socid, struct dram_para *para)
5249934aba4SIcenowy Zheng {
5259934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
5269934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
5279934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
5289934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
5299934aba4SIcenowy Zheng 
5309934aba4SIcenowy Zheng 	unsigned int i;
5319934aba4SIcenowy Zheng 
5329934aba4SIcenowy Zheng 	mctl_set_cr(socid, para);
5339934aba4SIcenowy Zheng 	mctl_set_timing_params(socid, para);
5349934aba4SIcenowy Zheng 	mctl_set_master_priority(socid);
5359934aba4SIcenowy Zheng 
5369934aba4SIcenowy Zheng 	/* setting VTC, default disable all VT */
5379934aba4SIcenowy Zheng 	clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
5389934aba4SIcenowy Zheng 	if (socid == SOCID_H5)
5399934aba4SIcenowy Zheng 		setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
5409934aba4SIcenowy Zheng 	else
5419934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
5429934aba4SIcenowy Zheng 
5439934aba4SIcenowy Zheng 	/* increase DFI_PHY_UPD clock */
5449934aba4SIcenowy Zheng 	writel(PROTECT_MAGIC, &mctl_com->protect);
5459934aba4SIcenowy Zheng 	udelay(100);
5469934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
5479934aba4SIcenowy Zheng 	writel(0x0, &mctl_com->protect);
5489934aba4SIcenowy Zheng 	udelay(100);
5499934aba4SIcenowy Zheng 
5509934aba4SIcenowy Zheng 	/* set dramc odt */
5519934aba4SIcenowy Zheng 	for (i = 0; i < 4; i++) {
5529934aba4SIcenowy Zheng 		u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
5539934aba4SIcenowy Zheng 				(0x3 << 12) | (0x3 << 14);
5549934aba4SIcenowy Zheng 		u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
5559934aba4SIcenowy Zheng 				DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
5569934aba4SIcenowy Zheng 
5579934aba4SIcenowy Zheng 		if (socid == SOCID_H5) {
5589934aba4SIcenowy Zheng 			clearmask |= 0x2 << 8;
5599934aba4SIcenowy Zheng 			setmask |= 0x4 << 8;
5609934aba4SIcenowy Zheng 		}
5619934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
5629934aba4SIcenowy Zheng 	}
5639934aba4SIcenowy Zheng 
5649934aba4SIcenowy Zheng 	/* AC PDR should always ON */
5659934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
5669934aba4SIcenowy Zheng 			0x1 << 1);
5679934aba4SIcenowy Zheng 
5689934aba4SIcenowy Zheng 	/* set DQS auto gating PD mode */
5699934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
5709934aba4SIcenowy Zheng 
5719934aba4SIcenowy Zheng 	if (socid == SOCID_H3) {
5729934aba4SIcenowy Zheng 		/* dx ddr_clk & hdr_clk dynamic mode */
5739934aba4SIcenowy Zheng 		clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
5749934aba4SIcenowy Zheng 
5759934aba4SIcenowy Zheng 		/* dphy & aphy phase select 270 degree */
5769934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
5779934aba4SIcenowy Zheng 				(0x1 << 10) | (0x2 << 8));
5789934aba4SIcenowy Zheng 	} else if (socid == SOCID_A64 || socid == SOCID_H5) {
5799934aba4SIcenowy Zheng 		/* dphy & aphy phase select ? */
5809934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
5819934aba4SIcenowy Zheng 				(0x0 << 10) | (0x3 << 8));
5829934aba4SIcenowy Zheng 	} else if (socid == SOCID_R40) {
5839934aba4SIcenowy Zheng 		/* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
5849934aba4SIcenowy Zheng 		clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
5859934aba4SIcenowy Zheng 
5869934aba4SIcenowy Zheng 		/* dphy & aphy phase select ? */
5879934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
5889934aba4SIcenowy Zheng 				(0x0 << 10) | (0x3 << 8));
5899934aba4SIcenowy Zheng 	}
5909934aba4SIcenowy Zheng 
5919934aba4SIcenowy Zheng 	/* set half DQ */
592f43a0099SIcenowy Zheng 	if (!para->bus_full_width) {
59387098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
5949934aba4SIcenowy Zheng 		writel(0x0, &mctl_ctl->dx[2].gcr);
5959934aba4SIcenowy Zheng 		writel(0x0, &mctl_ctl->dx[3].gcr);
59687098d70SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
59787098d70SIcenowy Zheng 		writel(0x0, &mctl_ctl->dx[1].gcr);
59887098d70SIcenowy Zheng #else
59987098d70SIcenowy Zheng #error Unsupported DRAM bus width!
60087098d70SIcenowy Zheng #endif
6019934aba4SIcenowy Zheng 	}
6029934aba4SIcenowy Zheng 
6039934aba4SIcenowy Zheng 	/* data training configuration */
6049934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
6059934aba4SIcenowy Zheng 			(para->dual_rank ? 0x3 : 0x1) << 24);
6069934aba4SIcenowy Zheng 
6079934aba4SIcenowy Zheng 	mctl_set_bit_delays(para);
6089934aba4SIcenowy Zheng 	udelay(50);
6099934aba4SIcenowy Zheng 
6109934aba4SIcenowy Zheng 	if (socid == SOCID_H3) {
6119934aba4SIcenowy Zheng 		mctl_h3_zq_calibration_quirk(para);
6129934aba4SIcenowy Zheng 
6139934aba4SIcenowy Zheng 		mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
6149934aba4SIcenowy Zheng 			      PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
6159934aba4SIcenowy Zheng 	} else if (socid == SOCID_A64 || socid == SOCID_H5) {
6169934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
6179934aba4SIcenowy Zheng 
6189934aba4SIcenowy Zheng 		mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
6199934aba4SIcenowy Zheng 			      PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
6209934aba4SIcenowy Zheng 		/* no PIR_QSGATE for H5 ???? */
6219934aba4SIcenowy Zheng 	} else if (socid == SOCID_R40) {
6229934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
6239934aba4SIcenowy Zheng 
6249934aba4SIcenowy Zheng 		mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
6259934aba4SIcenowy Zheng 			      PIR_DRAMRST | PIR_DRAMINIT);
6269934aba4SIcenowy Zheng 	}
6279934aba4SIcenowy Zheng 
6289934aba4SIcenowy Zheng 	/* detect ranks and bus width */
6299934aba4SIcenowy Zheng 	if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
6309934aba4SIcenowy Zheng 		/* only one rank */
63187098d70SIcenowy Zheng 		if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
63287098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
63387098d70SIcenowy Zheng 		    || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
63487098d70SIcenowy Zheng #endif
63587098d70SIcenowy Zheng 		    ) {
6369934aba4SIcenowy Zheng 			clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
6379934aba4SIcenowy Zheng 			para->dual_rank = 0;
6389934aba4SIcenowy Zheng 		}
6399934aba4SIcenowy Zheng 
6409934aba4SIcenowy Zheng 		/* only half DQ width */
64187098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
6429934aba4SIcenowy Zheng 		if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
6439934aba4SIcenowy Zheng 		    ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
6449934aba4SIcenowy Zheng 			writel(0x0, &mctl_ctl->dx[2].gcr);
6459934aba4SIcenowy Zheng 			writel(0x0, &mctl_ctl->dx[3].gcr);
646f43a0099SIcenowy Zheng 			para->bus_full_width = 0;
6479934aba4SIcenowy Zheng 		}
64887098d70SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
64987098d70SIcenowy Zheng 		if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
65087098d70SIcenowy Zheng 			writel(0x0, &mctl_ctl->dx[1].gcr);
65187098d70SIcenowy Zheng 			para->bus_full_width = 0;
65287098d70SIcenowy Zheng 		}
65387098d70SIcenowy Zheng #endif
6549934aba4SIcenowy Zheng 
6559934aba4SIcenowy Zheng 		mctl_set_cr(socid, para);
6569934aba4SIcenowy Zheng 		udelay(20);
6579934aba4SIcenowy Zheng 
6589934aba4SIcenowy Zheng 		/* re-train */
6599934aba4SIcenowy Zheng 		mctl_phy_init(PIR_QSGATE);
6609934aba4SIcenowy Zheng 		if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
6619934aba4SIcenowy Zheng 			return 1;
6629934aba4SIcenowy Zheng 	}
6639934aba4SIcenowy Zheng 
6649934aba4SIcenowy Zheng 	/* check the dramc status */
6659934aba4SIcenowy Zheng 	mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
6669934aba4SIcenowy Zheng 
6679934aba4SIcenowy Zheng 	/* liuke added for refresh debug */
6689934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
6699934aba4SIcenowy Zheng 	udelay(10);
6709934aba4SIcenowy Zheng 	clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
6719934aba4SIcenowy Zheng 	udelay(10);
6729934aba4SIcenowy Zheng 
6739934aba4SIcenowy Zheng 	/* set PGCR3, CKE polarity */
6749934aba4SIcenowy Zheng 	if (socid == SOCID_H3)
6759934aba4SIcenowy Zheng 		writel(0x00aa0060, &mctl_ctl->pgcr[3]);
6769934aba4SIcenowy Zheng 	else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
6779934aba4SIcenowy Zheng 		writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
6789934aba4SIcenowy Zheng 
6799934aba4SIcenowy Zheng 	/* power down zq calibration module for power save */
6809934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
6819934aba4SIcenowy Zheng 
6829934aba4SIcenowy Zheng 	/* enable master access */
6839934aba4SIcenowy Zheng 	writel(0xffffffff, &mctl_com->maer);
6849934aba4SIcenowy Zheng 
6859934aba4SIcenowy Zheng 	return 0;
6869934aba4SIcenowy Zheng }
6879934aba4SIcenowy Zheng 
6889934aba4SIcenowy Zheng static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
6899934aba4SIcenowy Zheng {
6909934aba4SIcenowy Zheng 	/* detect row address bits */
6919934aba4SIcenowy Zheng 	para->page_size = 512;
6929934aba4SIcenowy Zheng 	para->row_bits = 16;
693*66b12526SIcenowy Zheng 	para->bank_bits = 2;
6949934aba4SIcenowy Zheng 	mctl_set_cr(socid, para);
6959934aba4SIcenowy Zheng 
6969934aba4SIcenowy Zheng 	for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
697*66b12526SIcenowy Zheng 		if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
698*66b12526SIcenowy Zheng 			break;
699*66b12526SIcenowy Zheng 
700*66b12526SIcenowy Zheng 	/* detect bank address bits */
701*66b12526SIcenowy Zheng 	para->bank_bits = 3;
702*66b12526SIcenowy Zheng 	mctl_set_cr(socid, para);
703*66b12526SIcenowy Zheng 
704*66b12526SIcenowy Zheng 	for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
705*66b12526SIcenowy Zheng 		if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
7069934aba4SIcenowy Zheng 			break;
7079934aba4SIcenowy Zheng 
7089934aba4SIcenowy Zheng 	/* detect page size */
7099934aba4SIcenowy Zheng 	para->page_size = 8192;
7109934aba4SIcenowy Zheng 	mctl_set_cr(socid, para);
7119934aba4SIcenowy Zheng 
7129934aba4SIcenowy Zheng 	for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
7139934aba4SIcenowy Zheng 		if (mctl_mem_matches(para->page_size))
7149934aba4SIcenowy Zheng 			break;
7159934aba4SIcenowy Zheng }
7169934aba4SIcenowy Zheng 
7179934aba4SIcenowy Zheng /*
7189934aba4SIcenowy Zheng  * The actual values used here are taken from Allwinner provided boot0
7199934aba4SIcenowy Zheng  * binaries, though they are probably board specific, so would likely benefit
7209934aba4SIcenowy Zheng  * from invidual tuning for each board. Apparently a lot of boards copy from
7219934aba4SIcenowy Zheng  * some Allwinner reference design, so we go with those generic values for now
7229934aba4SIcenowy Zheng  * in the hope that they are reasonable for most (all?) boards.
7239934aba4SIcenowy Zheng  */
7249934aba4SIcenowy Zheng #define SUN8I_H3_DX_READ_DELAYS					\
7259934aba4SIcenowy Zheng 	{{ 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
7269934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
7279934aba4SIcenowy Zheng 	 { 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
7289934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 }}
7299934aba4SIcenowy Zheng #define SUN8I_H3_DX_WRITE_DELAYS				\
7309934aba4SIcenowy Zheng 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
7319934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
7329934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
7339934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  6 }}
7349934aba4SIcenowy Zheng #define SUN8I_H3_AC_DELAYS					\
7359934aba4SIcenowy Zheng 	{  0,  0,  0,  0,  0,  0,  0,  0,			\
7369934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
7379934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
7389934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0      }
7399934aba4SIcenowy Zheng 
7409934aba4SIcenowy Zheng #define SUN8I_R40_DX_READ_DELAYS				\
7419934aba4SIcenowy Zheng 	{{ 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
7429934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
7439934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
7449934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 } }
7459934aba4SIcenowy Zheng #define SUN8I_R40_DX_WRITE_DELAYS				\
7469934aba4SIcenowy Zheng 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
7479934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
7489934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
7499934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 } }
7509934aba4SIcenowy Zheng #define SUN8I_R40_AC_DELAYS					\
7519934aba4SIcenowy Zheng 	{  0,  0,  3,  0,  0,  0,  0,  0,			\
7529934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
7539934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
7549934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0      }
7559934aba4SIcenowy Zheng 
7569934aba4SIcenowy Zheng #define SUN50I_A64_DX_READ_DELAYS				\
7579934aba4SIcenowy Zheng 	{{ 16, 16, 16, 16, 17, 16, 16, 17, 16,  1,  0 },	\
7589934aba4SIcenowy Zheng 	 { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 },	\
7599934aba4SIcenowy Zheng 	 { 16, 17, 17, 16, 16, 16, 16, 16, 16,  0,  0 },	\
7609934aba4SIcenowy Zheng 	 { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 }}
7619934aba4SIcenowy Zheng #define SUN50I_A64_DX_WRITE_DELAYS				\
7629934aba4SIcenowy Zheng 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15 },	\
7639934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  1,  1,  1,  1,  0, 10, 10 },	\
7649934aba4SIcenowy Zheng 	 {  1,  0,  1,  1,  1,  1,  1,  1,  0, 11, 11 },	\
7659934aba4SIcenowy Zheng 	 {  1,  0,  0,  1,  1,  1,  1,  1,  0, 12, 12 }}
7669934aba4SIcenowy Zheng #define SUN50I_A64_AC_DELAYS					\
7679934aba4SIcenowy Zheng 	{  5,  5, 13, 10,  2,  5,  3,  3,			\
7689934aba4SIcenowy Zheng 	   0,  3,  3,  3,  1,  0,  0,  0,			\
7699934aba4SIcenowy Zheng 	   3,  4,  0,  3,  4,  1,  4,  0,			\
7709934aba4SIcenowy Zheng 	   1,  1,  0,  1, 13,  5,  4      }
7719934aba4SIcenowy Zheng 
7729934aba4SIcenowy Zheng #define SUN8I_H5_DX_READ_DELAYS					\
7739934aba4SIcenowy Zheng 	{{ 14, 15, 17, 17, 17, 17, 17, 18, 17,  3,  3 },	\
7749934aba4SIcenowy Zheng 	 { 21, 21, 12, 22, 21, 21, 21, 21, 21,  3,  3 },	\
7759934aba4SIcenowy Zheng 	 { 16, 19, 19, 17, 22, 22, 21, 22, 19,  3,  3 },	\
7769934aba4SIcenowy Zheng 	 { 21, 21, 22, 22, 20, 21, 19, 19, 19,  3,  3 } }
7779934aba4SIcenowy Zheng #define SUN8I_H5_DX_WRITE_DELAYS				\
7789934aba4SIcenowy Zheng 	{{  1,  2,  3,  4,  3,  4,  4,  4,  6,  6,  6 },	\
7799934aba4SIcenowy Zheng 	 {  6,  6,  6,  5,  5,  5,  5,  5,  6,  6,  6 },	\
7809934aba4SIcenowy Zheng 	 {  0,  2,  4,  2,  6,  5,  5,  5,  6,  6,  6 },	\
7819934aba4SIcenowy Zheng 	 {  3,  3,  3,  2,  2,  1,  1,  1,  4,  4,  4 } }
7829934aba4SIcenowy Zheng #define SUN8I_H5_AC_DELAYS					\
7839934aba4SIcenowy Zheng 	{  0,  0,  5,  5,  0,  0,  0,  0,			\
7849934aba4SIcenowy Zheng 	   0,  0,  0,  0,  3,  3,  3,  3,			\
7859934aba4SIcenowy Zheng 	   3,  3,  3,  3,  3,  3,  3,  3,			\
7869934aba4SIcenowy Zheng 	   3,  3,  3,  3,  2,  0,  0      }
7879934aba4SIcenowy Zheng 
7889934aba4SIcenowy Zheng unsigned long sunxi_dram_init(void)
7899934aba4SIcenowy Zheng {
7909934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
7919934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
7929934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
7939934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
7949934aba4SIcenowy Zheng 
7959934aba4SIcenowy Zheng 	struct dram_para para = {
7969934aba4SIcenowy Zheng 		.dual_rank = 0,
797f43a0099SIcenowy Zheng 		.bus_full_width = 1,
7989934aba4SIcenowy Zheng 		.row_bits = 15,
799*66b12526SIcenowy Zheng 		.bank_bits = 3,
8009934aba4SIcenowy Zheng 		.page_size = 4096,
8019934aba4SIcenowy Zheng 
8029934aba4SIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_H3)
8039934aba4SIcenowy Zheng 		.dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
8049934aba4SIcenowy Zheng 		.dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
8059934aba4SIcenowy Zheng 		.ac_delays	 = SUN8I_H3_AC_DELAYS,
8069934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_R40)
8079934aba4SIcenowy Zheng 		.dx_read_delays  = SUN8I_R40_DX_READ_DELAYS,
8089934aba4SIcenowy Zheng 		.dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
8099934aba4SIcenowy Zheng 		.ac_delays	 = SUN8I_R40_AC_DELAYS,
8109934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I)
8119934aba4SIcenowy Zheng 		.dx_read_delays  = SUN50I_A64_DX_READ_DELAYS,
8129934aba4SIcenowy Zheng 		.dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
8139934aba4SIcenowy Zheng 		.ac_delays	 = SUN50I_A64_AC_DELAYS,
8149934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I_H5)
8159934aba4SIcenowy Zheng 		.dx_read_delays  = SUN8I_H5_DX_READ_DELAYS,
8169934aba4SIcenowy Zheng 		.dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
8179934aba4SIcenowy Zheng 		.ac_delays	 = SUN8I_H5_AC_DELAYS,
8189934aba4SIcenowy Zheng #endif
8199934aba4SIcenowy Zheng 	};
8209934aba4SIcenowy Zheng /*
8219934aba4SIcenowy Zheng  * Let the compiler optimize alternatives away by passing this value into
8229934aba4SIcenowy Zheng  * the static functions. This saves us #ifdefs, but still keeps the binary
8239934aba4SIcenowy Zheng  * small.
8249934aba4SIcenowy Zheng  */
8259934aba4SIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_H3)
8269934aba4SIcenowy Zheng 	uint16_t socid = SOCID_H3;
8279934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_R40)
8289934aba4SIcenowy Zheng 	uint16_t socid = SOCID_R40;
8299934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I)
8309934aba4SIcenowy Zheng 	uint16_t socid = SOCID_A64;
8319934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I_H5)
8329934aba4SIcenowy Zheng 	uint16_t socid = SOCID_H5;
8339934aba4SIcenowy Zheng #endif
8349934aba4SIcenowy Zheng 
8359934aba4SIcenowy Zheng 	mctl_sys_init(socid, &para);
8369934aba4SIcenowy Zheng 	if (mctl_channel_init(socid, &para))
8379934aba4SIcenowy Zheng 		return 0;
8389934aba4SIcenowy Zheng 
8399934aba4SIcenowy Zheng 	if (para.dual_rank)
8409934aba4SIcenowy Zheng 		writel(0x00000303, &mctl_ctl->odtmap);
8419934aba4SIcenowy Zheng 	else
8429934aba4SIcenowy Zheng 		writel(0x00000201, &mctl_ctl->odtmap);
8439934aba4SIcenowy Zheng 	udelay(1);
8449934aba4SIcenowy Zheng 
8459934aba4SIcenowy Zheng 	/* odt delay */
8469934aba4SIcenowy Zheng 	if (socid == SOCID_H3)
8479934aba4SIcenowy Zheng 		writel(0x0c000400, &mctl_ctl->odtcfg);
8489934aba4SIcenowy Zheng 
8499934aba4SIcenowy Zheng 	if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
8509934aba4SIcenowy Zheng 		/* VTF enable (tpr13[8] == 1) */
8519934aba4SIcenowy Zheng 		setbits_le32(&mctl_ctl->vtfcr,
8529934aba4SIcenowy Zheng 			     (socid != SOCID_A64 ? 3 : 2) << 8);
8539934aba4SIcenowy Zheng 		/* DQ hold disable (tpr13[26] == 1) */
8549934aba4SIcenowy Zheng 		clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
8559934aba4SIcenowy Zheng 	}
8569934aba4SIcenowy Zheng 
8579934aba4SIcenowy Zheng 	/* clear credit value */
8589934aba4SIcenowy Zheng 	setbits_le32(&mctl_com->cccr, 1 << 31);
8599934aba4SIcenowy Zheng 	udelay(10);
8609934aba4SIcenowy Zheng 
8619934aba4SIcenowy Zheng 	mctl_auto_detect_dram_size(socid, &para);
8629934aba4SIcenowy Zheng 	mctl_set_cr(socid, &para);
8639934aba4SIcenowy Zheng 
864*66b12526SIcenowy Zheng 	return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
8659934aba4SIcenowy Zheng 	       (para.dual_rank ? 2 : 1);
8669934aba4SIcenowy Zheng }
867