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