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