xref: /rk3399_rockchip-uboot/drivers/ram/rockchip/sdram_px30.c (revision f588f59eac0afdfa1a2245ae1a95d4cfec9d943f)
11881cdb1SYouMin Chen // SPDX-License-Identifier: GPL-2.0
25eeb396bSKever Yang /*
31881cdb1SYouMin Chen  * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
45eeb396bSKever Yang  */
55eeb396bSKever Yang 
65eeb396bSKever Yang #include <common.h>
71881cdb1SYouMin Chen #include <debug_uart.h>
85eeb396bSKever Yang #include <dm.h>
95eeb396bSKever Yang #include <ram.h>
105eeb396bSKever Yang #include <syscon.h>
111881cdb1SYouMin Chen #include <asm/io.h>
125eeb396bSKever Yang #include <asm/arch/clock.h>
131881cdb1SYouMin Chen #include <asm/arch/cru_px30.h>
145eeb396bSKever Yang #include <asm/arch/grf_px30.h>
151881cdb1SYouMin Chen #include <asm/arch/hardware.h>
165eeb396bSKever Yang #include <asm/arch/sdram_common.h>
171881cdb1SYouMin Chen #include <asm/arch/sdram_px30.h>
181881cdb1SYouMin Chen 
191881cdb1SYouMin Chen /*
201881cdb1SYouMin Chen  * Because px30 sram size is small, so need define CONFIG_TPL_TINY_FRAMEWORK
211881cdb1SYouMin Chen  * to reduce TPL size when build TPL firmware.
221881cdb1SYouMin Chen  */
231881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD
241881cdb1SYouMin Chen #ifndef CONFIG_TPL_TINY_FRAMEWORK
251881cdb1SYouMin Chen #error please defined CONFIG_TPL_TINY_FRAMEWORK for px30 !!!
261881cdb1SYouMin Chen #endif
271881cdb1SYouMin Chen #endif
285eeb396bSKever Yang 
29cf41a383STang Yun ping #ifdef CONFIG_TPL_BUILD
30cf41a383STang Yun ping 
315eeb396bSKever Yang DECLARE_GLOBAL_DATA_PTR;
325eeb396bSKever Yang struct dram_info {
331881cdb1SYouMin Chen 	struct px30_ddr_pctl_regs *pctl;
341881cdb1SYouMin Chen 	struct px30_ddr_phy_regs *phy;
351881cdb1SYouMin Chen 	struct px30_cru *cru;
361881cdb1SYouMin Chen 	struct px30_msch_regs *msch;
371881cdb1SYouMin Chen 	struct px30_ddr_grf_regs *ddr_grf;
381881cdb1SYouMin Chen 	struct px30_grf *grf;
395eeb396bSKever Yang 	struct ram_info info;
405eeb396bSKever Yang 	struct px30_pmugrf *pmugrf;
415eeb396bSKever Yang };
425eeb396bSKever Yang 
431881cdb1SYouMin Chen #define PMUGRF_BASE_ADDR		0xFF010000
441881cdb1SYouMin Chen #define CRU_BASE_ADDR			0xFF2B0000
451881cdb1SYouMin Chen #define GRF_BASE_ADDR			0xFF140000
461881cdb1SYouMin Chen #define DDRC_BASE_ADDR			0xFF600000
471881cdb1SYouMin Chen #define DDR_PHY_BASE_ADDR		0xFF2A0000
481881cdb1SYouMin Chen #define SERVER_MSCH0_BASE_ADDR		0xFF530000
491881cdb1SYouMin Chen #define DDR_GRF_BASE_ADDR		0xff630000
501881cdb1SYouMin Chen 
511881cdb1SYouMin Chen struct dram_info dram_info;
521881cdb1SYouMin Chen 
531881cdb1SYouMin Chen struct px30_sdram_params sdram_configs[] = {
541881cdb1SYouMin Chen #include	"sdram-px30-lpddr3-detect-333.inc"
551881cdb1SYouMin Chen };
561881cdb1SYouMin Chen 
571881cdb1SYouMin Chen struct px30_ddr_skew skew = {
581881cdb1SYouMin Chen #include	"sdram-px30-ddr_skew.inc"
591881cdb1SYouMin Chen };
601881cdb1SYouMin Chen 
611881cdb1SYouMin Chen static void rkclk_ddr_reset(struct dram_info *dram,
621881cdb1SYouMin Chen 			    u32 ctl_srstn, u32 ctl_psrstn,
631881cdb1SYouMin Chen 			    u32 phy_srstn, u32 phy_psrstn)
641881cdb1SYouMin Chen {
651881cdb1SYouMin Chen 	writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) |
661881cdb1SYouMin Chen 	       upctl2_asrstn_req(ctl_srstn),
671881cdb1SYouMin Chen 	       &dram->cru->softrst_con[1]);
681881cdb1SYouMin Chen 	writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn),
691881cdb1SYouMin Chen 	       &dram->cru->softrst_con[2]);
701881cdb1SYouMin Chen }
711881cdb1SYouMin Chen 
721881cdb1SYouMin Chen static void rkclk_set_dpll(struct dram_info *dram, unsigned int mhz)
731881cdb1SYouMin Chen {
741881cdb1SYouMin Chen 	unsigned int refdiv, postdiv1, postdiv2, fbdiv;
751881cdb1SYouMin Chen 	int delay = 1000;
761881cdb1SYouMin Chen 
771881cdb1SYouMin Chen 	refdiv = 1;
781881cdb1SYouMin Chen 	if (mhz <= 300) {
791881cdb1SYouMin Chen 		postdiv1 = 4;
801881cdb1SYouMin Chen 		postdiv2 = 2;
811881cdb1SYouMin Chen 	} else if (mhz <= 400) {
821881cdb1SYouMin Chen 		postdiv1 = 6;
831881cdb1SYouMin Chen 		postdiv2 = 1;
841881cdb1SYouMin Chen 	} else if (mhz <= 600) {
851881cdb1SYouMin Chen 		postdiv1 = 4;
861881cdb1SYouMin Chen 		postdiv2 = 1;
871881cdb1SYouMin Chen 	} else if (mhz <= 800) {
881881cdb1SYouMin Chen 		postdiv1 = 3;
891881cdb1SYouMin Chen 		postdiv2 = 1;
901881cdb1SYouMin Chen 	} else if (mhz <= 1600) {
911881cdb1SYouMin Chen 		postdiv1 = 2;
921881cdb1SYouMin Chen 		postdiv2 = 1;
931881cdb1SYouMin Chen 	} else {
941881cdb1SYouMin Chen 		postdiv1 = 1;
951881cdb1SYouMin Chen 		postdiv2 = 1;
961881cdb1SYouMin Chen 	}
971881cdb1SYouMin Chen 	fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24;
981881cdb1SYouMin Chen 
991881cdb1SYouMin Chen 	writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode);
1001881cdb1SYouMin Chen 
1011881cdb1SYouMin Chen 	writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0);
1021881cdb1SYouMin Chen 	writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv),
1031881cdb1SYouMin Chen 	       &dram->cru->pll[1].con1);
1041881cdb1SYouMin Chen 
1051881cdb1SYouMin Chen 	while (delay > 0) {
1061881cdb1SYouMin Chen 		udelay(1);
1071881cdb1SYouMin Chen 		if (LOCK(readl(&dram->cru->pll[1].con1)))
1081881cdb1SYouMin Chen 			break;
1091881cdb1SYouMin Chen 		delay--;
1101881cdb1SYouMin Chen 	}
1111881cdb1SYouMin Chen 
1121881cdb1SYouMin Chen 	writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode);
1131881cdb1SYouMin Chen }
1141881cdb1SYouMin Chen 
1151881cdb1SYouMin Chen static void rkclk_configure_ddr(struct dram_info *dram,
1161881cdb1SYouMin Chen 				struct px30_sdram_params *sdram_params)
1171881cdb1SYouMin Chen {
1181881cdb1SYouMin Chen 	/* for inno ddr phy need 2*freq */
1191881cdb1SYouMin Chen 	rkclk_set_dpll(dram,  sdram_params->ddr_freq * 2);
1201881cdb1SYouMin Chen }
1211881cdb1SYouMin Chen 
1221881cdb1SYouMin Chen static void phy_soft_reset(struct dram_info *dram)
1231881cdb1SYouMin Chen {
1241881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
1251881cdb1SYouMin Chen 
1261881cdb1SYouMin Chen 	clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
1271881cdb1SYouMin Chen 	udelay(1);
1281881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
1291881cdb1SYouMin Chen 	udelay(5);
1301881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
1311881cdb1SYouMin Chen 	udelay(1);
1321881cdb1SYouMin Chen }
1331881cdb1SYouMin Chen 
1341881cdb1SYouMin Chen static int pctl_cfg(struct dram_info *dram,
1351881cdb1SYouMin Chen 		    struct px30_sdram_params *sdram_params)
1361881cdb1SYouMin Chen {
1371881cdb1SYouMin Chen 	u32 i;
1381881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
1391881cdb1SYouMin Chen 
1401881cdb1SYouMin Chen 	for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) {
1411881cdb1SYouMin Chen 		writel(sdram_params->pctl_regs.pctl[i][1],
1421881cdb1SYouMin Chen 		       pctl_base + sdram_params->pctl_regs.pctl[i][0]);
1431881cdb1SYouMin Chen 	}
1441881cdb1SYouMin Chen 	clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG,
1451881cdb1SYouMin Chen 			(0xff << 16) | 0x1f,
1461881cdb1SYouMin Chen 			((SR_IDLE & 0xff) << 16) | (PD_IDLE & 0x1f));
1471881cdb1SYouMin Chen 
1481881cdb1SYouMin Chen 	clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL,
1491881cdb1SYouMin Chen 			0xfff << 16,
1501881cdb1SYouMin Chen 			5 << 16);
1511881cdb1SYouMin Chen 	/* disable zqcs */
1521881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31);
1531881cdb1SYouMin Chen 
1541881cdb1SYouMin Chen 	return 0;
1551881cdb1SYouMin Chen }
1561881cdb1SYouMin Chen 
1571881cdb1SYouMin Chen /* return ddrconfig value
1581881cdb1SYouMin Chen  *       (-1), find ddrconfig fail
1591881cdb1SYouMin Chen  *       other, the ddrconfig value
1601881cdb1SYouMin Chen  * only support cs0_row >= cs1_row
1611881cdb1SYouMin Chen  */
1621881cdb1SYouMin Chen static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params)
1631881cdb1SYouMin Chen {
1641881cdb1SYouMin Chen 	u32 bw, die_bw, col, bank;
1651881cdb1SYouMin Chen 	u32 i, tmp;
1661881cdb1SYouMin Chen 	u32 ddrconf = -1;
1671881cdb1SYouMin Chen 
1681881cdb1SYouMin Chen 	bw = sdram_params->ch.bw;
1691881cdb1SYouMin Chen 	die_bw = sdram_params->ch.dbw;
1701881cdb1SYouMin Chen 	col = sdram_params->ch.col;
1711881cdb1SYouMin Chen 	bank = sdram_params->ch.bk;
1721881cdb1SYouMin Chen 
1731881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4) {
1741881cdb1SYouMin Chen 		if (die_bw == 0)
1751881cdb1SYouMin Chen 			ddrconf = 7 + bw;
1761881cdb1SYouMin Chen 		else
1771881cdb1SYouMin Chen 			ddrconf = 12 - bw;
1781881cdb1SYouMin Chen 		ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7];
1791881cdb1SYouMin Chen 	} else {
1801881cdb1SYouMin Chen 		tmp = ((bank - 2) << 3) | (col + bw - 10);
1811881cdb1SYouMin Chen 		for (i = 0; i < 7; i++)
1821881cdb1SYouMin Chen 			if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) {
1831881cdb1SYouMin Chen 				ddrconf = i;
1841881cdb1SYouMin Chen 				break;
1851881cdb1SYouMin Chen 			}
1861881cdb1SYouMin Chen 		if (i > 6)
1871881cdb1SYouMin Chen 			printascii("calculate ddrconfig error\n");
1881881cdb1SYouMin Chen 	}
1891881cdb1SYouMin Chen 
1901881cdb1SYouMin Chen 	return ddrconf;
1911881cdb1SYouMin Chen }
1921881cdb1SYouMin Chen 
1931881cdb1SYouMin Chen /* n: Unit bytes */
1941881cdb1SYouMin Chen static void copy_to_reg(u32 *dest, u32 *src, u32 n)
1951881cdb1SYouMin Chen {
1961881cdb1SYouMin Chen 	int i;
1971881cdb1SYouMin Chen 
1981881cdb1SYouMin Chen 	for (i = 0; i < n / sizeof(u32); i++) {
1991881cdb1SYouMin Chen 		writel(*src, dest);
2001881cdb1SYouMin Chen 		src++;
2011881cdb1SYouMin Chen 		dest++;
2021881cdb1SYouMin Chen 	}
2031881cdb1SYouMin Chen }
2041881cdb1SYouMin Chen 
2051881cdb1SYouMin Chen /*
2061881cdb1SYouMin Chen  * calculate controller dram address map, and setting to register.
2071881cdb1SYouMin Chen  * argument sdram_params->ch.ddrconf must be right value before
2081881cdb1SYouMin Chen  * call this function.
2091881cdb1SYouMin Chen  */
2101881cdb1SYouMin Chen static void set_ctl_address_map(struct dram_info *dram,
2111881cdb1SYouMin Chen 				struct px30_sdram_params *sdram_params)
2121881cdb1SYouMin Chen {
2131881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
2141881cdb1SYouMin Chen 	u32 cs_pst, bg, max_row, ddrconf;
2151881cdb1SYouMin Chen 	u32 i;
2161881cdb1SYouMin Chen 
2171881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
2181881cdb1SYouMin Chen 		/*
2191881cdb1SYouMin Chen 		 * DDR4 8bit dram BG = 2(4bank groups),
2201881cdb1SYouMin Chen 		 * 16bit dram BG = 1 (2 bank groups)
2211881cdb1SYouMin Chen 		 */
2221881cdb1SYouMin Chen 		bg = (sdram_params->ch.dbw == 0) ? 2 : 1;
2231881cdb1SYouMin Chen 	else
2241881cdb1SYouMin Chen 		bg = 0;
2251881cdb1SYouMin Chen 
2261881cdb1SYouMin Chen 	cs_pst = sdram_params->ch.bw + sdram_params->ch.col +
2271881cdb1SYouMin Chen 		bg + sdram_params->ch.bk + sdram_params->ch.cs0_row;
2281881cdb1SYouMin Chen 	if (cs_pst >= 32 || sdram_params->ch.rank == 1)
2291881cdb1SYouMin Chen 		writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0);
2301881cdb1SYouMin Chen 	else
2311881cdb1SYouMin Chen 		writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0);
2321881cdb1SYouMin Chen 
2331881cdb1SYouMin Chen 	ddrconf = sdram_params->ch.ddrconfig;
2341881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4) {
2351881cdb1SYouMin Chen 		for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) {
2361881cdb1SYouMin Chen 			if (d4_rbc_2_d3_rbc[i] == ddrconf) {
2371881cdb1SYouMin Chen 				ddrconf = 7 + i;
2381881cdb1SYouMin Chen 				break;
2391881cdb1SYouMin Chen 			}
2401881cdb1SYouMin Chen 		}
2411881cdb1SYouMin Chen 	}
2421881cdb1SYouMin Chen 
2431881cdb1SYouMin Chen 	copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1),
2441881cdb1SYouMin Chen 		    &addrmap[ddrconf][0], 8 * 4);
2451881cdb1SYouMin Chen 	max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf);
2461881cdb1SYouMin Chen 
2471881cdb1SYouMin Chen 	if (max_row < 12)
2481881cdb1SYouMin Chen 		printascii("set addrmap fail\n");
2491881cdb1SYouMin Chen 	/* need to disable row ahead of rank by set to 0xf */
2501881cdb1SYouMin Chen 	for (i = 17; i > max_row; i--)
2511881cdb1SYouMin Chen 		clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 +
2521881cdb1SYouMin Chen 			((i - 12) * 8 / 32) * 4,
2531881cdb1SYouMin Chen 			0xf << ((i - 12) * 8 % 32),
2541881cdb1SYouMin Chen 			0xf << ((i - 12) * 8 % 32));
2551881cdb1SYouMin Chen 
2561881cdb1SYouMin Chen 	if ((sdram_params->dramtype == LPDDR3 ||
2571881cdb1SYouMin Chen 	     sdram_params->dramtype == LPDDR2) &&
2581881cdb1SYouMin Chen 		 sdram_params->ch.row_3_4)
2591881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
2601881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4 && sdram_params->ch.bw != 0x2)
2611881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
2621881cdb1SYouMin Chen }
2631881cdb1SYouMin Chen 
2641881cdb1SYouMin Chen static void phy_dll_bypass_set(struct dram_info *dram, u32 freq)
2651881cdb1SYouMin Chen {
2661881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
2671881cdb1SYouMin Chen 	u32 tmp;
2681881cdb1SYouMin Chen 	u32 i, j;
2691881cdb1SYouMin Chen 
2701881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
2711881cdb1SYouMin Chen 	clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
2721881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
2731881cdb1SYouMin Chen 		j = 0x26 + i * 0x10;
2741881cdb1SYouMin Chen 		setbits_le32(PHY_REG(phy_base, j), 1 << 4);
2751881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
2761881cdb1SYouMin Chen 	}
2771881cdb1SYouMin Chen 
2781881cdb1SYouMin Chen 	if (freq <= (400 * MHz))
2791881cdb1SYouMin Chen 		/* DLL bypass */
2801881cdb1SYouMin Chen 		setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
2811881cdb1SYouMin Chen 	else
2821881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
2831881cdb1SYouMin Chen 
2841881cdb1SYouMin Chen 	if (freq <= (801 * MHz))
2851881cdb1SYouMin Chen 		tmp = 2;
2861881cdb1SYouMin Chen 	else
2871881cdb1SYouMin Chen 		tmp = 1;
2881881cdb1SYouMin Chen 
2891881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
2901881cdb1SYouMin Chen 		j = 0x28 + i * 0x10;
2911881cdb1SYouMin Chen 		writel(tmp, PHY_REG(phy_base, j));
2921881cdb1SYouMin Chen 	}
2931881cdb1SYouMin Chen }
2941881cdb1SYouMin Chen 
2951881cdb1SYouMin Chen static void set_ds_odt(struct dram_info *dram,
2961881cdb1SYouMin Chen 		       struct px30_sdram_params *sdram_params)
2971881cdb1SYouMin Chen {
2981881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
2991881cdb1SYouMin Chen 	u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
3001881cdb1SYouMin Chen 	u32 i, j;
3011881cdb1SYouMin Chen 
3021881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR3) {
3031881cdb1SYouMin Chen 		cmd_drv = PHY_DDR3_RON_RTT_34ohm;
3041881cdb1SYouMin Chen 		clk_drv = PHY_DDR3_RON_RTT_45ohm;
3051881cdb1SYouMin Chen 		dqs_drv = PHY_DDR3_RON_RTT_34ohm;
3061881cdb1SYouMin Chen 		dqs_odt = PHY_DDR3_RON_RTT_225ohm;
3071881cdb1SYouMin Chen 	} else {
3081881cdb1SYouMin Chen 		cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
3091881cdb1SYouMin Chen 		clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
3101881cdb1SYouMin Chen 		dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
3111881cdb1SYouMin Chen 		if (sdram_params->dramtype == LPDDR2)
3121881cdb1SYouMin Chen 			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
3131881cdb1SYouMin Chen 		else
3141881cdb1SYouMin Chen 			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
3151881cdb1SYouMin Chen 	}
3161881cdb1SYouMin Chen 	/* DS */
3171881cdb1SYouMin Chen 	writel(cmd_drv, PHY_REG(phy_base, 0x11));
3181881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
3191881cdb1SYouMin Chen 	writel(clk_drv, PHY_REG(phy_base, 0x16));
3201881cdb1SYouMin Chen 	writel(clk_drv, PHY_REG(phy_base, 0x18));
3211881cdb1SYouMin Chen 
3221881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
3231881cdb1SYouMin Chen 		j = 0x20 + i * 0x10;
3241881cdb1SYouMin Chen 		writel(dqs_drv, PHY_REG(phy_base, j));
3251881cdb1SYouMin Chen 		writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
3261881cdb1SYouMin Chen 		/* ODT */
3271881cdb1SYouMin Chen 		writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
3281881cdb1SYouMin Chen 		writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
3291881cdb1SYouMin Chen 	}
3301881cdb1SYouMin Chen }
3311881cdb1SYouMin Chen 
3321881cdb1SYouMin Chen static void phy_cfg(struct dram_info *dram,
3331881cdb1SYouMin Chen 		    struct px30_sdram_params *sdram_params)
3341881cdb1SYouMin Chen {
3351881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
3361881cdb1SYouMin Chen 	u32 i;
3371881cdb1SYouMin Chen 
3381881cdb1SYouMin Chen 	phy_dll_bypass_set(dram, sdram_params->ddr_freq);
3391881cdb1SYouMin Chen 	for (i = 0; sdram_params->phy_regs.phy[i][0] != 0xFFFFFFFF; i++) {
3401881cdb1SYouMin Chen 		writel(sdram_params->phy_regs.phy[i][1],
3411881cdb1SYouMin Chen 		       phy_base + sdram_params->phy_regs.phy[i][0]);
3421881cdb1SYouMin Chen 	}
3431881cdb1SYouMin Chen 	if (sdram_params->ch.bw == 2) {
3441881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
3451881cdb1SYouMin Chen 	} else if (sdram_params->ch.bw == 1) {
3461881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
3471881cdb1SYouMin Chen 		/* disable DQS2,DQS3 tx dll  for saving power */
3481881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
3491881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
3501881cdb1SYouMin Chen 	} else {
3511881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
3521881cdb1SYouMin Chen 		/* disable DQS2,DQS3 tx dll  for saving power */
3531881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
3541881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
3551881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
3561881cdb1SYouMin Chen 	}
3571881cdb1SYouMin Chen 	set_ds_odt(dram, sdram_params);
3581881cdb1SYouMin Chen 
3591881cdb1SYouMin Chen 	/* deskew */
3601881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 2), 8);
3611881cdb1SYouMin Chen 	copy_to_reg(PHY_REG(phy_base, 0xb0),
3621881cdb1SYouMin Chen 		    &sdram_params->skew->a0_a1_skew[0], 15 * 4);
3631881cdb1SYouMin Chen 	copy_to_reg(PHY_REG(phy_base, 0x70),
3641881cdb1SYouMin Chen 		    &sdram_params->skew->cs0_dm0_skew[0], 44 * 4);
3651881cdb1SYouMin Chen 	copy_to_reg(PHY_REG(phy_base, 0xc0),
36628d6bb02SYouMin Chen 		    &sdram_params->skew->cs1_dm0_skew[0], 44 * 4);
3671881cdb1SYouMin Chen }
3681881cdb1SYouMin Chen 
3691881cdb1SYouMin Chen static int update_refresh_reg(struct dram_info *dram)
3701881cdb1SYouMin Chen {
3711881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
3721881cdb1SYouMin Chen 	u32 ret;
3731881cdb1SYouMin Chen 
3741881cdb1SYouMin Chen 	ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1);
3751881cdb1SYouMin Chen 	writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3);
3761881cdb1SYouMin Chen 
3771881cdb1SYouMin Chen 	return 0;
3781881cdb1SYouMin Chen }
3791881cdb1SYouMin Chen 
3801881cdb1SYouMin Chen /*
3811881cdb1SYouMin Chen  * rank = 1: cs0
3821881cdb1SYouMin Chen  * rank = 2: cs1
3831881cdb1SYouMin Chen  */
3841881cdb1SYouMin Chen int read_mr(struct dram_info *dram, u32 rank, u32 mr_num)
3851881cdb1SYouMin Chen {
3861881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
3871881cdb1SYouMin Chen 	void __iomem *ddr_grf_base = dram->ddr_grf;
3881881cdb1SYouMin Chen 
3891881cdb1SYouMin Chen 	writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0);
3901881cdb1SYouMin Chen 	writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1);
3911881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
3921881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
3931881cdb1SYouMin Chen 		continue;
3941881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
3951881cdb1SYouMin Chen 		continue;
3961881cdb1SYouMin Chen 
3971881cdb1SYouMin Chen 	return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff);
3981881cdb1SYouMin Chen }
3991881cdb1SYouMin Chen 
4001881cdb1SYouMin Chen u32 disable_zqcs_arefresh(struct dram_info *dram)
4011881cdb1SYouMin Chen {
4021881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
4031881cdb1SYouMin Chen 	u32 dis_auto_zq = 0;
4041881cdb1SYouMin Chen 
4051881cdb1SYouMin Chen 	/* disable zqcs */
4061881cdb1SYouMin Chen 	if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
4071881cdb1SYouMin Chen 		(1ul << 31))) {
4081881cdb1SYouMin Chen 		dis_auto_zq = 1;
4091881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
4101881cdb1SYouMin Chen 	}
4111881cdb1SYouMin Chen 
4121881cdb1SYouMin Chen 	/* disable auto refresh */
4131881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
4141881cdb1SYouMin Chen 
4151881cdb1SYouMin Chen 	update_refresh_reg(dram);
4161881cdb1SYouMin Chen 
4171881cdb1SYouMin Chen 	return dis_auto_zq;
4181881cdb1SYouMin Chen }
4191881cdb1SYouMin Chen 
4201881cdb1SYouMin Chen void restore_zqcs_arefresh(struct dram_info *dram, u32 dis_auto_zq)
4211881cdb1SYouMin Chen {
4221881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
4231881cdb1SYouMin Chen 
4241881cdb1SYouMin Chen 	/* restore zqcs */
4251881cdb1SYouMin Chen 	if (dis_auto_zq)
4261881cdb1SYouMin Chen 		clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
4271881cdb1SYouMin Chen 
4281881cdb1SYouMin Chen 	/* restore auto refresh */
4291881cdb1SYouMin Chen 	clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
4301881cdb1SYouMin Chen 
4311881cdb1SYouMin Chen 	update_refresh_reg(dram);
4321881cdb1SYouMin Chen }
4331881cdb1SYouMin Chen 
4341881cdb1SYouMin Chen #define MIN(a, b)	(((a) > (b)) ? (b) : (a))
4351881cdb1SYouMin Chen #define MAX(a, b)	(((a) > (b)) ? (a) : (b))
4361881cdb1SYouMin Chen static u32 check_rd_gate(struct dram_info *dram)
4371881cdb1SYouMin Chen {
4381881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
4391881cdb1SYouMin Chen 
4401881cdb1SYouMin Chen 	u32 max_val = 0;
4411881cdb1SYouMin Chen 	u32 min_val = 0xff;
4421881cdb1SYouMin Chen 	u32 gate[4];
4431881cdb1SYouMin Chen 	u32 i, bw;
4441881cdb1SYouMin Chen 
4451881cdb1SYouMin Chen 	bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf;
4461881cdb1SYouMin Chen 	switch (bw) {
4471881cdb1SYouMin Chen 	case 0x1:
4481881cdb1SYouMin Chen 		bw = 1;
4491881cdb1SYouMin Chen 		break;
4501881cdb1SYouMin Chen 	case 0x3:
4511881cdb1SYouMin Chen 		bw = 2;
4521881cdb1SYouMin Chen 		break;
4531881cdb1SYouMin Chen 	case 0xf:
4541881cdb1SYouMin Chen 	default:
4551881cdb1SYouMin Chen 		bw = 4;
4561881cdb1SYouMin Chen 		break;
4571881cdb1SYouMin Chen 	}
4581881cdb1SYouMin Chen 
4591881cdb1SYouMin Chen 	for (i = 0; i < bw; i++) {
4601881cdb1SYouMin Chen 		gate[i] = readl(PHY_REG(phy_base, 0xfb + i));
4611881cdb1SYouMin Chen 		max_val = MAX(max_val, gate[i]);
4621881cdb1SYouMin Chen 		min_val = MIN(min_val, gate[i]);
4631881cdb1SYouMin Chen 	}
4641881cdb1SYouMin Chen 
4651881cdb1SYouMin Chen 	if (max_val > 0x80 || min_val < 0x20)
4661881cdb1SYouMin Chen 		return -1;
4671881cdb1SYouMin Chen 	else
4681881cdb1SYouMin Chen 		return 0;
4691881cdb1SYouMin Chen }
4701881cdb1SYouMin Chen 
4711881cdb1SYouMin Chen static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
4721881cdb1SYouMin Chen {
4731881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
4741881cdb1SYouMin Chen 	u32 ret;
4751881cdb1SYouMin Chen 	u32 dis_auto_zq = 0;
4761881cdb1SYouMin Chen 	u32 odt_val;
4771881cdb1SYouMin Chen 	u32 i, j;
4781881cdb1SYouMin Chen 
4791881cdb1SYouMin Chen 	odt_val = readl(PHY_REG(phy_base, 0x2e));
4801881cdb1SYouMin Chen 
4811881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
4821881cdb1SYouMin Chen 		j = 0x20 + i * 0x10;
4831881cdb1SYouMin Chen 		writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
4841881cdb1SYouMin Chen 		writel(0, PHY_REG(phy_base, j + 0xe));
4851881cdb1SYouMin Chen 	}
4861881cdb1SYouMin Chen 
4871881cdb1SYouMin Chen 	dis_auto_zq = disable_zqcs_arefresh(dram);
4881881cdb1SYouMin Chen 
4891881cdb1SYouMin Chen 	if (dramtype == DDR4) {
4901881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
4911881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
4921881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
4931881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
4941881cdb1SYouMin Chen 	}
4951881cdb1SYouMin Chen 	/* choose training cs */
4961881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
4971881cdb1SYouMin Chen 	/* enable gate training */
4981881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
4991881cdb1SYouMin Chen 	udelay(50);
5001881cdb1SYouMin Chen 	ret = readl(PHY_REG(phy_base, 0xff));
5011881cdb1SYouMin Chen 	/* disable gate training */
5021881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
5031881cdb1SYouMin Chen 	clrbits_le32(PHY_REG(phy_base, 2), 0x30);
5041881cdb1SYouMin Chen 	restore_zqcs_arefresh(dram, dis_auto_zq);
5051881cdb1SYouMin Chen 
5061881cdb1SYouMin Chen 	if (dramtype == DDR4) {
5071881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
5081881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
5091881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
5101881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
5111881cdb1SYouMin Chen 	}
5121881cdb1SYouMin Chen 
5131881cdb1SYouMin Chen 	if (ret & 0x10) {
5141881cdb1SYouMin Chen 		ret = -1;
5151881cdb1SYouMin Chen 	} else {
5161881cdb1SYouMin Chen 		ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
5171881cdb1SYouMin Chen 		ret = (ret == 0) ? 0 : -1;
5181881cdb1SYouMin Chen 	}
5191881cdb1SYouMin Chen 
5201881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
5211881cdb1SYouMin Chen 		j = 0x20 + i * 0x10;
5221881cdb1SYouMin Chen 		writel(odt_val, PHY_REG(phy_base, j + 0x1));
5231881cdb1SYouMin Chen 		writel(odt_val, PHY_REG(phy_base, j + 0xe));
5241881cdb1SYouMin Chen 	}
5251881cdb1SYouMin Chen 
5261881cdb1SYouMin Chen 	return ret;
5271881cdb1SYouMin Chen }
5281881cdb1SYouMin Chen 
5291881cdb1SYouMin Chen /* rank = 1: cs0
5301881cdb1SYouMin Chen  * rank = 2: cs1
5311881cdb1SYouMin Chen  * rank = 3: cs0 & cs1
5321881cdb1SYouMin Chen  * note: be careful of keep mr original val
5331881cdb1SYouMin Chen  */
5341881cdb1SYouMin Chen static int write_mr(struct dram_info *dram, u32 rank, u32 mr_num, u32 arg,
5351881cdb1SYouMin Chen 		    u32 dramtype)
5361881cdb1SYouMin Chen {
5371881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
5381881cdb1SYouMin Chen 
5391881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
5401881cdb1SYouMin Chen 		continue;
5411881cdb1SYouMin Chen 	if (dramtype == DDR3 || dramtype == DDR4) {
5421881cdb1SYouMin Chen 		writel((mr_num << 12) | (rank << 4) | (0 << 0),
5431881cdb1SYouMin Chen 		       pctl_base + DDR_PCTL2_MRCTRL0);
5441881cdb1SYouMin Chen 		writel(arg, pctl_base + DDR_PCTL2_MRCTRL1);
5451881cdb1SYouMin Chen 	} else {
5461881cdb1SYouMin Chen 		writel((rank << 4) | (0 << 0),
5471881cdb1SYouMin Chen 		       pctl_base + DDR_PCTL2_MRCTRL0);
5481881cdb1SYouMin Chen 		writel((mr_num << 8) | (arg & 0xff),
5491881cdb1SYouMin Chen 		       pctl_base + DDR_PCTL2_MRCTRL1);
5501881cdb1SYouMin Chen 	}
5511881cdb1SYouMin Chen 
5521881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
5531881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
5541881cdb1SYouMin Chen 		continue;
5551881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
5561881cdb1SYouMin Chen 		continue;
5571881cdb1SYouMin Chen 
5581881cdb1SYouMin Chen 	return 0;
5591881cdb1SYouMin Chen }
5601881cdb1SYouMin Chen 
5611881cdb1SYouMin Chen /*
5621881cdb1SYouMin Chen  * rank : 1:cs0, 2:cs1, 3:cs0&cs1
5631881cdb1SYouMin Chen  * vrefrate: 4500: 45%,
5641881cdb1SYouMin Chen  */
5651881cdb1SYouMin Chen static int write_vrefdq(struct dram_info *dram, u32 rank, u32 vrefrate,
5661881cdb1SYouMin Chen 			u32 dramtype)
5671881cdb1SYouMin Chen {
5681881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
5691881cdb1SYouMin Chen 	u32 tccd_l, value;
5701881cdb1SYouMin Chen 	u32 dis_auto_zq = 0;
5711881cdb1SYouMin Chen 
5721881cdb1SYouMin Chen 	if (dramtype != DDR4 || vrefrate < 4500 ||
5731881cdb1SYouMin Chen 	    vrefrate > 9200)
5741881cdb1SYouMin Chen 		return (-1);
5751881cdb1SYouMin Chen 
5761881cdb1SYouMin Chen 	tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf;
5771881cdb1SYouMin Chen 	tccd_l = (tccd_l - 4) << 10;
5781881cdb1SYouMin Chen 
5791881cdb1SYouMin Chen 	if (vrefrate > 7500) {
5801881cdb1SYouMin Chen 		/* range 1 */
5811881cdb1SYouMin Chen 		value = ((vrefrate - 6000) / 65) | tccd_l;
5821881cdb1SYouMin Chen 	} else {
5831881cdb1SYouMin Chen 		/* range 2 */
5841881cdb1SYouMin Chen 		value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6);
5851881cdb1SYouMin Chen 	}
5861881cdb1SYouMin Chen 
5871881cdb1SYouMin Chen 	dis_auto_zq = disable_zqcs_arefresh(dram);
5881881cdb1SYouMin Chen 
5891881cdb1SYouMin Chen 	/* enable vrefdq calibratin */
5901881cdb1SYouMin Chen 	write_mr(dram, rank, 6, value | (1 << 7), dramtype);
5911881cdb1SYouMin Chen 	udelay(1);/* tvrefdqe */
5921881cdb1SYouMin Chen 	/* write vrefdq value */
5931881cdb1SYouMin Chen 	write_mr(dram, rank, 6, value | (1 << 7), dramtype);
5941881cdb1SYouMin Chen 	udelay(1);/* tvref_time */
5951881cdb1SYouMin Chen 	write_mr(dram, rank, 6, value | (0 << 7), dramtype);
5961881cdb1SYouMin Chen 	udelay(1);/* tvrefdqx */
5971881cdb1SYouMin Chen 
5981881cdb1SYouMin Chen 	restore_zqcs_arefresh(dram, dis_auto_zq);
5991881cdb1SYouMin Chen 
6001881cdb1SYouMin Chen 	return 0;
6011881cdb1SYouMin Chen }
6021881cdb1SYouMin Chen 
6031881cdb1SYouMin Chen /*
6041881cdb1SYouMin Chen  * cs: 0:cs0
6051881cdb1SYouMin Chen  *	   1:cs1
6061881cdb1SYouMin Chen  *     else cs0+cs1
6071881cdb1SYouMin Chen  * note: it didn't consider about row_3_4
6081881cdb1SYouMin Chen  */
6091881cdb1SYouMin Chen u64 get_cs_cap(struct px30_sdram_params *sdram_params, u32 cs)
6101881cdb1SYouMin Chen {
6111881cdb1SYouMin Chen 	u32 bg;
6121881cdb1SYouMin Chen 	u64 cap[2];
6131881cdb1SYouMin Chen 
6141881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
6151881cdb1SYouMin Chen 		/* DDR4 8bit dram BG = 2(4bank groups),
6161881cdb1SYouMin Chen 		 * 16bit dram BG = 1 (2 bank groups)
6171881cdb1SYouMin Chen 		 */
6181881cdb1SYouMin Chen 		bg = (sdram_params->ch.dbw == 0) ? 2 : 1;
6191881cdb1SYouMin Chen 	else
6201881cdb1SYouMin Chen 		bg = 0;
6211881cdb1SYouMin Chen 	cap[0] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col +
6221881cdb1SYouMin Chen 		bg + sdram_params->ch.bk + sdram_params->ch.cs0_row);
6231881cdb1SYouMin Chen 
6241881cdb1SYouMin Chen 	if (sdram_params->ch.rank == 2)
6251881cdb1SYouMin Chen 		cap[1] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col +
6261881cdb1SYouMin Chen 			bg + sdram_params->ch.bk + sdram_params->ch.cs1_row);
6271881cdb1SYouMin Chen 	else
6281881cdb1SYouMin Chen 		cap[1] = 0;
6291881cdb1SYouMin Chen 
6301881cdb1SYouMin Chen 	if (cs == 0)
6311881cdb1SYouMin Chen 		return cap[0];
6321881cdb1SYouMin Chen 	else if (cs == 1)
6331881cdb1SYouMin Chen 		return cap[1];
6341881cdb1SYouMin Chen 	else
6351881cdb1SYouMin Chen 		return (cap[0] + cap[1]);
6361881cdb1SYouMin Chen }
6371881cdb1SYouMin Chen 
6381881cdb1SYouMin Chen static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
6391881cdb1SYouMin Chen {
6401881cdb1SYouMin Chen 	writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf);
6411881cdb1SYouMin Chen 	rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14);
6421881cdb1SYouMin Chen }
6431881cdb1SYouMin Chen 
6441881cdb1SYouMin Chen static void dram_all_config(struct dram_info *dram,
6451881cdb1SYouMin Chen 			    struct px30_sdram_params *sdram_params)
6461881cdb1SYouMin Chen {
6471881cdb1SYouMin Chen 	u32 sys_reg = 0;
6481881cdb1SYouMin Chen 	u32 sys_reg3 = 0;
6491881cdb1SYouMin Chen 	u64 cs_cap[2];
6501881cdb1SYouMin Chen 
6511881cdb1SYouMin Chen 	set_ddrconfig(dram, sdram_params->ch.ddrconfig);
6521881cdb1SYouMin Chen 
6531881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype);
6541881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_ROW_3_4(sdram_params->ch.row_3_4);
6551881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_RANK(sdram_params->ch.rank);
6561881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_COL(sdram_params->ch.col);
6571881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_BK(sdram_params->ch.bk);
6581881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_BW(sdram_params->ch.bw);
6591881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_DBW(sdram_params->ch.dbw);
6601881cdb1SYouMin Chen 
6611881cdb1SYouMin Chen 	SYS_REG_ENC_CS0_ROW_(sdram_params->ch.cs0_row, sys_reg, sys_reg3);
6621881cdb1SYouMin Chen 	if (sdram_params->ch.cs1_row)
6631881cdb1SYouMin Chen 		SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row, sys_reg,
6641881cdb1SYouMin Chen 				     sys_reg3);
6651881cdb1SYouMin Chen 	sys_reg3 |= SYS_REG_ENC_CS1_COL(sdram_params->ch.col);
6661881cdb1SYouMin Chen 	sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
6671881cdb1SYouMin Chen 
6681881cdb1SYouMin Chen 	writel(sys_reg, &dram->pmugrf->os_reg[2]);
6691881cdb1SYouMin Chen 	writel(sys_reg3, &dram->pmugrf->os_reg[3]);
6701881cdb1SYouMin Chen 
6711881cdb1SYouMin Chen 	cs_cap[0] = get_cs_cap(sdram_params, 0);
6721881cdb1SYouMin Chen 	cs_cap[1] = get_cs_cap(sdram_params, 1);
6731881cdb1SYouMin Chen 	writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) |
6741881cdb1SYouMin Chen 			(((cs_cap[0] >> 20) / 64) & 0xff),
6751881cdb1SYouMin Chen 			&dram->msch->devicesize);
6761881cdb1SYouMin Chen 
6771881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrtiminga0.d32,
6781881cdb1SYouMin Chen 	       &dram->msch->ddrtiminga0);
6791881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrtimingb0.d32,
6801881cdb1SYouMin Chen 	       &dram->msch->ddrtimingb0);
6811881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrtimingc0.d32,
6821881cdb1SYouMin Chen 	       &dram->msch->ddrtimingc0);
6831881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.devtodev0.d32,
6841881cdb1SYouMin Chen 	       &dram->msch->devtodev0);
6851881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrmode.d32, &dram->msch->ddrmode);
6861881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddr4timing.d32,
6871881cdb1SYouMin Chen 	       &dram->msch->ddr4timing);
6881881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->agingx0);
6891881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging0);
6901881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging1);
6911881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging2);
6921881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging3);
6931881cdb1SYouMin Chen }
6941881cdb1SYouMin Chen 
6951881cdb1SYouMin Chen static void enable_low_power(struct dram_info *dram,
6961881cdb1SYouMin Chen 			     struct px30_sdram_params *sdram_params)
6971881cdb1SYouMin Chen {
6981881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
699a82a427dSYouMin Chen 	void __iomem *phy_base = dram->phy;
7001881cdb1SYouMin Chen 	void __iomem *ddr_grf_base = dram->ddr_grf;
7011881cdb1SYouMin Chen 	u32 grf_lp_con;
7021881cdb1SYouMin Chen 
7031881cdb1SYouMin Chen 	/*
7041881cdb1SYouMin Chen 	 * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating
7051881cdb1SYouMin Chen 	 * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access
7061881cdb1SYouMin Chen 	 * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating
7071881cdb1SYouMin Chen 	 * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr
7081881cdb1SYouMin Chen 	 * bit4: grf_upctl_syscreq_cg_en = 1
7091881cdb1SYouMin Chen 	 *       ungating coreclk when c_sysreq assert
7101881cdb1SYouMin Chen 	 * bit8-11: grf_auto_sr_dly = 6
7111881cdb1SYouMin Chen 	 */
7121881cdb1SYouMin Chen 	writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]);
7131881cdb1SYouMin Chen 
7141881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
7151881cdb1SYouMin Chen 		grf_lp_con = (0x7 << 16) | (1 << 1);
7161881cdb1SYouMin Chen 	else if (sdram_params->dramtype == DDR3)
7171881cdb1SYouMin Chen 		grf_lp_con = (0x7 << 16) | (1 << 0);
7181881cdb1SYouMin Chen 	else
7191881cdb1SYouMin Chen 		grf_lp_con = (0x7 << 16) | (1 << 2);
7201881cdb1SYouMin Chen 
7211881cdb1SYouMin Chen 	/* en lpckdis_en */
7221881cdb1SYouMin Chen 	grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9);
7231881cdb1SYouMin Chen 	writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON);
7241881cdb1SYouMin Chen 
725a82a427dSYouMin Chen 	/* off digit module clock when enter power down */
726a82a427dSYouMin Chen 	setbits_le32(PHY_REG(phy_base, 7), 1 << 7);
727a82a427dSYouMin Chen 
7281881cdb1SYouMin Chen 	/* enable sr, pd */
7291881cdb1SYouMin Chen 	if (PD_IDLE == 0)
7301881cdb1SYouMin Chen 		clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
7311881cdb1SYouMin Chen 	else
7321881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
7331881cdb1SYouMin Chen 	if (SR_IDLE == 0)
7341881cdb1SYouMin Chen 		clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
7351881cdb1SYouMin Chen 	else
7361881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
7371881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3));
7381881cdb1SYouMin Chen }
7391881cdb1SYouMin Chen 
740504e252fSYouMin Chen static void print_ddr_info(struct px30_sdram_params *sdram_params)
7411881cdb1SYouMin Chen {
742504e252fSYouMin Chen 	u64 cap;
743504e252fSYouMin Chen 	u32 bg;
744504e252fSYouMin Chen 	u32 split;
7451881cdb1SYouMin Chen 
746504e252fSYouMin Chen 	split = readl(DDR_GRF_BASE_ADDR + DDR_GRF_SPLIT_CON);
747504e252fSYouMin Chen 	bg = (sdram_params->ch.dbw == 0) ? 2 : 1;
748504e252fSYouMin Chen 	switch (sdram_params->dramtype) {
749504e252fSYouMin Chen 	case LPDDR3:
750504e252fSYouMin Chen 		printascii("LPDDR3\n");
751504e252fSYouMin Chen 		break;
752504e252fSYouMin Chen 	case DDR3:
753504e252fSYouMin Chen 		printascii("DDR3\n");
754504e252fSYouMin Chen 		break;
755504e252fSYouMin Chen 	case DDR4:
756504e252fSYouMin Chen 		printascii("DDR4\n");
757504e252fSYouMin Chen 		break;
758504e252fSYouMin Chen 	case LPDDR2:
759504e252fSYouMin Chen 		printascii("LPDDR2\n");
760504e252fSYouMin Chen 		break;
761504e252fSYouMin Chen 	default:
762504e252fSYouMin Chen 		printascii("Unknown Device\n");
763504e252fSYouMin Chen 		break;
764504e252fSYouMin Chen 	}
7651881cdb1SYouMin Chen 
766504e252fSYouMin Chen 	printdec(sdram_params->ddr_freq);
767504e252fSYouMin Chen 	printascii("MHz\n");
768504e252fSYouMin Chen 	printascii("BW=");
769504e252fSYouMin Chen 	printdec(8 << sdram_params->ch.bw);
770504e252fSYouMin Chen 	printascii(" Col=");
771504e252fSYouMin Chen 	printdec(sdram_params->ch.col);
772504e252fSYouMin Chen 	printascii(" Bk=");
773504e252fSYouMin Chen 	printdec(0x1 << sdram_params->ch.bk);
774504e252fSYouMin Chen 	if (sdram_params->dramtype == DDR4) {
775504e252fSYouMin Chen 		printascii(" BG=");
776504e252fSYouMin Chen 		printdec(1 << bg);
777504e252fSYouMin Chen 	}
778504e252fSYouMin Chen 	printascii(" CS0 Row=");
779504e252fSYouMin Chen 	printdec(sdram_params->ch.cs0_row);
780504e252fSYouMin Chen 	if (sdram_params->ch.cs0_high16bit_row !=
781504e252fSYouMin Chen 		sdram_params->ch.cs0_row) {
782504e252fSYouMin Chen 		printascii("/");
783504e252fSYouMin Chen 		printdec(sdram_params->ch.cs0_high16bit_row);
784504e252fSYouMin Chen 	}
785504e252fSYouMin Chen 	if (sdram_params->ch.rank > 1) {
786504e252fSYouMin Chen 		printascii(" CS1 Row=");
787504e252fSYouMin Chen 		printdec(sdram_params->ch.cs1_row);
788504e252fSYouMin Chen 		if (sdram_params->ch.cs1_high16bit_row !=
789504e252fSYouMin Chen 			sdram_params->ch.cs1_row) {
790504e252fSYouMin Chen 			printascii("/");
791504e252fSYouMin Chen 			printdec(sdram_params->ch.cs1_high16bit_row);
792504e252fSYouMin Chen 		}
793504e252fSYouMin Chen 	}
794504e252fSYouMin Chen 	printascii(" CS=");
795504e252fSYouMin Chen 	printdec(sdram_params->ch.rank);
796504e252fSYouMin Chen 	printascii(" Die BW=");
797504e252fSYouMin Chen 	printdec(8 << sdram_params->ch.dbw);
798504e252fSYouMin Chen 
799504e252fSYouMin Chen 	cap = get_cs_cap(sdram_params, 3);
800504e252fSYouMin Chen 	if (sdram_params->ch.row_3_4)
801504e252fSYouMin Chen 		cap = cap * 3 / 4;
802504e252fSYouMin Chen 	else if (!(split & (1 << SPLIT_BYPASS_OFFSET)))
803504e252fSYouMin Chen 		cap = cap / 2 + ((split & 0xff) << 24) / 2;
804504e252fSYouMin Chen 
805504e252fSYouMin Chen 	printascii(" Size=");
806504e252fSYouMin Chen 	printdec(cap >> 20);
807504e252fSYouMin Chen 	printascii("MB\n");
8081881cdb1SYouMin Chen }
8091881cdb1SYouMin Chen 
8101881cdb1SYouMin Chen /*
8111881cdb1SYouMin Chen  * pre_init: 0: pre init for dram cap detect
8121881cdb1SYouMin Chen  * 1: detect correct cap(except cs1 row)info, than reinit
8131881cdb1SYouMin Chen  * 2: after reinit, we detect cs1_row, if cs1_row not equal
8141881cdb1SYouMin Chen  *    to cs0_row and cs is in middle on ddrconf map, we need
8151881cdb1SYouMin Chen  *    to reinit dram, than set the correct ddrconf.
8161881cdb1SYouMin Chen  */
8171881cdb1SYouMin Chen static int sdram_init_(struct dram_info *dram,
8181881cdb1SYouMin Chen 		       struct px30_sdram_params *sdram_params, u32 pre_init)
8191881cdb1SYouMin Chen {
8201881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
8211881cdb1SYouMin Chen 
8221881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 1, 1, 1);
8231881cdb1SYouMin Chen 	udelay(10);
8241881cdb1SYouMin Chen 	/*
8251881cdb1SYouMin Chen 	 * dereset ddr phy psrstn to config pll,
8261881cdb1SYouMin Chen 	 * if using phy pll psrstn must be dereset
8271881cdb1SYouMin Chen 	 * before config pll
8281881cdb1SYouMin Chen 	 */
8291881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 1, 1, 0);
8301881cdb1SYouMin Chen 	rkclk_configure_ddr(dram, sdram_params);
8311881cdb1SYouMin Chen 
8321881cdb1SYouMin Chen 	/* release phy srst to provide clk to ctrl */
8331881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 1, 0, 0);
8341881cdb1SYouMin Chen 	udelay(10);
8351881cdb1SYouMin Chen 	phy_soft_reset(dram);
8361881cdb1SYouMin Chen 	/* release ctrl presetn, and config ctl registers */
8371881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 0, 0, 0);
8381881cdb1SYouMin Chen 	pctl_cfg(dram, sdram_params);
8391881cdb1SYouMin Chen 	sdram_params->ch.ddrconfig = calculate_ddrconfig(sdram_params);
8401881cdb1SYouMin Chen 	set_ctl_address_map(dram, sdram_params);
8411881cdb1SYouMin Chen 	phy_cfg(dram, sdram_params);
8421881cdb1SYouMin Chen 
8431881cdb1SYouMin Chen 	/* enable dfi_init_start to init phy after ctl srstn deassert */
8441881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
8451881cdb1SYouMin Chen 
8461881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 0, 0, 0, 0);
8471881cdb1SYouMin Chen 	/* wait for dfi_init_done and dram init complete */
8481881cdb1SYouMin Chen 	while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
8491881cdb1SYouMin Chen 		continue;
8501881cdb1SYouMin Chen 
8511881cdb1SYouMin Chen 	if (sdram_params->dramtype == LPDDR3)
8521881cdb1SYouMin Chen 		write_mr(dram, 3, 11, 3, LPDDR3);
8531881cdb1SYouMin Chen 
8541881cdb1SYouMin Chen 	/* do ddr gate training */
8551881cdb1SYouMin Chen redo_cs0_training:
8561881cdb1SYouMin Chen 	if (data_training(dram, 0, sdram_params->dramtype) != 0) {
8571881cdb1SYouMin Chen 		if (pre_init != 0)
8581881cdb1SYouMin Chen 			printascii("DTT cs0 error\n");
8591881cdb1SYouMin Chen 		return -1;
8601881cdb1SYouMin Chen 	}
8611881cdb1SYouMin Chen 	if (check_rd_gate(dram)) {
8621881cdb1SYouMin Chen 		printascii("re training cs0");
8631881cdb1SYouMin Chen 		goto redo_cs0_training;
8641881cdb1SYouMin Chen 	}
8651881cdb1SYouMin Chen 
8661881cdb1SYouMin Chen 	if (sdram_params->dramtype == LPDDR3) {
8671881cdb1SYouMin Chen 		if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
8681881cdb1SYouMin Chen 			return -1;
8691881cdb1SYouMin Chen 	} else if (sdram_params->dramtype == LPDDR2) {
8701881cdb1SYouMin Chen 		if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
8711881cdb1SYouMin Chen 			return -1;
8721881cdb1SYouMin Chen 	}
8731881cdb1SYouMin Chen 	/* for px30: when 2cs, both 2 cs should be training */
8741881cdb1SYouMin Chen 	if (pre_init != 0 && sdram_params->ch.rank == 2) {
8751881cdb1SYouMin Chen redo_cs1_training:
8761881cdb1SYouMin Chen 		if (data_training(dram, 1, sdram_params->dramtype) != 0) {
8771881cdb1SYouMin Chen 			printascii("DTT cs1 error\n");
8781881cdb1SYouMin Chen 			return -1;
8791881cdb1SYouMin Chen 		}
8801881cdb1SYouMin Chen 		if (check_rd_gate(dram)) {
8811881cdb1SYouMin Chen 			printascii("re training cs1");
8821881cdb1SYouMin Chen 			goto redo_cs1_training;
8831881cdb1SYouMin Chen 		}
8841881cdb1SYouMin Chen 	}
8851881cdb1SYouMin Chen 
8861881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
8871881cdb1SYouMin Chen 		write_vrefdq(dram, 0x3, 5670, sdram_params->dramtype);
8881881cdb1SYouMin Chen 
8891881cdb1SYouMin Chen 	dram_all_config(dram, sdram_params);
8901881cdb1SYouMin Chen 	enable_low_power(dram, sdram_params);
8911881cdb1SYouMin Chen 
8921881cdb1SYouMin Chen 	return 0;
8931881cdb1SYouMin Chen }
8941881cdb1SYouMin Chen 
8951881cdb1SYouMin Chen static u64 dram_detect_cap(struct dram_info *dram,
8961881cdb1SYouMin Chen 			   struct px30_sdram_params *sdram_params,
8971881cdb1SYouMin Chen 			   unsigned char channel)
8981881cdb1SYouMin Chen {
8991881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
9001881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
9011881cdb1SYouMin Chen 
9021881cdb1SYouMin Chen 	/*
9031881cdb1SYouMin Chen 	 * for ddr3: ddrconf = 3
9041881cdb1SYouMin Chen 	 * for ddr4: ddrconf = 12
9051881cdb1SYouMin Chen 	 * for lpddr3: ddrconf = 3
9061881cdb1SYouMin Chen 	 * default bw = 1
9071881cdb1SYouMin Chen 	 */
9081881cdb1SYouMin Chen 	u32 bk, bktmp;
9091881cdb1SYouMin Chen 	u32 col, coltmp;
9101881cdb1SYouMin Chen 	u32 row, rowtmp, row_3_4;
9111881cdb1SYouMin Chen 	void __iomem *test_addr, *test_addr1;
9121881cdb1SYouMin Chen 	u32 dbw;
9131881cdb1SYouMin Chen 	u32 cs;
9141881cdb1SYouMin Chen 	u32 bw = 1;
9151881cdb1SYouMin Chen 	u64 cap = 0;
9161881cdb1SYouMin Chen 	u32 dram_type = sdram_params->dramtype;
9171881cdb1SYouMin Chen 	u32 pwrctl;
9181881cdb1SYouMin Chen 
9191881cdb1SYouMin Chen 	if (dram_type != DDR4) {
9201881cdb1SYouMin Chen 		/* detect col and bk for ddr3/lpddr3 */
9211881cdb1SYouMin Chen 		coltmp = 12;
9221881cdb1SYouMin Chen 		bktmp = 3;
923*f588f59eSYouMin Chen 		if (dram_type == LPDDR2)
924*f588f59eSYouMin Chen 			rowtmp = 15;
925*f588f59eSYouMin Chen 		else
9261881cdb1SYouMin Chen 			rowtmp = 16;
9271881cdb1SYouMin Chen 
9281881cdb1SYouMin Chen 		for (col = coltmp; col >= 9; col -= 1) {
9291881cdb1SYouMin Chen 			writel(0, CONFIG_SYS_SDRAM_BASE);
9301881cdb1SYouMin Chen 			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
9311881cdb1SYouMin Chen 					(1ul << (col + bw - 1ul)));
9321881cdb1SYouMin Chen 			writel(PATTERN, test_addr);
9331881cdb1SYouMin Chen 			if ((readl(test_addr) == PATTERN) &&
9341881cdb1SYouMin Chen 			    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
9351881cdb1SYouMin Chen 				break;
9361881cdb1SYouMin Chen 		}
9371881cdb1SYouMin Chen 		if (col == 8) {
9381881cdb1SYouMin Chen 			printascii("col error\n");
9391881cdb1SYouMin Chen 			goto cap_err;
9401881cdb1SYouMin Chen 		}
9411881cdb1SYouMin Chen 
9421881cdb1SYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
9431881cdb1SYouMin Chen 				(1ul << (coltmp + bktmp + bw - 1ul)));
9441881cdb1SYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
9451881cdb1SYouMin Chen 		writel(PATTERN, test_addr);
9461881cdb1SYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
9471881cdb1SYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
9481881cdb1SYouMin Chen 			bk = 3;
9491881cdb1SYouMin Chen 		else
9501881cdb1SYouMin Chen 			bk = 2;
9511881cdb1SYouMin Chen 		if (dram_type == DDR3)
9521881cdb1SYouMin Chen 			dbw = 1;
9531881cdb1SYouMin Chen 		else
9541881cdb1SYouMin Chen 			dbw = 2;
9551881cdb1SYouMin Chen 	} else {
9561881cdb1SYouMin Chen 		/* detect bg for ddr4 */
9571881cdb1SYouMin Chen 		coltmp = 10;
9581881cdb1SYouMin Chen 		bktmp = 4;
9591881cdb1SYouMin Chen 		rowtmp = 17;
9601881cdb1SYouMin Chen 
9611881cdb1SYouMin Chen 		col = 10;
9621881cdb1SYouMin Chen 		bk = 2;
9631881cdb1SYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
9641881cdb1SYouMin Chen 				(1ul << (coltmp + bw + 1ul)));
9651881cdb1SYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
9661881cdb1SYouMin Chen 		writel(PATTERN, test_addr);
9671881cdb1SYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
9681881cdb1SYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
9691881cdb1SYouMin Chen 			dbw = 0;
9701881cdb1SYouMin Chen 		else
9711881cdb1SYouMin Chen 			dbw = 1;
9721881cdb1SYouMin Chen 	}
9731881cdb1SYouMin Chen 	/* detect row */
9741881cdb1SYouMin Chen 	for (row = rowtmp; row > 12; row--) {
9751881cdb1SYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
9761881cdb1SYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
9771881cdb1SYouMin Chen 				(1ul << (row + bktmp + coltmp + bw - 1ul)));
9781881cdb1SYouMin Chen 		writel(PATTERN, test_addr);
9791881cdb1SYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
9801881cdb1SYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
9811881cdb1SYouMin Chen 			break;
9821881cdb1SYouMin Chen 	}
9831881cdb1SYouMin Chen 	if (row == 12) {
9841881cdb1SYouMin Chen 		printascii("row error");
9851881cdb1SYouMin Chen 		goto cap_err;
9861881cdb1SYouMin Chen 	}
9871881cdb1SYouMin Chen 	/* detect row_3_4 */
9881881cdb1SYouMin Chen 	test_addr = CONFIG_SYS_SDRAM_BASE;
9891881cdb1SYouMin Chen 	test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
9901881cdb1SYouMin Chen 			(0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
9911881cdb1SYouMin Chen 
9921881cdb1SYouMin Chen 	writel(0, test_addr);
9931881cdb1SYouMin Chen 	writel(PATTERN, test_addr1);
9941881cdb1SYouMin Chen 	if ((readl(test_addr) == 0) &&
9951881cdb1SYouMin Chen 	    (readl(test_addr1) == PATTERN))
9961881cdb1SYouMin Chen 		row_3_4 = 0;
9971881cdb1SYouMin Chen 	else
9981881cdb1SYouMin Chen 		row_3_4 = 1;
9991881cdb1SYouMin Chen 
10001881cdb1SYouMin Chen 	/* disable auto low-power */
10011881cdb1SYouMin Chen 	pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
10021881cdb1SYouMin Chen 	writel(0, pctl_base + DDR_PCTL2_PWRCTL);
10031881cdb1SYouMin Chen 
10041881cdb1SYouMin Chen 	/* bw and cs detect using phy read gate training */
10051881cdb1SYouMin Chen 	if (data_training(dram, 1, dram_type) == 0)
10061881cdb1SYouMin Chen 		cs = 1;
10071881cdb1SYouMin Chen 	else
10081881cdb1SYouMin Chen 		cs = 0;
10091881cdb1SYouMin Chen 
10101881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
10111881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
10121881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
10131881cdb1SYouMin Chen 
10141881cdb1SYouMin Chen 	phy_soft_reset(dram);
10151881cdb1SYouMin Chen 
10161881cdb1SYouMin Chen 	if (data_training(dram, 0, dram_type) == 0)
10171881cdb1SYouMin Chen 		bw = 2;
10181881cdb1SYouMin Chen 	else
10191881cdb1SYouMin Chen 		bw = 1;
10201881cdb1SYouMin Chen 
10211881cdb1SYouMin Chen 	/* restore auto low-power */
10221881cdb1SYouMin Chen 	writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
10231881cdb1SYouMin Chen 
10241881cdb1SYouMin Chen 	sdram_params->ch.rank = cs + 1;
10251881cdb1SYouMin Chen 	sdram_params->ch.col = col;
10261881cdb1SYouMin Chen 	sdram_params->ch.bk = bk;
10271881cdb1SYouMin Chen 	sdram_params->ch.dbw = dbw;
10281881cdb1SYouMin Chen 	sdram_params->ch.bw = bw;
10291881cdb1SYouMin Chen 	sdram_params->ch.cs0_row = row;
10301881cdb1SYouMin Chen 	sdram_params->ch.cs0_high16bit_row = row;
10311881cdb1SYouMin Chen 	if (cs) {
10321881cdb1SYouMin Chen 		sdram_params->ch.cs1_row = row;
10331881cdb1SYouMin Chen 		sdram_params->ch.cs1_high16bit_row = row;
10341881cdb1SYouMin Chen 	} else {
10351881cdb1SYouMin Chen 		sdram_params->ch.cs1_row = 0;
10361881cdb1SYouMin Chen 		sdram_params->ch.cs1_high16bit_row = 0;
10371881cdb1SYouMin Chen 	}
10381881cdb1SYouMin Chen 	sdram_params->ch.row_3_4 = row_3_4;
10391881cdb1SYouMin Chen 
10401881cdb1SYouMin Chen 	if (dram_type == DDR4)
10411881cdb1SYouMin Chen 		cap = 1llu << (cs + row + bk + col + ((dbw == 0) ? 2 : 1) + bw);
10421881cdb1SYouMin Chen 	else
10431881cdb1SYouMin Chen 		cap = 1llu << (cs + row + bk + col + bw);
10441881cdb1SYouMin Chen 
10451881cdb1SYouMin Chen 	return cap;
10461881cdb1SYouMin Chen 
10471881cdb1SYouMin Chen cap_err:
10481881cdb1SYouMin Chen 	return 0;
10491881cdb1SYouMin Chen }
10501881cdb1SYouMin Chen 
10511881cdb1SYouMin Chen static u32 remodify_sdram_params(struct px30_sdram_params *sdram_params)
10521881cdb1SYouMin Chen {
10531881cdb1SYouMin Chen 	u32 tmp = 0, tmp_adr = 0, i;
10541881cdb1SYouMin Chen 
10551881cdb1SYouMin Chen 	for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) {
10561881cdb1SYouMin Chen 		if (sdram_params->pctl_regs.pctl[i][0] == 0) {
10571881cdb1SYouMin Chen 			tmp = sdram_params->pctl_regs.pctl[i][1];/* MSTR */
10581881cdb1SYouMin Chen 			tmp_adr = i;
10591881cdb1SYouMin Chen 		}
10601881cdb1SYouMin Chen 	}
10611881cdb1SYouMin Chen 
10621881cdb1SYouMin Chen 	tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12));
10631881cdb1SYouMin Chen 
10641881cdb1SYouMin Chen 	switch (sdram_params->ch.dbw) {
10651881cdb1SYouMin Chen 	case 2:
10661881cdb1SYouMin Chen 		tmp |= (3ul << 30);
10671881cdb1SYouMin Chen 		break;
10681881cdb1SYouMin Chen 	case 1:
10691881cdb1SYouMin Chen 		tmp |= (2ul << 30);
10701881cdb1SYouMin Chen 		break;
10711881cdb1SYouMin Chen 	case 0:
10721881cdb1SYouMin Chen 	default:
10731881cdb1SYouMin Chen 		tmp |= (1ul << 30);
10741881cdb1SYouMin Chen 		break;
10751881cdb1SYouMin Chen 	}
10761881cdb1SYouMin Chen 
1077175c2742SYouMin Chen 	/*
1078175c2742SYouMin Chen 	 * If DDR3 or DDR4 MSTR.active_ranks=1,
1079175c2742SYouMin Chen 	 * it will gate memory clock when enter power down.
1080175c2742SYouMin Chen 	 * Force set active_ranks to 3 to workaround it.
1081175c2742SYouMin Chen 	 */
1082175c2742SYouMin Chen 	if (sdram_params->ch.rank == 2 || sdram_params->dramtype == DDR3 ||
1083175c2742SYouMin Chen 	    sdram_params->dramtype == DDR4)
10841881cdb1SYouMin Chen 		tmp |= 3 << 24;
10851881cdb1SYouMin Chen 	else
10861881cdb1SYouMin Chen 		tmp |= 1 << 24;
10871881cdb1SYouMin Chen 
10881881cdb1SYouMin Chen 	tmp |= (2 - sdram_params->ch.bw) << 12;
10891881cdb1SYouMin Chen 
10901881cdb1SYouMin Chen 	sdram_params->pctl_regs.pctl[tmp_adr][1] = tmp;
10911881cdb1SYouMin Chen 
10921881cdb1SYouMin Chen 	return 0;
10931881cdb1SYouMin Chen }
10941881cdb1SYouMin Chen 
10951881cdb1SYouMin Chen int dram_detect_high_row(struct dram_info *dram,
10961881cdb1SYouMin Chen 			 struct px30_sdram_params *sdram_params,
10971881cdb1SYouMin Chen 			 unsigned char channel)
10981881cdb1SYouMin Chen {
10991881cdb1SYouMin Chen 	sdram_params->ch.cs0_high16bit_row = sdram_params->ch.cs0_row;
11001881cdb1SYouMin Chen 	sdram_params->ch.cs1_high16bit_row = sdram_params->ch.cs1_row;
11011881cdb1SYouMin Chen 
11021881cdb1SYouMin Chen 	return 0;
11031881cdb1SYouMin Chen }
11041881cdb1SYouMin Chen 
11051881cdb1SYouMin Chen static int dram_detect_cs1_row(struct px30_sdram_params *sdram_params,
11061881cdb1SYouMin Chen 			       unsigned char channel)
11071881cdb1SYouMin Chen {
11081881cdb1SYouMin Chen 	u32 ret = 0;
11091881cdb1SYouMin Chen 	void __iomem *test_addr;
11101881cdb1SYouMin Chen 	u32 row, bktmp, coltmp, bw;
11111881cdb1SYouMin Chen 	u64 cs0_cap;
11121881cdb1SYouMin Chen 	u32 byte_mask;
11131881cdb1SYouMin Chen 
11141881cdb1SYouMin Chen 	if (sdram_params->ch.rank == 2) {
11151881cdb1SYouMin Chen 		cs0_cap = get_cs_cap(sdram_params, 0);
11161881cdb1SYouMin Chen 
11171881cdb1SYouMin Chen 		if (sdram_params->dramtype == DDR4) {
11181881cdb1SYouMin Chen 			if (sdram_params->ch.dbw == 0)
11191881cdb1SYouMin Chen 				bktmp = sdram_params->ch.bk + 2;
11201881cdb1SYouMin Chen 			else
11211881cdb1SYouMin Chen 				bktmp = sdram_params->ch.bk + 1;
11221881cdb1SYouMin Chen 		} else {
11231881cdb1SYouMin Chen 			bktmp = sdram_params->ch.bk;
11241881cdb1SYouMin Chen 		}
11251881cdb1SYouMin Chen 		bw = sdram_params->ch.bw;
11261881cdb1SYouMin Chen 		coltmp = sdram_params->ch.col;
11271881cdb1SYouMin Chen 
11281881cdb1SYouMin Chen 		/*
11291881cdb1SYouMin Chen 		 * because px30 support axi split,min bandwidth
11301881cdb1SYouMin Chen 		 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
11311881cdb1SYouMin Chen 		 * so we check low 16bit data when detect cs1 row.
11321881cdb1SYouMin Chen 		 * if cs0 is 16bit/8bit, we check low 8bit data.
11331881cdb1SYouMin Chen 		 */
11341881cdb1SYouMin Chen 		if (bw == 2)
11351881cdb1SYouMin Chen 			byte_mask = 0xFFFF;
11361881cdb1SYouMin Chen 		else
11371881cdb1SYouMin Chen 			byte_mask = 0xFF;
11381881cdb1SYouMin Chen 
11391881cdb1SYouMin Chen 		/* detect cs1 row */
11401881cdb1SYouMin Chen 		for (row = sdram_params->ch.cs0_row; row > 12; row--) {
11411881cdb1SYouMin Chen 			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
11421881cdb1SYouMin Chen 				    cs0_cap +
11431881cdb1SYouMin Chen 				    (1ul << (row + bktmp + coltmp + bw - 1ul)));
11441881cdb1SYouMin Chen 			writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
11451881cdb1SYouMin Chen 			writel(PATTERN, test_addr);
11461881cdb1SYouMin Chen 
11471881cdb1SYouMin Chen 			if (((readl(test_addr) & byte_mask) ==
11481881cdb1SYouMin Chen 			     (PATTERN & byte_mask)) &&
11491881cdb1SYouMin Chen 			    ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
11501881cdb1SYouMin Chen 			      byte_mask) == 0)) {
11511881cdb1SYouMin Chen 				ret = row;
11521881cdb1SYouMin Chen 				break;
11531881cdb1SYouMin Chen 			}
11541881cdb1SYouMin Chen 		}
11551881cdb1SYouMin Chen 	}
11561881cdb1SYouMin Chen 
11571881cdb1SYouMin Chen 	return ret;
11581881cdb1SYouMin Chen }
11591881cdb1SYouMin Chen 
11601881cdb1SYouMin Chen /* return: 0 = success, other = fail */
11611881cdb1SYouMin Chen static int sdram_init_detect(struct dram_info *dram,
11621881cdb1SYouMin Chen 			     struct px30_sdram_params *sdram_params)
11631881cdb1SYouMin Chen {
11641881cdb1SYouMin Chen 	u32 ret;
11651881cdb1SYouMin Chen 	u32 sys_reg = 0;
11661881cdb1SYouMin Chen 	u32 sys_reg3 = 0;
11671881cdb1SYouMin Chen 
11681881cdb1SYouMin Chen 	if (sdram_init_(dram, sdram_params, 0) != 0)
11691881cdb1SYouMin Chen 		return -1;
11701881cdb1SYouMin Chen 
11711881cdb1SYouMin Chen 	if (dram_detect_cap(dram, sdram_params, 0) == 0)
11721881cdb1SYouMin Chen 		return -1;
11731881cdb1SYouMin Chen 
11741881cdb1SYouMin Chen 	/* modify bw, cs related timing */
11751881cdb1SYouMin Chen 	remodify_sdram_params(sdram_params);
11761881cdb1SYouMin Chen 	/* reinit sdram by real dram cap */
11771881cdb1SYouMin Chen 	ret = sdram_init_(dram, sdram_params, 1);
11781881cdb1SYouMin Chen 	if (ret != 0)
11791881cdb1SYouMin Chen 		goto out;
11801881cdb1SYouMin Chen 
11811881cdb1SYouMin Chen 	/* redetect cs1 row */
11821881cdb1SYouMin Chen 	sdram_params->ch.cs1_row =
11831881cdb1SYouMin Chen 		dram_detect_cs1_row(sdram_params, 0);
11841881cdb1SYouMin Chen 	if (sdram_params->ch.cs1_row) {
11851881cdb1SYouMin Chen 		sys_reg = readl(&dram->pmugrf->os_reg[2]);
11861881cdb1SYouMin Chen 		sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
11871881cdb1SYouMin Chen 		SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row,
11881881cdb1SYouMin Chen 				     sys_reg, sys_reg3);
11891881cdb1SYouMin Chen 		writel(sys_reg, &dram->pmugrf->os_reg[2]);
11901881cdb1SYouMin Chen 		writel(sys_reg3, &dram->pmugrf->os_reg[3]);
11911881cdb1SYouMin Chen 	}
11921881cdb1SYouMin Chen 
11931881cdb1SYouMin Chen 	ret = dram_detect_high_row(dram, sdram_params, 0);
11941881cdb1SYouMin Chen 
11951881cdb1SYouMin Chen out:
11961881cdb1SYouMin Chen 	return ret;
11971881cdb1SYouMin Chen }
11981881cdb1SYouMin Chen 
11991881cdb1SYouMin Chen struct px30_sdram_params
12001881cdb1SYouMin Chen 		*get_default_sdram_config(void)
12011881cdb1SYouMin Chen {
12021881cdb1SYouMin Chen 	sdram_configs[0].skew = &skew;
12031881cdb1SYouMin Chen 
12041881cdb1SYouMin Chen 	return &sdram_configs[0];
12051881cdb1SYouMin Chen }
12061881cdb1SYouMin Chen 
12071881cdb1SYouMin Chen /* return: 0 = success, other = fail */
12081881cdb1SYouMin Chen int sdram_init(void)
12091881cdb1SYouMin Chen {
12101881cdb1SYouMin Chen 	struct px30_sdram_params *sdram_params;
12111881cdb1SYouMin Chen 	int ret = 0;
12121881cdb1SYouMin Chen 
12131881cdb1SYouMin Chen 	dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
12141881cdb1SYouMin Chen 	dram_info.pctl = (void *)DDRC_BASE_ADDR;
12151881cdb1SYouMin Chen 	dram_info.grf = (void *)GRF_BASE_ADDR;
12161881cdb1SYouMin Chen 	dram_info.cru = (void *)CRU_BASE_ADDR;
12171881cdb1SYouMin Chen 	dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
12181881cdb1SYouMin Chen 	dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
12191881cdb1SYouMin Chen 	dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
12201881cdb1SYouMin Chen 
12211881cdb1SYouMin Chen 	sdram_params = get_default_sdram_config();
12221881cdb1SYouMin Chen 	ret = sdram_init_detect(&dram_info, sdram_params);
12231881cdb1SYouMin Chen 
12241881cdb1SYouMin Chen 	if (ret)
12251881cdb1SYouMin Chen 		goto error;
12261881cdb1SYouMin Chen 
1227504e252fSYouMin Chen 	print_ddr_info(sdram_params);
1228504e252fSYouMin Chen 
12291881cdb1SYouMin Chen 	printascii("out\n");
12301881cdb1SYouMin Chen 	return ret;
12311881cdb1SYouMin Chen error:
12321881cdb1SYouMin Chen 	return (-1);
12331881cdb1SYouMin Chen }
12341881cdb1SYouMin Chen #endif /* CONFIG_TPL_BUILD */
1235