xref: /rk3399_ARM-atf/plat/imx/imx8ulp/dram.c (revision 1c408d3c40abbe48064c1e2ef5224c1d6edca3cd)
1478af8d3SJacky Bai /*
2478af8d3SJacky Bai  * Copyright 2021-2024 NXP
3478af8d3SJacky Bai  *
4478af8d3SJacky Bai  * SPDX-License-Identifier: BSD-3-Clause
5478af8d3SJacky Bai  */
6478af8d3SJacky Bai 
7478af8d3SJacky Bai #include <assert.h>
8478af8d3SJacky Bai #include <stdbool.h>
9478af8d3SJacky Bai 
10caee2733SJacky Bai #include <arch_helpers.h>
11caee2733SJacky Bai #include <bl31/interrupt_mgmt.h>
12caee2733SJacky Bai #include <common/runtime_svc.h>
13478af8d3SJacky Bai #include <lib/mmio.h>
14caee2733SJacky Bai #include <lib/spinlock.h>
15caee2733SJacky Bai #include <plat/common/platform.h>
16caee2733SJacky Bai 
17478af8d3SJacky Bai #include <platform_def.h>
18478af8d3SJacky Bai 
19caee2733SJacky Bai #include <dram.h>
20478af8d3SJacky Bai #include <upower_api.h>
21478af8d3SJacky Bai 
22478af8d3SJacky Bai #define PHY_FREQ_SEL_INDEX(x)		((x) << 16)
23478af8d3SJacky Bai #define PHY_FREQ_MULTICAST_EN(x)	((x) << 8)
24478af8d3SJacky Bai #define DENALI_PHY_1537			U(0x5804)
25478af8d3SJacky Bai 
26478af8d3SJacky Bai #define IMX_DDRC_BASE			U(0x2E060000)
27478af8d3SJacky Bai #define SAVED_DRAM_DATA_BASE		U(0x20055000)
28ee25e6a5SAdrian Alonso #define DENALI_CTL_143			U(0x23C)
29ee25e6a5SAdrian Alonso #define DENALI_CTL_144			U(0x240)
30ee25e6a5SAdrian Alonso #define DENALI_CTL_146			U(0x248)
31ee25e6a5SAdrian Alonso #define LP_STATE_CS_IDLE		U(0x404000)
32ee25e6a5SAdrian Alonso #define LP_STATE_CS_PD_CG		U(0x4F4F00)
33478af8d3SJacky Bai #define LPI_WAKEUP_EN_SHIFT		U(8)
34478af8d3SJacky Bai #define IMX_LPAV_SIM_BASE		0x2DA50000
35478af8d3SJacky Bai #define LPDDR_CTRL			0x14
36478af8d3SJacky Bai #define LPDDR_AUTO_LP_MODE_DISABLE	BIT(24)
37478af8d3SJacky Bai #define SOC_LP_CMD_SHIFT		U(15)
38478af8d3SJacky Bai #define LPDDR_CTRL2			0x18
39ee25e6a5SAdrian Alonso #define LPDDR_EN_CLKGATE		(0x1<<17)
40ee25e6a5SAdrian Alonso #define LPDDR_MAX_CLKDIV_EN		(0x1 << 16)
41ee25e6a5SAdrian Alonso #define LP_AUTO_ENTRY_EN		0x4
42ee25e6a5SAdrian Alonso #define LP_AUTO_EXIT_EN			0xF
43478af8d3SJacky Bai 
44478af8d3SJacky Bai #define DENALI_CTL_00			U(0x0)
45478af8d3SJacky Bai #define DENALI_CTL_23			U(0x5c)
46478af8d3SJacky Bai #define DFIBUS_FREQ_INIT_SHIFT		U(24)
47478af8d3SJacky Bai #define TSREF2PHYMSTR_SHIFT		U(8)
48478af8d3SJacky Bai #define TSREF2PHYMSTR_MASK		GENMASK(13, 8)
49478af8d3SJacky Bai 
50478af8d3SJacky Bai #define DENALI_CTL_24			U(0x60)
51478af8d3SJacky Bai #define DENALI_CTL_25			U(0x64)
52478af8d3SJacky Bai 
53478af8d3SJacky Bai #define DENALI_CTL_93			U(0x174)
54478af8d3SJacky Bai #define PWRUP_SREFRESH_EXIT		BIT(0)
55478af8d3SJacky Bai 
56478af8d3SJacky Bai #define DENALI_CTL_127				U(0x1fc)
57478af8d3SJacky Bai #define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE	BIT(16)
58478af8d3SJacky Bai 
59478af8d3SJacky Bai #define DENALI_CTL_147			U(0x24c)
60478af8d3SJacky Bai #define DENALI_CTL_153			U(0x264)
61478af8d3SJacky Bai #define PCPCS_PD_EN			BIT(8)
62478af8d3SJacky Bai 
63478af8d3SJacky Bai #define DENALI_CTL_249			U(0x3E4)
64478af8d3SJacky Bai #define DENALI_CTL_266			U(0x428)
65478af8d3SJacky Bai 
66478af8d3SJacky Bai #define DENALI_PHY_1547			U(0x582c)
67478af8d3SJacky Bai #define PHY_LP4_BOOT_DISABLE		BIT(8)
68478af8d3SJacky Bai 
69478af8d3SJacky Bai #define DENALI_PHY_1559			U(0x585c)
70478af8d3SJacky Bai #define DENALI_PHY_1590			U(0x58D8)
71478af8d3SJacky Bai 
72478af8d3SJacky Bai #define DENALI_PI_00			U(0x2000)
73478af8d3SJacky Bai #define DENALI_PI_04			U(0x2010)
74478af8d3SJacky Bai #define DENALI_PI_52			U(0x20D0)
75478af8d3SJacky Bai #define DENALI_PI_26			U(0x2068)
76478af8d3SJacky Bai #define DENALI_PI_33			U(0x2084)
77478af8d3SJacky Bai #define DENALI_PI_65			U(0x2104)
78478af8d3SJacky Bai #define DENALI_PI_77			U(0x2134)
79478af8d3SJacky Bai #define DENALI_PI_134			U(0x2218)
80478af8d3SJacky Bai #define DENALI_PI_131			U(0x220C)
81478af8d3SJacky Bai #define DENALI_PI_132			U(0x2210)
82478af8d3SJacky Bai #define DENALI_PI_134			U(0x2218)
83478af8d3SJacky Bai #define DENALI_PI_137			U(0x2224)
84478af8d3SJacky Bai #define DENALI_PI_174			U(0x22B8)
85478af8d3SJacky Bai #define DENALI_PI_175			U(0x22BC)
86478af8d3SJacky Bai #define DENALI_PI_181			U(0x22D4)
87478af8d3SJacky Bai #define DENALI_PI_182			U(0x22D8)
88478af8d3SJacky Bai #define DENALI_PI_191			U(0x22FC)
89478af8d3SJacky Bai #define DENALI_PI_192			U(0x2300)
90478af8d3SJacky Bai #define DENALI_PI_212			U(0x2350)
91478af8d3SJacky Bai #define DENALI_PI_214			U(0x2358)
92478af8d3SJacky Bai #define DENALI_PI_217			U(0x2364)
93478af8d3SJacky Bai 
94478af8d3SJacky Bai #define LPDDR3_TYPE	U(0x7)
95478af8d3SJacky Bai #define LPDDR4_TYPE	U(0xB)
96478af8d3SJacky Bai 
97478af8d3SJacky Bai extern void upower_wait_resp(void);
98478af8d3SJacky Bai 
99478af8d3SJacky Bai struct dram_cfg_param {
100478af8d3SJacky Bai 	uint32_t reg;
101478af8d3SJacky Bai 	uint32_t val;
102478af8d3SJacky Bai };
103478af8d3SJacky Bai 
104478af8d3SJacky Bai struct dram_timing_info {
105478af8d3SJacky Bai 	/* ddr controller config */
106478af8d3SJacky Bai 	struct dram_cfg_param *ctl_cfg;
107478af8d3SJacky Bai 	unsigned int ctl_cfg_num;
108478af8d3SJacky Bai 	/* pi config */
109478af8d3SJacky Bai 	struct dram_cfg_param *pi_cfg;
110478af8d3SJacky Bai 	unsigned int pi_cfg_num;
111478af8d3SJacky Bai 	/* phy freq1 config */
112478af8d3SJacky Bai 	struct dram_cfg_param *phy_f1_cfg;
113478af8d3SJacky Bai 	unsigned int phy_f1_cfg_num;
114478af8d3SJacky Bai 	/* phy freq2 config */
115478af8d3SJacky Bai 	struct dram_cfg_param *phy_f2_cfg;
116478af8d3SJacky Bai 	unsigned int phy_f2_cfg_num;
117ee25e6a5SAdrian Alonso 	/* automatic low power config */
118ee25e6a5SAdrian Alonso 	struct dram_cfg_param *auto_lp_cfg;
119ee25e6a5SAdrian Alonso 	unsigned int auto_lp_cfg_num;
120478af8d3SJacky Bai 	/* initialized drate table */
121478af8d3SJacky Bai 	unsigned int fsp_table[3];
122478af8d3SJacky Bai };
123478af8d3SJacky Bai 
124478af8d3SJacky Bai #define CTL_NUM		U(680)
125478af8d3SJacky Bai #define PI_NUM		U(298)
126478af8d3SJacky Bai #define PHY_NUM		U(1654)
127478af8d3SJacky Bai #define PHY_DIFF_NUM	U(49)
128ee25e6a5SAdrian Alonso #define AUTO_LP_NUM	U(3)
129478af8d3SJacky Bai struct dram_cfg {
130478af8d3SJacky Bai 	uint32_t ctl_cfg[CTL_NUM];
131478af8d3SJacky Bai 	uint32_t pi_cfg[PI_NUM];
132478af8d3SJacky Bai 	uint32_t phy_full[PHY_NUM];
133478af8d3SJacky Bai 	uint32_t phy_diff[PHY_DIFF_NUM];
134ee25e6a5SAdrian Alonso 	uint32_t auto_lp_cfg[AUTO_LP_NUM];
135478af8d3SJacky Bai };
136478af8d3SJacky Bai 
137478af8d3SJacky Bai struct dram_timing_info *info;
138478af8d3SJacky Bai struct dram_cfg *dram_timing_cfg;
139478af8d3SJacky Bai 
140478af8d3SJacky Bai /* mark if dram cfg is already saved */
141478af8d3SJacky Bai static bool dram_cfg_saved;
142ee25e6a5SAdrian Alonso static bool dram_auto_lp_true;
143ee25e6a5SAdrian Alonso static uint32_t dram_class, dram_ctl_143;
144478af8d3SJacky Bai 
145478af8d3SJacky Bai /* PHY register index for frequency diff */
146478af8d3SJacky Bai uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
147478af8d3SJacky Bai 90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
148478af8d3SJacky Bai 346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
149478af8d3SJacky Bai 370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
150478af8d3SJacky Bai 616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
151478af8d3SJacky Bai 871, 872, 882, 1063, 1319, 1566, 1624, 1625
152478af8d3SJacky Bai };
153478af8d3SJacky Bai 
154caee2733SJacky Bai /* lock used for DDR DVFS */
155caee2733SJacky Bai spinlock_t dfs_lock;
156caee2733SJacky Bai static volatile uint32_t core_count;
157caee2733SJacky Bai static volatile bool in_progress;
158416c4433SJacky Bai static volatile bool sys_dvfs;
159caee2733SJacky Bai static int num_fsp;
160caee2733SJacky Bai 
ddr_init(void)161478af8d3SJacky Bai static void ddr_init(void)
162478af8d3SJacky Bai {
163478af8d3SJacky Bai 	unsigned int i;
164478af8d3SJacky Bai 
165478af8d3SJacky Bai 	/* restore the ddr ctl config */
166478af8d3SJacky Bai 	for (i = 0U; i < CTL_NUM; i++) {
167478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
168478af8d3SJacky Bai 	}
169478af8d3SJacky Bai 
170478af8d3SJacky Bai 	/* load the PI registers */
171478af8d3SJacky Bai 	for (i = 0U; i < PI_NUM; i++) {
172478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
173478af8d3SJacky Bai 	}
174478af8d3SJacky Bai 
175478af8d3SJacky Bai 
176478af8d3SJacky Bai 	 /* restore all PHY registers for all the fsp. */
177478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
178478af8d3SJacky Bai 	/* restore all the phy configs */
179478af8d3SJacky Bai 	for (i = 0U; i < PHY_NUM; i++) {
180478af8d3SJacky Bai 		/* skip the reserved registers space */
181478af8d3SJacky Bai 		if (i >= 121U && i <= 255U) {
182478af8d3SJacky Bai 			continue;
183478af8d3SJacky Bai 		}
184478af8d3SJacky Bai 		if (i >= 377U && i <= 511U) {
185478af8d3SJacky Bai 			continue;
186478af8d3SJacky Bai 		}
187478af8d3SJacky Bai 		if (i >= 633U && i <= 767U) {
188478af8d3SJacky Bai 			continue;
189478af8d3SJacky Bai 		}
190478af8d3SJacky Bai 		if (i >= 889U && i <= 1023U) {
191478af8d3SJacky Bai 			continue;
192478af8d3SJacky Bai 		}
193478af8d3SJacky Bai 		if (i >= 1065U && i <= 1279U) {
194478af8d3SJacky Bai 			continue;
195478af8d3SJacky Bai 		}
196478af8d3SJacky Bai 		if (i >= 1321U && i <= 1535U) {
197478af8d3SJacky Bai 			continue;
198478af8d3SJacky Bai 		}
199478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
200478af8d3SJacky Bai 	}
201478af8d3SJacky Bai 
202478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
203478af8d3SJacky Bai 		/* restore only the diff. */
204478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
205478af8d3SJacky Bai 		for (i = 0U; i < PHY_DIFF_NUM; i++) {
206478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
207478af8d3SJacky Bai 				      dram_timing_cfg->phy_diff[i]);
208478af8d3SJacky Bai 		}
209478af8d3SJacky Bai 	}
210478af8d3SJacky Bai 
211478af8d3SJacky Bai 	/* Re-enable MULTICAST mode */
212478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
213478af8d3SJacky Bai }
214478af8d3SJacky Bai 
dram_lp_auto_disable(void)215ee25e6a5SAdrian Alonso void dram_lp_auto_disable(void)
216ee25e6a5SAdrian Alonso {
217ee25e6a5SAdrian Alonso 	uint32_t lp_auto_en;
218ee25e6a5SAdrian Alonso 
219ee25e6a5SAdrian Alonso 	dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
220ee25e6a5SAdrian Alonso 					      sizeof(struct dram_timing_info));
221ee25e6a5SAdrian Alonso 	lp_auto_en = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & (LP_AUTO_ENTRY_EN << 24));
222ee25e6a5SAdrian Alonso 	/* Save initial config */
223ee25e6a5SAdrian Alonso 	dram_ctl_143 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_143);
224ee25e6a5SAdrian Alonso 
225ee25e6a5SAdrian Alonso 	if (lp_auto_en && !dram_auto_lp_true) {
226ee25e6a5SAdrian Alonso 		/* 0.a Save DDRC auto low-power mode parameter */
227ee25e6a5SAdrian Alonso 		dram_timing_cfg->auto_lp_cfg[0] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
228ee25e6a5SAdrian Alonso 		dram_timing_cfg->auto_lp_cfg[1] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_147);
229ee25e6a5SAdrian Alonso 		dram_timing_cfg->auto_lp_cfg[2] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146);
230ee25e6a5SAdrian Alonso 		/* Set LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 to Maximum */
231ee25e6a5SAdrian Alonso 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_143, 0xF << 24);
232ee25e6a5SAdrian Alonso 		/* 0.b Disable DDRC auto low-power mode interface */
233ee25e6a5SAdrian Alonso 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_146, LP_AUTO_ENTRY_EN << 24);
234ee25e6a5SAdrian Alonso 		/* 0.c Read any location to get DRAM out of Self-refresh */
235*8d50c91bSJi Luo 		mmio_read_32(DEVICE2_BASE);
236ee25e6a5SAdrian Alonso 		/* 0.d Confirm DRAM is out of Self-refresh */
237ee25e6a5SAdrian Alonso 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
238ee25e6a5SAdrian Alonso 			LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
239ee25e6a5SAdrian Alonso 			;
240ee25e6a5SAdrian Alonso 		}
241ee25e6a5SAdrian Alonso 		/* 0.e Disable DDRC auto low-power exit */
242ee25e6a5SAdrian Alonso 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_147, LP_AUTO_EXIT_EN);
243ee25e6a5SAdrian Alonso 		/* dram low power mode flag */
244ee25e6a5SAdrian Alonso 		dram_auto_lp_true = true;
245ee25e6a5SAdrian Alonso 	}
246ee25e6a5SAdrian Alonso }
247ee25e6a5SAdrian Alonso 
dram_lp_auto_enable(void)248ee25e6a5SAdrian Alonso void dram_lp_auto_enable(void)
249ee25e6a5SAdrian Alonso {
250ee25e6a5SAdrian Alonso 	/* Switch back to Auto Low-power mode */
251ee25e6a5SAdrian Alonso 	if (dram_auto_lp_true) {
252ee25e6a5SAdrian Alonso 		/* 12.a Confirm DRAM is out of Self-refresh */
253ee25e6a5SAdrian Alonso 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
254ee25e6a5SAdrian Alonso 			LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
255ee25e6a5SAdrian Alonso 			;
256ee25e6a5SAdrian Alonso 		}
257ee25e6a5SAdrian Alonso 		/* 12.b Enable DDRC auto low-power exit */
258ee25e6a5SAdrian Alonso 		/*
259ee25e6a5SAdrian Alonso 		 * 12.c TBC! : Set DENALI_CTL_144 [LPI_CTRL_REQ_EN[24]] and
260ee25e6a5SAdrian Alonso 		 * [DFI_LP_VERSION[16]] back to default settings = 1b'1.
261ee25e6a5SAdrian Alonso 		 */
262ee25e6a5SAdrian Alonso 		/*
263ee25e6a5SAdrian Alonso 		 * 12.d Reconfigure DENALI_CTL_144 [LPI_WAKEUP_EN[5:0]] bit
264ee25e6a5SAdrian Alonso 		 * LPI_WAKEUP_EN[3] = 1b'1.
265ee25e6a5SAdrian Alonso 		 */
266ee25e6a5SAdrian Alonso 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, dram_timing_cfg->auto_lp_cfg[0]);
267ee25e6a5SAdrian Alonso 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_147, dram_timing_cfg->auto_lp_cfg[1]);
268ee25e6a5SAdrian Alonso 		/* 12.e Re-enable DDRC auto low-power mode interface */
269ee25e6a5SAdrian Alonso 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_146, dram_timing_cfg->auto_lp_cfg[2]);
270ee25e6a5SAdrian Alonso 		/* restore ctl config */
271ee25e6a5SAdrian Alonso 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_143, dram_ctl_143);
272ee25e6a5SAdrian Alonso 		/* dram low power mode flag */
273ee25e6a5SAdrian Alonso 		dram_auto_lp_true = false;
274ee25e6a5SAdrian Alonso 	}
275ee25e6a5SAdrian Alonso }
276ee25e6a5SAdrian Alonso 
dram_enter_self_refresh(void)277ee25e6a5SAdrian Alonso void dram_enter_self_refresh(void)
278ee25e6a5SAdrian Alonso {
279ee25e6a5SAdrian Alonso 	/* disable auto low power interface */
280ee25e6a5SAdrian Alonso 	dram_lp_auto_disable();
281ee25e6a5SAdrian Alonso 	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
282ee25e6a5SAdrian Alonso 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
283ee25e6a5SAdrian Alonso 	/* 1.a Clock gate PCC_LPDDR4[CGC] and no software reset PCC_LPDDR4[SWRST] */
284ee25e6a5SAdrian Alonso 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, (BIT(30) | BIT(28)));
285ee25e6a5SAdrian Alonso 
286ee25e6a5SAdrian Alonso 	/*
287ee25e6a5SAdrian Alonso 	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
288ee25e6a5SAdrian Alonso 	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
289ee25e6a5SAdrian Alonso 	 * long with mem and ctlr clk gating or self-refresh power-down long
290ee25e6a5SAdrian Alonso 	 * with mem and ctlr clk gating'
291ee25e6a5SAdrian Alonso 	 */
292ee25e6a5SAdrian Alonso 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
293ee25e6a5SAdrian Alonso 	/* TODO: Needed ? 2.a DENALI_CTL_144[LPI_TIMER_WAKEUP_F2] */
294ee25e6a5SAdrian Alonso 	//mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(0));
295ee25e6a5SAdrian Alonso 
296ee25e6a5SAdrian Alonso 	/*
297ee25e6a5SAdrian Alonso 	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
298ee25e6a5SAdrian Alonso 	 * the logic to automatic handles low power entry/exit. This is the recommended
299ee25e6a5SAdrian Alonso 	 * option over handling through software.
300ee25e6a5SAdrian Alonso 	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
301ee25e6a5SAdrian Alonso 	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
302ee25e6a5SAdrian Alonso 	 * since LPPDR logic will be power gated).
303ee25e6a5SAdrian Alonso 	 */
304ee25e6a5SAdrian Alonso 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
305ee25e6a5SAdrian Alonso 	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
306ee25e6a5SAdrian Alonso 			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
307ee25e6a5SAdrian Alonso 	/* 3.c clock gate ddr controller */
308ee25e6a5SAdrian Alonso 	mmio_setbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_EN_CLKGATE);
309ee25e6a5SAdrian Alonso 	/* 3.d lpddr max clk div en */
310ee25e6a5SAdrian Alonso 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_MAX_CLKDIV_EN);
311ee25e6a5SAdrian Alonso }
312ee25e6a5SAdrian Alonso 
dram_exit_self_refresh(void)313ee25e6a5SAdrian Alonso void dram_exit_self_refresh(void)
314ee25e6a5SAdrian Alonso {
315ee25e6a5SAdrian Alonso 	dram_lp_auto_enable();
316ee25e6a5SAdrian Alonso }
317ee25e6a5SAdrian Alonso 
dram_enter_retention(void)318478af8d3SJacky Bai void dram_enter_retention(void)
319478af8d3SJacky Bai {
320478af8d3SJacky Bai 	unsigned int i;
321478af8d3SJacky Bai 
322ee25e6a5SAdrian Alonso 	dram_lp_auto_disable();
323ee25e6a5SAdrian Alonso 
324478af8d3SJacky Bai 	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
325478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
326478af8d3SJacky Bai 
327478af8d3SJacky Bai 	/*
328478af8d3SJacky Bai 	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
329478af8d3SJacky Bai 	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
330478af8d3SJacky Bai 	 * long with mem and ctlr clk gating or self-refresh  power-down
331478af8d3SJacky Bai 	 * long with mem and ctlr clk gating'
332478af8d3SJacky Bai 	 */
333478af8d3SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
334478af8d3SJacky Bai 
335478af8d3SJacky Bai 	/*
336478af8d3SJacky Bai 	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
337478af8d3SJacky Bai 	 * the logic to automatic handles low power entry/exit. This is the recommended
338478af8d3SJacky Bai 	 * option over handling through software.
339478af8d3SJacky Bai 	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
340478af8d3SJacky Bai 	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
341478af8d3SJacky Bai 	 * since LPPDR logic will be power gated).
342478af8d3SJacky Bai 	 */
343478af8d3SJacky Bai 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
344478af8d3SJacky Bai 	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
345478af8d3SJacky Bai 			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
346478af8d3SJacky Bai 
347478af8d3SJacky Bai 	/* Save DDR Controller & PHY config.
348478af8d3SJacky Bai 	 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
349478af8d3SJacky Bai 	 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
350478af8d3SJacky Bai 	 * F1 & F2 into phy_f2_cfg.
351478af8d3SJacky Bai 	 */
352478af8d3SJacky Bai 	if (!dram_cfg_saved) {
353478af8d3SJacky Bai 		info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
354478af8d3SJacky Bai 		dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
355478af8d3SJacky Bai 					sizeof(struct dram_timing_info));
356478af8d3SJacky Bai 
357478af8d3SJacky Bai 		/* get the dram type */
358478af8d3SJacky Bai 		dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
359478af8d3SJacky Bai 		dram_class = (dram_class >> 8) & 0xf;
360478af8d3SJacky Bai 
361478af8d3SJacky Bai 		/* save the ctl registers */
362478af8d3SJacky Bai 		for (i = 0U; i < CTL_NUM; i++) {
363478af8d3SJacky Bai 			dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
364478af8d3SJacky Bai 		}
365478af8d3SJacky Bai 		dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
366478af8d3SJacky Bai 
367478af8d3SJacky Bai 		/* save the PI registers */
368478af8d3SJacky Bai 		for (i = 0U; i < PI_NUM; i++) {
369478af8d3SJacky Bai 			dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
370478af8d3SJacky Bai 		}
371478af8d3SJacky Bai 		dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
372478af8d3SJacky Bai 
373478af8d3SJacky Bai 		/*
374478af8d3SJacky Bai 		 * Read and store all PHY registers. full array is a full
375478af8d3SJacky Bai 		 * copy for all the setpoint
376478af8d3SJacky Bai 		 */
377478af8d3SJacky Bai 		if (dram_class == LPDDR4_TYPE) {
378478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
379478af8d3SJacky Bai 			for (i = 0U; i < PHY_NUM; i++) {
380478af8d3SJacky Bai 				/* Make sure MULTICASE is enabled */
381478af8d3SJacky Bai 				if (i == 1537U) {
382478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = 0x100;
383478af8d3SJacky Bai 				} else {
384478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
385478af8d3SJacky Bai 				}
386478af8d3SJacky Bai 			}
387478af8d3SJacky Bai 
388478af8d3SJacky Bai 			/*
389478af8d3SJacky Bai 			 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
390478af8d3SJacky Bai 			 * Read and store only the diff.
391478af8d3SJacky Bai 			 */
392478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
393478af8d3SJacky Bai 			/* save only the frequency based diff config to save memory */
394478af8d3SJacky Bai 			for (i = 0U; i < PHY_DIFF_NUM; i++) {
395478af8d3SJacky Bai 				dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
396478af8d3SJacky Bai 									    freq_specific_reg_array[i] * 4);
397478af8d3SJacky Bai 			}
398478af8d3SJacky Bai 		} else {
399478af8d3SJacky Bai 			/* LPDDR3, only f1 need to save */
400478af8d3SJacky Bai 			for (i = 0U; i < info->phy_f1_cfg_num; i++) {
401478af8d3SJacky Bai 				info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
402478af8d3SJacky Bai 			}
403478af8d3SJacky Bai 		}
404478af8d3SJacky Bai 
405478af8d3SJacky Bai 		dram_cfg_saved = true;
406478af8d3SJacky Bai 	}
407478af8d3SJacky Bai }
408478af8d3SJacky Bai 
dram_exit_retention(void)409478af8d3SJacky Bai void dram_exit_retention(void)
410478af8d3SJacky Bai {
411478af8d3SJacky Bai 	uint32_t val;
412478af8d3SJacky Bai 
413478af8d3SJacky Bai 	/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
414478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
415478af8d3SJacky Bai 
416478af8d3SJacky Bai 	/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
417478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
418478af8d3SJacky Bai 
419478af8d3SJacky Bai 	/* 3. Reload the LPDDR CTL/PI/PHY register */
420478af8d3SJacky Bai 	ddr_init();
421478af8d3SJacky Bai 
422478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
423478af8d3SJacky Bai 		/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
424478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
425478af8d3SJacky Bai 
426478af8d3SJacky Bai 		/*
427478af8d3SJacky Bai 		 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
428478af8d3SJacky Bai 		 * from controller.
429478af8d3SJacky Bai 		 */
430478af8d3SJacky Bai 		/*
431478af8d3SJacky Bai 		 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
432478af8d3SJacky Bai 		 * self refresh exit from PI
433478af8d3SJacky Bai 		 */
434478af8d3SJacky Bai 		/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
435478af8d3SJacky Bai 		/*
436478af8d3SJacky Bai 		 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
437478af8d3SJacky Bai 		 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
438478af8d3SJacky Bai 		 * Enable non initialization trainings.
439478af8d3SJacky Bai 		 */
440478af8d3SJacky Bai 		/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
441478af8d3SJacky Bai 		/* 4f. PI_DLL_RESET=0x1 */
442478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
443478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT = 1 */
444478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
445478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
446478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
447478af8d3SJacky Bai 		/* PI_INT_LVL_EN = 0 */
448478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
449478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
450478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
451478af8d3SJacky Bai 		/* PI_WRLVL_EN_F2 = 3 */
452478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
453478af8d3SJacky Bai 		/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
454478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
455478af8d3SJacky Bai 		/* PI_CALVL_EN_F2 = 3 */
456478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
457478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F0 = 3 */
458478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
459478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F1 = 3 */
460478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
461478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F2 = 3 */
462478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
463478af8d3SJacky Bai 		/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
464478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
465478af8d3SJacky Bai 		/*
466478af8d3SJacky Bai 		 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
467478af8d3SJacky Bai 		 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
468478af8d3SJacky Bai 		 */
469478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
470478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
471478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
472478af8d3SJacky Bai 	} else {
473478af8d3SJacky Bai 		/* PI_DLL_RESET=1 */
474478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
475478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT=1 */
476478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
477478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
478478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
479478af8d3SJacky Bai 		/* PI_INT_LVL_EN=0 */
480478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
481478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0=3 */
482478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
483478af8d3SJacky Bai 		/* PI_CALVL_EN_F0=3 */
484478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
485478af8d3SJacky Bai 		/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
486478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
487478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
488478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
489478af8d3SJacky Bai 	}
490478af8d3SJacky Bai 
491478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
492478af8d3SJacky Bai 
493478af8d3SJacky Bai 	/* Force in-order AXI read data */
494478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
495478af8d3SJacky Bai 
496478af8d3SJacky Bai 	/*
497478af8d3SJacky Bai 	 * Disable special R/W group switches so that R/W group placement
498478af8d3SJacky Bai 	 * is always at END of R/W group.
499478af8d3SJacky Bai 	 */
500478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
501478af8d3SJacky Bai 
502478af8d3SJacky Bai 	/* Reduce time for IO pad calibration */
503478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
504478af8d3SJacky Bai 
505478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
506478af8d3SJacky Bai 
507478af8d3SJacky Bai 	/* PD disable */
508478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
509478af8d3SJacky Bai 	/*
510478af8d3SJacky Bai 	 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
511478af8d3SJacky Bai 	 * to 1b'0, PCPCS_PD_EN to 1b'0
512478af8d3SJacky Bai 	 */
513478af8d3SJacky Bai 
514478af8d3SJacky Bai 	upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
515478af8d3SJacky Bai 	upower_wait_resp();
516478af8d3SJacky Bai 
517478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
518478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
519478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
520478af8d3SJacky Bai 
521478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
522478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
523478af8d3SJacky Bai 	} else {
524478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
525478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
526478af8d3SJacky Bai 
527478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
528478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
529478af8d3SJacky Bai 	}
530478af8d3SJacky Bai 
531478af8d3SJacky Bai 	/* 9. DENALI_CTL_266:  Wait for INT_STATUS_INIT=0x2 */
532478af8d3SJacky Bai 	do {
533478af8d3SJacky Bai 		val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
534478af8d3SJacky Bai 	} while (val != 0x2);
535478af8d3SJacky Bai 
536478af8d3SJacky Bai 	/*
537478af8d3SJacky Bai 	 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
538478af8d3SJacky Bai 	 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
539478af8d3SJacky Bai 	 */
540478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
541478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
542478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
543478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
544478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
545478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
546478af8d3SJacky Bai 
547478af8d3SJacky Bai 		/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
548478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
549478af8d3SJacky Bai 			;
550478af8d3SJacky Bai 		}
551478af8d3SJacky Bai 	} else {
552478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
553478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
554478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
555478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
556478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
557478af8d3SJacky Bai 			;
558478af8d3SJacky Bai 		}
559478af8d3SJacky Bai 	}
560ee25e6a5SAdrian Alonso 
561ee25e6a5SAdrian Alonso 	dram_lp_auto_enable();
562478af8d3SJacky Bai }
563caee2733SJacky Bai 
564caee2733SJacky Bai #define LPDDR_DONE       (0x1<<4)
565caee2733SJacky Bai #define SOC_FREQ_CHG_ACK (0x1<<6)
566caee2733SJacky Bai #define SOC_FREQ_CHG_REQ (0x1<<7)
567caee2733SJacky Bai #define LPI_WAKEUP_EN    (0x4<<8)
568caee2733SJacky Bai #define SOC_FREQ_REQ     (0x1<<11)
569caee2733SJacky Bai 
set_cgc2_ddrclk(uint8_t src,uint8_t div)570caee2733SJacky Bai static void set_cgc2_ddrclk(uint8_t src, uint8_t div)
571caee2733SJacky Bai {
572caee2733SJacky Bai 
573caee2733SJacky Bai 	/* Wait until the reg is unlocked for writing */
574caee2733SJacky Bai 	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31))
575caee2733SJacky Bai 		;
576caee2733SJacky Bai 
577caee2733SJacky Bai 	mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21));
578caee2733SJacky Bai 	/* Wait for the clock switching done */
579caee2733SJacky Bai 	while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27)))
580caee2733SJacky Bai 		;
581caee2733SJacky Bai }
set_ddr_clk(uint32_t ddr_freq)582caee2733SJacky Bai static void set_ddr_clk(uint32_t ddr_freq)
583caee2733SJacky Bai {
584caee2733SJacky Bai 	/* Disable DDR clock */
585caee2733SJacky Bai 	mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
586caee2733SJacky Bai 	switch (ddr_freq) {
587caee2733SJacky Bai 	/* boot frequency ? */
588caee2733SJacky Bai 	case 48:
589caee2733SJacky Bai 		set_cgc2_ddrclk(2, 0);
590caee2733SJacky Bai 		break;
591caee2733SJacky Bai 	/* default bypass frequency for fsp 1 */
592caee2733SJacky Bai 	case 192:
593caee2733SJacky Bai 		set_cgc2_ddrclk(0, 1);
594caee2733SJacky Bai 		break;
595caee2733SJacky Bai 	case 384:
596caee2733SJacky Bai 		set_cgc2_ddrclk(0, 0);
597caee2733SJacky Bai 		break;
598caee2733SJacky Bai 	case 264:
599caee2733SJacky Bai 		set_cgc2_ddrclk(4, 3);
600caee2733SJacky Bai 		break;
601caee2733SJacky Bai 	case 528:
602caee2733SJacky Bai 		set_cgc2_ddrclk(4, 1);
603caee2733SJacky Bai 		break;
604caee2733SJacky Bai 	default:
605caee2733SJacky Bai 		break;
606caee2733SJacky Bai 	}
607caee2733SJacky Bai 	/* Enable DDR clock */
608caee2733SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
609caee2733SJacky Bai 
610caee2733SJacky Bai 	/* Wait until the reg is unlocked for writing */
611caee2733SJacky Bai 	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) {
612caee2733SJacky Bai 		;
613caee2733SJacky Bai 	}
614caee2733SJacky Bai }
615caee2733SJacky Bai 
616caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL	(IMX_LPAV_SIM_BASE + 0x14)
617caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL2	(IMX_LPAV_SIM_BASE + 0x18)
618caee2733SJacky Bai #define MAX_FSP_NUM	U(3)
619caee2733SJacky Bai #define DDR_DFS_GET_FSP_COUNT	0x10
620caee2733SJacky Bai #define DDR_BYPASS_DRATE	U(400)
621caee2733SJacky Bai 
622416c4433SJacky Bai extern int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val);
623416c4433SJacky Bai 
624caee2733SJacky Bai /* Normally, we only switch frequency between 1(bypass) and 2(highest) */
lpddr4_dfs(uint32_t freq_index)625caee2733SJacky Bai int lpddr4_dfs(uint32_t freq_index)
626caee2733SJacky Bai {
627caee2733SJacky Bai 	uint32_t lpddr_ctrl, lpddr_ctrl2;
628caee2733SJacky Bai 	uint32_t ddr_ctl_144;
629caee2733SJacky Bai 
630caee2733SJacky Bai 	/*
631caee2733SJacky Bai 	 * Valid index: 0 to 2
632caee2733SJacky Bai 	 * index 0: boot frequency
633caee2733SJacky Bai 	 * index 1: bypass frequency
634caee2733SJacky Bai 	 * index 2: highest frequency
635caee2733SJacky Bai 	 */
636caee2733SJacky Bai 	if (freq_index > 2U) {
637caee2733SJacky Bai 		return -1;
638caee2733SJacky Bai 	}
639caee2733SJacky Bai 
640416c4433SJacky Bai 	/*
641416c4433SJacky Bai 	 * increase the voltage to 1.1V firstly before increase frequency
642416c4433SJacky Bai 	 * and APD enter OD mode
643416c4433SJacky Bai 	 */
644416c4433SJacky Bai 	if (freq_index == 2U && sys_dvfs) {
645416c4433SJacky Bai 		upower_pmic_i2c_write(0x22, 0x28);
646416c4433SJacky Bai 	}
647416c4433SJacky Bai 
648caee2733SJacky Bai 	/* Enable LPI_WAKEUP_EN */
649caee2733SJacky Bai 	ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
650caee2733SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN);
651caee2733SJacky Bai 
652caee2733SJacky Bai 	/* put DRAM into long self-refresh & clock gating */
653caee2733SJacky Bai 	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
654caee2733SJacky Bai 	lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9);
655caee2733SJacky Bai 	mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl);
656caee2733SJacky Bai 
657caee2733SJacky Bai 	/* Gating the clock */
658caee2733SJacky Bai 	lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2);
659caee2733SJacky Bai 	mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE);
660caee2733SJacky Bai 
661caee2733SJacky Bai 	/* Request frequency change */
662caee2733SJacky Bai 	mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ);
663caee2733SJacky Bai 
664caee2733SJacky Bai 	do {
665caee2733SJacky Bai 		lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
666caee2733SJacky Bai 		if (lpddr_ctrl & SOC_FREQ_CHG_REQ) {
667caee2733SJacky Bai 			/* Bypass mode */
668caee2733SJacky Bai 			if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) {
669caee2733SJacky Bai 				/* Change to PLL bypass mode */
670caee2733SJacky Bai 				mmio_write_32(IMX_LPAV_SIM_BASE, 0x1);
671caee2733SJacky Bai 				/* change the ddr clock source & frequency */
672caee2733SJacky Bai 				set_ddr_clk(info->fsp_table[freq_index]);
673caee2733SJacky Bai 			} else {
674caee2733SJacky Bai 				/* Change to PLL unbypass mode */
675caee2733SJacky Bai 				mmio_write_32(IMX_LPAV_SIM_BASE, 0x0);
676caee2733SJacky Bai 				/* change the ddr clock source & frequency */
677caee2733SJacky Bai 				set_ddr_clk(info->fsp_table[freq_index] >> 1);
678caee2733SJacky Bai 			}
679caee2733SJacky Bai 
680caee2733SJacky Bai 			mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK);
681caee2733SJacky Bai 			continue;
682caee2733SJacky Bai 		}
683caee2733SJacky Bai 	} while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */
684caee2733SJacky Bai 
685caee2733SJacky Bai 	/* restore the original setting */
686caee2733SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144);
687caee2733SJacky Bai 	mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2);
688caee2733SJacky Bai 
689caee2733SJacky Bai 	/* Check the DFS result */
690caee2733SJacky Bai 	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF;
691caee2733SJacky Bai 	if (lpddr_ctrl != 0U) {
692caee2733SJacky Bai 		/* Must be something wrong, return failure */
693caee2733SJacky Bai 		return -1;
694caee2733SJacky Bai 	}
695caee2733SJacky Bai 
696416c4433SJacky Bai 	/* decrease the BUCK3 voltage after frequency changed to lower
697416c4433SJacky Bai 	 * and APD in ND_MODE
698416c4433SJacky Bai 	 */
699416c4433SJacky Bai 	if (freq_index == 1U && sys_dvfs) {
700416c4433SJacky Bai 		upower_pmic_i2c_write(0x22, 0x20);
701416c4433SJacky Bai 	}
702416c4433SJacky Bai 
703caee2733SJacky Bai 	/* DFS done successfully */
704caee2733SJacky Bai 	return 0;
705caee2733SJacky Bai }
706caee2733SJacky Bai 
707caee2733SJacky Bai /* for the non-primary core, waiting for DFS done */
waiting_dvfs(uint32_t id,uint32_t flags,void * handle,void * cookie)708caee2733SJacky Bai static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
709caee2733SJacky Bai 		void *handle, void *cookie)
710caee2733SJacky Bai {
711caee2733SJacky Bai 	uint32_t irq;
712caee2733SJacky Bai 
713caee2733SJacky Bai 	irq = plat_ic_acknowledge_interrupt();
714caee2733SJacky Bai 	if (irq < 1022U) {
715caee2733SJacky Bai 		plat_ic_end_of_interrupt(irq);
716caee2733SJacky Bai 	}
717caee2733SJacky Bai 
718caee2733SJacky Bai 	/* set the WFE done status */
719caee2733SJacky Bai 	spin_lock(&dfs_lock);
720caee2733SJacky Bai 	core_count++;
721caee2733SJacky Bai 	dsb();
722caee2733SJacky Bai 	spin_unlock(&dfs_lock);
723caee2733SJacky Bai 
724caee2733SJacky Bai 	while (in_progress) {
725caee2733SJacky Bai 		wfe();
726caee2733SJacky Bai 	}
727caee2733SJacky Bai 
728caee2733SJacky Bai 	return 0;
729caee2733SJacky Bai }
730caee2733SJacky Bai 
dram_dvfs_handler(uint32_t smc_fid,void * handle,u_register_t x1,u_register_t x2,u_register_t x3)731caee2733SJacky Bai int dram_dvfs_handler(uint32_t smc_fid, void *handle,
732caee2733SJacky Bai 		u_register_t x1, u_register_t x2, u_register_t x3)
733caee2733SJacky Bai {
734caee2733SJacky Bai 	unsigned int fsp_index = x1;
735caee2733SJacky Bai 	uint32_t online_cpus = x2 - 1;
736caee2733SJacky Bai 	uint64_t mpidr = read_mpidr_el1();
737caee2733SJacky Bai 	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
738caee2733SJacky Bai 
739caee2733SJacky Bai 	/* Get the number of FSPs */
740caee2733SJacky Bai 	if (x1 == DDR_DFS_GET_FSP_COUNT) {
741caee2733SJacky Bai 		SMC_RET2(handle, num_fsp, info->fsp_table[1]);
742caee2733SJacky Bai 	}
743caee2733SJacky Bai 
744caee2733SJacky Bai 	/* start lpddr frequency scaling */
745caee2733SJacky Bai 	in_progress = true;
746416c4433SJacky Bai 	sys_dvfs = x3 ? true : false;
747caee2733SJacky Bai 	dsb();
748caee2733SJacky Bai 
749caee2733SJacky Bai 	/* notify other core wait for scaling done */
750caee2733SJacky Bai 	for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++)
751caee2733SJacky Bai 		/* Skip raise SGI for current CPU */
752caee2733SJacky Bai 		if (i != cpu_id) {
753caee2733SJacky Bai 			plat_ic_raise_el3_sgi(0x8, i);
754caee2733SJacky Bai 		}
755caee2733SJacky Bai 
756caee2733SJacky Bai 	/* Make sure all the cpu in WFE */
757caee2733SJacky Bai 	while (online_cpus != core_count) {
758caee2733SJacky Bai 		;
759caee2733SJacky Bai 	}
760caee2733SJacky Bai 
761caee2733SJacky Bai 	/* Flush the L1/L2 cache */
762caee2733SJacky Bai 	dcsw_op_all(DCCSW);
763caee2733SJacky Bai 
764caee2733SJacky Bai 	lpddr4_dfs(fsp_index);
765caee2733SJacky Bai 
766caee2733SJacky Bai 	in_progress = false;
767caee2733SJacky Bai 	core_count = 0;
768caee2733SJacky Bai 	dsb();
769caee2733SJacky Bai 	sev();
770caee2733SJacky Bai 	isb();
771caee2733SJacky Bai 
772caee2733SJacky Bai 	SMC_RET1(handle, 0);
773caee2733SJacky Bai }
774caee2733SJacky Bai 
dram_init(void)775caee2733SJacky Bai void dram_init(void)
776caee2733SJacky Bai {
777caee2733SJacky Bai 	uint32_t flags = 0;
778caee2733SJacky Bai 	uint32_t rc;
779caee2733SJacky Bai 	unsigned int i;
780caee2733SJacky Bai 
781caee2733SJacky Bai 	/* Register the EL3 handler for DDR DVFS */
782caee2733SJacky Bai 	set_interrupt_rm_flag(flags, NON_SECURE);
783caee2733SJacky Bai 	rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
784caee2733SJacky Bai 	if (rc) {
785caee2733SJacky Bai 		panic();
786caee2733SJacky Bai 	}
787caee2733SJacky Bai 
788caee2733SJacky Bai 	info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
789caee2733SJacky Bai 
790caee2733SJacky Bai 	/* Get the num of the supported Fsp */
791caee2733SJacky Bai 	for (i = 0; i < MAX_FSP_NUM; i++) {
792caee2733SJacky Bai 		if (!info->fsp_table[i]) {
793caee2733SJacky Bai 			break;
794caee2733SJacky Bai 		}
795caee2733SJacky Bai 	}
796caee2733SJacky Bai 
797caee2733SJacky Bai 	num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i;
798caee2733SJacky Bai }
799