xref: /rk3399_ARM-atf/plat/rockchip/rk3576/drivers/dmc/suspend.c (revision 04b2fb42b171e3fbf2ef823558ac5b0119663dc7)
1*036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause
2*036935a8SXiaoDong Huang /*
3*036935a8SXiaoDong Huang  * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
4*036935a8SXiaoDong Huang  */
5*036935a8SXiaoDong Huang 
6*036935a8SXiaoDong Huang #include <assert.h>
7*036935a8SXiaoDong Huang #include <errno.h>
8*036935a8SXiaoDong Huang 
9*036935a8SXiaoDong Huang #include <arch_helpers.h>
10*036935a8SXiaoDong Huang #include <bl31/bl31.h>
11*036935a8SXiaoDong Huang #include <common/debug.h>
12*036935a8SXiaoDong Huang #include <drivers/console.h>
13*036935a8SXiaoDong Huang #include <drivers/delay_timer.h>
14*036935a8SXiaoDong Huang #include <lib/mmio.h>
15*036935a8SXiaoDong Huang #include <platform.h>
16*036935a8SXiaoDong Huang #include <platform_def.h>
17*036935a8SXiaoDong Huang 
18*036935a8SXiaoDong Huang #include <dmc_rk3576.h>
19*036935a8SXiaoDong Huang #include <rk3576_def.h>
20*036935a8SXiaoDong Huang #include <soc.h>
21*036935a8SXiaoDong Huang 
22*036935a8SXiaoDong Huang struct rk3576_dmc_config dmc_config;
23*036935a8SXiaoDong Huang 
24*036935a8SXiaoDong Huang /* DDR_PHY */
25*036935a8SXiaoDong Huang #define LP_CON0				0x0018
26*036935a8SXiaoDong Huang #define DFI_LP_CON0			0x0e04
27*036935a8SXiaoDong Huang /* DDR_CTL */
28*036935a8SXiaoDong Huang #define DDRCTL_STAT			0x10014
29*036935a8SXiaoDong Huang #define DDRCTL_PWRCTL			0x10180
30*036935a8SXiaoDong Huang #define DDRCTL_CLKGATECTL		0x1018c
31*036935a8SXiaoDong Huang 
32*036935a8SXiaoDong Huang /* LP_CON0 */
33*036935a8SXiaoDong Huang #define DS_IO_PD			BIT(14)
34*036935a8SXiaoDong Huang #define SCHD_HW_CLOCK_GATING_DISABLE	BIT(13)
35*036935a8SXiaoDong Huang #define PCL_PD				BIT(12)
36*036935a8SXiaoDong Huang #define DQS_ENABLE			BIT(10)
37*036935a8SXiaoDong Huang #define WCK_ENABLE			BIT(9)
38*036935a8SXiaoDong Huang #define CTRL_DQS_DRV_OFF		BIT(8)
39*036935a8SXiaoDong Huang #define CTRL_SCHEDULER_EN		BIT(6)
40*036935a8SXiaoDong Huang 
41*036935a8SXiaoDong Huang /* DFI_LP_CON0 0x0e04 */
42*036935a8SXiaoDong Huang #define DFI_LP_MODE_APB			BIT(31)
43*036935a8SXiaoDong Huang 
44*036935a8SXiaoDong Huang /* DDRCTL_STAT 0x10014 */
45*036935a8SXiaoDong Huang #define CTL_SELFREF_STATE_SHIFT		(12)
46*036935a8SXiaoDong Huang #define CTL_SELFREF_STATE_MASK		(0x7 << CTL_SELFREF_STATE_SHIFT)
47*036935a8SXiaoDong Huang #define CTL_NOT_IN_SELF_REFRESH		(0x0 << CTL_SELFREF_STATE_SHIFT)
48*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_1		(0x1 << CTL_SELFREF_STATE_SHIFT)
49*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_POWER_DOWN	(0x2 << CTL_SELFREF_STATE_SHIFT)
50*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_2		(0x3 << CTL_SELFREF_STATE_SHIFT)
51*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_DEEP_SLEEP	(0x4 << CTL_SELFREF_STATE_SHIFT)
52*036935a8SXiaoDong Huang #define CTL_SELFREF_TYPE_SHIFT		(4)
53*036935a8SXiaoDong Huang #define CTL_SELFREF_TYPE_MASK		(0x3 << CTL_SELFREF_TYPE_SHIFT)
54*036935a8SXiaoDong Huang #define CTL_SELFREF_NOT_BY_PHY		(0x1 << CTL_SELFREF_TYPE_SHIFT)
55*036935a8SXiaoDong Huang #define CTL_SELFREF_NOT_BY_AUTO		(0x2 << CTL_SELFREF_TYPE_SHIFT)
56*036935a8SXiaoDong Huang #define CTL_SELFREF_BY_AUTO		(0x3 << CTL_SELFREF_TYPE_SHIFT)
57*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_MASK		(0x7)
58*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_INIT		(0x0)
59*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_NORMAL	(0x1)
60*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_PD		(0x2)
61*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_SR_SRPD	(0x3)
62*036935a8SXiaoDong Huang 
63*036935a8SXiaoDong Huang /* DDRCTL_PWRCTL 0x10180 */
64*036935a8SXiaoDong Huang #define CTL_DSM_EN			BIT(18)
65*036935a8SXiaoDong Huang #define CTL_STAY_IN_SELFREF		BIT(15)
66*036935a8SXiaoDong Huang #define CTL_SELFREF_SW			BIT(11)
67*036935a8SXiaoDong Huang #define CTL_EN_DFI_DRAM_CLK_DISABLE	BIT(9)
68*036935a8SXiaoDong Huang #define CTL_POWERDOWN_EN_MASK		(0xf)
69*036935a8SXiaoDong Huang #define CTL_POWERDOWN_EN_SHIFT		(4)
70*036935a8SXiaoDong Huang #define CTL_SELFREF_EN_MASK		(0xf)
71*036935a8SXiaoDong Huang #define CTL_SELFREF_EN_SHIFT		(0)
72*036935a8SXiaoDong Huang 
73*036935a8SXiaoDong Huang #define SYS_REG_DEC_CHINFO(n, ch)	(((n) >> (28 + (ch))) & 0x1)
74*036935a8SXiaoDong Huang #define SYS_REG_DEC_CHINFO_V3(reg2, ch) SYS_REG_DEC_CHINFO(reg2, ch)
75*036935a8SXiaoDong Huang 
76*036935a8SXiaoDong Huang #define SYS_REG_DEC_NUM_CH(n)		(1 + (((n) >> 12) & 0x1))
77*036935a8SXiaoDong Huang #define SYS_REG_DEC_NUM_CH_V3(reg2)	SYS_REG_DEC_NUM_CH(reg2)
78*036935a8SXiaoDong Huang 
exit_low_power(uint32_t ch,struct rk3576_dmc_config * configs)79*036935a8SXiaoDong Huang static void exit_low_power(uint32_t ch, struct rk3576_dmc_config *configs)
80*036935a8SXiaoDong Huang {
81*036935a8SXiaoDong Huang 	/* LP_CON0: [12]pcl_pd */
82*036935a8SXiaoDong Huang 	configs->low_power[ch].pcl_pd = mmio_read_32(DDRPHY_BASE_CH(0) + LP_CON0) & PCL_PD;
83*036935a8SXiaoDong Huang 	mmio_clrbits_32(DDRPHY_BASE_CH(ch) + LP_CON0, PCL_PD);
84*036935a8SXiaoDong Huang 
85*036935a8SXiaoDong Huang 	/* Disable low power activities */
86*036935a8SXiaoDong Huang 	configs->low_power[ch].pwrctl = mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL);
87*036935a8SXiaoDong Huang 	mmio_clrbits_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL,
88*036935a8SXiaoDong Huang 			CTL_DSM_EN | (CTL_POWERDOWN_EN_MASK << CTL_POWERDOWN_EN_SHIFT) |
89*036935a8SXiaoDong Huang 			(CTL_SELFREF_EN_MASK << CTL_SELFREF_EN_SHIFT));
90*036935a8SXiaoDong Huang 	while ((mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_STAT) & CTL_OPERATING_MODE_MASK) !=
91*036935a8SXiaoDong Huang 		CTL_OPERATING_MODE_NORMAL)
92*036935a8SXiaoDong Huang 		continue;
93*036935a8SXiaoDong Huang 
94*036935a8SXiaoDong Huang 	/* DDR_GRF_CHA_CON6: [6:0]rd_lat_delay, [14:8]wr_lat_delay, [15]cmd_dly_eq0_en */
95*036935a8SXiaoDong Huang 	configs->low_power[ch].grf_ddr_con6 =
96*036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6)) & 0xff7f;
97*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6), (0x1ul << (15 + 16)));
98*036935a8SXiaoDong Huang 
99*036935a8SXiaoDong Huang 	/* DDR_GRF_CHA_CON0: [12:8]ddrctl_axi_cg_en */
100*036935a8SXiaoDong Huang 	configs->low_power[ch].grf_ddr_con0 =
101*036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0)) & 0x1f00;
102*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0), 0x1f000000);
103*036935a8SXiaoDong Huang 
104*036935a8SXiaoDong Huang 	/*
105*036935a8SXiaoDong Huang 	 * DDR_GRF_CHA_CON1:
106*036935a8SXiaoDong Huang 	 * [15]ddrctl_apb_pclk_cg_en, [12]ddrmon_pclk_cg_en, [7]dfi_scramble_cg_en,
107*036935a8SXiaoDong Huang 	 * [6]ddrctl_mem_cg_en, [5]bsm_clk_cg_en, [2]ddrctl_core_cg_en, [1]ddrctl_apb_cg_en
108*036935a8SXiaoDong Huang 	 */
109*036935a8SXiaoDong Huang 	configs->low_power[ch].grf_ddr_con1 =
110*036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1)) & 0x90e6;
111*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1), 0x90e60000);
112*036935a8SXiaoDong Huang 
113*036935a8SXiaoDong Huang 	configs->low_power[ch].hwlp_0 = mmio_read_32(HWLP_BASE_CH(ch) + 0x0);
114*036935a8SXiaoDong Huang 	mmio_write_32(HWLP_BASE_CH(ch) + 0x0, 0x0);
115*036935a8SXiaoDong Huang 	configs->low_power[ch].hwlp_c = mmio_read_32(HWLP_BASE_CH(ch) + 0xc);
116*036935a8SXiaoDong Huang 	mmio_write_32(HWLP_BASE_CH(ch) + 0xc, 0x0);
117*036935a8SXiaoDong Huang 
118*036935a8SXiaoDong Huang 	/* DDR_GRF_CHA_PHY_CON0: [14]ddrphy_pclk_cg_en */
119*036935a8SXiaoDong Huang 	configs->low_power[ch].grf_ddrphy_con0 =
120*036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch)) & BIT(14);
121*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch), BIT(14 + 16));
122*036935a8SXiaoDong Huang 
123*036935a8SXiaoDong Huang 	/* CLKGATECTL: [5:0]bsm_clk_on */
124*036935a8SXiaoDong Huang 	configs->low_power[ch].clkgatectl =
125*036935a8SXiaoDong Huang 		mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_CLKGATECTL) & 0x3f;
126*036935a8SXiaoDong Huang 	/* DFI_LP_CON0: [31]dfi_lp_mode_apb */
127*036935a8SXiaoDong Huang 	configs->low_power[ch].dfi_lp_mode_apb =
128*036935a8SXiaoDong Huang 		(mmio_read_32(DDRPHY_BASE_CH(ch) + DFI_LP_CON0) >> 31) & 0x1;
129*036935a8SXiaoDong Huang }
130*036935a8SXiaoDong Huang 
resume_low_power(uint32_t ch,struct rk3576_dmc_config * configs)131*036935a8SXiaoDong Huang static void resume_low_power(uint32_t ch, struct rk3576_dmc_config *configs)
132*036935a8SXiaoDong Huang {
133*036935a8SXiaoDong Huang 	/* DFI_LP_CON0: [31]dfi_lp_mode_apb */
134*036935a8SXiaoDong Huang 	if (configs->low_power[ch].dfi_lp_mode_apb != 0)
135*036935a8SXiaoDong Huang 		mmio_setbits_32(DDRPHY_BASE_CH(ch) + DFI_LP_CON0, DFI_LP_MODE_APB);
136*036935a8SXiaoDong Huang 
137*036935a8SXiaoDong Huang 	/* CLKGATECTL: [5:0]bsm_clk_on */
138*036935a8SXiaoDong Huang 	mmio_clrsetbits_32(UMCTL_BASE_CH(ch) + DDRCTL_CLKGATECTL,
139*036935a8SXiaoDong Huang 			   0x3f, configs->low_power[ch].clkgatectl & 0x3f);
140*036935a8SXiaoDong Huang 
141*036935a8SXiaoDong Huang 	/* DDR_GRF_CHA_CON6: [6:0]rd_lat_delay, [14:8]wr_lat_delay, [15]cmd_dly_eq0_en */
142*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6),
143*036935a8SXiaoDong Huang 		      (0xff7ful << 16) | configs->low_power[ch].grf_ddr_con6);
144*036935a8SXiaoDong Huang 
145*036935a8SXiaoDong Huang 	mmio_write_32(HWLP_BASE_CH(ch) + 0xc, configs->low_power[ch].hwlp_c);
146*036935a8SXiaoDong Huang 	mmio_write_32(HWLP_BASE_CH(ch) + 0x0, configs->low_power[ch].hwlp_0);
147*036935a8SXiaoDong Huang 
148*036935a8SXiaoDong Huang 	/* DDR_GRF_CHA_CON0: [12:8]ddrctl_axi_cg_en */
149*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0),
150*036935a8SXiaoDong Huang 		      (0x1f00ul << 16) | configs->low_power[ch].grf_ddr_con0);
151*036935a8SXiaoDong Huang 
152*036935a8SXiaoDong Huang 	/*
153*036935a8SXiaoDong Huang 	 * DDR_GRF_CHA_CON1:
154*036935a8SXiaoDong Huang 	 * [15]ddrctl_apb_pclk_cg_en, [12]ddrmon_pclk_cg_en, [7]dfi_scramble_cg_en,
155*036935a8SXiaoDong Huang 	 * [6]ddrctl_mem_cg_en, [5]bsm_clk_cg_en, [2]ddrctl_core_cg_en, [1]ddrctl_apb_cg_en
156*036935a8SXiaoDong Huang 	 */
157*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1),
158*036935a8SXiaoDong Huang 		      (0x90e6ul << 16) | configs->low_power[ch].grf_ddr_con1);
159*036935a8SXiaoDong Huang 
160*036935a8SXiaoDong Huang 	/* DDR_GRF_CHA_PHY_CON0: [14]ddrphy_pclk_cg_en */
161*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch),
162*036935a8SXiaoDong Huang 		      BIT(14 + 16) | configs->low_power[ch].grf_ddrphy_con0);
163*036935a8SXiaoDong Huang 
164*036935a8SXiaoDong Huang 	/* reset low power activities */
165*036935a8SXiaoDong Huang 	mmio_write_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL, configs->low_power[ch].pwrctl);
166*036935a8SXiaoDong Huang 
167*036935a8SXiaoDong Huang 	/* LP_CON0: [12]pcl_pd */
168*036935a8SXiaoDong Huang 	if (configs->low_power[ch].pcl_pd != 0)
169*036935a8SXiaoDong Huang 		mmio_setbits_32(DDRPHY_BASE_CH(ch) + LP_CON0, PCL_PD);
170*036935a8SXiaoDong Huang }
171*036935a8SXiaoDong Huang 
dmc_save(void)172*036935a8SXiaoDong Huang void dmc_save(void)
173*036935a8SXiaoDong Huang {
174*036935a8SXiaoDong Huang 	uint32_t i, channel_num;
175*036935a8SXiaoDong Huang 
176*036935a8SXiaoDong Huang 	channel_num =
177*036935a8SXiaoDong Huang 		SYS_REG_DEC_NUM_CH_V3(mmio_read_32(PMU1_GRF_BASE + PMUGRF_OS_REG(2)));
178*036935a8SXiaoDong Huang 
179*036935a8SXiaoDong Huang 	for (i = 0; i < channel_num; i++)
180*036935a8SXiaoDong Huang 		exit_low_power(i, &dmc_config);
181*036935a8SXiaoDong Huang }
182*036935a8SXiaoDong Huang 
dmc_restore(void)183*036935a8SXiaoDong Huang void dmc_restore(void)
184*036935a8SXiaoDong Huang {
185*036935a8SXiaoDong Huang 	uint32_t i, channel_num;
186*036935a8SXiaoDong Huang 
187*036935a8SXiaoDong Huang 	channel_num = SYS_REG_DEC_NUM_CH_V3(mmio_read_32(PMU1_GRF_BASE + PMUGRF_OS_REG(2)));
188*036935a8SXiaoDong Huang 
189*036935a8SXiaoDong Huang 	for (i = 0; i < channel_num; i++)
190*036935a8SXiaoDong Huang 		resume_low_power(i, &dmc_config);
191*036935a8SXiaoDong Huang }
192