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>
11*2a6ffa99SJacky Bai #include <gpc_reg.h>
12c71793c6SJacky Bai #include <platform_def.h>
13c71793c6SJacky Bai
14c71793c6SJacky Bai #define SRC_DDR1_RCR (IMX_SRC_BASE + 0x1000)
15c71793c6SJacky Bai #define SRC_DDR2_RCR (IMX_SRC_BASE + 0x1004)
16c71793c6SJacky Bai
17c71793c6SJacky Bai #define CCM_SRC_CTRL_OFFSET (IMX_CCM_BASE + 0x800)
18c71793c6SJacky Bai #define CCM_CCGR_OFFSET (IMX_CCM_BASE + 0x4000)
194bf50192SJacky Bai #define CCM_TARGET_ROOT_OFFSET (IMX_CCM_BASE + 0x8000)
20c71793c6SJacky Bai #define CCM_SRC_CTRL(n) (CCM_SRC_CTRL_OFFSET + 0x10 * (n))
21c71793c6SJacky Bai #define CCM_CCGR(n) (CCM_CCGR_OFFSET + 0x10 * (n))
224bf50192SJacky Bai #define CCM_TARGET_ROOT(n) (CCM_TARGET_ROOT_OFFSET + 0x80 * (n))
23c71793c6SJacky Bai
24c71793c6SJacky Bai #define DBGCAM_EMPTY 0x36000000
25c71793c6SJacky Bai
rank_setting_update(void)2633300849SJacky Bai static void rank_setting_update(void)
2733300849SJacky Bai {
2833300849SJacky Bai uint32_t i, offset;
2933300849SJacky Bai uint32_t pstate_num = dram_info.num_fsp;
3033300849SJacky Bai
310331b1c6SJacky Bai /* only support maximum 3 setpoints */
320331b1c6SJacky Bai pstate_num = (pstate_num > MAX_FSP_NUM) ? MAX_FSP_NUM : pstate_num;
330331b1c6SJacky Bai
3433300849SJacky Bai for (i = 0U; i < pstate_num; i++) {
3533300849SJacky Bai offset = i ? (i + 1) * 0x1000 : 0U;
3633300849SJacky Bai mmio_write_32(DDRC_DRAMTMG2(0) + offset, dram_info.rank_setting[i][0]);
3733300849SJacky Bai if (dram_info.dram_type != DDRC_LPDDR4) {
3833300849SJacky Bai mmio_write_32(DDRC_DRAMTMG9(0) + offset, dram_info.rank_setting[i][1]);
3933300849SJacky Bai }
4033300849SJacky Bai
4133300849SJacky Bai #if !defined(PLAT_imx8mq)
4233300849SJacky Bai mmio_write_32(DDRC_RANKCTL(0) + offset,
4333300849SJacky Bai dram_info.rank_setting[i][2]);
4433300849SJacky Bai #endif
4533300849SJacky Bai }
4633300849SJacky Bai #if defined(PLAT_imx8mq)
4733300849SJacky Bai mmio_write_32(DDRC_RANKCTL(0), dram_info.rank_setting[0][2]);
4833300849SJacky Bai #endif
4933300849SJacky Bai }
5033300849SJacky Bai
dram_enter_retention(void)51c71793c6SJacky Bai void dram_enter_retention(void)
52c71793c6SJacky Bai {
53c71793c6SJacky Bai /* Wait DBGCAM to be empty */
54c71793c6SJacky Bai while (mmio_read_32(DDRC_DBGCAM(0)) != DBGCAM_EMPTY) {
55c71793c6SJacky Bai ;
56c71793c6SJacky Bai }
57c71793c6SJacky Bai
58c71793c6SJacky Bai /* Block AXI ports from taking anymore transactions */
59c71793c6SJacky Bai mmio_write_32(DDRC_PCTRL_0(0), 0x0);
60c71793c6SJacky Bai /* Wait until all AXI ports are idle */
61c71793c6SJacky Bai while (mmio_read_32(DDRC_PSTAT(0)) & 0x10001) {
62c71793c6SJacky Bai ;
63c71793c6SJacky Bai }
64c71793c6SJacky Bai
65c71793c6SJacky Bai /* Enter self refresh */
66c71793c6SJacky Bai mmio_write_32(DDRC_PWRCTL(0), 0xaa);
67c71793c6SJacky Bai
68c71793c6SJacky Bai /* LPDDR4 & DDR4/DDR3L need to check different status */
69c71793c6SJacky Bai if (dram_info.dram_type == DDRC_LPDDR4) {
70c71793c6SJacky Bai while (0x223 != (mmio_read_32(DDRC_STAT(0)) & 0x33f)) {
71c71793c6SJacky Bai ;
72c71793c6SJacky Bai }
73c71793c6SJacky Bai } else {
74c71793c6SJacky Bai while (0x23 != (mmio_read_32(DDRC_STAT(0)) & 0x3f)) {
75c71793c6SJacky Bai ;
76c71793c6SJacky Bai }
77c71793c6SJacky Bai }
78c71793c6SJacky Bai
79c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x0);
80c71793c6SJacky Bai mmio_write_32(DDRC_SWCTL(0), 0x0);
81c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
82c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x1f20);
83c71793c6SJacky Bai
84c71793c6SJacky Bai while (mmio_read_32(DDRC_DFISTAT(0)) & 0x1) {
85c71793c6SJacky Bai ;
86c71793c6SJacky Bai }
87c71793c6SJacky Bai
88c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
89c71793c6SJacky Bai /* wait DFISTAT.dfi_init_complete to 1 */
90c71793c6SJacky Bai while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
91c71793c6SJacky Bai ;
92c71793c6SJacky Bai }
93c71793c6SJacky Bai
94c71793c6SJacky Bai mmio_write_32(DDRC_SWCTL(0), 0x1);
95c71793c6SJacky Bai
96c71793c6SJacky Bai /* should check PhyInLP3 pub reg */
97c71793c6SJacky Bai dwc_ddrphy_apb_wr(0xd0000, 0x0);
98c71793c6SJacky Bai if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
99c71793c6SJacky Bai INFO("PhyInLP3 = 1\n");
100c71793c6SJacky Bai }
101c71793c6SJacky Bai dwc_ddrphy_apb_wr(0xd0000, 0x1);
102c71793c6SJacky Bai
103c71793c6SJacky Bai /* pwrdnreqn_async adbm/adbs of ddr */
104*2a6ffa99SJacky Bai mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, DDRMIX_ADB400_SYNC);
105*2a6ffa99SJacky Bai while (mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & DDRMIX_ADB400_ACK)
106c71793c6SJacky Bai ;
107*2a6ffa99SJacky Bai mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, DDRMIX_ADB400_SYNC);
108*2a6ffa99SJacky Bai
109c71793c6SJacky Bai /* remove PowerOk */
110c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F000008);
111c71793c6SJacky Bai
112c71793c6SJacky Bai mmio_write_32(CCM_CCGR(5), 0);
113c71793c6SJacky Bai mmio_write_32(CCM_SRC_CTRL(15), 2);
114c71793c6SJacky Bai
115c71793c6SJacky Bai /* enable the phy iso */
116*2a6ffa99SJacky Bai mmio_setbits_32(IMX_GPC_BASE + DDRMIX_PGC, 1);
117*2a6ffa99SJacky Bai mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, DDRMIX_PWR_REQ);
118c71793c6SJacky Bai
119c71793c6SJacky Bai VERBOSE("dram enter retention\n");
120c71793c6SJacky Bai }
121c71793c6SJacky Bai
dram_exit_retention(void)122c71793c6SJacky Bai void dram_exit_retention(void)
123c71793c6SJacky Bai {
124c71793c6SJacky Bai VERBOSE("dram exit retention\n");
125c71793c6SJacky Bai /* assert all reset */
126c71793c6SJacky Bai #if defined(PLAT_imx8mq)
127c71793c6SJacky Bai mmio_write_32(SRC_DDR2_RCR, 0x8F000003);
128c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
129c71793c6SJacky Bai mmio_write_32(SRC_DDR2_RCR, 0x8F000000);
130c71793c6SJacky Bai #else
131c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F00001F);
132c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
133c71793c6SJacky Bai #endif
134c71793c6SJacky Bai mmio_write_32(CCM_CCGR(5), 2);
135c71793c6SJacky Bai mmio_write_32(CCM_SRC_CTRL(15), 2);
136c71793c6SJacky Bai
1374bf50192SJacky Bai /* change the clock source of dram_apb_clk_root */
1384bf50192SJacky Bai mmio_write_32(CCM_TARGET_ROOT(65) + 0x8, (0x7 << 24) | (0x7 << 16));
1394bf50192SJacky Bai mmio_write_32(CCM_TARGET_ROOT(65) + 0x4, (0x4 << 24) | (0x3 << 16));
1404bf50192SJacky Bai
141c71793c6SJacky Bai /* disable iso */
142*2a6ffa99SJacky Bai mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, DDRMIX_PWR_REQ);
143c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F000006);
144c71793c6SJacky Bai
145c71793c6SJacky Bai /* wait dram pll locked */
146c71793c6SJacky Bai while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
147c71793c6SJacky Bai ;
148c71793c6SJacky Bai }
149c71793c6SJacky Bai
150c71793c6SJacky Bai /* ddrc re-init */
151c71793c6SJacky Bai dram_umctl2_init(dram_info.timing_info);
152c71793c6SJacky Bai
153c71793c6SJacky Bai /*
154c71793c6SJacky Bai * Skips the DRAM init routine and starts up in selfrefresh mode
155c71793c6SJacky Bai * Program INIT0.skip_dram_init = 2'b11
156c71793c6SJacky Bai */
157c71793c6SJacky Bai mmio_setbits_32(DDRC_INIT0(0), 0xc0000000);
158c71793c6SJacky Bai /* Keeps the controller in self-refresh mode */
159c71793c6SJacky Bai mmio_write_32(DDRC_PWRCTL(0), 0xaa);
160c71793c6SJacky Bai mmio_write_32(DDRC_DBG1(0), 0x0);
161c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F000004);
162c71793c6SJacky Bai mmio_write_32(SRC_DDR1_RCR, 0x8F000000);
163c71793c6SJacky Bai
164c71793c6SJacky Bai /* before write Dynamic reg, sw_done should be 0 */
165c71793c6SJacky Bai mmio_write_32(DDRC_SWCTL(0), 0x0);
1662003fa94SJacky Bai
1672003fa94SJacky Bai #if !PLAT_imx8mn
168c71793c6SJacky Bai if (dram_info.dram_type == DDRC_LPDDR4) {
169c71793c6SJacky Bai mmio_write_32(DDRC_DDR_SS_GPR0, 0x01); /*LPDDR4 mode */
170c71793c6SJacky Bai }
1712003fa94SJacky Bai #endif /* !PLAT_imx8mn */
1722003fa94SJacky Bai
173c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x0);
174c71793c6SJacky Bai
175c71793c6SJacky Bai /* dram phy re-init */
176c71793c6SJacky Bai dram_phy_init(dram_info.timing_info);
177c71793c6SJacky Bai
17833300849SJacky Bai /* workaround for rank-to-rank issue */
17933300849SJacky Bai rank_setting_update();
18033300849SJacky Bai
181c71793c6SJacky Bai /* DWC_DDRPHYA_APBONLY0_MicroContMuxSel */
182c71793c6SJacky Bai dwc_ddrphy_apb_wr(0xd0000, 0x0);
183c71793c6SJacky Bai while (dwc_ddrphy_apb_rd(0x20097)) {
184c71793c6SJacky Bai ;
185c71793c6SJacky Bai }
186c71793c6SJacky Bai dwc_ddrphy_apb_wr(0xd0000, 0x1);
187c71793c6SJacky Bai
188c71793c6SJacky Bai /* before write Dynamic reg, sw_done should be 0 */
189c71793c6SJacky Bai mmio_write_32(DDRC_SWCTL(0), 0x0);
190c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x20);
191c71793c6SJacky Bai /* wait DFISTAT.dfi_init_complete to 1 */
192c71793c6SJacky Bai while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
193c71793c6SJacky Bai ;
194c71793c6SJacky Bai }
195c71793c6SJacky Bai
196c71793c6SJacky Bai /* clear DFIMISC.dfi_init_start */
197c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x0);
198c71793c6SJacky Bai /* set DFIMISC.dfi_init_complete_en */
199c71793c6SJacky Bai mmio_write_32(DDRC_DFIMISC(0), 0x1);
200c71793c6SJacky Bai
201c71793c6SJacky Bai /* set SWCTL.sw_done to enable quasi-dynamic register programming */
202c71793c6SJacky Bai mmio_write_32(DDRC_SWCTL(0), 0x1);
203c71793c6SJacky Bai /* wait SWSTAT.sw_done_ack to 1 */
204c71793c6SJacky Bai while (!(mmio_read_32(DDRC_SWSTAT(0)) & 0x1)) {
205c71793c6SJacky Bai ;
206c71793c6SJacky Bai }
207c71793c6SJacky Bai
208c71793c6SJacky Bai mmio_write_32(DDRC_PWRCTL(0), 0x88);
209c71793c6SJacky Bai /* wait STAT to normal state */
210c71793c6SJacky Bai while (0x1 != (mmio_read_32(DDRC_STAT(0)) & 0x7)) {
211c71793c6SJacky Bai ;
212c71793c6SJacky Bai }
213c71793c6SJacky Bai
214c71793c6SJacky Bai mmio_write_32(DDRC_PCTRL_0(0), 0x1);
215c71793c6SJacky Bai /* dis_auto-refresh is set to 0 */
216c71793c6SJacky Bai mmio_write_32(DDRC_RFSHCTL3(0), 0x0);
217c71793c6SJacky Bai
218c71793c6SJacky Bai /* should check PhyInLP3 pub reg */
219c71793c6SJacky Bai dwc_ddrphy_apb_wr(0xd0000, 0x0);
220c71793c6SJacky Bai if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
221c71793c6SJacky Bai VERBOSE("PHYInLP3 = 0\n");
222c71793c6SJacky Bai }
223c71793c6SJacky Bai dwc_ddrphy_apb_wr(0xd0000, 0x1);
224c71793c6SJacky Bai }
225