xref: /rk3399_ARM-atf/plat/imx/imx8ulp/dram.c (revision 478af8d3c34576793a820733ddba6449c2cf2fac)
1*478af8d3SJacky Bai /*
2*478af8d3SJacky Bai  * Copyright 2021-2024 NXP
3*478af8d3SJacky Bai  *
4*478af8d3SJacky Bai  * SPDX-License-Identifier: BSD-3-Clause
5*478af8d3SJacky Bai  */
6*478af8d3SJacky Bai 
7*478af8d3SJacky Bai #include <assert.h>
8*478af8d3SJacky Bai #include <stdbool.h>
9*478af8d3SJacky Bai 
10*478af8d3SJacky Bai #include <lib/mmio.h>
11*478af8d3SJacky Bai #include <platform_def.h>
12*478af8d3SJacky Bai 
13*478af8d3SJacky Bai #include <upower_api.h>
14*478af8d3SJacky Bai 
15*478af8d3SJacky Bai #define PHY_FREQ_SEL_INDEX(x)		((x) << 16)
16*478af8d3SJacky Bai #define PHY_FREQ_MULTICAST_EN(x)	((x) << 8)
17*478af8d3SJacky Bai #define DENALI_PHY_1537			U(0x5804)
18*478af8d3SJacky Bai 
19*478af8d3SJacky Bai #define IMX_DDRC_BASE			U(0x2E060000)
20*478af8d3SJacky Bai #define SAVED_DRAM_DATA_BASE		U(0x20055000)
21*478af8d3SJacky Bai #define DENALI_CTL_144			0x240
22*478af8d3SJacky Bai #define LPI_WAKEUP_EN_SHIFT		U(8)
23*478af8d3SJacky Bai #define IMX_LPAV_SIM_BASE		0x2DA50000
24*478af8d3SJacky Bai #define LPDDR_CTRL			0x14
25*478af8d3SJacky Bai #define LPDDR_AUTO_LP_MODE_DISABLE	BIT(24)
26*478af8d3SJacky Bai #define SOC_LP_CMD_SHIFT		U(15)
27*478af8d3SJacky Bai #define LPDDR_CTRL2			0x18
28*478af8d3SJacky Bai 
29*478af8d3SJacky Bai #define DENALI_CTL_00			U(0x0)
30*478af8d3SJacky Bai #define DENALI_CTL_23			U(0x5c)
31*478af8d3SJacky Bai #define DFIBUS_FREQ_INIT_SHIFT		U(24)
32*478af8d3SJacky Bai #define TSREF2PHYMSTR_SHIFT		U(8)
33*478af8d3SJacky Bai #define TSREF2PHYMSTR_MASK		GENMASK(13, 8)
34*478af8d3SJacky Bai 
35*478af8d3SJacky Bai #define DENALI_CTL_24			U(0x60)
36*478af8d3SJacky Bai #define DENALI_CTL_25			U(0x64)
37*478af8d3SJacky Bai 
38*478af8d3SJacky Bai #define DENALI_CTL_93			U(0x174)
39*478af8d3SJacky Bai #define PWRUP_SREFRESH_EXIT		BIT(0)
40*478af8d3SJacky Bai 
41*478af8d3SJacky Bai #define DENALI_CTL_127				U(0x1fc)
42*478af8d3SJacky Bai #define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE	BIT(16)
43*478af8d3SJacky Bai 
44*478af8d3SJacky Bai #define DENALI_CTL_147			U(0x24c)
45*478af8d3SJacky Bai #define DENALI_CTL_153			U(0x264)
46*478af8d3SJacky Bai #define PCPCS_PD_EN			BIT(8)
47*478af8d3SJacky Bai 
48*478af8d3SJacky Bai #define DENALI_CTL_249			U(0x3E4)
49*478af8d3SJacky Bai #define DENALI_CTL_266			U(0x428)
50*478af8d3SJacky Bai 
51*478af8d3SJacky Bai #define DENALI_PHY_1547			U(0x582c)
52*478af8d3SJacky Bai #define PHY_LP4_BOOT_DISABLE		BIT(8)
53*478af8d3SJacky Bai 
54*478af8d3SJacky Bai #define DENALI_PHY_1559			U(0x585c)
55*478af8d3SJacky Bai #define DENALI_PHY_1590			U(0x58D8)
56*478af8d3SJacky Bai 
57*478af8d3SJacky Bai #define DENALI_PI_00			U(0x2000)
58*478af8d3SJacky Bai #define DENALI_PI_04			U(0x2010)
59*478af8d3SJacky Bai #define DENALI_PI_52			U(0x20D0)
60*478af8d3SJacky Bai #define DENALI_PI_26			U(0x2068)
61*478af8d3SJacky Bai #define DENALI_PI_33			U(0x2084)
62*478af8d3SJacky Bai #define DENALI_PI_65			U(0x2104)
63*478af8d3SJacky Bai #define DENALI_PI_77			U(0x2134)
64*478af8d3SJacky Bai #define DENALI_PI_134			U(0x2218)
65*478af8d3SJacky Bai #define DENALI_PI_131			U(0x220C)
66*478af8d3SJacky Bai #define DENALI_PI_132			U(0x2210)
67*478af8d3SJacky Bai #define DENALI_PI_134			U(0x2218)
68*478af8d3SJacky Bai #define DENALI_PI_137			U(0x2224)
69*478af8d3SJacky Bai #define DENALI_PI_174			U(0x22B8)
70*478af8d3SJacky Bai #define DENALI_PI_175			U(0x22BC)
71*478af8d3SJacky Bai #define DENALI_PI_181			U(0x22D4)
72*478af8d3SJacky Bai #define DENALI_PI_182			U(0x22D8)
73*478af8d3SJacky Bai #define DENALI_PI_191			U(0x22FC)
74*478af8d3SJacky Bai #define DENALI_PI_192			U(0x2300)
75*478af8d3SJacky Bai #define DENALI_PI_212			U(0x2350)
76*478af8d3SJacky Bai #define DENALI_PI_214			U(0x2358)
77*478af8d3SJacky Bai #define DENALI_PI_217			U(0x2364)
78*478af8d3SJacky Bai 
79*478af8d3SJacky Bai #define LPDDR3_TYPE	U(0x7)
80*478af8d3SJacky Bai #define LPDDR4_TYPE	U(0xB)
81*478af8d3SJacky Bai 
82*478af8d3SJacky Bai extern void upower_wait_resp(void);
83*478af8d3SJacky Bai 
84*478af8d3SJacky Bai struct dram_cfg_param {
85*478af8d3SJacky Bai 	uint32_t reg;
86*478af8d3SJacky Bai 	uint32_t val;
87*478af8d3SJacky Bai };
88*478af8d3SJacky Bai 
89*478af8d3SJacky Bai struct dram_timing_info {
90*478af8d3SJacky Bai 	/* ddr controller config */
91*478af8d3SJacky Bai 	struct dram_cfg_param *ctl_cfg;
92*478af8d3SJacky Bai 	unsigned int ctl_cfg_num;
93*478af8d3SJacky Bai 	/* pi config */
94*478af8d3SJacky Bai 	struct dram_cfg_param *pi_cfg;
95*478af8d3SJacky Bai 	unsigned int pi_cfg_num;
96*478af8d3SJacky Bai 	/* phy freq1 config */
97*478af8d3SJacky Bai 	struct dram_cfg_param *phy_f1_cfg;
98*478af8d3SJacky Bai 	unsigned int phy_f1_cfg_num;
99*478af8d3SJacky Bai 	/* phy freq2 config */
100*478af8d3SJacky Bai 	struct dram_cfg_param *phy_f2_cfg;
101*478af8d3SJacky Bai 	unsigned int phy_f2_cfg_num;
102*478af8d3SJacky Bai 	/* initialized drate table */
103*478af8d3SJacky Bai 	unsigned int fsp_table[3];
104*478af8d3SJacky Bai };
105*478af8d3SJacky Bai 
106*478af8d3SJacky Bai #define CTL_NUM		U(680)
107*478af8d3SJacky Bai #define PI_NUM		U(298)
108*478af8d3SJacky Bai #define PHY_NUM		U(1654)
109*478af8d3SJacky Bai #define PHY_DIFF_NUM	U(49)
110*478af8d3SJacky Bai struct dram_cfg {
111*478af8d3SJacky Bai 	uint32_t ctl_cfg[CTL_NUM];
112*478af8d3SJacky Bai 	uint32_t pi_cfg[PI_NUM];
113*478af8d3SJacky Bai 	uint32_t phy_full[PHY_NUM];
114*478af8d3SJacky Bai 	uint32_t phy_diff[PHY_DIFF_NUM];
115*478af8d3SJacky Bai };
116*478af8d3SJacky Bai 
117*478af8d3SJacky Bai struct dram_timing_info *info;
118*478af8d3SJacky Bai struct dram_cfg *dram_timing_cfg;
119*478af8d3SJacky Bai 
120*478af8d3SJacky Bai /* mark if dram cfg is already saved */
121*478af8d3SJacky Bai static bool dram_cfg_saved;
122*478af8d3SJacky Bai static uint32_t dram_class;
123*478af8d3SJacky Bai 
124*478af8d3SJacky Bai /* PHY register index for frequency diff */
125*478af8d3SJacky Bai uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
126*478af8d3SJacky Bai 90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
127*478af8d3SJacky Bai 346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
128*478af8d3SJacky Bai 370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
129*478af8d3SJacky Bai 616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
130*478af8d3SJacky Bai 871, 872, 882, 1063, 1319, 1566, 1624, 1625
131*478af8d3SJacky Bai };
132*478af8d3SJacky Bai 
133*478af8d3SJacky Bai static void ddr_init(void)
134*478af8d3SJacky Bai {
135*478af8d3SJacky Bai 	unsigned int i;
136*478af8d3SJacky Bai 
137*478af8d3SJacky Bai 	/* restore the ddr ctl config */
138*478af8d3SJacky Bai 	for (i = 0U; i < CTL_NUM; i++) {
139*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
140*478af8d3SJacky Bai 	}
141*478af8d3SJacky Bai 
142*478af8d3SJacky Bai 	/* load the PI registers */
143*478af8d3SJacky Bai 	for (i = 0U; i < PI_NUM; i++) {
144*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
145*478af8d3SJacky Bai 	}
146*478af8d3SJacky Bai 
147*478af8d3SJacky Bai 
148*478af8d3SJacky Bai 	 /* restore all PHY registers for all the fsp. */
149*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
150*478af8d3SJacky Bai 	/* restore all the phy configs */
151*478af8d3SJacky Bai 	for (i = 0U; i < PHY_NUM; i++) {
152*478af8d3SJacky Bai 		/* skip the reserved registers space */
153*478af8d3SJacky Bai 		if (i >= 121U && i <= 255U) {
154*478af8d3SJacky Bai 			continue;
155*478af8d3SJacky Bai 		}
156*478af8d3SJacky Bai 		if (i >= 377U && i <= 511U) {
157*478af8d3SJacky Bai 			continue;
158*478af8d3SJacky Bai 		}
159*478af8d3SJacky Bai 		if (i >= 633U && i <= 767U) {
160*478af8d3SJacky Bai 			continue;
161*478af8d3SJacky Bai 		}
162*478af8d3SJacky Bai 		if (i >= 889U && i <= 1023U) {
163*478af8d3SJacky Bai 			continue;
164*478af8d3SJacky Bai 		}
165*478af8d3SJacky Bai 		if (i >= 1065U && i <= 1279U) {
166*478af8d3SJacky Bai 			continue;
167*478af8d3SJacky Bai 		}
168*478af8d3SJacky Bai 		if (i >= 1321U && i <= 1535U) {
169*478af8d3SJacky Bai 			continue;
170*478af8d3SJacky Bai 		}
171*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
172*478af8d3SJacky Bai 	}
173*478af8d3SJacky Bai 
174*478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
175*478af8d3SJacky Bai 		/* restore only the diff. */
176*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
177*478af8d3SJacky Bai 		for (i = 0U; i < PHY_DIFF_NUM; i++) {
178*478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
179*478af8d3SJacky Bai 				      dram_timing_cfg->phy_diff[i]);
180*478af8d3SJacky Bai 		}
181*478af8d3SJacky Bai 	}
182*478af8d3SJacky Bai 
183*478af8d3SJacky Bai 	/* Re-enable MULTICAST mode */
184*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
185*478af8d3SJacky Bai }
186*478af8d3SJacky Bai 
187*478af8d3SJacky Bai void dram_enter_retention(void)
188*478af8d3SJacky Bai {
189*478af8d3SJacky Bai 	unsigned int i;
190*478af8d3SJacky Bai 
191*478af8d3SJacky Bai 	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
192*478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
193*478af8d3SJacky Bai 
194*478af8d3SJacky Bai 	/*
195*478af8d3SJacky Bai 	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
196*478af8d3SJacky Bai 	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
197*478af8d3SJacky Bai 	 * long with mem and ctlr clk gating or self-refresh  power-down
198*478af8d3SJacky Bai 	 * long with mem and ctlr clk gating'
199*478af8d3SJacky Bai 	 */
200*478af8d3SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
201*478af8d3SJacky Bai 
202*478af8d3SJacky Bai 	/*
203*478af8d3SJacky Bai 	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
204*478af8d3SJacky Bai 	 * the logic to automatic handles low power entry/exit. This is the recommended
205*478af8d3SJacky Bai 	 * option over handling through software.
206*478af8d3SJacky Bai 	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
207*478af8d3SJacky Bai 	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
208*478af8d3SJacky Bai 	 * since LPPDR logic will be power gated).
209*478af8d3SJacky Bai 	 */
210*478af8d3SJacky Bai 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
211*478af8d3SJacky Bai 	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
212*478af8d3SJacky Bai 			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
213*478af8d3SJacky Bai 
214*478af8d3SJacky Bai 	/* Save DDR Controller & PHY config.
215*478af8d3SJacky Bai 	 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
216*478af8d3SJacky Bai 	 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
217*478af8d3SJacky Bai 	 * F1 & F2 into phy_f2_cfg.
218*478af8d3SJacky Bai 	 */
219*478af8d3SJacky Bai 	if (!dram_cfg_saved) {
220*478af8d3SJacky Bai 		info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
221*478af8d3SJacky Bai 		dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
222*478af8d3SJacky Bai 					sizeof(struct dram_timing_info));
223*478af8d3SJacky Bai 
224*478af8d3SJacky Bai 		/* get the dram type */
225*478af8d3SJacky Bai 		dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
226*478af8d3SJacky Bai 		dram_class = (dram_class >> 8) & 0xf;
227*478af8d3SJacky Bai 
228*478af8d3SJacky Bai 		/* save the ctl registers */
229*478af8d3SJacky Bai 		for (i = 0U; i < CTL_NUM; i++) {
230*478af8d3SJacky Bai 			dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
231*478af8d3SJacky Bai 		}
232*478af8d3SJacky Bai 		dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
233*478af8d3SJacky Bai 
234*478af8d3SJacky Bai 		/* save the PI registers */
235*478af8d3SJacky Bai 		for (i = 0U; i < PI_NUM; i++) {
236*478af8d3SJacky Bai 			dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
237*478af8d3SJacky Bai 		}
238*478af8d3SJacky Bai 		dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
239*478af8d3SJacky Bai 
240*478af8d3SJacky Bai 		/*
241*478af8d3SJacky Bai 		 * Read and store all PHY registers. full array is a full
242*478af8d3SJacky Bai 		 * copy for all the setpoint
243*478af8d3SJacky Bai 		 */
244*478af8d3SJacky Bai 		if (dram_class == LPDDR4_TYPE) {
245*478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
246*478af8d3SJacky Bai 			for (i = 0U; i < PHY_NUM; i++) {
247*478af8d3SJacky Bai 				/* Make sure MULTICASE is enabled */
248*478af8d3SJacky Bai 				if (i == 1537U) {
249*478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = 0x100;
250*478af8d3SJacky Bai 				} else {
251*478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
252*478af8d3SJacky Bai 				}
253*478af8d3SJacky Bai 			}
254*478af8d3SJacky Bai 
255*478af8d3SJacky Bai 			/*
256*478af8d3SJacky Bai 			 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
257*478af8d3SJacky Bai 			 * Read and store only the diff.
258*478af8d3SJacky Bai 			 */
259*478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
260*478af8d3SJacky Bai 			/* save only the frequency based diff config to save memory */
261*478af8d3SJacky Bai 			for (i = 0U; i < PHY_DIFF_NUM; i++) {
262*478af8d3SJacky Bai 				dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
263*478af8d3SJacky Bai 									    freq_specific_reg_array[i] * 4);
264*478af8d3SJacky Bai 			}
265*478af8d3SJacky Bai 		} else {
266*478af8d3SJacky Bai 			/* LPDDR3, only f1 need to save */
267*478af8d3SJacky Bai 			for (i = 0U; i < info->phy_f1_cfg_num; i++) {
268*478af8d3SJacky Bai 				info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
269*478af8d3SJacky Bai 			}
270*478af8d3SJacky Bai 		}
271*478af8d3SJacky Bai 
272*478af8d3SJacky Bai 		dram_cfg_saved = true;
273*478af8d3SJacky Bai 	}
274*478af8d3SJacky Bai }
275*478af8d3SJacky Bai 
276*478af8d3SJacky Bai void dram_exit_retention(void)
277*478af8d3SJacky Bai {
278*478af8d3SJacky Bai 	uint32_t val;
279*478af8d3SJacky Bai 
280*478af8d3SJacky Bai 	/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
281*478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
282*478af8d3SJacky Bai 
283*478af8d3SJacky Bai 	/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
284*478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
285*478af8d3SJacky Bai 
286*478af8d3SJacky Bai 	/* 3. Reload the LPDDR CTL/PI/PHY register */
287*478af8d3SJacky Bai 	ddr_init();
288*478af8d3SJacky Bai 
289*478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
290*478af8d3SJacky Bai 		/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
291*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
292*478af8d3SJacky Bai 
293*478af8d3SJacky Bai 		/*
294*478af8d3SJacky Bai 		 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
295*478af8d3SJacky Bai 		 * from controller.
296*478af8d3SJacky Bai 		 */
297*478af8d3SJacky Bai 		/*
298*478af8d3SJacky Bai 		 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
299*478af8d3SJacky Bai 		 * self refresh exit from PI
300*478af8d3SJacky Bai 		 */
301*478af8d3SJacky Bai 		/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
302*478af8d3SJacky Bai 		/*
303*478af8d3SJacky Bai 		 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
304*478af8d3SJacky Bai 		 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
305*478af8d3SJacky Bai 		 * Enable non initialization trainings.
306*478af8d3SJacky Bai 		 */
307*478af8d3SJacky Bai 		/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
308*478af8d3SJacky Bai 		/* 4f. PI_DLL_RESET=0x1 */
309*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
310*478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT = 1 */
311*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
312*478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
313*478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
314*478af8d3SJacky Bai 		/* PI_INT_LVL_EN = 0 */
315*478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
316*478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
317*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
318*478af8d3SJacky Bai 		/* PI_WRLVL_EN_F2 = 3 */
319*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
320*478af8d3SJacky Bai 		/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
321*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
322*478af8d3SJacky Bai 		/* PI_CALVL_EN_F2 = 3 */
323*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
324*478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F0 = 3 */
325*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
326*478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F1 = 3 */
327*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
328*478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F2 = 3 */
329*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
330*478af8d3SJacky Bai 		/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
331*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
332*478af8d3SJacky Bai 		/*
333*478af8d3SJacky Bai 		 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
334*478af8d3SJacky Bai 		 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
335*478af8d3SJacky Bai 		 */
336*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
337*478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
338*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
339*478af8d3SJacky Bai 	} else {
340*478af8d3SJacky Bai 		/* PI_DLL_RESET=1 */
341*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
342*478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT=1 */
343*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
344*478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
345*478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
346*478af8d3SJacky Bai 		/* PI_INT_LVL_EN=0 */
347*478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
348*478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0=3 */
349*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
350*478af8d3SJacky Bai 		/* PI_CALVL_EN_F0=3 */
351*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
352*478af8d3SJacky Bai 		/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
353*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
354*478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
355*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
356*478af8d3SJacky Bai 	}
357*478af8d3SJacky Bai 
358*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
359*478af8d3SJacky Bai 
360*478af8d3SJacky Bai 	/* Force in-order AXI read data */
361*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
362*478af8d3SJacky Bai 
363*478af8d3SJacky Bai 	/*
364*478af8d3SJacky Bai 	 * Disable special R/W group switches so that R/W group placement
365*478af8d3SJacky Bai 	 * is always at END of R/W group.
366*478af8d3SJacky Bai 	 */
367*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
368*478af8d3SJacky Bai 
369*478af8d3SJacky Bai 	/* Reduce time for IO pad calibration */
370*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
371*478af8d3SJacky Bai 
372*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
373*478af8d3SJacky Bai 
374*478af8d3SJacky Bai 	/* PD disable */
375*478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
376*478af8d3SJacky Bai 	/*
377*478af8d3SJacky Bai 	 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
378*478af8d3SJacky Bai 	 * to 1b'0, PCPCS_PD_EN to 1b'0
379*478af8d3SJacky Bai 	 */
380*478af8d3SJacky Bai 
381*478af8d3SJacky Bai 	upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
382*478af8d3SJacky Bai 	upower_wait_resp();
383*478af8d3SJacky Bai 
384*478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
385*478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
386*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
387*478af8d3SJacky Bai 
388*478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
389*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
390*478af8d3SJacky Bai 	} else {
391*478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
392*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
393*478af8d3SJacky Bai 
394*478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
395*478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
396*478af8d3SJacky Bai 	}
397*478af8d3SJacky Bai 
398*478af8d3SJacky Bai 	/* 9. DENALI_CTL_266:  Wait for INT_STATUS_INIT=0x2 */
399*478af8d3SJacky Bai 	do {
400*478af8d3SJacky Bai 		val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
401*478af8d3SJacky Bai 	} while (val != 0x2);
402*478af8d3SJacky Bai 
403*478af8d3SJacky Bai 	/*
404*478af8d3SJacky Bai 	 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
405*478af8d3SJacky Bai 	 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
406*478af8d3SJacky Bai 	 */
407*478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
408*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
409*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
410*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
411*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
412*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
413*478af8d3SJacky Bai 
414*478af8d3SJacky Bai 		/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
415*478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
416*478af8d3SJacky Bai 			;
417*478af8d3SJacky Bai 		}
418*478af8d3SJacky Bai 	} else {
419*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
420*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
421*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
422*478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
423*478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
424*478af8d3SJacky Bai 			;
425*478af8d3SJacky Bai 		}
426*478af8d3SJacky Bai 	}
427*478af8d3SJacky Bai }
428