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