xref: /arm-trusted-firmware/plat/imx/imx8m/ddr/dram_retention.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright 2018-2023 NXP
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <stdbool.h>
8*91f16700Schasinglulu #include <lib/mmio.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <dram.h>
11*91f16700Schasinglulu #include <gpc_reg.h>
12*91f16700Schasinglulu #include <platform_def.h>
13*91f16700Schasinglulu 
14*91f16700Schasinglulu #define SRC_DDR1_RCR		(IMX_SRC_BASE + 0x1000)
15*91f16700Schasinglulu #define SRC_DDR2_RCR		(IMX_SRC_BASE + 0x1004)
16*91f16700Schasinglulu 
17*91f16700Schasinglulu #define CCM_SRC_CTRL_OFFSET     (IMX_CCM_BASE + 0x800)
18*91f16700Schasinglulu #define CCM_CCGR_OFFSET         (IMX_CCM_BASE + 0x4000)
19*91f16700Schasinglulu #define CCM_TARGET_ROOT_OFFSET	(IMX_CCM_BASE + 0x8000)
20*91f16700Schasinglulu #define CCM_SRC_CTRL(n)		(CCM_SRC_CTRL_OFFSET + 0x10 * (n))
21*91f16700Schasinglulu #define CCM_CCGR(n)		(CCM_CCGR_OFFSET + 0x10 * (n))
22*91f16700Schasinglulu #define CCM_TARGET_ROOT(n)	(CCM_TARGET_ROOT_OFFSET + 0x80 * (n))
23*91f16700Schasinglulu 
24*91f16700Schasinglulu #define DBGCAM_EMPTY		0x36000000
25*91f16700Schasinglulu 
26*91f16700Schasinglulu static void rank_setting_update(void)
27*91f16700Schasinglulu {
28*91f16700Schasinglulu 	uint32_t i, offset;
29*91f16700Schasinglulu 	uint32_t pstate_num = dram_info.num_fsp;
30*91f16700Schasinglulu 
31*91f16700Schasinglulu 	/* only support maximum 3 setpoints */
32*91f16700Schasinglulu 	pstate_num = (pstate_num > MAX_FSP_NUM) ? MAX_FSP_NUM : pstate_num;
33*91f16700Schasinglulu 
34*91f16700Schasinglulu 	for (i = 0U; i < pstate_num; i++) {
35*91f16700Schasinglulu 		offset = i ? (i + 1) * 0x1000 : 0U;
36*91f16700Schasinglulu 		mmio_write_32(DDRC_DRAMTMG2(0) + offset, dram_info.rank_setting[i][0]);
37*91f16700Schasinglulu 		if (dram_info.dram_type != DDRC_LPDDR4) {
38*91f16700Schasinglulu 			mmio_write_32(DDRC_DRAMTMG9(0) + offset, dram_info.rank_setting[i][1]);
39*91f16700Schasinglulu 		}
40*91f16700Schasinglulu 
41*91f16700Schasinglulu #if !defined(PLAT_imx8mq)
42*91f16700Schasinglulu 		mmio_write_32(DDRC_RANKCTL(0) + offset,
43*91f16700Schasinglulu 			dram_info.rank_setting[i][2]);
44*91f16700Schasinglulu #endif
45*91f16700Schasinglulu 	}
46*91f16700Schasinglulu #if defined(PLAT_imx8mq)
47*91f16700Schasinglulu 		mmio_write_32(DDRC_RANKCTL(0), dram_info.rank_setting[0][2]);
48*91f16700Schasinglulu #endif
49*91f16700Schasinglulu }
50*91f16700Schasinglulu 
51*91f16700Schasinglulu void dram_enter_retention(void)
52*91f16700Schasinglulu {
53*91f16700Schasinglulu 	/* Wait DBGCAM to be empty */
54*91f16700Schasinglulu 	while (mmio_read_32(DDRC_DBGCAM(0)) != DBGCAM_EMPTY) {
55*91f16700Schasinglulu 		;
56*91f16700Schasinglulu 	}
57*91f16700Schasinglulu 
58*91f16700Schasinglulu 	/* Block AXI ports from taking anymore transactions */
59*91f16700Schasinglulu 	mmio_write_32(DDRC_PCTRL_0(0), 0x0);
60*91f16700Schasinglulu 	/* Wait until all AXI ports are idle */
61*91f16700Schasinglulu 	while (mmio_read_32(DDRC_PSTAT(0)) & 0x10001) {
62*91f16700Schasinglulu 		;
63*91f16700Schasinglulu 	}
64*91f16700Schasinglulu 
65*91f16700Schasinglulu 	/* Enter self refresh */
66*91f16700Schasinglulu 	mmio_write_32(DDRC_PWRCTL(0), 0xaa);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	/* LPDDR4 & DDR4/DDR3L need to check different status */
69*91f16700Schasinglulu 	if (dram_info.dram_type == DDRC_LPDDR4) {
70*91f16700Schasinglulu 		while (0x223 != (mmio_read_32(DDRC_STAT(0)) & 0x33f)) {
71*91f16700Schasinglulu 			;
72*91f16700Schasinglulu 		}
73*91f16700Schasinglulu 	} else {
74*91f16700Schasinglulu 		while (0x23 != (mmio_read_32(DDRC_STAT(0)) & 0x3f)) {
75*91f16700Schasinglulu 			;
76*91f16700Schasinglulu 		}
77*91f16700Schasinglulu 	}
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x0);
80*91f16700Schasinglulu 	mmio_write_32(DDRC_SWCTL(0), 0x0);
81*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
82*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x1f20);
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	while (mmio_read_32(DDRC_DFISTAT(0)) & 0x1) {
85*91f16700Schasinglulu 		;
86*91f16700Schasinglulu 	}
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
89*91f16700Schasinglulu 	/* wait DFISTAT.dfi_init_complete to 1 */
90*91f16700Schasinglulu 	while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
91*91f16700Schasinglulu 		;
92*91f16700Schasinglulu 	}
93*91f16700Schasinglulu 
94*91f16700Schasinglulu 	mmio_write_32(DDRC_SWCTL(0), 0x1);
95*91f16700Schasinglulu 
96*91f16700Schasinglulu 	/* should check PhyInLP3 pub reg */
97*91f16700Schasinglulu 	dwc_ddrphy_apb_wr(0xd0000, 0x0);
98*91f16700Schasinglulu 	if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
99*91f16700Schasinglulu 		INFO("PhyInLP3 = 1\n");
100*91f16700Schasinglulu 	}
101*91f16700Schasinglulu 	dwc_ddrphy_apb_wr(0xd0000, 0x1);
102*91f16700Schasinglulu 
103*91f16700Schasinglulu 	/* pwrdnreqn_async adbm/adbs of ddr */
104*91f16700Schasinglulu 	mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, DDRMIX_ADB400_SYNC);
105*91f16700Schasinglulu 	while (mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & DDRMIX_ADB400_ACK)
106*91f16700Schasinglulu 		;
107*91f16700Schasinglulu 	mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, DDRMIX_ADB400_SYNC);
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 	/* remove PowerOk */
110*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F000008);
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	mmio_write_32(CCM_CCGR(5), 0);
113*91f16700Schasinglulu 	mmio_write_32(CCM_SRC_CTRL(15), 2);
114*91f16700Schasinglulu 
115*91f16700Schasinglulu 	/* enable the phy iso */
116*91f16700Schasinglulu 	mmio_setbits_32(IMX_GPC_BASE + DDRMIX_PGC, 1);
117*91f16700Schasinglulu 	mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, DDRMIX_PWR_REQ);
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 	VERBOSE("dram enter retention\n");
120*91f16700Schasinglulu }
121*91f16700Schasinglulu 
122*91f16700Schasinglulu void dram_exit_retention(void)
123*91f16700Schasinglulu {
124*91f16700Schasinglulu 	VERBOSE("dram exit retention\n");
125*91f16700Schasinglulu 	/* assert all reset */
126*91f16700Schasinglulu #if defined(PLAT_imx8mq)
127*91f16700Schasinglulu 	mmio_write_32(SRC_DDR2_RCR, 0x8F000003);
128*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
129*91f16700Schasinglulu 	mmio_write_32(SRC_DDR2_RCR, 0x8F000000);
130*91f16700Schasinglulu #else
131*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F00001F);
132*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
133*91f16700Schasinglulu #endif
134*91f16700Schasinglulu 	mmio_write_32(CCM_CCGR(5), 2);
135*91f16700Schasinglulu 	mmio_write_32(CCM_SRC_CTRL(15), 2);
136*91f16700Schasinglulu 
137*91f16700Schasinglulu 	/* change the clock source of dram_apb_clk_root */
138*91f16700Schasinglulu 	mmio_write_32(CCM_TARGET_ROOT(65) + 0x8, (0x7 << 24) | (0x7 << 16));
139*91f16700Schasinglulu 	mmio_write_32(CCM_TARGET_ROOT(65) + 0x4, (0x4 << 24) | (0x3 << 16));
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 	/* disable iso */
142*91f16700Schasinglulu 	mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, DDRMIX_PWR_REQ);
143*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F000006);
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 	/* wait dram pll locked */
146*91f16700Schasinglulu 	while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
147*91f16700Schasinglulu 		;
148*91f16700Schasinglulu 	}
149*91f16700Schasinglulu 
150*91f16700Schasinglulu 	/* ddrc re-init */
151*91f16700Schasinglulu 	dram_umctl2_init(dram_info.timing_info);
152*91f16700Schasinglulu 
153*91f16700Schasinglulu 	/*
154*91f16700Schasinglulu 	 * Skips the DRAM init routine and starts up in selfrefresh mode
155*91f16700Schasinglulu 	 * Program INIT0.skip_dram_init = 2'b11
156*91f16700Schasinglulu 	 */
157*91f16700Schasinglulu 	mmio_setbits_32(DDRC_INIT0(0), 0xc0000000);
158*91f16700Schasinglulu 	/* Keeps the controller in self-refresh mode */
159*91f16700Schasinglulu 	mmio_write_32(DDRC_PWRCTL(0), 0xaa);
160*91f16700Schasinglulu 	mmio_write_32(DDRC_DBG1(0), 0x0);
161*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F000004);
162*91f16700Schasinglulu 	mmio_write_32(SRC_DDR1_RCR, 0x8F000000);
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	/* before write Dynamic reg, sw_done should be 0 */
165*91f16700Schasinglulu 	mmio_write_32(DDRC_SWCTL(0), 0x0);
166*91f16700Schasinglulu 
167*91f16700Schasinglulu #if !PLAT_imx8mn
168*91f16700Schasinglulu 	if (dram_info.dram_type == DDRC_LPDDR4) {
169*91f16700Schasinglulu 		mmio_write_32(DDRC_DDR_SS_GPR0, 0x01); /*LPDDR4 mode */
170*91f16700Schasinglulu 	}
171*91f16700Schasinglulu #endif /* !PLAT_imx8mn */
172*91f16700Schasinglulu 
173*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x0);
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	/* dram phy re-init */
176*91f16700Schasinglulu 	dram_phy_init(dram_info.timing_info);
177*91f16700Schasinglulu 
178*91f16700Schasinglulu 	/* workaround for rank-to-rank issue */
179*91f16700Schasinglulu 	rank_setting_update();
180*91f16700Schasinglulu 
181*91f16700Schasinglulu 	/* DWC_DDRPHYA_APBONLY0_MicroContMuxSel */
182*91f16700Schasinglulu 	dwc_ddrphy_apb_wr(0xd0000, 0x0);
183*91f16700Schasinglulu 	while (dwc_ddrphy_apb_rd(0x20097)) {
184*91f16700Schasinglulu 		;
185*91f16700Schasinglulu 	}
186*91f16700Schasinglulu 	dwc_ddrphy_apb_wr(0xd0000, 0x1);
187*91f16700Schasinglulu 
188*91f16700Schasinglulu 	/* before write Dynamic reg, sw_done should be 0 */
189*91f16700Schasinglulu 	mmio_write_32(DDRC_SWCTL(0), 0x0);
190*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x20);
191*91f16700Schasinglulu 	/* wait DFISTAT.dfi_init_complete to 1 */
192*91f16700Schasinglulu 	while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
193*91f16700Schasinglulu 		;
194*91f16700Schasinglulu 	}
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	/* clear DFIMISC.dfi_init_start */
197*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x0);
198*91f16700Schasinglulu 	/* set DFIMISC.dfi_init_complete_en */
199*91f16700Schasinglulu 	mmio_write_32(DDRC_DFIMISC(0), 0x1);
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	/* set SWCTL.sw_done to enable quasi-dynamic register programming */
202*91f16700Schasinglulu 	mmio_write_32(DDRC_SWCTL(0), 0x1);
203*91f16700Schasinglulu 	/* wait SWSTAT.sw_done_ack to 1 */
204*91f16700Schasinglulu 	while (!(mmio_read_32(DDRC_SWSTAT(0)) & 0x1)) {
205*91f16700Schasinglulu 		;
206*91f16700Schasinglulu 	}
207*91f16700Schasinglulu 
208*91f16700Schasinglulu 	mmio_write_32(DDRC_PWRCTL(0), 0x88);
209*91f16700Schasinglulu 	/* wait STAT to normal state */
210*91f16700Schasinglulu 	while (0x1 != (mmio_read_32(DDRC_STAT(0)) & 0x7)) {
211*91f16700Schasinglulu 		;
212*91f16700Schasinglulu 	}
213*91f16700Schasinglulu 
214*91f16700Schasinglulu 	mmio_write_32(DDRC_PCTRL_0(0), 0x1);
215*91f16700Schasinglulu 	 /* dis_auto-refresh is set to 0 */
216*91f16700Schasinglulu 	mmio_write_32(DDRC_RFSHCTL3(0), 0x0);
217*91f16700Schasinglulu 
218*91f16700Schasinglulu 	/* should check PhyInLP3 pub reg */
219*91f16700Schasinglulu 	dwc_ddrphy_apb_wr(0xd0000, 0x0);
220*91f16700Schasinglulu 	if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
221*91f16700Schasinglulu 		VERBOSE("PHYInLP3 = 0\n");
222*91f16700Schasinglulu 	}
223*91f16700Schasinglulu 	dwc_ddrphy_apb_wr(0xd0000, 0x1);
224*91f16700Schasinglulu }
225