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