xref: /rk3399_rockchip-uboot/drivers/ram/rockchip/sdram_px30.c (revision 1881cdb1bc0debc2d5c5e1f752bc5bca78ae8fc0)
1*1881cdb1SYouMin Chen // SPDX-License-Identifier: GPL-2.0
25eeb396bSKever Yang /*
3*1881cdb1SYouMin Chen  * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
45eeb396bSKever Yang  */
55eeb396bSKever Yang 
65eeb396bSKever Yang #include <common.h>
7*1881cdb1SYouMin Chen #include <debug_uart.h>
85eeb396bSKever Yang #include <dm.h>
95eeb396bSKever Yang #include <ram.h>
105eeb396bSKever Yang #include <syscon.h>
11*1881cdb1SYouMin Chen #include <asm/io.h>
125eeb396bSKever Yang #include <asm/arch/clock.h>
13*1881cdb1SYouMin Chen #include <asm/arch/cru_px30.h>
145eeb396bSKever Yang #include <asm/arch/grf_px30.h>
15*1881cdb1SYouMin Chen #include <asm/arch/hardware.h>
165eeb396bSKever Yang #include <asm/arch/sdram_common.h>
17*1881cdb1SYouMin Chen #include <asm/arch/sdram_px30.h>
18*1881cdb1SYouMin Chen 
19*1881cdb1SYouMin Chen /*
20*1881cdb1SYouMin Chen  * Because px30 sram size is small, so need define CONFIG_TPL_TINY_FRAMEWORK
21*1881cdb1SYouMin Chen  * to reduce TPL size when build TPL firmware.
22*1881cdb1SYouMin Chen  */
23*1881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD
24*1881cdb1SYouMin Chen #ifndef CONFIG_TPL_TINY_FRAMEWORK
25*1881cdb1SYouMin Chen #error please defined CONFIG_TPL_TINY_FRAMEWORK for px30 !!!
26*1881cdb1SYouMin Chen #endif
27*1881cdb1SYouMin Chen #endif
285eeb396bSKever Yang 
295eeb396bSKever Yang DECLARE_GLOBAL_DATA_PTR;
305eeb396bSKever Yang struct dram_info {
31*1881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD
32*1881cdb1SYouMin Chen 	struct px30_ddr_pctl_regs *pctl;
33*1881cdb1SYouMin Chen 	struct px30_ddr_phy_regs *phy;
34*1881cdb1SYouMin Chen 	struct px30_cru *cru;
35*1881cdb1SYouMin Chen 	struct px30_msch_regs *msch;
36*1881cdb1SYouMin Chen 	struct px30_ddr_grf_regs *ddr_grf;
37*1881cdb1SYouMin Chen 	struct px30_grf *grf;
38*1881cdb1SYouMin Chen #endif
395eeb396bSKever Yang 	struct ram_info info;
405eeb396bSKever Yang 	struct px30_pmugrf *pmugrf;
415eeb396bSKever Yang };
425eeb396bSKever Yang 
43*1881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD
44*1881cdb1SYouMin Chen #define PMUGRF_BASE_ADDR		0xFF010000
45*1881cdb1SYouMin Chen #define CRU_BASE_ADDR			0xFF2B0000
46*1881cdb1SYouMin Chen #define GRF_BASE_ADDR			0xFF140000
47*1881cdb1SYouMin Chen #define DDRC_BASE_ADDR			0xFF600000
48*1881cdb1SYouMin Chen #define DDR_PHY_BASE_ADDR		0xFF2A0000
49*1881cdb1SYouMin Chen #define SERVER_MSCH0_BASE_ADDR		0xFF530000
50*1881cdb1SYouMin Chen #define DDR_GRF_BASE_ADDR		0xff630000
51*1881cdb1SYouMin Chen 
52*1881cdb1SYouMin Chen struct dram_info dram_info;
53*1881cdb1SYouMin Chen 
54*1881cdb1SYouMin Chen struct px30_sdram_params sdram_configs[] = {
55*1881cdb1SYouMin Chen #include	"sdram-px30-lpddr3-detect-333.inc"
56*1881cdb1SYouMin Chen };
57*1881cdb1SYouMin Chen 
58*1881cdb1SYouMin Chen struct px30_ddr_skew skew = {
59*1881cdb1SYouMin Chen #include	"sdram-px30-ddr_skew.inc"
60*1881cdb1SYouMin Chen };
61*1881cdb1SYouMin Chen 
62*1881cdb1SYouMin Chen static void rkclk_ddr_reset(struct dram_info *dram,
63*1881cdb1SYouMin Chen 			    u32 ctl_srstn, u32 ctl_psrstn,
64*1881cdb1SYouMin Chen 			    u32 phy_srstn, u32 phy_psrstn)
65*1881cdb1SYouMin Chen {
66*1881cdb1SYouMin Chen 	writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) |
67*1881cdb1SYouMin Chen 	       upctl2_asrstn_req(ctl_srstn),
68*1881cdb1SYouMin Chen 	       &dram->cru->softrst_con[1]);
69*1881cdb1SYouMin Chen 	writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn),
70*1881cdb1SYouMin Chen 	       &dram->cru->softrst_con[2]);
71*1881cdb1SYouMin Chen }
72*1881cdb1SYouMin Chen 
73*1881cdb1SYouMin Chen static void rkclk_set_dpll(struct dram_info *dram, unsigned int mhz)
74*1881cdb1SYouMin Chen {
75*1881cdb1SYouMin Chen 	unsigned int refdiv, postdiv1, postdiv2, fbdiv;
76*1881cdb1SYouMin Chen 	int delay = 1000;
77*1881cdb1SYouMin Chen 
78*1881cdb1SYouMin Chen 	refdiv = 1;
79*1881cdb1SYouMin Chen 	if (mhz <= 300) {
80*1881cdb1SYouMin Chen 		postdiv1 = 4;
81*1881cdb1SYouMin Chen 		postdiv2 = 2;
82*1881cdb1SYouMin Chen 	} else if (mhz <= 400) {
83*1881cdb1SYouMin Chen 		postdiv1 = 6;
84*1881cdb1SYouMin Chen 		postdiv2 = 1;
85*1881cdb1SYouMin Chen 	} else if (mhz <= 600) {
86*1881cdb1SYouMin Chen 		postdiv1 = 4;
87*1881cdb1SYouMin Chen 		postdiv2 = 1;
88*1881cdb1SYouMin Chen 	} else if (mhz <= 800) {
89*1881cdb1SYouMin Chen 		postdiv1 = 3;
90*1881cdb1SYouMin Chen 		postdiv2 = 1;
91*1881cdb1SYouMin Chen 	} else if (mhz <= 1600) {
92*1881cdb1SYouMin Chen 		postdiv1 = 2;
93*1881cdb1SYouMin Chen 		postdiv2 = 1;
94*1881cdb1SYouMin Chen 	} else {
95*1881cdb1SYouMin Chen 		postdiv1 = 1;
96*1881cdb1SYouMin Chen 		postdiv2 = 1;
97*1881cdb1SYouMin Chen 	}
98*1881cdb1SYouMin Chen 	fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24;
99*1881cdb1SYouMin Chen 
100*1881cdb1SYouMin Chen 	writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode);
101*1881cdb1SYouMin Chen 
102*1881cdb1SYouMin Chen 	writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0);
103*1881cdb1SYouMin Chen 	writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv),
104*1881cdb1SYouMin Chen 	       &dram->cru->pll[1].con1);
105*1881cdb1SYouMin Chen 
106*1881cdb1SYouMin Chen 	while (delay > 0) {
107*1881cdb1SYouMin Chen 		udelay(1);
108*1881cdb1SYouMin Chen 		if (LOCK(readl(&dram->cru->pll[1].con1)))
109*1881cdb1SYouMin Chen 			break;
110*1881cdb1SYouMin Chen 		delay--;
111*1881cdb1SYouMin Chen 	}
112*1881cdb1SYouMin Chen 
113*1881cdb1SYouMin Chen 	writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode);
114*1881cdb1SYouMin Chen }
115*1881cdb1SYouMin Chen 
116*1881cdb1SYouMin Chen static void rkclk_configure_ddr(struct dram_info *dram,
117*1881cdb1SYouMin Chen 				struct px30_sdram_params *sdram_params)
118*1881cdb1SYouMin Chen {
119*1881cdb1SYouMin Chen 	/* for inno ddr phy need 2*freq */
120*1881cdb1SYouMin Chen 	rkclk_set_dpll(dram,  sdram_params->ddr_freq * 2);
121*1881cdb1SYouMin Chen }
122*1881cdb1SYouMin Chen 
123*1881cdb1SYouMin Chen static void phy_soft_reset(struct dram_info *dram)
124*1881cdb1SYouMin Chen {
125*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
126*1881cdb1SYouMin Chen 
127*1881cdb1SYouMin Chen 	clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
128*1881cdb1SYouMin Chen 	udelay(1);
129*1881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
130*1881cdb1SYouMin Chen 	udelay(5);
131*1881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
132*1881cdb1SYouMin Chen 	udelay(1);
133*1881cdb1SYouMin Chen }
134*1881cdb1SYouMin Chen 
135*1881cdb1SYouMin Chen static int pctl_cfg(struct dram_info *dram,
136*1881cdb1SYouMin Chen 		    struct px30_sdram_params *sdram_params)
137*1881cdb1SYouMin Chen {
138*1881cdb1SYouMin Chen 	u32 i;
139*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
140*1881cdb1SYouMin Chen 
141*1881cdb1SYouMin Chen 	for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) {
142*1881cdb1SYouMin Chen 		writel(sdram_params->pctl_regs.pctl[i][1],
143*1881cdb1SYouMin Chen 		       pctl_base + sdram_params->pctl_regs.pctl[i][0]);
144*1881cdb1SYouMin Chen 	}
145*1881cdb1SYouMin Chen 	clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG,
146*1881cdb1SYouMin Chen 			(0xff << 16) | 0x1f,
147*1881cdb1SYouMin Chen 			((SR_IDLE & 0xff) << 16) | (PD_IDLE & 0x1f));
148*1881cdb1SYouMin Chen 
149*1881cdb1SYouMin Chen 	clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL,
150*1881cdb1SYouMin Chen 			0xfff << 16,
151*1881cdb1SYouMin Chen 			5 << 16);
152*1881cdb1SYouMin Chen 	/* disable zqcs */
153*1881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31);
154*1881cdb1SYouMin Chen 
155*1881cdb1SYouMin Chen 	return 0;
156*1881cdb1SYouMin Chen }
157*1881cdb1SYouMin Chen 
158*1881cdb1SYouMin Chen /* return ddrconfig value
159*1881cdb1SYouMin Chen  *       (-1), find ddrconfig fail
160*1881cdb1SYouMin Chen  *       other, the ddrconfig value
161*1881cdb1SYouMin Chen  * only support cs0_row >= cs1_row
162*1881cdb1SYouMin Chen  */
163*1881cdb1SYouMin Chen static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params)
164*1881cdb1SYouMin Chen {
165*1881cdb1SYouMin Chen 	u32 bw, die_bw, col, bank;
166*1881cdb1SYouMin Chen 	u32 i, tmp;
167*1881cdb1SYouMin Chen 	u32 ddrconf = -1;
168*1881cdb1SYouMin Chen 
169*1881cdb1SYouMin Chen 	bw = sdram_params->ch.bw;
170*1881cdb1SYouMin Chen 	die_bw = sdram_params->ch.dbw;
171*1881cdb1SYouMin Chen 	col = sdram_params->ch.col;
172*1881cdb1SYouMin Chen 	bank = sdram_params->ch.bk;
173*1881cdb1SYouMin Chen 
174*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4) {
175*1881cdb1SYouMin Chen 		if (die_bw == 0)
176*1881cdb1SYouMin Chen 			ddrconf = 7 + bw;
177*1881cdb1SYouMin Chen 		else
178*1881cdb1SYouMin Chen 			ddrconf = 12 - bw;
179*1881cdb1SYouMin Chen 		ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7];
180*1881cdb1SYouMin Chen 	} else {
181*1881cdb1SYouMin Chen 		tmp = ((bank - 2) << 3) | (col + bw - 10);
182*1881cdb1SYouMin Chen 		for (i = 0; i < 7; i++)
183*1881cdb1SYouMin Chen 			if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) {
184*1881cdb1SYouMin Chen 				ddrconf = i;
185*1881cdb1SYouMin Chen 				break;
186*1881cdb1SYouMin Chen 			}
187*1881cdb1SYouMin Chen 		if (i > 6)
188*1881cdb1SYouMin Chen 			printascii("calculate ddrconfig error\n");
189*1881cdb1SYouMin Chen 	}
190*1881cdb1SYouMin Chen 
191*1881cdb1SYouMin Chen 	return ddrconf;
192*1881cdb1SYouMin Chen }
193*1881cdb1SYouMin Chen 
194*1881cdb1SYouMin Chen /* n: Unit bytes */
195*1881cdb1SYouMin Chen static void copy_to_reg(u32 *dest, u32 *src, u32 n)
196*1881cdb1SYouMin Chen {
197*1881cdb1SYouMin Chen 	int i;
198*1881cdb1SYouMin Chen 
199*1881cdb1SYouMin Chen 	for (i = 0; i < n / sizeof(u32); i++) {
200*1881cdb1SYouMin Chen 		writel(*src, dest);
201*1881cdb1SYouMin Chen 		src++;
202*1881cdb1SYouMin Chen 		dest++;
203*1881cdb1SYouMin Chen 	}
204*1881cdb1SYouMin Chen }
205*1881cdb1SYouMin Chen 
206*1881cdb1SYouMin Chen /*
207*1881cdb1SYouMin Chen  * calculate controller dram address map, and setting to register.
208*1881cdb1SYouMin Chen  * argument sdram_params->ch.ddrconf must be right value before
209*1881cdb1SYouMin Chen  * call this function.
210*1881cdb1SYouMin Chen  */
211*1881cdb1SYouMin Chen static void set_ctl_address_map(struct dram_info *dram,
212*1881cdb1SYouMin Chen 				struct px30_sdram_params *sdram_params)
213*1881cdb1SYouMin Chen {
214*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
215*1881cdb1SYouMin Chen 	u32 cs_pst, bg, max_row, ddrconf;
216*1881cdb1SYouMin Chen 	u32 i;
217*1881cdb1SYouMin Chen 
218*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
219*1881cdb1SYouMin Chen 		/*
220*1881cdb1SYouMin Chen 		 * DDR4 8bit dram BG = 2(4bank groups),
221*1881cdb1SYouMin Chen 		 * 16bit dram BG = 1 (2 bank groups)
222*1881cdb1SYouMin Chen 		 */
223*1881cdb1SYouMin Chen 		bg = (sdram_params->ch.dbw == 0) ? 2 : 1;
224*1881cdb1SYouMin Chen 	else
225*1881cdb1SYouMin Chen 		bg = 0;
226*1881cdb1SYouMin Chen 
227*1881cdb1SYouMin Chen 	cs_pst = sdram_params->ch.bw + sdram_params->ch.col +
228*1881cdb1SYouMin Chen 		bg + sdram_params->ch.bk + sdram_params->ch.cs0_row;
229*1881cdb1SYouMin Chen 	if (cs_pst >= 32 || sdram_params->ch.rank == 1)
230*1881cdb1SYouMin Chen 		writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0);
231*1881cdb1SYouMin Chen 	else
232*1881cdb1SYouMin Chen 		writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0);
233*1881cdb1SYouMin Chen 
234*1881cdb1SYouMin Chen 	ddrconf = sdram_params->ch.ddrconfig;
235*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4) {
236*1881cdb1SYouMin Chen 		for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) {
237*1881cdb1SYouMin Chen 			if (d4_rbc_2_d3_rbc[i] == ddrconf) {
238*1881cdb1SYouMin Chen 				ddrconf = 7 + i;
239*1881cdb1SYouMin Chen 				break;
240*1881cdb1SYouMin Chen 			}
241*1881cdb1SYouMin Chen 		}
242*1881cdb1SYouMin Chen 	}
243*1881cdb1SYouMin Chen 
244*1881cdb1SYouMin Chen 	copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1),
245*1881cdb1SYouMin Chen 		    &addrmap[ddrconf][0], 8 * 4);
246*1881cdb1SYouMin Chen 	max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf);
247*1881cdb1SYouMin Chen 
248*1881cdb1SYouMin Chen 	if (max_row < 12)
249*1881cdb1SYouMin Chen 		printascii("set addrmap fail\n");
250*1881cdb1SYouMin Chen 	/* need to disable row ahead of rank by set to 0xf */
251*1881cdb1SYouMin Chen 	for (i = 17; i > max_row; i--)
252*1881cdb1SYouMin Chen 		clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 +
253*1881cdb1SYouMin Chen 			((i - 12) * 8 / 32) * 4,
254*1881cdb1SYouMin Chen 			0xf << ((i - 12) * 8 % 32),
255*1881cdb1SYouMin Chen 			0xf << ((i - 12) * 8 % 32));
256*1881cdb1SYouMin Chen 
257*1881cdb1SYouMin Chen 	if ((sdram_params->dramtype == LPDDR3 ||
258*1881cdb1SYouMin Chen 	     sdram_params->dramtype == LPDDR2) &&
259*1881cdb1SYouMin Chen 		 sdram_params->ch.row_3_4)
260*1881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
261*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4 && sdram_params->ch.bw != 0x2)
262*1881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
263*1881cdb1SYouMin Chen }
264*1881cdb1SYouMin Chen 
265*1881cdb1SYouMin Chen static void phy_dll_bypass_set(struct dram_info *dram, u32 freq)
266*1881cdb1SYouMin Chen {
267*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
268*1881cdb1SYouMin Chen 	u32 tmp;
269*1881cdb1SYouMin Chen 	u32 i, j;
270*1881cdb1SYouMin Chen 
271*1881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
272*1881cdb1SYouMin Chen 	clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
273*1881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
274*1881cdb1SYouMin Chen 		j = 0x26 + i * 0x10;
275*1881cdb1SYouMin Chen 		setbits_le32(PHY_REG(phy_base, j), 1 << 4);
276*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
277*1881cdb1SYouMin Chen 	}
278*1881cdb1SYouMin Chen 
279*1881cdb1SYouMin Chen 	if (freq <= (400 * MHz))
280*1881cdb1SYouMin Chen 		/* DLL bypass */
281*1881cdb1SYouMin Chen 		setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
282*1881cdb1SYouMin Chen 	else
283*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
284*1881cdb1SYouMin Chen 
285*1881cdb1SYouMin Chen 	if (freq <= (801 * MHz))
286*1881cdb1SYouMin Chen 		tmp = 2;
287*1881cdb1SYouMin Chen 	else
288*1881cdb1SYouMin Chen 		tmp = 1;
289*1881cdb1SYouMin Chen 
290*1881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
291*1881cdb1SYouMin Chen 		j = 0x28 + i * 0x10;
292*1881cdb1SYouMin Chen 		writel(tmp, PHY_REG(phy_base, j));
293*1881cdb1SYouMin Chen 	}
294*1881cdb1SYouMin Chen }
295*1881cdb1SYouMin Chen 
296*1881cdb1SYouMin Chen static void set_ds_odt(struct dram_info *dram,
297*1881cdb1SYouMin Chen 		       struct px30_sdram_params *sdram_params)
298*1881cdb1SYouMin Chen {
299*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
300*1881cdb1SYouMin Chen 	u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
301*1881cdb1SYouMin Chen 	u32 i, j;
302*1881cdb1SYouMin Chen 
303*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR3) {
304*1881cdb1SYouMin Chen 		cmd_drv = PHY_DDR3_RON_RTT_34ohm;
305*1881cdb1SYouMin Chen 		clk_drv = PHY_DDR3_RON_RTT_45ohm;
306*1881cdb1SYouMin Chen 		dqs_drv = PHY_DDR3_RON_RTT_34ohm;
307*1881cdb1SYouMin Chen 		dqs_odt = PHY_DDR3_RON_RTT_225ohm;
308*1881cdb1SYouMin Chen 	} else {
309*1881cdb1SYouMin Chen 		cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
310*1881cdb1SYouMin Chen 		clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
311*1881cdb1SYouMin Chen 		dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
312*1881cdb1SYouMin Chen 		if (sdram_params->dramtype == LPDDR2)
313*1881cdb1SYouMin Chen 			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
314*1881cdb1SYouMin Chen 		else
315*1881cdb1SYouMin Chen 			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
316*1881cdb1SYouMin Chen 	}
317*1881cdb1SYouMin Chen 	/* DS */
318*1881cdb1SYouMin Chen 	writel(cmd_drv, PHY_REG(phy_base, 0x11));
319*1881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
320*1881cdb1SYouMin Chen 	writel(clk_drv, PHY_REG(phy_base, 0x16));
321*1881cdb1SYouMin Chen 	writel(clk_drv, PHY_REG(phy_base, 0x18));
322*1881cdb1SYouMin Chen 
323*1881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
324*1881cdb1SYouMin Chen 		j = 0x20 + i * 0x10;
325*1881cdb1SYouMin Chen 		writel(dqs_drv, PHY_REG(phy_base, j));
326*1881cdb1SYouMin Chen 		writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
327*1881cdb1SYouMin Chen 		/* ODT */
328*1881cdb1SYouMin Chen 		writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
329*1881cdb1SYouMin Chen 		writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
330*1881cdb1SYouMin Chen 	}
331*1881cdb1SYouMin Chen }
332*1881cdb1SYouMin Chen 
333*1881cdb1SYouMin Chen static void phy_cfg(struct dram_info *dram,
334*1881cdb1SYouMin Chen 		    struct px30_sdram_params *sdram_params)
335*1881cdb1SYouMin Chen {
336*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
337*1881cdb1SYouMin Chen 	u32 i;
338*1881cdb1SYouMin Chen 
339*1881cdb1SYouMin Chen 	phy_dll_bypass_set(dram, sdram_params->ddr_freq);
340*1881cdb1SYouMin Chen 	for (i = 0; sdram_params->phy_regs.phy[i][0] != 0xFFFFFFFF; i++) {
341*1881cdb1SYouMin Chen 		writel(sdram_params->phy_regs.phy[i][1],
342*1881cdb1SYouMin Chen 		       phy_base + sdram_params->phy_regs.phy[i][0]);
343*1881cdb1SYouMin Chen 	}
344*1881cdb1SYouMin Chen 	if (sdram_params->ch.bw == 2) {
345*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
346*1881cdb1SYouMin Chen 	} else if (sdram_params->ch.bw == 1) {
347*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
348*1881cdb1SYouMin Chen 		/* disable DQS2,DQS3 tx dll  for saving power */
349*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
350*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
351*1881cdb1SYouMin Chen 	} else {
352*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
353*1881cdb1SYouMin Chen 		/* disable DQS2,DQS3 tx dll  for saving power */
354*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
355*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
356*1881cdb1SYouMin Chen 		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
357*1881cdb1SYouMin Chen 	}
358*1881cdb1SYouMin Chen 	set_ds_odt(dram, sdram_params);
359*1881cdb1SYouMin Chen 
360*1881cdb1SYouMin Chen 	/* deskew */
361*1881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 2), 8);
362*1881cdb1SYouMin Chen 	copy_to_reg(PHY_REG(phy_base, 0xb0),
363*1881cdb1SYouMin Chen 		    &sdram_params->skew->a0_a1_skew[0], 15 * 4);
364*1881cdb1SYouMin Chen 	copy_to_reg(PHY_REG(phy_base, 0x70),
365*1881cdb1SYouMin Chen 		    &sdram_params->skew->cs0_dm0_skew[0], 44 * 4);
366*1881cdb1SYouMin Chen 	copy_to_reg(PHY_REG(phy_base, 0xc0),
367*1881cdb1SYouMin Chen 		    &sdram_params->skew->cs0_dm1_skew[0], 44 * 4);
368*1881cdb1SYouMin Chen }
369*1881cdb1SYouMin Chen 
370*1881cdb1SYouMin Chen static int update_refresh_reg(struct dram_info *dram)
371*1881cdb1SYouMin Chen {
372*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
373*1881cdb1SYouMin Chen 	u32 ret;
374*1881cdb1SYouMin Chen 
375*1881cdb1SYouMin Chen 	ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1);
376*1881cdb1SYouMin Chen 	writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3);
377*1881cdb1SYouMin Chen 
378*1881cdb1SYouMin Chen 	return 0;
379*1881cdb1SYouMin Chen }
380*1881cdb1SYouMin Chen 
381*1881cdb1SYouMin Chen /*
382*1881cdb1SYouMin Chen  * rank = 1: cs0
383*1881cdb1SYouMin Chen  * rank = 2: cs1
384*1881cdb1SYouMin Chen  */
385*1881cdb1SYouMin Chen int read_mr(struct dram_info *dram, u32 rank, u32 mr_num)
386*1881cdb1SYouMin Chen {
387*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
388*1881cdb1SYouMin Chen 	void __iomem *ddr_grf_base = dram->ddr_grf;
389*1881cdb1SYouMin Chen 
390*1881cdb1SYouMin Chen 	writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0);
391*1881cdb1SYouMin Chen 	writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1);
392*1881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
393*1881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
394*1881cdb1SYouMin Chen 		continue;
395*1881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
396*1881cdb1SYouMin Chen 		continue;
397*1881cdb1SYouMin Chen 
398*1881cdb1SYouMin Chen 	return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff);
399*1881cdb1SYouMin Chen }
400*1881cdb1SYouMin Chen 
401*1881cdb1SYouMin Chen u32 disable_zqcs_arefresh(struct dram_info *dram)
402*1881cdb1SYouMin Chen {
403*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
404*1881cdb1SYouMin Chen 	u32 dis_auto_zq = 0;
405*1881cdb1SYouMin Chen 
406*1881cdb1SYouMin Chen 	/* disable zqcs */
407*1881cdb1SYouMin Chen 	if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
408*1881cdb1SYouMin Chen 		(1ul << 31))) {
409*1881cdb1SYouMin Chen 		dis_auto_zq = 1;
410*1881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
411*1881cdb1SYouMin Chen 	}
412*1881cdb1SYouMin Chen 
413*1881cdb1SYouMin Chen 	/* disable auto refresh */
414*1881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
415*1881cdb1SYouMin Chen 
416*1881cdb1SYouMin Chen 	update_refresh_reg(dram);
417*1881cdb1SYouMin Chen 
418*1881cdb1SYouMin Chen 	return dis_auto_zq;
419*1881cdb1SYouMin Chen }
420*1881cdb1SYouMin Chen 
421*1881cdb1SYouMin Chen void restore_zqcs_arefresh(struct dram_info *dram, u32 dis_auto_zq)
422*1881cdb1SYouMin Chen {
423*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
424*1881cdb1SYouMin Chen 
425*1881cdb1SYouMin Chen 	/* restore zqcs */
426*1881cdb1SYouMin Chen 	if (dis_auto_zq)
427*1881cdb1SYouMin Chen 		clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
428*1881cdb1SYouMin Chen 
429*1881cdb1SYouMin Chen 	/* restore auto refresh */
430*1881cdb1SYouMin Chen 	clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
431*1881cdb1SYouMin Chen 
432*1881cdb1SYouMin Chen 	update_refresh_reg(dram);
433*1881cdb1SYouMin Chen }
434*1881cdb1SYouMin Chen 
435*1881cdb1SYouMin Chen #define MIN(a, b)	(((a) > (b)) ? (b) : (a))
436*1881cdb1SYouMin Chen #define MAX(a, b)	(((a) > (b)) ? (a) : (b))
437*1881cdb1SYouMin Chen static u32 check_rd_gate(struct dram_info *dram)
438*1881cdb1SYouMin Chen {
439*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
440*1881cdb1SYouMin Chen 
441*1881cdb1SYouMin Chen 	u32 max_val = 0;
442*1881cdb1SYouMin Chen 	u32 min_val = 0xff;
443*1881cdb1SYouMin Chen 	u32 gate[4];
444*1881cdb1SYouMin Chen 	u32 i, bw;
445*1881cdb1SYouMin Chen 
446*1881cdb1SYouMin Chen 	bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf;
447*1881cdb1SYouMin Chen 	switch (bw) {
448*1881cdb1SYouMin Chen 	case 0x1:
449*1881cdb1SYouMin Chen 		bw = 1;
450*1881cdb1SYouMin Chen 		break;
451*1881cdb1SYouMin Chen 	case 0x3:
452*1881cdb1SYouMin Chen 		bw = 2;
453*1881cdb1SYouMin Chen 		break;
454*1881cdb1SYouMin Chen 	case 0xf:
455*1881cdb1SYouMin Chen 	default:
456*1881cdb1SYouMin Chen 		bw = 4;
457*1881cdb1SYouMin Chen 		break;
458*1881cdb1SYouMin Chen 	}
459*1881cdb1SYouMin Chen 
460*1881cdb1SYouMin Chen 	for (i = 0; i < bw; i++) {
461*1881cdb1SYouMin Chen 		gate[i] = readl(PHY_REG(phy_base, 0xfb + i));
462*1881cdb1SYouMin Chen 		max_val = MAX(max_val, gate[i]);
463*1881cdb1SYouMin Chen 		min_val = MIN(min_val, gate[i]);
464*1881cdb1SYouMin Chen 	}
465*1881cdb1SYouMin Chen 
466*1881cdb1SYouMin Chen 	if (max_val > 0x80 || min_val < 0x20)
467*1881cdb1SYouMin Chen 		return -1;
468*1881cdb1SYouMin Chen 	else
469*1881cdb1SYouMin Chen 		return 0;
470*1881cdb1SYouMin Chen }
471*1881cdb1SYouMin Chen 
472*1881cdb1SYouMin Chen static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
473*1881cdb1SYouMin Chen {
474*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
475*1881cdb1SYouMin Chen 	u32 ret;
476*1881cdb1SYouMin Chen 	u32 dis_auto_zq = 0;
477*1881cdb1SYouMin Chen 	u32 odt_val;
478*1881cdb1SYouMin Chen 	u32 i, j;
479*1881cdb1SYouMin Chen 
480*1881cdb1SYouMin Chen 	odt_val = readl(PHY_REG(phy_base, 0x2e));
481*1881cdb1SYouMin Chen 
482*1881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
483*1881cdb1SYouMin Chen 		j = 0x20 + i * 0x10;
484*1881cdb1SYouMin Chen 		writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
485*1881cdb1SYouMin Chen 		writel(0, PHY_REG(phy_base, j + 0xe));
486*1881cdb1SYouMin Chen 	}
487*1881cdb1SYouMin Chen 
488*1881cdb1SYouMin Chen 	dis_auto_zq = disable_zqcs_arefresh(dram);
489*1881cdb1SYouMin Chen 
490*1881cdb1SYouMin Chen 	if (dramtype == DDR4) {
491*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
492*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
493*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
494*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
495*1881cdb1SYouMin Chen 	}
496*1881cdb1SYouMin Chen 	/* choose training cs */
497*1881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
498*1881cdb1SYouMin Chen 	/* enable gate training */
499*1881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
500*1881cdb1SYouMin Chen 	udelay(50);
501*1881cdb1SYouMin Chen 	ret = readl(PHY_REG(phy_base, 0xff));
502*1881cdb1SYouMin Chen 	/* disable gate training */
503*1881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
504*1881cdb1SYouMin Chen 	clrbits_le32(PHY_REG(phy_base, 2), 0x30);
505*1881cdb1SYouMin Chen 	restore_zqcs_arefresh(dram, dis_auto_zq);
506*1881cdb1SYouMin Chen 
507*1881cdb1SYouMin Chen 	if (dramtype == DDR4) {
508*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
509*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
510*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
511*1881cdb1SYouMin Chen 		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
512*1881cdb1SYouMin Chen 	}
513*1881cdb1SYouMin Chen 
514*1881cdb1SYouMin Chen 	if (ret & 0x10) {
515*1881cdb1SYouMin Chen 		ret = -1;
516*1881cdb1SYouMin Chen 	} else {
517*1881cdb1SYouMin Chen 		ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
518*1881cdb1SYouMin Chen 		ret = (ret == 0) ? 0 : -1;
519*1881cdb1SYouMin Chen 	}
520*1881cdb1SYouMin Chen 
521*1881cdb1SYouMin Chen 	for (i = 0; i < 4; i++) {
522*1881cdb1SYouMin Chen 		j = 0x20 + i * 0x10;
523*1881cdb1SYouMin Chen 		writel(odt_val, PHY_REG(phy_base, j + 0x1));
524*1881cdb1SYouMin Chen 		writel(odt_val, PHY_REG(phy_base, j + 0xe));
525*1881cdb1SYouMin Chen 	}
526*1881cdb1SYouMin Chen 
527*1881cdb1SYouMin Chen 	return ret;
528*1881cdb1SYouMin Chen }
529*1881cdb1SYouMin Chen 
530*1881cdb1SYouMin Chen /* rank = 1: cs0
531*1881cdb1SYouMin Chen  * rank = 2: cs1
532*1881cdb1SYouMin Chen  * rank = 3: cs0 & cs1
533*1881cdb1SYouMin Chen  * note: be careful of keep mr original val
534*1881cdb1SYouMin Chen  */
535*1881cdb1SYouMin Chen static int write_mr(struct dram_info *dram, u32 rank, u32 mr_num, u32 arg,
536*1881cdb1SYouMin Chen 		    u32 dramtype)
537*1881cdb1SYouMin Chen {
538*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
539*1881cdb1SYouMin Chen 
540*1881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
541*1881cdb1SYouMin Chen 		continue;
542*1881cdb1SYouMin Chen 	if (dramtype == DDR3 || dramtype == DDR4) {
543*1881cdb1SYouMin Chen 		writel((mr_num << 12) | (rank << 4) | (0 << 0),
544*1881cdb1SYouMin Chen 		       pctl_base + DDR_PCTL2_MRCTRL0);
545*1881cdb1SYouMin Chen 		writel(arg, pctl_base + DDR_PCTL2_MRCTRL1);
546*1881cdb1SYouMin Chen 	} else {
547*1881cdb1SYouMin Chen 		writel((rank << 4) | (0 << 0),
548*1881cdb1SYouMin Chen 		       pctl_base + DDR_PCTL2_MRCTRL0);
549*1881cdb1SYouMin Chen 		writel((mr_num << 8) | (arg & 0xff),
550*1881cdb1SYouMin Chen 		       pctl_base + DDR_PCTL2_MRCTRL1);
551*1881cdb1SYouMin Chen 	}
552*1881cdb1SYouMin Chen 
553*1881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
554*1881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
555*1881cdb1SYouMin Chen 		continue;
556*1881cdb1SYouMin Chen 	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
557*1881cdb1SYouMin Chen 		continue;
558*1881cdb1SYouMin Chen 
559*1881cdb1SYouMin Chen 	return 0;
560*1881cdb1SYouMin Chen }
561*1881cdb1SYouMin Chen 
562*1881cdb1SYouMin Chen /*
563*1881cdb1SYouMin Chen  * rank : 1:cs0, 2:cs1, 3:cs0&cs1
564*1881cdb1SYouMin Chen  * vrefrate: 4500: 45%,
565*1881cdb1SYouMin Chen  */
566*1881cdb1SYouMin Chen static int write_vrefdq(struct dram_info *dram, u32 rank, u32 vrefrate,
567*1881cdb1SYouMin Chen 			u32 dramtype)
568*1881cdb1SYouMin Chen {
569*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
570*1881cdb1SYouMin Chen 	u32 tccd_l, value;
571*1881cdb1SYouMin Chen 	u32 dis_auto_zq = 0;
572*1881cdb1SYouMin Chen 
573*1881cdb1SYouMin Chen 	if (dramtype != DDR4 || vrefrate < 4500 ||
574*1881cdb1SYouMin Chen 	    vrefrate > 9200)
575*1881cdb1SYouMin Chen 		return (-1);
576*1881cdb1SYouMin Chen 
577*1881cdb1SYouMin Chen 	tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf;
578*1881cdb1SYouMin Chen 	tccd_l = (tccd_l - 4) << 10;
579*1881cdb1SYouMin Chen 
580*1881cdb1SYouMin Chen 	if (vrefrate > 7500) {
581*1881cdb1SYouMin Chen 		/* range 1 */
582*1881cdb1SYouMin Chen 		value = ((vrefrate - 6000) / 65) | tccd_l;
583*1881cdb1SYouMin Chen 	} else {
584*1881cdb1SYouMin Chen 		/* range 2 */
585*1881cdb1SYouMin Chen 		value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6);
586*1881cdb1SYouMin Chen 	}
587*1881cdb1SYouMin Chen 
588*1881cdb1SYouMin Chen 	dis_auto_zq = disable_zqcs_arefresh(dram);
589*1881cdb1SYouMin Chen 
590*1881cdb1SYouMin Chen 	/* enable vrefdq calibratin */
591*1881cdb1SYouMin Chen 	write_mr(dram, rank, 6, value | (1 << 7), dramtype);
592*1881cdb1SYouMin Chen 	udelay(1);/* tvrefdqe */
593*1881cdb1SYouMin Chen 	/* write vrefdq value */
594*1881cdb1SYouMin Chen 	write_mr(dram, rank, 6, value | (1 << 7), dramtype);
595*1881cdb1SYouMin Chen 	udelay(1);/* tvref_time */
596*1881cdb1SYouMin Chen 	write_mr(dram, rank, 6, value | (0 << 7), dramtype);
597*1881cdb1SYouMin Chen 	udelay(1);/* tvrefdqx */
598*1881cdb1SYouMin Chen 
599*1881cdb1SYouMin Chen 	restore_zqcs_arefresh(dram, dis_auto_zq);
600*1881cdb1SYouMin Chen 
601*1881cdb1SYouMin Chen 	return 0;
602*1881cdb1SYouMin Chen }
603*1881cdb1SYouMin Chen 
604*1881cdb1SYouMin Chen /*
605*1881cdb1SYouMin Chen  * cs: 0:cs0
606*1881cdb1SYouMin Chen  *	   1:cs1
607*1881cdb1SYouMin Chen  *     else cs0+cs1
608*1881cdb1SYouMin Chen  * note: it didn't consider about row_3_4
609*1881cdb1SYouMin Chen  */
610*1881cdb1SYouMin Chen u64 get_cs_cap(struct px30_sdram_params *sdram_params, u32 cs)
611*1881cdb1SYouMin Chen {
612*1881cdb1SYouMin Chen 	u32 bg;
613*1881cdb1SYouMin Chen 	u64 cap[2];
614*1881cdb1SYouMin Chen 
615*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
616*1881cdb1SYouMin Chen 		/* DDR4 8bit dram BG = 2(4bank groups),
617*1881cdb1SYouMin Chen 		 * 16bit dram BG = 1 (2 bank groups)
618*1881cdb1SYouMin Chen 		 */
619*1881cdb1SYouMin Chen 		bg = (sdram_params->ch.dbw == 0) ? 2 : 1;
620*1881cdb1SYouMin Chen 	else
621*1881cdb1SYouMin Chen 		bg = 0;
622*1881cdb1SYouMin Chen 	cap[0] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col +
623*1881cdb1SYouMin Chen 		bg + sdram_params->ch.bk + sdram_params->ch.cs0_row);
624*1881cdb1SYouMin Chen 
625*1881cdb1SYouMin Chen 	if (sdram_params->ch.rank == 2)
626*1881cdb1SYouMin Chen 		cap[1] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col +
627*1881cdb1SYouMin Chen 			bg + sdram_params->ch.bk + sdram_params->ch.cs1_row);
628*1881cdb1SYouMin Chen 	else
629*1881cdb1SYouMin Chen 		cap[1] = 0;
630*1881cdb1SYouMin Chen 
631*1881cdb1SYouMin Chen 	if (cs == 0)
632*1881cdb1SYouMin Chen 		return cap[0];
633*1881cdb1SYouMin Chen 	else if (cs == 1)
634*1881cdb1SYouMin Chen 		return cap[1];
635*1881cdb1SYouMin Chen 	else
636*1881cdb1SYouMin Chen 		return (cap[0] + cap[1]);
637*1881cdb1SYouMin Chen }
638*1881cdb1SYouMin Chen 
639*1881cdb1SYouMin Chen static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
640*1881cdb1SYouMin Chen {
641*1881cdb1SYouMin Chen 	writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf);
642*1881cdb1SYouMin Chen 	rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14);
643*1881cdb1SYouMin Chen }
644*1881cdb1SYouMin Chen 
645*1881cdb1SYouMin Chen static void dram_all_config(struct dram_info *dram,
646*1881cdb1SYouMin Chen 			    struct px30_sdram_params *sdram_params)
647*1881cdb1SYouMin Chen {
648*1881cdb1SYouMin Chen 	u32 sys_reg = 0;
649*1881cdb1SYouMin Chen 	u32 sys_reg3 = 0;
650*1881cdb1SYouMin Chen 	u64 cs_cap[2];
651*1881cdb1SYouMin Chen 
652*1881cdb1SYouMin Chen 	set_ddrconfig(dram, sdram_params->ch.ddrconfig);
653*1881cdb1SYouMin Chen 
654*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype);
655*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_ROW_3_4(sdram_params->ch.row_3_4);
656*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_RANK(sdram_params->ch.rank);
657*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_COL(sdram_params->ch.col);
658*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_BK(sdram_params->ch.bk);
659*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_BW(sdram_params->ch.bw);
660*1881cdb1SYouMin Chen 	sys_reg |= SYS_REG_ENC_DBW(sdram_params->ch.dbw);
661*1881cdb1SYouMin Chen 
662*1881cdb1SYouMin Chen 	SYS_REG_ENC_CS0_ROW_(sdram_params->ch.cs0_row, sys_reg, sys_reg3);
663*1881cdb1SYouMin Chen 	if (sdram_params->ch.cs1_row)
664*1881cdb1SYouMin Chen 		SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row, sys_reg,
665*1881cdb1SYouMin Chen 				     sys_reg3);
666*1881cdb1SYouMin Chen 	sys_reg3 |= SYS_REG_ENC_CS1_COL(sdram_params->ch.col);
667*1881cdb1SYouMin Chen 	sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
668*1881cdb1SYouMin Chen 
669*1881cdb1SYouMin Chen 	writel(sys_reg, &dram->pmugrf->os_reg[2]);
670*1881cdb1SYouMin Chen 	writel(sys_reg3, &dram->pmugrf->os_reg[3]);
671*1881cdb1SYouMin Chen 
672*1881cdb1SYouMin Chen 	cs_cap[0] = get_cs_cap(sdram_params, 0);
673*1881cdb1SYouMin Chen 	cs_cap[1] = get_cs_cap(sdram_params, 1);
674*1881cdb1SYouMin Chen 	writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) |
675*1881cdb1SYouMin Chen 			(((cs_cap[0] >> 20) / 64) & 0xff),
676*1881cdb1SYouMin Chen 			&dram->msch->devicesize);
677*1881cdb1SYouMin Chen 
678*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrtiminga0.d32,
679*1881cdb1SYouMin Chen 	       &dram->msch->ddrtiminga0);
680*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrtimingb0.d32,
681*1881cdb1SYouMin Chen 	       &dram->msch->ddrtimingb0);
682*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrtimingc0.d32,
683*1881cdb1SYouMin Chen 	       &dram->msch->ddrtimingc0);
684*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.devtodev0.d32,
685*1881cdb1SYouMin Chen 	       &dram->msch->devtodev0);
686*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddrmode.d32, &dram->msch->ddrmode);
687*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.ddr4timing.d32,
688*1881cdb1SYouMin Chen 	       &dram->msch->ddr4timing);
689*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->agingx0);
690*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging0);
691*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging1);
692*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging2);
693*1881cdb1SYouMin Chen 	writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging3);
694*1881cdb1SYouMin Chen }
695*1881cdb1SYouMin Chen 
696*1881cdb1SYouMin Chen static void enable_low_power(struct dram_info *dram,
697*1881cdb1SYouMin Chen 			     struct px30_sdram_params *sdram_params)
698*1881cdb1SYouMin Chen {
699*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
700*1881cdb1SYouMin Chen 	void __iomem *ddr_grf_base = dram->ddr_grf;
701*1881cdb1SYouMin Chen 	u32 grf_lp_con;
702*1881cdb1SYouMin Chen 
703*1881cdb1SYouMin Chen 	/*
704*1881cdb1SYouMin Chen 	 * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating
705*1881cdb1SYouMin Chen 	 * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access
706*1881cdb1SYouMin Chen 	 * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating
707*1881cdb1SYouMin Chen 	 * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr
708*1881cdb1SYouMin Chen 	 * bit4: grf_upctl_syscreq_cg_en = 1
709*1881cdb1SYouMin Chen 	 *       ungating coreclk when c_sysreq assert
710*1881cdb1SYouMin Chen 	 * bit8-11: grf_auto_sr_dly = 6
711*1881cdb1SYouMin Chen 	 */
712*1881cdb1SYouMin Chen 	writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]);
713*1881cdb1SYouMin Chen 
714*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
715*1881cdb1SYouMin Chen 		grf_lp_con = (0x7 << 16) | (1 << 1);
716*1881cdb1SYouMin Chen 	else if (sdram_params->dramtype == DDR3)
717*1881cdb1SYouMin Chen 		grf_lp_con = (0x7 << 16) | (1 << 0);
718*1881cdb1SYouMin Chen 	else
719*1881cdb1SYouMin Chen 		grf_lp_con = (0x7 << 16) | (1 << 2);
720*1881cdb1SYouMin Chen 
721*1881cdb1SYouMin Chen 	/* en lpckdis_en */
722*1881cdb1SYouMin Chen 	grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9);
723*1881cdb1SYouMin Chen 	writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON);
724*1881cdb1SYouMin Chen 
725*1881cdb1SYouMin Chen 	/* enable sr, pd */
726*1881cdb1SYouMin Chen 	if (PD_IDLE == 0)
727*1881cdb1SYouMin Chen 		clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
728*1881cdb1SYouMin Chen 	else
729*1881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
730*1881cdb1SYouMin Chen 	if (SR_IDLE == 0)
731*1881cdb1SYouMin Chen 		clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
732*1881cdb1SYouMin Chen 	else
733*1881cdb1SYouMin Chen 		setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
734*1881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3));
735*1881cdb1SYouMin Chen }
736*1881cdb1SYouMin Chen 
737*1881cdb1SYouMin Chen static int print_dec2hex(int i)
738*1881cdb1SYouMin Chen {
739*1881cdb1SYouMin Chen 	int tmp;
740*1881cdb1SYouMin Chen 
741*1881cdb1SYouMin Chen 	tmp = (i % 10);
742*1881cdb1SYouMin Chen 	tmp |= ((i % 100) / 10) << 4;
743*1881cdb1SYouMin Chen 	tmp |= ((i % 1000) / 100) << 8;
744*1881cdb1SYouMin Chen 
745*1881cdb1SYouMin Chen 	return tmp;
746*1881cdb1SYouMin Chen }
747*1881cdb1SYouMin Chen 
748*1881cdb1SYouMin Chen /*
749*1881cdb1SYouMin Chen  * pre_init: 0: pre init for dram cap detect
750*1881cdb1SYouMin Chen  * 1: detect correct cap(except cs1 row)info, than reinit
751*1881cdb1SYouMin Chen  * 2: after reinit, we detect cs1_row, if cs1_row not equal
752*1881cdb1SYouMin Chen  *    to cs0_row and cs is in middle on ddrconf map, we need
753*1881cdb1SYouMin Chen  *    to reinit dram, than set the correct ddrconf.
754*1881cdb1SYouMin Chen  */
755*1881cdb1SYouMin Chen static int sdram_init_(struct dram_info *dram,
756*1881cdb1SYouMin Chen 		       struct px30_sdram_params *sdram_params, u32 pre_init)
757*1881cdb1SYouMin Chen {
758*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
759*1881cdb1SYouMin Chen 
760*1881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 1, 1, 1);
761*1881cdb1SYouMin Chen 	udelay(10);
762*1881cdb1SYouMin Chen 	/*
763*1881cdb1SYouMin Chen 	 * dereset ddr phy psrstn to config pll,
764*1881cdb1SYouMin Chen 	 * if using phy pll psrstn must be dereset
765*1881cdb1SYouMin Chen 	 * before config pll
766*1881cdb1SYouMin Chen 	 */
767*1881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 1, 1, 0);
768*1881cdb1SYouMin Chen 	rkclk_configure_ddr(dram, sdram_params);
769*1881cdb1SYouMin Chen 
770*1881cdb1SYouMin Chen 	if (pre_init == 1) {
771*1881cdb1SYouMin Chen 		switch (sdram_params->dramtype) {
772*1881cdb1SYouMin Chen 		case DDR3:
773*1881cdb1SYouMin Chen 			printascii("DDR3\n");
774*1881cdb1SYouMin Chen 			break;
775*1881cdb1SYouMin Chen 		case DDR4:
776*1881cdb1SYouMin Chen 			printascii("DDR4\n");
777*1881cdb1SYouMin Chen 			break;
778*1881cdb1SYouMin Chen 		case LPDDR2:
779*1881cdb1SYouMin Chen 			printascii("LPDDR2\n");
780*1881cdb1SYouMin Chen 			break;
781*1881cdb1SYouMin Chen 		case LPDDR3:
782*1881cdb1SYouMin Chen 		default:
783*1881cdb1SYouMin Chen 			printascii("LPDDR3\n");
784*1881cdb1SYouMin Chen 			break;
785*1881cdb1SYouMin Chen 		}
786*1881cdb1SYouMin Chen 		printhex4(print_dec2hex(sdram_params->ddr_freq));
787*1881cdb1SYouMin Chen 		printascii("MHz\n");
788*1881cdb1SYouMin Chen 	}
789*1881cdb1SYouMin Chen 
790*1881cdb1SYouMin Chen 	/* release phy srst to provide clk to ctrl */
791*1881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 1, 0, 0);
792*1881cdb1SYouMin Chen 	udelay(10);
793*1881cdb1SYouMin Chen 	phy_soft_reset(dram);
794*1881cdb1SYouMin Chen 	/* release ctrl presetn, and config ctl registers */
795*1881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 1, 0, 0, 0);
796*1881cdb1SYouMin Chen 	pctl_cfg(dram, sdram_params);
797*1881cdb1SYouMin Chen 	sdram_params->ch.ddrconfig = calculate_ddrconfig(sdram_params);
798*1881cdb1SYouMin Chen 	set_ctl_address_map(dram, sdram_params);
799*1881cdb1SYouMin Chen 	phy_cfg(dram, sdram_params);
800*1881cdb1SYouMin Chen 
801*1881cdb1SYouMin Chen 	/* enable dfi_init_start to init phy after ctl srstn deassert */
802*1881cdb1SYouMin Chen 	setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
803*1881cdb1SYouMin Chen 
804*1881cdb1SYouMin Chen 	rkclk_ddr_reset(dram, 0, 0, 0, 0);
805*1881cdb1SYouMin Chen 	/* wait for dfi_init_done and dram init complete */
806*1881cdb1SYouMin Chen 	while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
807*1881cdb1SYouMin Chen 		continue;
808*1881cdb1SYouMin Chen 
809*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == LPDDR3)
810*1881cdb1SYouMin Chen 		write_mr(dram, 3, 11, 3, LPDDR3);
811*1881cdb1SYouMin Chen 
812*1881cdb1SYouMin Chen 	/* do ddr gate training */
813*1881cdb1SYouMin Chen redo_cs0_training:
814*1881cdb1SYouMin Chen 	if (data_training(dram, 0, sdram_params->dramtype) != 0) {
815*1881cdb1SYouMin Chen 		if (pre_init != 0)
816*1881cdb1SYouMin Chen 			printascii("DTT cs0 error\n");
817*1881cdb1SYouMin Chen 		return -1;
818*1881cdb1SYouMin Chen 	}
819*1881cdb1SYouMin Chen 	if (check_rd_gate(dram)) {
820*1881cdb1SYouMin Chen 		printascii("re training cs0");
821*1881cdb1SYouMin Chen 		goto redo_cs0_training;
822*1881cdb1SYouMin Chen 	}
823*1881cdb1SYouMin Chen 
824*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == LPDDR3) {
825*1881cdb1SYouMin Chen 		if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
826*1881cdb1SYouMin Chen 			return -1;
827*1881cdb1SYouMin Chen 	} else if (sdram_params->dramtype == LPDDR2) {
828*1881cdb1SYouMin Chen 		if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
829*1881cdb1SYouMin Chen 			return -1;
830*1881cdb1SYouMin Chen 	}
831*1881cdb1SYouMin Chen 	/* for px30: when 2cs, both 2 cs should be training */
832*1881cdb1SYouMin Chen 	if (pre_init != 0 && sdram_params->ch.rank == 2) {
833*1881cdb1SYouMin Chen redo_cs1_training:
834*1881cdb1SYouMin Chen 		if (data_training(dram, 1, sdram_params->dramtype) != 0) {
835*1881cdb1SYouMin Chen 			printascii("DTT cs1 error\n");
836*1881cdb1SYouMin Chen 			return -1;
837*1881cdb1SYouMin Chen 		}
838*1881cdb1SYouMin Chen 		if (check_rd_gate(dram)) {
839*1881cdb1SYouMin Chen 			printascii("re training cs1");
840*1881cdb1SYouMin Chen 			goto redo_cs1_training;
841*1881cdb1SYouMin Chen 		}
842*1881cdb1SYouMin Chen 	}
843*1881cdb1SYouMin Chen 
844*1881cdb1SYouMin Chen 	if (sdram_params->dramtype == DDR4)
845*1881cdb1SYouMin Chen 		write_vrefdq(dram, 0x3, 5670, sdram_params->dramtype);
846*1881cdb1SYouMin Chen 
847*1881cdb1SYouMin Chen 	dram_all_config(dram, sdram_params);
848*1881cdb1SYouMin Chen 	enable_low_power(dram, sdram_params);
849*1881cdb1SYouMin Chen 
850*1881cdb1SYouMin Chen 	return 0;
851*1881cdb1SYouMin Chen }
852*1881cdb1SYouMin Chen 
853*1881cdb1SYouMin Chen static u64 dram_detect_cap(struct dram_info *dram,
854*1881cdb1SYouMin Chen 			   struct px30_sdram_params *sdram_params,
855*1881cdb1SYouMin Chen 			   unsigned char channel)
856*1881cdb1SYouMin Chen {
857*1881cdb1SYouMin Chen 	void __iomem *pctl_base = dram->pctl;
858*1881cdb1SYouMin Chen 	void __iomem *phy_base = dram->phy;
859*1881cdb1SYouMin Chen 
860*1881cdb1SYouMin Chen 	/*
861*1881cdb1SYouMin Chen 	 * for ddr3: ddrconf = 3
862*1881cdb1SYouMin Chen 	 * for ddr4: ddrconf = 12
863*1881cdb1SYouMin Chen 	 * for lpddr3: ddrconf = 3
864*1881cdb1SYouMin Chen 	 * default bw = 1
865*1881cdb1SYouMin Chen 	 */
866*1881cdb1SYouMin Chen 	u32 bk, bktmp;
867*1881cdb1SYouMin Chen 	u32 col, coltmp;
868*1881cdb1SYouMin Chen 	u32 row, rowtmp, row_3_4;
869*1881cdb1SYouMin Chen 	void __iomem *test_addr, *test_addr1;
870*1881cdb1SYouMin Chen 	u32 dbw;
871*1881cdb1SYouMin Chen 	u32 cs;
872*1881cdb1SYouMin Chen 	u32 bw = 1;
873*1881cdb1SYouMin Chen 	u64 cap = 0;
874*1881cdb1SYouMin Chen 	u32 dram_type = sdram_params->dramtype;
875*1881cdb1SYouMin Chen 	u32 pwrctl;
876*1881cdb1SYouMin Chen 
877*1881cdb1SYouMin Chen 	if (dram_type != DDR4) {
878*1881cdb1SYouMin Chen 		/* detect col and bk for ddr3/lpddr3 */
879*1881cdb1SYouMin Chen 		coltmp = 12;
880*1881cdb1SYouMin Chen 		bktmp = 3;
881*1881cdb1SYouMin Chen 		rowtmp = 16;
882*1881cdb1SYouMin Chen 
883*1881cdb1SYouMin Chen 		for (col = coltmp; col >= 9; col -= 1) {
884*1881cdb1SYouMin Chen 			writel(0, CONFIG_SYS_SDRAM_BASE);
885*1881cdb1SYouMin Chen 			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
886*1881cdb1SYouMin Chen 					(1ul << (col + bw - 1ul)));
887*1881cdb1SYouMin Chen 			writel(PATTERN, test_addr);
888*1881cdb1SYouMin Chen 			if ((readl(test_addr) == PATTERN) &&
889*1881cdb1SYouMin Chen 			    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
890*1881cdb1SYouMin Chen 				break;
891*1881cdb1SYouMin Chen 		}
892*1881cdb1SYouMin Chen 		if (col == 8) {
893*1881cdb1SYouMin Chen 			printascii("col error\n");
894*1881cdb1SYouMin Chen 			goto cap_err;
895*1881cdb1SYouMin Chen 		}
896*1881cdb1SYouMin Chen 
897*1881cdb1SYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
898*1881cdb1SYouMin Chen 				(1ul << (coltmp + bktmp + bw - 1ul)));
899*1881cdb1SYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
900*1881cdb1SYouMin Chen 		writel(PATTERN, test_addr);
901*1881cdb1SYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
902*1881cdb1SYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
903*1881cdb1SYouMin Chen 			bk = 3;
904*1881cdb1SYouMin Chen 		else
905*1881cdb1SYouMin Chen 			bk = 2;
906*1881cdb1SYouMin Chen 		if (dram_type == DDR3)
907*1881cdb1SYouMin Chen 			dbw = 1;
908*1881cdb1SYouMin Chen 		else
909*1881cdb1SYouMin Chen 			dbw = 2;
910*1881cdb1SYouMin Chen 	} else {
911*1881cdb1SYouMin Chen 		/* detect bg for ddr4 */
912*1881cdb1SYouMin Chen 		coltmp = 10;
913*1881cdb1SYouMin Chen 		bktmp = 4;
914*1881cdb1SYouMin Chen 		rowtmp = 17;
915*1881cdb1SYouMin Chen 
916*1881cdb1SYouMin Chen 		col = 10;
917*1881cdb1SYouMin Chen 		bk = 2;
918*1881cdb1SYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
919*1881cdb1SYouMin Chen 				(1ul << (coltmp + bw + 1ul)));
920*1881cdb1SYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
921*1881cdb1SYouMin Chen 		writel(PATTERN, test_addr);
922*1881cdb1SYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
923*1881cdb1SYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
924*1881cdb1SYouMin Chen 			dbw = 0;
925*1881cdb1SYouMin Chen 		else
926*1881cdb1SYouMin Chen 			dbw = 1;
927*1881cdb1SYouMin Chen 	}
928*1881cdb1SYouMin Chen 	/* detect row */
929*1881cdb1SYouMin Chen 	for (row = rowtmp; row > 12; row--) {
930*1881cdb1SYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
931*1881cdb1SYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
932*1881cdb1SYouMin Chen 				(1ul << (row + bktmp + coltmp + bw - 1ul)));
933*1881cdb1SYouMin Chen 		writel(PATTERN, test_addr);
934*1881cdb1SYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
935*1881cdb1SYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
936*1881cdb1SYouMin Chen 			break;
937*1881cdb1SYouMin Chen 	}
938*1881cdb1SYouMin Chen 	if (row == 12) {
939*1881cdb1SYouMin Chen 		printascii("row error");
940*1881cdb1SYouMin Chen 		goto cap_err;
941*1881cdb1SYouMin Chen 	}
942*1881cdb1SYouMin Chen 	/* detect row_3_4 */
943*1881cdb1SYouMin Chen 	test_addr = CONFIG_SYS_SDRAM_BASE;
944*1881cdb1SYouMin Chen 	test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
945*1881cdb1SYouMin Chen 			(0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
946*1881cdb1SYouMin Chen 
947*1881cdb1SYouMin Chen 	writel(0, test_addr);
948*1881cdb1SYouMin Chen 	writel(PATTERN, test_addr1);
949*1881cdb1SYouMin Chen 	if ((readl(test_addr) == 0) &&
950*1881cdb1SYouMin Chen 	    (readl(test_addr1) == PATTERN))
951*1881cdb1SYouMin Chen 		row_3_4 = 0;
952*1881cdb1SYouMin Chen 	else
953*1881cdb1SYouMin Chen 		row_3_4 = 1;
954*1881cdb1SYouMin Chen 
955*1881cdb1SYouMin Chen 	/* disable auto low-power */
956*1881cdb1SYouMin Chen 	pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
957*1881cdb1SYouMin Chen 	writel(0, pctl_base + DDR_PCTL2_PWRCTL);
958*1881cdb1SYouMin Chen 
959*1881cdb1SYouMin Chen 	/* bw and cs detect using phy read gate training */
960*1881cdb1SYouMin Chen 	if (data_training(dram, 1, dram_type) == 0)
961*1881cdb1SYouMin Chen 		cs = 1;
962*1881cdb1SYouMin Chen 	else
963*1881cdb1SYouMin Chen 		cs = 0;
964*1881cdb1SYouMin Chen 
965*1881cdb1SYouMin Chen 	clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
966*1881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
967*1881cdb1SYouMin Chen 	setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
968*1881cdb1SYouMin Chen 
969*1881cdb1SYouMin Chen 	phy_soft_reset(dram);
970*1881cdb1SYouMin Chen 
971*1881cdb1SYouMin Chen 	if (data_training(dram, 0, dram_type) == 0)
972*1881cdb1SYouMin Chen 		bw = 2;
973*1881cdb1SYouMin Chen 	else
974*1881cdb1SYouMin Chen 		bw = 1;
975*1881cdb1SYouMin Chen 
976*1881cdb1SYouMin Chen 	/* restore auto low-power */
977*1881cdb1SYouMin Chen 	writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
978*1881cdb1SYouMin Chen 
979*1881cdb1SYouMin Chen 	sdram_params->ch.rank = cs + 1;
980*1881cdb1SYouMin Chen 	sdram_params->ch.col = col;
981*1881cdb1SYouMin Chen 	sdram_params->ch.bk = bk;
982*1881cdb1SYouMin Chen 	sdram_params->ch.dbw = dbw;
983*1881cdb1SYouMin Chen 	sdram_params->ch.bw = bw;
984*1881cdb1SYouMin Chen 	sdram_params->ch.cs0_row = row;
985*1881cdb1SYouMin Chen 	sdram_params->ch.cs0_high16bit_row = row;
986*1881cdb1SYouMin Chen 	if (cs) {
987*1881cdb1SYouMin Chen 		sdram_params->ch.cs1_row = row;
988*1881cdb1SYouMin Chen 		sdram_params->ch.cs1_high16bit_row = row;
989*1881cdb1SYouMin Chen 	} else {
990*1881cdb1SYouMin Chen 		sdram_params->ch.cs1_row = 0;
991*1881cdb1SYouMin Chen 		sdram_params->ch.cs1_high16bit_row = 0;
992*1881cdb1SYouMin Chen 	}
993*1881cdb1SYouMin Chen 	sdram_params->ch.row_3_4 = row_3_4;
994*1881cdb1SYouMin Chen 
995*1881cdb1SYouMin Chen 	if (dram_type == DDR4)
996*1881cdb1SYouMin Chen 		cap = 1llu << (cs + row + bk + col + ((dbw == 0) ? 2 : 1) + bw);
997*1881cdb1SYouMin Chen 	else
998*1881cdb1SYouMin Chen 		cap = 1llu << (cs + row + bk + col + bw);
999*1881cdb1SYouMin Chen 
1000*1881cdb1SYouMin Chen 	return cap;
1001*1881cdb1SYouMin Chen 
1002*1881cdb1SYouMin Chen cap_err:
1003*1881cdb1SYouMin Chen 	return 0;
1004*1881cdb1SYouMin Chen }
1005*1881cdb1SYouMin Chen 
1006*1881cdb1SYouMin Chen static u32 remodify_sdram_params(struct px30_sdram_params *sdram_params)
1007*1881cdb1SYouMin Chen {
1008*1881cdb1SYouMin Chen 	u32 tmp = 0, tmp_adr = 0, i;
1009*1881cdb1SYouMin Chen 
1010*1881cdb1SYouMin Chen 	for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) {
1011*1881cdb1SYouMin Chen 		if (sdram_params->pctl_regs.pctl[i][0] == 0) {
1012*1881cdb1SYouMin Chen 			tmp = sdram_params->pctl_regs.pctl[i][1];/* MSTR */
1013*1881cdb1SYouMin Chen 			tmp_adr = i;
1014*1881cdb1SYouMin Chen 		}
1015*1881cdb1SYouMin Chen 	}
1016*1881cdb1SYouMin Chen 
1017*1881cdb1SYouMin Chen 	tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12));
1018*1881cdb1SYouMin Chen 
1019*1881cdb1SYouMin Chen 	switch (sdram_params->ch.dbw) {
1020*1881cdb1SYouMin Chen 	case 2:
1021*1881cdb1SYouMin Chen 		tmp |= (3ul << 30);
1022*1881cdb1SYouMin Chen 		break;
1023*1881cdb1SYouMin Chen 	case 1:
1024*1881cdb1SYouMin Chen 		tmp |= (2ul << 30);
1025*1881cdb1SYouMin Chen 		break;
1026*1881cdb1SYouMin Chen 	case 0:
1027*1881cdb1SYouMin Chen 	default:
1028*1881cdb1SYouMin Chen 		tmp |= (1ul << 30);
1029*1881cdb1SYouMin Chen 		break;
1030*1881cdb1SYouMin Chen 	}
1031*1881cdb1SYouMin Chen 
1032*1881cdb1SYouMin Chen 	if (sdram_params->ch.rank == 2)
1033*1881cdb1SYouMin Chen 		tmp |= 3 << 24;
1034*1881cdb1SYouMin Chen 	else
1035*1881cdb1SYouMin Chen 		tmp |= 1 << 24;
1036*1881cdb1SYouMin Chen 
1037*1881cdb1SYouMin Chen 	tmp |= (2 - sdram_params->ch.bw) << 12;
1038*1881cdb1SYouMin Chen 
1039*1881cdb1SYouMin Chen 	sdram_params->pctl_regs.pctl[tmp_adr][1] = tmp;
1040*1881cdb1SYouMin Chen 
1041*1881cdb1SYouMin Chen 	return 0;
1042*1881cdb1SYouMin Chen }
1043*1881cdb1SYouMin Chen 
1044*1881cdb1SYouMin Chen int dram_detect_high_row(struct dram_info *dram,
1045*1881cdb1SYouMin Chen 			 struct px30_sdram_params *sdram_params,
1046*1881cdb1SYouMin Chen 			 unsigned char channel)
1047*1881cdb1SYouMin Chen {
1048*1881cdb1SYouMin Chen 	sdram_params->ch.cs0_high16bit_row = sdram_params->ch.cs0_row;
1049*1881cdb1SYouMin Chen 	sdram_params->ch.cs1_high16bit_row = sdram_params->ch.cs1_row;
1050*1881cdb1SYouMin Chen 
1051*1881cdb1SYouMin Chen 	return 0;
1052*1881cdb1SYouMin Chen }
1053*1881cdb1SYouMin Chen 
1054*1881cdb1SYouMin Chen static int dram_detect_cs1_row(struct px30_sdram_params *sdram_params,
1055*1881cdb1SYouMin Chen 			       unsigned char channel)
1056*1881cdb1SYouMin Chen {
1057*1881cdb1SYouMin Chen 	u32 ret = 0;
1058*1881cdb1SYouMin Chen 	void __iomem *test_addr;
1059*1881cdb1SYouMin Chen 	u32 row, bktmp, coltmp, bw;
1060*1881cdb1SYouMin Chen 	u64 cs0_cap;
1061*1881cdb1SYouMin Chen 	u32 byte_mask;
1062*1881cdb1SYouMin Chen 
1063*1881cdb1SYouMin Chen 	if (sdram_params->ch.rank == 2) {
1064*1881cdb1SYouMin Chen 		cs0_cap = get_cs_cap(sdram_params, 0);
1065*1881cdb1SYouMin Chen 
1066*1881cdb1SYouMin Chen 		if (sdram_params->dramtype == DDR4) {
1067*1881cdb1SYouMin Chen 			if (sdram_params->ch.dbw == 0)
1068*1881cdb1SYouMin Chen 				bktmp = sdram_params->ch.bk + 2;
1069*1881cdb1SYouMin Chen 			else
1070*1881cdb1SYouMin Chen 				bktmp = sdram_params->ch.bk + 1;
1071*1881cdb1SYouMin Chen 		} else {
1072*1881cdb1SYouMin Chen 			bktmp = sdram_params->ch.bk;
1073*1881cdb1SYouMin Chen 		}
1074*1881cdb1SYouMin Chen 		bw = sdram_params->ch.bw;
1075*1881cdb1SYouMin Chen 		coltmp = sdram_params->ch.col;
1076*1881cdb1SYouMin Chen 
1077*1881cdb1SYouMin Chen 		/*
1078*1881cdb1SYouMin Chen 		 * because px30 support axi split,min bandwidth
1079*1881cdb1SYouMin Chen 		 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
1080*1881cdb1SYouMin Chen 		 * so we check low 16bit data when detect cs1 row.
1081*1881cdb1SYouMin Chen 		 * if cs0 is 16bit/8bit, we check low 8bit data.
1082*1881cdb1SYouMin Chen 		 */
1083*1881cdb1SYouMin Chen 		if (bw == 2)
1084*1881cdb1SYouMin Chen 			byte_mask = 0xFFFF;
1085*1881cdb1SYouMin Chen 		else
1086*1881cdb1SYouMin Chen 			byte_mask = 0xFF;
1087*1881cdb1SYouMin Chen 
1088*1881cdb1SYouMin Chen 		/* detect cs1 row */
1089*1881cdb1SYouMin Chen 		for (row = sdram_params->ch.cs0_row; row > 12; row--) {
1090*1881cdb1SYouMin Chen 			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
1091*1881cdb1SYouMin Chen 				    cs0_cap +
1092*1881cdb1SYouMin Chen 				    (1ul << (row + bktmp + coltmp + bw - 1ul)));
1093*1881cdb1SYouMin Chen 			writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
1094*1881cdb1SYouMin Chen 			writel(PATTERN, test_addr);
1095*1881cdb1SYouMin Chen 
1096*1881cdb1SYouMin Chen 			if (((readl(test_addr) & byte_mask) ==
1097*1881cdb1SYouMin Chen 			     (PATTERN & byte_mask)) &&
1098*1881cdb1SYouMin Chen 			    ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
1099*1881cdb1SYouMin Chen 			      byte_mask) == 0)) {
1100*1881cdb1SYouMin Chen 				ret = row;
1101*1881cdb1SYouMin Chen 				break;
1102*1881cdb1SYouMin Chen 			}
1103*1881cdb1SYouMin Chen 		}
1104*1881cdb1SYouMin Chen 	}
1105*1881cdb1SYouMin Chen 
1106*1881cdb1SYouMin Chen 	return ret;
1107*1881cdb1SYouMin Chen }
1108*1881cdb1SYouMin Chen 
1109*1881cdb1SYouMin Chen /* return: 0 = success, other = fail */
1110*1881cdb1SYouMin Chen static int sdram_init_detect(struct dram_info *dram,
1111*1881cdb1SYouMin Chen 			     struct px30_sdram_params *sdram_params)
1112*1881cdb1SYouMin Chen {
1113*1881cdb1SYouMin Chen 	u32 ret;
1114*1881cdb1SYouMin Chen 	u32 sys_reg = 0;
1115*1881cdb1SYouMin Chen 	u32 sys_reg3 = 0;
1116*1881cdb1SYouMin Chen 
1117*1881cdb1SYouMin Chen 	if (sdram_init_(dram, sdram_params, 0) != 0)
1118*1881cdb1SYouMin Chen 		return -1;
1119*1881cdb1SYouMin Chen 
1120*1881cdb1SYouMin Chen 	if (dram_detect_cap(dram, sdram_params, 0) == 0)
1121*1881cdb1SYouMin Chen 		return -1;
1122*1881cdb1SYouMin Chen 
1123*1881cdb1SYouMin Chen 	/* modify bw, cs related timing */
1124*1881cdb1SYouMin Chen 	remodify_sdram_params(sdram_params);
1125*1881cdb1SYouMin Chen 	/* reinit sdram by real dram cap */
1126*1881cdb1SYouMin Chen 	ret = sdram_init_(dram, sdram_params, 1);
1127*1881cdb1SYouMin Chen 	if (ret != 0)
1128*1881cdb1SYouMin Chen 		goto out;
1129*1881cdb1SYouMin Chen 
1130*1881cdb1SYouMin Chen 	/* redetect cs1 row */
1131*1881cdb1SYouMin Chen 	sdram_params->ch.cs1_row =
1132*1881cdb1SYouMin Chen 		dram_detect_cs1_row(sdram_params, 0);
1133*1881cdb1SYouMin Chen 	if (sdram_params->ch.cs1_row) {
1134*1881cdb1SYouMin Chen 		sys_reg = readl(&dram->pmugrf->os_reg[2]);
1135*1881cdb1SYouMin Chen 		sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
1136*1881cdb1SYouMin Chen 		SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row,
1137*1881cdb1SYouMin Chen 				     sys_reg, sys_reg3);
1138*1881cdb1SYouMin Chen 		writel(sys_reg, &dram->pmugrf->os_reg[2]);
1139*1881cdb1SYouMin Chen 		writel(sys_reg3, &dram->pmugrf->os_reg[3]);
1140*1881cdb1SYouMin Chen 	}
1141*1881cdb1SYouMin Chen 
1142*1881cdb1SYouMin Chen 	ret = dram_detect_high_row(dram, sdram_params, 0);
1143*1881cdb1SYouMin Chen 
1144*1881cdb1SYouMin Chen out:
1145*1881cdb1SYouMin Chen 	return ret;
1146*1881cdb1SYouMin Chen }
1147*1881cdb1SYouMin Chen 
1148*1881cdb1SYouMin Chen struct px30_sdram_params
1149*1881cdb1SYouMin Chen 		*get_default_sdram_config(void)
1150*1881cdb1SYouMin Chen {
1151*1881cdb1SYouMin Chen 	sdram_configs[0].skew = &skew;
1152*1881cdb1SYouMin Chen 
1153*1881cdb1SYouMin Chen 	return &sdram_configs[0];
1154*1881cdb1SYouMin Chen }
1155*1881cdb1SYouMin Chen 
1156*1881cdb1SYouMin Chen /* return: 0 = success, other = fail */
1157*1881cdb1SYouMin Chen int sdram_init(void)
1158*1881cdb1SYouMin Chen {
1159*1881cdb1SYouMin Chen 	struct px30_sdram_params *sdram_params;
1160*1881cdb1SYouMin Chen 	int ret = 0;
1161*1881cdb1SYouMin Chen 
1162*1881cdb1SYouMin Chen 	printascii("DDR Init V1.07\n");
1163*1881cdb1SYouMin Chen 
1164*1881cdb1SYouMin Chen 	dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
1165*1881cdb1SYouMin Chen 	dram_info.pctl = (void *)DDRC_BASE_ADDR;
1166*1881cdb1SYouMin Chen 	dram_info.grf = (void *)GRF_BASE_ADDR;
1167*1881cdb1SYouMin Chen 	dram_info.cru = (void *)CRU_BASE_ADDR;
1168*1881cdb1SYouMin Chen 	dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
1169*1881cdb1SYouMin Chen 	dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
1170*1881cdb1SYouMin Chen 	dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
1171*1881cdb1SYouMin Chen 
1172*1881cdb1SYouMin Chen 	sdram_params = get_default_sdram_config();
1173*1881cdb1SYouMin Chen 	ret = sdram_init_detect(&dram_info, sdram_params);
1174*1881cdb1SYouMin Chen 
1175*1881cdb1SYouMin Chen 	if (ret)
1176*1881cdb1SYouMin Chen 		goto error;
1177*1881cdb1SYouMin Chen 
1178*1881cdb1SYouMin Chen 	printascii("out\n");
1179*1881cdb1SYouMin Chen 	return ret;
1180*1881cdb1SYouMin Chen error:
1181*1881cdb1SYouMin Chen 	return (-1);
1182*1881cdb1SYouMin Chen }
1183*1881cdb1SYouMin Chen 
1184*1881cdb1SYouMin Chen #else /* CONFIG_TPL_BUILD */
1185*1881cdb1SYouMin Chen 
11865eeb396bSKever Yang static int px30_dmc_probe(struct udevice *dev)
11875eeb396bSKever Yang {
11885eeb396bSKever Yang 	struct dram_info *priv = dev_get_priv(dev);
11895eeb396bSKever Yang 
119089f991f8SJoseph Chen 	priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
11915eeb396bSKever Yang 	debug("%s: pmugrf=%p\n", __func__, priv->pmugrf);
11925eeb396bSKever Yang 	priv->info.base = CONFIG_SYS_SDRAM_BASE;
1193*1881cdb1SYouMin Chen 	priv->info.size =
1194*1881cdb1SYouMin Chen 		rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg[2]);
11955eeb396bSKever Yang 
11965eeb396bSKever Yang 	return 0;
11975eeb396bSKever Yang }
11985eeb396bSKever Yang 
11995eeb396bSKever Yang static int px30_dmc_get_info(struct udevice *dev, struct ram_info *info)
12005eeb396bSKever Yang {
12015eeb396bSKever Yang 	struct dram_info *priv = dev_get_priv(dev);
12025eeb396bSKever Yang 
12035eeb396bSKever Yang 	*info = priv->info;
12045eeb396bSKever Yang 
12055eeb396bSKever Yang 	return 0;
12065eeb396bSKever Yang }
12075eeb396bSKever Yang 
12085eeb396bSKever Yang static struct ram_ops px30_dmc_ops = {
12095eeb396bSKever Yang 	.get_info = px30_dmc_get_info,
12105eeb396bSKever Yang };
12115eeb396bSKever Yang 
12125eeb396bSKever Yang static const struct udevice_id px30_dmc_ids[] = {
12135eeb396bSKever Yang 	{ .compatible = "rockchip,px30-dmc" },
12145eeb396bSKever Yang 	{ }
12155eeb396bSKever Yang };
12165eeb396bSKever Yang 
12175eeb396bSKever Yang U_BOOT_DRIVER(dmc_px30) = {
12185eeb396bSKever Yang 	.name = "rockchip_px30_dmc",
12195eeb396bSKever Yang 	.id = UCLASS_RAM,
12205eeb396bSKever Yang 	.of_match = px30_dmc_ids,
12215eeb396bSKever Yang 	.ops = &px30_dmc_ops,
12225eeb396bSKever Yang 	.probe = px30_dmc_probe,
12235eeb396bSKever Yang 	.priv_auto_alloc_size = sizeof(struct dram_info),
12245eeb396bSKever Yang };
1225*1881cdb1SYouMin Chen #endif /* CONFIG_TPL_BUILD */
1226