1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
29934aba4SIcenowy Zheng /*
39934aba4SIcenowy Zheng  * sun8i H3 platform dram controller init
49934aba4SIcenowy Zheng  *
59934aba4SIcenowy Zheng  * (C) Copyright 2007-2015 Allwinner Technology Co.
69934aba4SIcenowy Zheng  *                         Jerry Wang <wangflord@allwinnertech.com>
79934aba4SIcenowy Zheng  * (C) Copyright 2015      Vishnu Patekar <vishnupatekar0510@gmail.com>
89934aba4SIcenowy Zheng  * (C) Copyright 2015      Hans de Goede <hdegoede@redhat.com>
99934aba4SIcenowy Zheng  * (C) Copyright 2015      Jens Kuske <jenskuske@gmail.com>
109934aba4SIcenowy Zheng  */
119934aba4SIcenowy Zheng #include <common.h>
129934aba4SIcenowy Zheng #include <asm/io.h>
139934aba4SIcenowy Zheng #include <asm/arch/clock.h>
149934aba4SIcenowy Zheng #include <asm/arch/dram.h>
159934aba4SIcenowy Zheng #include <asm/arch/cpu.h>
169934aba4SIcenowy Zheng #include <linux/kconfig.h>
179934aba4SIcenowy Zheng 
mctl_phy_init(u32 val)189934aba4SIcenowy Zheng static void mctl_phy_init(u32 val)
199934aba4SIcenowy Zheng {
209934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
219934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
229934aba4SIcenowy Zheng 
239934aba4SIcenowy Zheng 	writel(val | PIR_INIT, &mctl_ctl->pir);
249934aba4SIcenowy Zheng 	mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
259934aba4SIcenowy Zheng }
269934aba4SIcenowy Zheng 
mctl_set_bit_delays(struct dram_para * para)279934aba4SIcenowy Zheng static void mctl_set_bit_delays(struct dram_para *para)
289934aba4SIcenowy Zheng {
299934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
309934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
319934aba4SIcenowy Zheng 	int i, j;
329934aba4SIcenowy Zheng 
339934aba4SIcenowy Zheng 	clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
349934aba4SIcenowy Zheng 
359934aba4SIcenowy Zheng 	for (i = 0; i < NR_OF_BYTE_LANES; i++)
369934aba4SIcenowy Zheng 		for (j = 0; j < LINES_PER_BYTE_LANE; j++)
379934aba4SIcenowy Zheng 			writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
389934aba4SIcenowy Zheng 			       DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
399934aba4SIcenowy Zheng 			       &mctl_ctl->dx[i].bdlr[j]);
409934aba4SIcenowy Zheng 
419934aba4SIcenowy Zheng 	for (i = 0; i < 31; i++)
429934aba4SIcenowy Zheng 		writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
439934aba4SIcenowy Zheng 		       &mctl_ctl->acbdlr[i]);
449934aba4SIcenowy Zheng 
459934aba4SIcenowy Zheng #ifdef CONFIG_MACH_SUN8I_R40
469934aba4SIcenowy Zheng 	/* DQSn, DMn, DQn output enable bit delay */
479934aba4SIcenowy Zheng 	for (i = 0; i < 4; i++)
489934aba4SIcenowy Zheng 		writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
499934aba4SIcenowy Zheng #endif
509934aba4SIcenowy Zheng 
519934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
529934aba4SIcenowy Zheng }
539934aba4SIcenowy Zheng 
549934aba4SIcenowy Zheng enum {
559934aba4SIcenowy Zheng 	MBUS_PORT_CPU           = 0,
569934aba4SIcenowy Zheng 	MBUS_PORT_GPU           = 1,
579934aba4SIcenowy Zheng 	MBUS_PORT_UNUSED	= 2,
589934aba4SIcenowy Zheng 	MBUS_PORT_DMA           = 3,
599934aba4SIcenowy Zheng 	MBUS_PORT_VE            = 4,
609934aba4SIcenowy Zheng 	MBUS_PORT_CSI           = 5,
619934aba4SIcenowy Zheng 	MBUS_PORT_NAND          = 6,
629934aba4SIcenowy Zheng 	MBUS_PORT_SS            = 7,
639934aba4SIcenowy Zheng 	MBUS_PORT_TS            = 8,
649934aba4SIcenowy Zheng 	MBUS_PORT_DI            = 9,
659934aba4SIcenowy Zheng 	MBUS_PORT_DE            = 10,
669934aba4SIcenowy Zheng 	MBUS_PORT_DE_CFD        = 11,
679934aba4SIcenowy Zheng 	MBUS_PORT_UNKNOWN1	= 12,
689934aba4SIcenowy Zheng 	MBUS_PORT_UNKNOWN2	= 13,
699934aba4SIcenowy Zheng 	MBUS_PORT_UNKNOWN3	= 14,
709934aba4SIcenowy Zheng };
719934aba4SIcenowy Zheng 
729934aba4SIcenowy Zheng enum {
739934aba4SIcenowy Zheng 	MBUS_QOS_LOWEST = 0,
749934aba4SIcenowy Zheng 	MBUS_QOS_LOW,
759934aba4SIcenowy Zheng 	MBUS_QOS_HIGH,
769934aba4SIcenowy Zheng 	MBUS_QOS_HIGHEST
779934aba4SIcenowy Zheng };
789934aba4SIcenowy Zheng 
mbus_configure_port(u8 port,bool bwlimit,bool priority,u8 qos,u8 waittime,u8 acs,u16 bwl0,u16 bwl1,u16 bwl2)799934aba4SIcenowy Zheng inline void mbus_configure_port(u8 port,
809934aba4SIcenowy Zheng 				bool bwlimit,
819934aba4SIcenowy Zheng 				bool priority,
829934aba4SIcenowy Zheng 				u8 qos,         /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
839934aba4SIcenowy Zheng 				u8 waittime,    /* 0 .. 0xf */
849934aba4SIcenowy Zheng 				u8 acs,         /* 0 .. 0xff */
859934aba4SIcenowy Zheng 				u16 bwl0,       /* 0 .. 0xffff, bandwidth limit in MB/s */
869934aba4SIcenowy Zheng 				u16 bwl1,
879934aba4SIcenowy Zheng 				u16 bwl2)
889934aba4SIcenowy Zheng {
899934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
909934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
919934aba4SIcenowy Zheng 
929934aba4SIcenowy Zheng 	const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
939934aba4SIcenowy Zheng 			   | (priority ? (1 << 1) : 0)
949934aba4SIcenowy Zheng 			   | ((qos & 0x3) << 2)
959934aba4SIcenowy Zheng 			   | ((waittime & 0xf) << 4)
969934aba4SIcenowy Zheng 			   | ((acs & 0xff) << 8)
979934aba4SIcenowy Zheng 			   | (bwl0 << 16) );
989934aba4SIcenowy Zheng 	const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
999934aba4SIcenowy Zheng 
1009934aba4SIcenowy Zheng 	debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
1019934aba4SIcenowy Zheng 	writel(cfg0, &mctl_com->mcr[port][0]);
1029934aba4SIcenowy Zheng 	writel(cfg1, &mctl_com->mcr[port][1]);
1039934aba4SIcenowy Zheng }
1049934aba4SIcenowy Zheng 
1059934aba4SIcenowy Zheng #define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)	\
1069934aba4SIcenowy Zheng 	mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
1079934aba4SIcenowy Zheng 			    MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
1089934aba4SIcenowy Zheng 
mctl_set_master_priority_h3(void)1099934aba4SIcenowy Zheng static void mctl_set_master_priority_h3(void)
1109934aba4SIcenowy Zheng {
1119934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1129934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1139934aba4SIcenowy Zheng 
1149934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1159934aba4SIcenowy Zheng 	writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
1169934aba4SIcenowy Zheng 
1179934aba4SIcenowy Zheng 	/* set cpu high priority */
1189934aba4SIcenowy Zheng 	writel(0x00000001, &mctl_com->mapr);
1199934aba4SIcenowy Zheng 
1209934aba4SIcenowy Zheng 	MBUS_CONF(   CPU,  true, HIGHEST, 0,  512,  256,  128);
1219934aba4SIcenowy Zheng 	MBUS_CONF(   GPU,  true,    HIGH, 0, 1536, 1024,  256);
1229934aba4SIcenowy Zheng 	MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
1239934aba4SIcenowy Zheng 	MBUS_CONF(   DMA,  true, HIGHEST, 0,  256,  128,   32);
1249934aba4SIcenowy Zheng 	MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
1259934aba4SIcenowy Zheng 	MBUS_CONF(   CSI,  true, HIGHEST, 0,  256,  128,   32);
1269934aba4SIcenowy Zheng 	MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
1279934aba4SIcenowy Zheng 	MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
1289934aba4SIcenowy Zheng 	MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
1299934aba4SIcenowy Zheng 	MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
1309934aba4SIcenowy Zheng 	MBUS_CONF(    DE,  true, HIGHEST, 3, 8192, 6120, 1024);
1319934aba4SIcenowy Zheng 	MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1024,  288,   64);
1329934aba4SIcenowy Zheng }
1339934aba4SIcenowy Zheng 
mctl_set_master_priority_a64(void)1349934aba4SIcenowy Zheng static void mctl_set_master_priority_a64(void)
1359934aba4SIcenowy Zheng {
1369934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1379934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1389934aba4SIcenowy Zheng 
1399934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1409934aba4SIcenowy Zheng 	writel(399, &mctl_com->tmr);
1419934aba4SIcenowy Zheng 	writel((1 << 16), &mctl_com->bwcr);
1429934aba4SIcenowy Zheng 
1439934aba4SIcenowy Zheng 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
1449934aba4SIcenowy Zheng 	 * initialise it */
1459934aba4SIcenowy Zheng 	MBUS_CONF(   CPU,  true, HIGHEST, 0,  160,  100,   80);
1469934aba4SIcenowy Zheng 	MBUS_CONF(   GPU, false,    HIGH, 0, 1536, 1400,  256);
1479934aba4SIcenowy Zheng 	MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
1489934aba4SIcenowy Zheng 	MBUS_CONF(   DMA,  true,    HIGH, 0,  256,   80,  100);
1499934aba4SIcenowy Zheng 	MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
1509934aba4SIcenowy Zheng 	MBUS_CONF(   CSI,  true,    HIGH, 0,  256,  128,    0);
1519934aba4SIcenowy Zheng 	MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
1529934aba4SIcenowy Zheng 	MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
1539934aba4SIcenowy Zheng 	MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
1549934aba4SIcenowy Zheng 	MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
1559934aba4SIcenowy Zheng 	MBUS_CONF(    DE,  true,    HIGH, 2, 8192, 6144, 2048);
1569934aba4SIcenowy Zheng 	MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1280,  144,   64);
1579934aba4SIcenowy Zheng 
1589934aba4SIcenowy Zheng 	writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
1599934aba4SIcenowy Zheng }
1609934aba4SIcenowy Zheng 
mctl_set_master_priority_h5(void)1619934aba4SIcenowy Zheng static void mctl_set_master_priority_h5(void)
1629934aba4SIcenowy Zheng {
1639934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1649934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1659934aba4SIcenowy Zheng 
1669934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1679934aba4SIcenowy Zheng 	writel(399, &mctl_com->tmr);
1689934aba4SIcenowy Zheng 	writel((1 << 16), &mctl_com->bwcr);
1699934aba4SIcenowy Zheng 
1709934aba4SIcenowy Zheng 	/* set cpu high priority */
1719934aba4SIcenowy Zheng 	writel(0x00000001, &mctl_com->mapr);
1729934aba4SIcenowy Zheng 
1739934aba4SIcenowy Zheng 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet
1749934aba4SIcenowy Zheng 	 * they initialise it */
1759934aba4SIcenowy Zheng 	MBUS_CONF(   CPU, true, HIGHEST, 0,  300,  260,  150);
1769934aba4SIcenowy Zheng 	MBUS_CONF(   GPU, true, HIGHEST, 0,  600,  400,  200);
1779934aba4SIcenowy Zheng 	MBUS_CONF(UNUSED, true, HIGHEST, 0,  512,  256,   96);
1789934aba4SIcenowy Zheng 	MBUS_CONF(   DMA, true, HIGHEST, 0,  256,  128,   32);
1799934aba4SIcenowy Zheng 	MBUS_CONF(    VE, true, HIGHEST, 0, 1900, 1500, 1000);
1809934aba4SIcenowy Zheng 	MBUS_CONF(   CSI, true, HIGHEST, 0,  150,  120,  100);
1819934aba4SIcenowy Zheng 	MBUS_CONF(  NAND, true,    HIGH, 0,  256,  128,   64);
1829934aba4SIcenowy Zheng 	MBUS_CONF(    SS, true, HIGHEST, 0,  256,  128,   64);
1839934aba4SIcenowy Zheng 	MBUS_CONF(    TS, true, HIGHEST, 0,  256,  128,   64);
1849934aba4SIcenowy Zheng 	MBUS_CONF(    DI, true,    HIGH, 0, 1024,  256,   64);
1859934aba4SIcenowy Zheng 	MBUS_CONF(    DE, true, HIGHEST, 3, 3400, 2400, 1024);
1869934aba4SIcenowy Zheng 	MBUS_CONF(DE_CFD, true, HIGHEST, 0,  600,  400,  200);
1879934aba4SIcenowy Zheng }
1889934aba4SIcenowy Zheng 
mctl_set_master_priority_r40(void)1899934aba4SIcenowy Zheng static void mctl_set_master_priority_r40(void)
1909934aba4SIcenowy Zheng {
1919934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
1929934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1939934aba4SIcenowy Zheng 
1949934aba4SIcenowy Zheng 	/* enable bandwidth limit windows and set windows size 1us */
1959934aba4SIcenowy Zheng 	writel(399, &mctl_com->tmr);
1969934aba4SIcenowy Zheng 	writel((1 << 16), &mctl_com->bwcr);
1979934aba4SIcenowy Zheng 
1989934aba4SIcenowy Zheng 	/* set cpu high priority */
1999934aba4SIcenowy Zheng 	writel(0x00000001, &mctl_com->mapr);
2009934aba4SIcenowy Zheng 
2019934aba4SIcenowy Zheng 	/* Port 2 is reserved per Allwinner's linux-3.10 source, yet
2029934aba4SIcenowy Zheng 	 * they initialise it */
2039934aba4SIcenowy Zheng 	MBUS_CONF(     CPU, true, HIGHEST, 0,  300,  260,  150);
2049934aba4SIcenowy Zheng 	MBUS_CONF(     GPU, true, HIGHEST, 0,  600,  400,  200);
2059934aba4SIcenowy Zheng 	MBUS_CONF(  UNUSED, true, HIGHEST, 0,  512,  256,   96);
2069934aba4SIcenowy Zheng 	MBUS_CONF(     DMA, true, HIGHEST, 0,  256,  128,   32);
2079934aba4SIcenowy Zheng 	MBUS_CONF(      VE, true, HIGHEST, 0, 1900, 1500, 1000);
2089934aba4SIcenowy Zheng 	MBUS_CONF(     CSI, true, HIGHEST, 0,  150,  120,  100);
2099934aba4SIcenowy Zheng 	MBUS_CONF(    NAND, true,    HIGH, 0,  256,  128,   64);
2109934aba4SIcenowy Zheng 	MBUS_CONF(      SS, true, HIGHEST, 0,  256,  128,   64);
2119934aba4SIcenowy Zheng 	MBUS_CONF(      TS, true, HIGHEST, 0,  256,  128,   64);
2129934aba4SIcenowy Zheng 	MBUS_CONF(      DI, true,    HIGH, 0, 1024,  256,   64);
2139934aba4SIcenowy Zheng 
2149934aba4SIcenowy Zheng 	/*
2159934aba4SIcenowy Zheng 	 * The port names are probably wrong, but no correct sources
2169934aba4SIcenowy Zheng 	 * are available.
2179934aba4SIcenowy Zheng 	 */
2189934aba4SIcenowy Zheng 	MBUS_CONF(      DE, true,    HIGH, 0,  128,   48,    0);
2199934aba4SIcenowy Zheng 	MBUS_CONF(  DE_CFD, true,    HIGH, 0,  384,  256,    0);
2209934aba4SIcenowy Zheng 	MBUS_CONF(UNKNOWN1, true, HIGHEST, 0,  512,  384,  256);
2219934aba4SIcenowy Zheng 	MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
2229934aba4SIcenowy Zheng 	MBUS_CONF(UNKNOWN3, true,    HIGH, 0, 1280,  144,   64);
2239934aba4SIcenowy Zheng }
2249934aba4SIcenowy Zheng 
mctl_set_master_priority(uint16_t socid)2259934aba4SIcenowy Zheng static void mctl_set_master_priority(uint16_t socid)
2269934aba4SIcenowy Zheng {
2279934aba4SIcenowy Zheng 	switch (socid) {
2289934aba4SIcenowy Zheng 	case SOCID_H3:
2299934aba4SIcenowy Zheng 		mctl_set_master_priority_h3();
2309934aba4SIcenowy Zheng 		return;
2319934aba4SIcenowy Zheng 	case SOCID_A64:
2329934aba4SIcenowy Zheng 		mctl_set_master_priority_a64();
2339934aba4SIcenowy Zheng 		return;
2349934aba4SIcenowy Zheng 	case SOCID_H5:
2359934aba4SIcenowy Zheng 		mctl_set_master_priority_h5();
2369934aba4SIcenowy Zheng 		return;
2379934aba4SIcenowy Zheng 	case SOCID_R40:
2389934aba4SIcenowy Zheng 		mctl_set_master_priority_r40();
2399934aba4SIcenowy Zheng 		return;
2409934aba4SIcenowy Zheng 	}
2419934aba4SIcenowy Zheng }
2429934aba4SIcenowy Zheng 
bin_to_mgray(int val)2439934aba4SIcenowy Zheng static u32 bin_to_mgray(int val)
2449934aba4SIcenowy Zheng {
2459934aba4SIcenowy Zheng 	static const u8 lookup_table[32] = {
2469934aba4SIcenowy Zheng 		0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
2479934aba4SIcenowy Zheng 		0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
2489934aba4SIcenowy Zheng 		0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
2499934aba4SIcenowy Zheng 		0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
2509934aba4SIcenowy Zheng 	};
2519934aba4SIcenowy Zheng 
2529934aba4SIcenowy Zheng 	return lookup_table[clamp(val, 0, 31)];
2539934aba4SIcenowy Zheng }
2549934aba4SIcenowy Zheng 
mgray_to_bin(u32 val)2559934aba4SIcenowy Zheng static int mgray_to_bin(u32 val)
2569934aba4SIcenowy Zheng {
2579934aba4SIcenowy Zheng 	static const u8 lookup_table[32] = {
2589934aba4SIcenowy Zheng 		0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
2599934aba4SIcenowy Zheng 		0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
2609934aba4SIcenowy Zheng 		0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
2619934aba4SIcenowy Zheng 		0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
2629934aba4SIcenowy Zheng 	};
2639934aba4SIcenowy Zheng 
2649934aba4SIcenowy Zheng 	return lookup_table[val & 0x1f];
2659934aba4SIcenowy Zheng }
2669934aba4SIcenowy Zheng 
mctl_h3_zq_calibration_quirk(struct dram_para * para)2679934aba4SIcenowy Zheng static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
2689934aba4SIcenowy Zheng {
2699934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
2709934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
27187098d70SIcenowy Zheng 	int zq_count;
27287098d70SIcenowy Zheng 
27387098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_16BIT
27487098d70SIcenowy Zheng 	zq_count = 4;
27587098d70SIcenowy Zheng #else
27687098d70SIcenowy Zheng 	zq_count = 6;
27787098d70SIcenowy Zheng #endif
2789934aba4SIcenowy Zheng 
2799934aba4SIcenowy Zheng 	if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
2809934aba4SIcenowy Zheng 	    (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
2819934aba4SIcenowy Zheng 		u32 reg_val;
2829934aba4SIcenowy Zheng 
2839934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
2849934aba4SIcenowy Zheng 				CONFIG_DRAM_ZQ & 0xffff);
2859934aba4SIcenowy Zheng 
2869934aba4SIcenowy Zheng 		writel(PIR_CLRSR, &mctl_ctl->pir);
2879934aba4SIcenowy Zheng 		mctl_phy_init(PIR_ZCAL);
2889934aba4SIcenowy Zheng 
2899934aba4SIcenowy Zheng 		reg_val = readl(&mctl_ctl->zqdr[0]);
2909934aba4SIcenowy Zheng 		reg_val &= (0x1f << 16) | (0x1f << 0);
2919934aba4SIcenowy Zheng 		reg_val |= reg_val << 8;
2929934aba4SIcenowy Zheng 		writel(reg_val, &mctl_ctl->zqdr[0]);
2939934aba4SIcenowy Zheng 
2949934aba4SIcenowy Zheng 		reg_val = readl(&mctl_ctl->zqdr[1]);
2959934aba4SIcenowy Zheng 		reg_val &= (0x1f << 16) | (0x1f << 0);
2969934aba4SIcenowy Zheng 		reg_val |= reg_val << 8;
2979934aba4SIcenowy Zheng 		writel(reg_val, &mctl_ctl->zqdr[1]);
2989934aba4SIcenowy Zheng 		writel(reg_val, &mctl_ctl->zqdr[2]);
2999934aba4SIcenowy Zheng 	} else {
3009934aba4SIcenowy Zheng 		int i;
3019934aba4SIcenowy Zheng 		u16 zq_val[6];
3029934aba4SIcenowy Zheng 		u8 val;
3039934aba4SIcenowy Zheng 
3049934aba4SIcenowy Zheng 		writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
3059934aba4SIcenowy Zheng 
30687098d70SIcenowy Zheng 		for (i = 0; i < zq_count; i++) {
3079934aba4SIcenowy Zheng 			u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
3089934aba4SIcenowy Zheng 
3099934aba4SIcenowy Zheng 			writel((zq << 20) | (zq << 16) | (zq << 12) |
3109934aba4SIcenowy Zheng 					(zq << 8) | (zq << 4) | (zq << 0),
3119934aba4SIcenowy Zheng 					&mctl_ctl->zqcr);
3129934aba4SIcenowy Zheng 
3139934aba4SIcenowy Zheng 			writel(PIR_CLRSR, &mctl_ctl->pir);
3149934aba4SIcenowy Zheng 			mctl_phy_init(PIR_ZCAL);
3159934aba4SIcenowy Zheng 
3169934aba4SIcenowy Zheng 			zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
3179934aba4SIcenowy Zheng 			writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
3189934aba4SIcenowy Zheng 
3199934aba4SIcenowy Zheng 			writel(PIR_CLRSR, &mctl_ctl->pir);
3209934aba4SIcenowy Zheng 			mctl_phy_init(PIR_ZCAL);
3219934aba4SIcenowy Zheng 
3229934aba4SIcenowy Zheng 			val = readl(&mctl_ctl->zqdr[0]) >> 24;
3239934aba4SIcenowy Zheng 			zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
3249934aba4SIcenowy Zheng 		}
3259934aba4SIcenowy Zheng 
3269934aba4SIcenowy Zheng 		writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
3279934aba4SIcenowy Zheng 		writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
32887098d70SIcenowy Zheng 		if (zq_count > 4)
32987098d70SIcenowy Zheng 			writel((zq_val[5] << 16) | zq_val[4],
33087098d70SIcenowy Zheng 			       &mctl_ctl->zqdr[2]);
3319934aba4SIcenowy Zheng 	}
3329934aba4SIcenowy Zheng }
3339934aba4SIcenowy Zheng 
mctl_set_cr(uint16_t socid,struct dram_para * para)3349934aba4SIcenowy Zheng static void mctl_set_cr(uint16_t socid, struct dram_para *para)
3359934aba4SIcenowy Zheng {
3369934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
3379934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
3389934aba4SIcenowy Zheng 
339f6457ce5SIcenowy Zheng 	writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
340f6457ce5SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DDR3
341f6457ce5SIcenowy Zheng 	       MCTL_CR_DDR3 | MCTL_CR_2T |
34267337e68SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DDR2
34367337e68SIcenowy Zheng 	       MCTL_CR_DDR2 | MCTL_CR_2T |
34472cc9870SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_LPDDR3
34572cc9870SIcenowy Zheng 	       MCTL_CR_LPDDR3 | MCTL_CR_1T |
346f6457ce5SIcenowy Zheng #else
347f6457ce5SIcenowy Zheng #error Unsupported DRAM type!
348f6457ce5SIcenowy Zheng #endif
34966b12526SIcenowy Zheng 	       (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
350f43a0099SIcenowy Zheng 	       MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
3519934aba4SIcenowy Zheng 	       (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
3529934aba4SIcenowy Zheng 	       MCTL_CR_PAGE_SIZE(para->page_size) |
3539934aba4SIcenowy Zheng 	       MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
3549934aba4SIcenowy Zheng 
3559934aba4SIcenowy Zheng 	if (socid == SOCID_R40) {
3569934aba4SIcenowy Zheng 		if (para->dual_rank)
3579934aba4SIcenowy Zheng 			panic("Dual rank memory not supported\n");
3589934aba4SIcenowy Zheng 
3599934aba4SIcenowy Zheng 		/* Mux pin to A15 address line for single rank memory. */
3609934aba4SIcenowy Zheng 		setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
3619934aba4SIcenowy Zheng 	}
3629934aba4SIcenowy Zheng }
3639934aba4SIcenowy Zheng 
mctl_sys_init(uint16_t socid,struct dram_para * para)3649934aba4SIcenowy Zheng static void mctl_sys_init(uint16_t socid, struct dram_para *para)
3659934aba4SIcenowy Zheng {
3669934aba4SIcenowy Zheng 	struct sunxi_ccm_reg * const ccm =
3679934aba4SIcenowy Zheng 			(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
3689934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
3699934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
3709934aba4SIcenowy Zheng 
3719934aba4SIcenowy Zheng 	clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
3729934aba4SIcenowy Zheng 	clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
3739934aba4SIcenowy Zheng 	clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
3749934aba4SIcenowy Zheng 	clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
3759934aba4SIcenowy Zheng 	clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
3769934aba4SIcenowy Zheng 	if (socid == SOCID_A64 || socid == SOCID_R40)
3779934aba4SIcenowy Zheng 		clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
3789934aba4SIcenowy Zheng 	udelay(10);
3799934aba4SIcenowy Zheng 
3809934aba4SIcenowy Zheng 	clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
3819934aba4SIcenowy Zheng 	udelay(1000);
3829934aba4SIcenowy Zheng 
3839934aba4SIcenowy Zheng 	if (socid == SOCID_A64 || socid == SOCID_R40) {
3849934aba4SIcenowy Zheng 		clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
3859934aba4SIcenowy Zheng 		clrsetbits_le32(&ccm->dram_clk_cfg,
3869934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV_MASK |
3879934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_MASK,
3889934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV(1) |
3899934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_PLL11 |
3909934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_UPD);
3919934aba4SIcenowy Zheng 	} else if (socid == SOCID_H3 || socid == SOCID_H5) {
3929934aba4SIcenowy Zheng 		clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
3939934aba4SIcenowy Zheng 		clrsetbits_le32(&ccm->dram_clk_cfg,
3949934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV_MASK |
3959934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_MASK,
3969934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_DIV(1) |
3979934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_SRC_PLL5 |
3989934aba4SIcenowy Zheng 				CCM_DRAMCLK_CFG_UPD);
3999934aba4SIcenowy Zheng 	}
4009934aba4SIcenowy Zheng 	mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
4019934aba4SIcenowy Zheng 
4029934aba4SIcenowy Zheng 	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
4039934aba4SIcenowy Zheng 	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
4049934aba4SIcenowy Zheng 	setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
4059934aba4SIcenowy Zheng 	setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
4069934aba4SIcenowy Zheng 
4079934aba4SIcenowy Zheng 	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
4089934aba4SIcenowy Zheng 	udelay(10);
4099934aba4SIcenowy Zheng 
4109934aba4SIcenowy Zheng 	writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
4119934aba4SIcenowy Zheng 	udelay(500);
4129934aba4SIcenowy Zheng }
4139934aba4SIcenowy Zheng 
4149934aba4SIcenowy Zheng /* These are more guessed based on some Allwinner code. */
4159934aba4SIcenowy Zheng #define DX_GCR_ODT_DYNAMIC	(0x0 << 4)
4169934aba4SIcenowy Zheng #define DX_GCR_ODT_ALWAYS_ON	(0x1 << 4)
4179934aba4SIcenowy Zheng #define DX_GCR_ODT_OFF		(0x2 << 4)
4189934aba4SIcenowy Zheng 
mctl_channel_init(uint16_t socid,struct dram_para * para)4199934aba4SIcenowy Zheng static int mctl_channel_init(uint16_t socid, struct dram_para *para)
4209934aba4SIcenowy Zheng {
4219934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
4229934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
4239934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
4249934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
4259934aba4SIcenowy Zheng 
4269934aba4SIcenowy Zheng 	unsigned int i;
4279934aba4SIcenowy Zheng 
4289934aba4SIcenowy Zheng 	mctl_set_cr(socid, para);
4299934aba4SIcenowy Zheng 	mctl_set_timing_params(socid, para);
4309934aba4SIcenowy Zheng 	mctl_set_master_priority(socid);
4319934aba4SIcenowy Zheng 
4329934aba4SIcenowy Zheng 	/* setting VTC, default disable all VT */
4339934aba4SIcenowy Zheng 	clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
4349934aba4SIcenowy Zheng 	if (socid == SOCID_H5)
4359934aba4SIcenowy Zheng 		setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
4369934aba4SIcenowy Zheng 	else
4379934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
4389934aba4SIcenowy Zheng 
4399934aba4SIcenowy Zheng 	/* increase DFI_PHY_UPD clock */
4409934aba4SIcenowy Zheng 	writel(PROTECT_MAGIC, &mctl_com->protect);
4419934aba4SIcenowy Zheng 	udelay(100);
4429934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
4439934aba4SIcenowy Zheng 	writel(0x0, &mctl_com->protect);
4449934aba4SIcenowy Zheng 	udelay(100);
4459934aba4SIcenowy Zheng 
4469934aba4SIcenowy Zheng 	/* set dramc odt */
4479934aba4SIcenowy Zheng 	for (i = 0; i < 4; i++) {
4489934aba4SIcenowy Zheng 		u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
4499934aba4SIcenowy Zheng 				(0x3 << 12) | (0x3 << 14);
4509934aba4SIcenowy Zheng 		u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
4519934aba4SIcenowy Zheng 				DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
4529934aba4SIcenowy Zheng 
4539934aba4SIcenowy Zheng 		if (socid == SOCID_H5) {
4549934aba4SIcenowy Zheng 			clearmask |= 0x2 << 8;
4559934aba4SIcenowy Zheng 			setmask |= 0x4 << 8;
4569934aba4SIcenowy Zheng 		}
4579934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
4589934aba4SIcenowy Zheng 	}
4599934aba4SIcenowy Zheng 
4609934aba4SIcenowy Zheng 	/* AC PDR should always ON */
4619934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
4629934aba4SIcenowy Zheng 			0x1 << 1);
4639934aba4SIcenowy Zheng 
4649934aba4SIcenowy Zheng 	/* set DQS auto gating PD mode */
4659934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
4669934aba4SIcenowy Zheng 
4679934aba4SIcenowy Zheng 	if (socid == SOCID_H3) {
4689934aba4SIcenowy Zheng 		/* dx ddr_clk & hdr_clk dynamic mode */
4699934aba4SIcenowy Zheng 		clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
4709934aba4SIcenowy Zheng 
4719934aba4SIcenowy Zheng 		/* dphy & aphy phase select 270 degree */
4729934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
4739934aba4SIcenowy Zheng 				(0x1 << 10) | (0x2 << 8));
4749934aba4SIcenowy Zheng 	} else if (socid == SOCID_A64 || socid == SOCID_H5) {
4759934aba4SIcenowy Zheng 		/* dphy & aphy phase select ? */
4769934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
4779934aba4SIcenowy Zheng 				(0x0 << 10) | (0x3 << 8));
4789934aba4SIcenowy Zheng 	} else if (socid == SOCID_R40) {
4799934aba4SIcenowy Zheng 		/* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
4809934aba4SIcenowy Zheng 		clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
4819934aba4SIcenowy Zheng 
4829934aba4SIcenowy Zheng 		/* dphy & aphy phase select ? */
4839934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
4849934aba4SIcenowy Zheng 				(0x0 << 10) | (0x3 << 8));
4859934aba4SIcenowy Zheng 	}
4869934aba4SIcenowy Zheng 
4879934aba4SIcenowy Zheng 	/* set half DQ */
488f43a0099SIcenowy Zheng 	if (!para->bus_full_width) {
48987098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
4909934aba4SIcenowy Zheng 		writel(0x0, &mctl_ctl->dx[2].gcr);
4919934aba4SIcenowy Zheng 		writel(0x0, &mctl_ctl->dx[3].gcr);
49287098d70SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
49387098d70SIcenowy Zheng 		writel(0x0, &mctl_ctl->dx[1].gcr);
49487098d70SIcenowy Zheng #else
49587098d70SIcenowy Zheng #error Unsupported DRAM bus width!
49687098d70SIcenowy Zheng #endif
4979934aba4SIcenowy Zheng 	}
4989934aba4SIcenowy Zheng 
4999934aba4SIcenowy Zheng 	/* data training configuration */
5009934aba4SIcenowy Zheng 	clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
5019934aba4SIcenowy Zheng 			(para->dual_rank ? 0x3 : 0x1) << 24);
5029934aba4SIcenowy Zheng 
5039934aba4SIcenowy Zheng 	mctl_set_bit_delays(para);
5049934aba4SIcenowy Zheng 	udelay(50);
5059934aba4SIcenowy Zheng 
5069934aba4SIcenowy Zheng 	if (socid == SOCID_H3) {
5079934aba4SIcenowy Zheng 		mctl_h3_zq_calibration_quirk(para);
5089934aba4SIcenowy Zheng 
5099934aba4SIcenowy Zheng 		mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
5109934aba4SIcenowy Zheng 			      PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
5119934aba4SIcenowy Zheng 	} else if (socid == SOCID_A64 || socid == SOCID_H5) {
5129934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
5139934aba4SIcenowy Zheng 
5149934aba4SIcenowy Zheng 		mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
5159934aba4SIcenowy Zheng 			      PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
5169934aba4SIcenowy Zheng 		/* no PIR_QSGATE for H5 ???? */
5179934aba4SIcenowy Zheng 	} else if (socid == SOCID_R40) {
5189934aba4SIcenowy Zheng 		clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
5199934aba4SIcenowy Zheng 
5209934aba4SIcenowy Zheng 		mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
5219934aba4SIcenowy Zheng 			      PIR_DRAMRST | PIR_DRAMINIT);
5229934aba4SIcenowy Zheng 	}
5239934aba4SIcenowy Zheng 
5249934aba4SIcenowy Zheng 	/* detect ranks and bus width */
5259934aba4SIcenowy Zheng 	if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
5269934aba4SIcenowy Zheng 		/* only one rank */
52787098d70SIcenowy Zheng 		if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
52887098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
52987098d70SIcenowy Zheng 		    || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
53087098d70SIcenowy Zheng #endif
53187098d70SIcenowy Zheng 		    ) {
5329934aba4SIcenowy Zheng 			clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
5339934aba4SIcenowy Zheng 			para->dual_rank = 0;
5349934aba4SIcenowy Zheng 		}
5359934aba4SIcenowy Zheng 
5369934aba4SIcenowy Zheng 		/* only half DQ width */
53787098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
5389934aba4SIcenowy Zheng 		if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
5399934aba4SIcenowy Zheng 		    ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
5409934aba4SIcenowy Zheng 			writel(0x0, &mctl_ctl->dx[2].gcr);
5419934aba4SIcenowy Zheng 			writel(0x0, &mctl_ctl->dx[3].gcr);
542f43a0099SIcenowy Zheng 			para->bus_full_width = 0;
5439934aba4SIcenowy Zheng 		}
54487098d70SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
54587098d70SIcenowy Zheng 		if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
54687098d70SIcenowy Zheng 			writel(0x0, &mctl_ctl->dx[1].gcr);
54787098d70SIcenowy Zheng 			para->bus_full_width = 0;
54887098d70SIcenowy Zheng 		}
54987098d70SIcenowy Zheng #endif
5509934aba4SIcenowy Zheng 
5519934aba4SIcenowy Zheng 		mctl_set_cr(socid, para);
5529934aba4SIcenowy Zheng 		udelay(20);
5539934aba4SIcenowy Zheng 
5549934aba4SIcenowy Zheng 		/* re-train */
5559934aba4SIcenowy Zheng 		mctl_phy_init(PIR_QSGATE);
5569934aba4SIcenowy Zheng 		if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
5579934aba4SIcenowy Zheng 			return 1;
5589934aba4SIcenowy Zheng 	}
5599934aba4SIcenowy Zheng 
5609934aba4SIcenowy Zheng 	/* check the dramc status */
5619934aba4SIcenowy Zheng 	mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
5629934aba4SIcenowy Zheng 
5639934aba4SIcenowy Zheng 	/* liuke added for refresh debug */
5649934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
5659934aba4SIcenowy Zheng 	udelay(10);
5669934aba4SIcenowy Zheng 	clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
5679934aba4SIcenowy Zheng 	udelay(10);
5689934aba4SIcenowy Zheng 
5699934aba4SIcenowy Zheng 	/* set PGCR3, CKE polarity */
5709934aba4SIcenowy Zheng 	if (socid == SOCID_H3)
5719934aba4SIcenowy Zheng 		writel(0x00aa0060, &mctl_ctl->pgcr[3]);
5729934aba4SIcenowy Zheng 	else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
5739934aba4SIcenowy Zheng 		writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
5749934aba4SIcenowy Zheng 
5759934aba4SIcenowy Zheng 	/* power down zq calibration module for power save */
5769934aba4SIcenowy Zheng 	setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
5779934aba4SIcenowy Zheng 
5789934aba4SIcenowy Zheng 	/* enable master access */
5799934aba4SIcenowy Zheng 	writel(0xffffffff, &mctl_com->maer);
5809934aba4SIcenowy Zheng 
5819934aba4SIcenowy Zheng 	return 0;
5829934aba4SIcenowy Zheng }
5839934aba4SIcenowy Zheng 
mctl_auto_detect_dram_size(uint16_t socid,struct dram_para * para)5849934aba4SIcenowy Zheng static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
5859934aba4SIcenowy Zheng {
5869934aba4SIcenowy Zheng 	/* detect row address bits */
5879934aba4SIcenowy Zheng 	para->page_size = 512;
5889934aba4SIcenowy Zheng 	para->row_bits = 16;
58966b12526SIcenowy Zheng 	para->bank_bits = 2;
5909934aba4SIcenowy Zheng 	mctl_set_cr(socid, para);
5919934aba4SIcenowy Zheng 
5929934aba4SIcenowy Zheng 	for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
59366b12526SIcenowy Zheng 		if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
59466b12526SIcenowy Zheng 			break;
59566b12526SIcenowy Zheng 
59666b12526SIcenowy Zheng 	/* detect bank address bits */
59766b12526SIcenowy Zheng 	para->bank_bits = 3;
59866b12526SIcenowy Zheng 	mctl_set_cr(socid, para);
59966b12526SIcenowy Zheng 
60066b12526SIcenowy Zheng 	for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
60166b12526SIcenowy Zheng 		if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
6029934aba4SIcenowy Zheng 			break;
6039934aba4SIcenowy Zheng 
6049934aba4SIcenowy Zheng 	/* detect page size */
6059934aba4SIcenowy Zheng 	para->page_size = 8192;
6069934aba4SIcenowy Zheng 	mctl_set_cr(socid, para);
6079934aba4SIcenowy Zheng 
6089934aba4SIcenowy Zheng 	for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
6099934aba4SIcenowy Zheng 		if (mctl_mem_matches(para->page_size))
6109934aba4SIcenowy Zheng 			break;
6119934aba4SIcenowy Zheng }
6129934aba4SIcenowy Zheng 
6139934aba4SIcenowy Zheng /*
6149934aba4SIcenowy Zheng  * The actual values used here are taken from Allwinner provided boot0
6159934aba4SIcenowy Zheng  * binaries, though they are probably board specific, so would likely benefit
6169934aba4SIcenowy Zheng  * from invidual tuning for each board. Apparently a lot of boards copy from
6179934aba4SIcenowy Zheng  * some Allwinner reference design, so we go with those generic values for now
6189934aba4SIcenowy Zheng  * in the hope that they are reasonable for most (all?) boards.
6199934aba4SIcenowy Zheng  */
6209934aba4SIcenowy Zheng #define SUN8I_H3_DX_READ_DELAYS					\
6219934aba4SIcenowy Zheng 	{{ 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
6229934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
6239934aba4SIcenowy Zheng 	 { 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
6249934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 }}
6259934aba4SIcenowy Zheng #define SUN8I_H3_DX_WRITE_DELAYS				\
6269934aba4SIcenowy Zheng 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
6279934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
6289934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
6299934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  6 }}
6309934aba4SIcenowy Zheng #define SUN8I_H3_AC_DELAYS					\
6319934aba4SIcenowy Zheng 	{  0,  0,  0,  0,  0,  0,  0,  0,			\
6329934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
6339934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
6349934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0      }
6359934aba4SIcenowy Zheng 
6369934aba4SIcenowy Zheng #define SUN8I_R40_DX_READ_DELAYS				\
6379934aba4SIcenowy Zheng 	{{ 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
6389934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
6399934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
6409934aba4SIcenowy Zheng 	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 } }
6419934aba4SIcenowy Zheng #define SUN8I_R40_DX_WRITE_DELAYS				\
6429934aba4SIcenowy Zheng 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
6439934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
6449934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 },	\
6459934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0 } }
6469934aba4SIcenowy Zheng #define SUN8I_R40_AC_DELAYS					\
6479934aba4SIcenowy Zheng 	{  0,  0,  3,  0,  0,  0,  0,  0,			\
6489934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
6499934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0,  0,			\
6509934aba4SIcenowy Zheng 	   0,  0,  0,  0,  0,  0,  0      }
6519934aba4SIcenowy Zheng 
6529934aba4SIcenowy Zheng #define SUN50I_A64_DX_READ_DELAYS				\
6539934aba4SIcenowy Zheng 	{{ 16, 16, 16, 16, 17, 16, 16, 17, 16,  1,  0 },	\
6549934aba4SIcenowy Zheng 	 { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 },	\
6559934aba4SIcenowy Zheng 	 { 16, 17, 17, 16, 16, 16, 16, 16, 16,  0,  0 },	\
6569934aba4SIcenowy Zheng 	 { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 }}
6579934aba4SIcenowy Zheng #define SUN50I_A64_DX_WRITE_DELAYS				\
6589934aba4SIcenowy Zheng 	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15 },	\
6599934aba4SIcenowy Zheng 	 {  0,  0,  0,  0,  1,  1,  1,  1,  0, 10, 10 },	\
6609934aba4SIcenowy Zheng 	 {  1,  0,  1,  1,  1,  1,  1,  1,  0, 11, 11 },	\
6619934aba4SIcenowy Zheng 	 {  1,  0,  0,  1,  1,  1,  1,  1,  0, 12, 12 }}
6629934aba4SIcenowy Zheng #define SUN50I_A64_AC_DELAYS					\
6639934aba4SIcenowy Zheng 	{  5,  5, 13, 10,  2,  5,  3,  3,			\
6649934aba4SIcenowy Zheng 	   0,  3,  3,  3,  1,  0,  0,  0,			\
6659934aba4SIcenowy Zheng 	   3,  4,  0,  3,  4,  1,  4,  0,			\
6669934aba4SIcenowy Zheng 	   1,  1,  0,  1, 13,  5,  4      }
6679934aba4SIcenowy Zheng 
6689934aba4SIcenowy Zheng #define SUN8I_H5_DX_READ_DELAYS					\
6699934aba4SIcenowy Zheng 	{{ 14, 15, 17, 17, 17, 17, 17, 18, 17,  3,  3 },	\
6709934aba4SIcenowy Zheng 	 { 21, 21, 12, 22, 21, 21, 21, 21, 21,  3,  3 },	\
6719934aba4SIcenowy Zheng 	 { 16, 19, 19, 17, 22, 22, 21, 22, 19,  3,  3 },	\
6729934aba4SIcenowy Zheng 	 { 21, 21, 22, 22, 20, 21, 19, 19, 19,  3,  3 } }
6739934aba4SIcenowy Zheng #define SUN8I_H5_DX_WRITE_DELAYS				\
6749934aba4SIcenowy Zheng 	{{  1,  2,  3,  4,  3,  4,  4,  4,  6,  6,  6 },	\
6759934aba4SIcenowy Zheng 	 {  6,  6,  6,  5,  5,  5,  5,  5,  6,  6,  6 },	\
6769934aba4SIcenowy Zheng 	 {  0,  2,  4,  2,  6,  5,  5,  5,  6,  6,  6 },	\
6779934aba4SIcenowy Zheng 	 {  3,  3,  3,  2,  2,  1,  1,  1,  4,  4,  4 } }
6789934aba4SIcenowy Zheng #define SUN8I_H5_AC_DELAYS					\
6799934aba4SIcenowy Zheng 	{  0,  0,  5,  5,  0,  0,  0,  0,			\
6809934aba4SIcenowy Zheng 	   0,  0,  0,  0,  3,  3,  3,  3,			\
6819934aba4SIcenowy Zheng 	   3,  3,  3,  3,  3,  3,  3,  3,			\
6829934aba4SIcenowy Zheng 	   3,  3,  3,  3,  2,  0,  0      }
6839934aba4SIcenowy Zheng 
sunxi_dram_init(void)6849934aba4SIcenowy Zheng unsigned long sunxi_dram_init(void)
6859934aba4SIcenowy Zheng {
6869934aba4SIcenowy Zheng 	struct sunxi_mctl_com_reg * const mctl_com =
6879934aba4SIcenowy Zheng 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
6889934aba4SIcenowy Zheng 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
6899934aba4SIcenowy Zheng 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
6909934aba4SIcenowy Zheng 
6919934aba4SIcenowy Zheng 	struct dram_para para = {
692176868bcSIcenowy Zheng 		.dual_rank = 1,
693f43a0099SIcenowy Zheng 		.bus_full_width = 1,
6949934aba4SIcenowy Zheng 		.row_bits = 15,
69566b12526SIcenowy Zheng 		.bank_bits = 3,
6969934aba4SIcenowy Zheng 		.page_size = 4096,
6979934aba4SIcenowy Zheng 
6989934aba4SIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_H3)
6999934aba4SIcenowy Zheng 		.dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
7009934aba4SIcenowy Zheng 		.dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
7019934aba4SIcenowy Zheng 		.ac_delays	 = SUN8I_H3_AC_DELAYS,
7029934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_R40)
7039934aba4SIcenowy Zheng 		.dx_read_delays  = SUN8I_R40_DX_READ_DELAYS,
7049934aba4SIcenowy Zheng 		.dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
7059934aba4SIcenowy Zheng 		.ac_delays	 = SUN8I_R40_AC_DELAYS,
7069934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I)
7079934aba4SIcenowy Zheng 		.dx_read_delays  = SUN50I_A64_DX_READ_DELAYS,
7089934aba4SIcenowy Zheng 		.dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
7099934aba4SIcenowy Zheng 		.ac_delays	 = SUN50I_A64_AC_DELAYS,
7109934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I_H5)
7119934aba4SIcenowy Zheng 		.dx_read_delays  = SUN8I_H5_DX_READ_DELAYS,
7129934aba4SIcenowy Zheng 		.dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
7139934aba4SIcenowy Zheng 		.ac_delays	 = SUN8I_H5_AC_DELAYS,
7149934aba4SIcenowy Zheng #endif
7159934aba4SIcenowy Zheng 	};
7169934aba4SIcenowy Zheng /*
7179934aba4SIcenowy Zheng  * Let the compiler optimize alternatives away by passing this value into
7189934aba4SIcenowy Zheng  * the static functions. This saves us #ifdefs, but still keeps the binary
7199934aba4SIcenowy Zheng  * small.
7209934aba4SIcenowy Zheng  */
7219934aba4SIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_H3)
7229934aba4SIcenowy Zheng 	uint16_t socid = SOCID_H3;
7239934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_R40)
7249934aba4SIcenowy Zheng 	uint16_t socid = SOCID_R40;
725176868bcSIcenowy Zheng 	/* Currently we cannot support R40 with dual rank memory */
726176868bcSIcenowy Zheng 	para.dual_rank = 0;
7273ec0698bSIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_V3S)
7283ec0698bSIcenowy Zheng 	/* TODO: set delays and mbus priority for V3s */
7293ec0698bSIcenowy Zheng 	uint16_t socid = SOCID_H3;
7309934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I)
7319934aba4SIcenowy Zheng 	uint16_t socid = SOCID_A64;
7329934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I_H5)
7339934aba4SIcenowy Zheng 	uint16_t socid = SOCID_H5;
7349934aba4SIcenowy Zheng #endif
7359934aba4SIcenowy Zheng 
7369934aba4SIcenowy Zheng 	mctl_sys_init(socid, &para);
7379934aba4SIcenowy Zheng 	if (mctl_channel_init(socid, &para))
7389934aba4SIcenowy Zheng 		return 0;
7399934aba4SIcenowy Zheng 
7409934aba4SIcenowy Zheng 	if (para.dual_rank)
7419934aba4SIcenowy Zheng 		writel(0x00000303, &mctl_ctl->odtmap);
7429934aba4SIcenowy Zheng 	else
7439934aba4SIcenowy Zheng 		writel(0x00000201, &mctl_ctl->odtmap);
7449934aba4SIcenowy Zheng 	udelay(1);
7459934aba4SIcenowy Zheng 
7469934aba4SIcenowy Zheng 	/* odt delay */
7479934aba4SIcenowy Zheng 	if (socid == SOCID_H3)
7489934aba4SIcenowy Zheng 		writel(0x0c000400, &mctl_ctl->odtcfg);
7499934aba4SIcenowy Zheng 
7509934aba4SIcenowy Zheng 	if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
7519934aba4SIcenowy Zheng 		/* VTF enable (tpr13[8] == 1) */
7529934aba4SIcenowy Zheng 		setbits_le32(&mctl_ctl->vtfcr,
7539934aba4SIcenowy Zheng 			     (socid != SOCID_A64 ? 3 : 2) << 8);
7549934aba4SIcenowy Zheng 		/* DQ hold disable (tpr13[26] == 1) */
7559934aba4SIcenowy Zheng 		clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
7569934aba4SIcenowy Zheng 	}
7579934aba4SIcenowy Zheng 
7589934aba4SIcenowy Zheng 	/* clear credit value */
7599934aba4SIcenowy Zheng 	setbits_le32(&mctl_com->cccr, 1 << 31);
7609934aba4SIcenowy Zheng 	udelay(10);
7619934aba4SIcenowy Zheng 
7629934aba4SIcenowy Zheng 	mctl_auto_detect_dram_size(socid, &para);
7639934aba4SIcenowy Zheng 	mctl_set_cr(socid, &para);
7649934aba4SIcenowy Zheng 
76566b12526SIcenowy Zheng 	return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
7669934aba4SIcenowy Zheng 	       (para.dual_rank ? 2 : 1);
7679934aba4SIcenowy Zheng }
768