xref: /rk3399_ARM-atf/plat/mediatek/drivers/mtcmos/mtcmos.c (revision fa55368a72cacaeda0ce1a10d2a076329e6fa9b4)
1a881aebcSirving-ch-lin /*
2a881aebcSirving-ch-lin  * Copyright (c) 2025, MediaTek Inc. All rights reserved.
3a881aebcSirving-ch-lin  *
4a881aebcSirving-ch-lin  * SPDX-License-Identifier: BSD-3-Clause
5a881aebcSirving-ch-lin  */
6a881aebcSirving-ch-lin #include <stdint.h>
7a881aebcSirving-ch-lin 
8a881aebcSirving-ch-lin #include <common/debug.h>
9a881aebcSirving-ch-lin #include <drivers/delay_timer.h>
10a881aebcSirving-ch-lin #include <lib/mmio.h>
11a881aebcSirving-ch-lin #include <lib/spinlock.h>
12a881aebcSirving-ch-lin #include <platform_def.h>
13a881aebcSirving-ch-lin 
14a881aebcSirving-ch-lin #include <mtcmos.h>
15a881aebcSirving-ch-lin 
16a881aebcSirving-ch-lin #define SPM_PROJECT_CODE	0xB16
17a881aebcSirving-ch-lin 
18a881aebcSirving-ch-lin #define PWR_RST_B	BIT(0)
19a881aebcSirving-ch-lin #define PWR_ISO		BIT(1)
20a881aebcSirving-ch-lin #define PWR_ON		BIT(2)
21a881aebcSirving-ch-lin #define PWR_ON_2ND	BIT(3)
22a881aebcSirving-ch-lin #define PWR_CLK_DIS	BIT(4)
23a881aebcSirving-ch-lin #define PWR_ACK		BIT(30)
24a881aebcSirving-ch-lin #define PWR_ACK_2ND	BIT(31)
25a881aebcSirving-ch-lin 
26*41004253Sirving-ch-lin #define SRAM_PDN		BIT(8)
27*41004253Sirving-ch-lin #define SRAM_PDN_ACK		BIT(12)
28a881aebcSirving-ch-lin 
29a881aebcSirving-ch-lin #define MTCMOS_TIMEOUT_US	500
30a881aebcSirving-ch-lin 
31a881aebcSirving-ch-lin #define MTCMOS_ETIMEDOUT	25
32a881aebcSirving-ch-lin 
33a881aebcSirving-ch-lin static spinlock_t mtcmos_ctrl_lock;
34a881aebcSirving-ch-lin 
mtcmos_wait_for_state(uint32_t reg,uint32_t mask,bool is_set)35a881aebcSirving-ch-lin static int mtcmos_wait_for_state(uint32_t reg, uint32_t mask, bool is_set)
36a881aebcSirving-ch-lin {
37a881aebcSirving-ch-lin 	uint32_t retry = MTCMOS_TIMEOUT_US;
38a881aebcSirving-ch-lin 	uint32_t expect = is_set ? mask : 0;
39a881aebcSirving-ch-lin 
40a881aebcSirving-ch-lin 	do {
41a881aebcSirving-ch-lin 		if ((mmio_read_32(reg) & mask) == expect)
42a881aebcSirving-ch-lin 			return 0;
43a881aebcSirving-ch-lin 		udelay(1);
44a881aebcSirving-ch-lin 		retry--;
45a881aebcSirving-ch-lin 	} while (retry);
46a881aebcSirving-ch-lin 
47a881aebcSirving-ch-lin 	ERROR("%s(0x%x, 0x%x, %d) timeout, reg_val=0x%x\n",
48a881aebcSirving-ch-lin 	      __func__, reg, mask, is_set, mmio_read_32(reg));
49a881aebcSirving-ch-lin 
50a881aebcSirving-ch-lin 	return -MTCMOS_ETIMEDOUT;
51a881aebcSirving-ch-lin }
52a881aebcSirving-ch-lin 
53a881aebcSirving-ch-lin 
spm_mtcmos_ctrl_bus_prot(const struct bus_protect * bp_table,uint32_t bp_steps)54*41004253Sirving-ch-lin static int spm_mtcmos_ctrl_bus_prot(const struct bus_protect *bp_table, uint32_t bp_steps)
55a881aebcSirving-ch-lin {
56*41004253Sirving-ch-lin 	int i;
57a881aebcSirving-ch-lin 
58*41004253Sirving-ch-lin 	for (i = 0; i < bp_steps; i++) {
59*41004253Sirving-ch-lin 		mmio_write_32(bp_table[i].en_addr, bp_table[i].mask);
60*41004253Sirving-ch-lin 		if (bp_table[i].rdy_addr) {
61*41004253Sirving-ch-lin 			if (mtcmos_wait_for_state(bp_table[i].rdy_addr, bp_table[i].mask, true))
62a881aebcSirving-ch-lin 				return -MTCMOS_ETIMEDOUT;
63a881aebcSirving-ch-lin 		}
64*41004253Sirving-ch-lin 	}
65a881aebcSirving-ch-lin 	return 0;
66a881aebcSirving-ch-lin }
67a881aebcSirving-ch-lin 
68*41004253Sirving-ch-lin 
spm_mtcmos_ctrl(enum mtcmos_state state,uintptr_t reg,bool has_sram,int * rtff_save_flag,const struct bus_protect * bp_table,uint32_t bp_steps)69*41004253Sirving-ch-lin static int spm_mtcmos_ctrl(enum mtcmos_state state, uintptr_t reg,
70*41004253Sirving-ch-lin 			   bool has_sram, int *rtff_save_flag,
71*41004253Sirving-ch-lin 			   const struct bus_protect *bp_table, uint32_t bp_steps)
72a881aebcSirving-ch-lin {
73a881aebcSirving-ch-lin 	int ret = 0;
74a881aebcSirving-ch-lin 
75a881aebcSirving-ch-lin 	spin_lock(&mtcmos_ctrl_lock);
76a881aebcSirving-ch-lin 
77a881aebcSirving-ch-lin 	mmio_write_32(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | BIT(0));
78a881aebcSirving-ch-lin 
79a881aebcSirving-ch-lin 	if (state == STA_POWER_DOWN) {
80*41004253Sirving-ch-lin 		ret = spm_mtcmos_ctrl_bus_prot(bp_table, bp_steps);
81a881aebcSirving-ch-lin 		if (ret)
82a881aebcSirving-ch-lin 			goto exit;
83a881aebcSirving-ch-lin 
84*41004253Sirving-ch-lin 		if (has_sram) {
85*41004253Sirving-ch-lin 			mmio_setbits_32(reg, SRAM_PDN);
86*41004253Sirving-ch-lin 			ret = mtcmos_wait_for_state(reg, SRAM_PDN_ACK, true);
87a881aebcSirving-ch-lin 			if (ret)
88a881aebcSirving-ch-lin 				goto exit;
89a881aebcSirving-ch-lin 		}
90a881aebcSirving-ch-lin 
91a881aebcSirving-ch-lin 		mmio_setbits_32(reg, RTFF_CLK_DIS);
92a881aebcSirving-ch-lin 		mmio_setbits_32(reg, RTFF_SAVE);
93a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, RTFF_SAVE);
94a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, RTFF_CLK_DIS);
95*41004253Sirving-ch-lin #ifdef RTFF_SAVE_FLAG
96a881aebcSirving-ch-lin 		mmio_setbits_32(reg, RTFF_SAVE_FLAG);
97*41004253Sirving-ch-lin #endif
98*41004253Sirving-ch-lin 		*rtff_save_flag = 1;
99*41004253Sirving-ch-lin 
100a881aebcSirving-ch-lin 
101a881aebcSirving-ch-lin 		mmio_setbits_32(reg, PWR_ISO);
102a881aebcSirving-ch-lin 		mmio_setbits_32(reg, PWR_CLK_DIS);
103a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, PWR_RST_B);
104a881aebcSirving-ch-lin 
105a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, PWR_ON);
106a881aebcSirving-ch-lin 		ret = mtcmos_wait_for_state(reg, PWR_ACK, false);
107a881aebcSirving-ch-lin 		if (ret)
108a881aebcSirving-ch-lin 			goto exit;
109a881aebcSirving-ch-lin 
110a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, PWR_ON_2ND);
111a881aebcSirving-ch-lin 		ret = mtcmos_wait_for_state(reg, PWR_ACK_2ND, false);
112a881aebcSirving-ch-lin 		if (ret)
113a881aebcSirving-ch-lin 			goto exit;
114a881aebcSirving-ch-lin 	} else if (state == STA_POWER_ON) {
115a881aebcSirving-ch-lin 		mmio_setbits_32(reg, PWR_ON);
116a881aebcSirving-ch-lin 		ret = mtcmos_wait_for_state(reg, PWR_ACK, true);
117a881aebcSirving-ch-lin 		if (ret)
118a881aebcSirving-ch-lin 			goto exit;
119a881aebcSirving-ch-lin 
120a881aebcSirving-ch-lin 		udelay(50);
121a881aebcSirving-ch-lin 
122a881aebcSirving-ch-lin 		mmio_setbits_32(reg, PWR_ON_2ND);
123a881aebcSirving-ch-lin 		ret = mtcmos_wait_for_state(reg, PWR_ACK_2ND, true);
124a881aebcSirving-ch-lin 		if (ret)
125a881aebcSirving-ch-lin 			goto exit;
126a881aebcSirving-ch-lin 
127a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, PWR_CLK_DIS);
128a881aebcSirving-ch-lin 		mmio_clrbits_32(reg, PWR_ISO);
129a881aebcSirving-ch-lin 		udelay(10);
130a881aebcSirving-ch-lin 		mmio_setbits_32(reg, PWR_RST_B);
131a881aebcSirving-ch-lin 
132*41004253Sirving-ch-lin 
133*41004253Sirving-ch-lin 		if (*rtff_save_flag == 1) {
134a881aebcSirving-ch-lin 			mmio_setbits_32(reg, RTFF_CLK_DIS);
135a881aebcSirving-ch-lin 			mmio_clrbits_32(reg, RTFF_NRESTORE);
136a881aebcSirving-ch-lin 			mmio_setbits_32(reg, RTFF_NRESTORE);
137a881aebcSirving-ch-lin 			mmio_clrbits_32(reg, RTFF_CLK_DIS);
138*41004253Sirving-ch-lin #ifdef RTFF_SAVE_FLAG
139*41004253Sirving-ch-lin 			mmio_clrbits_32(reg, RTFF_SAVE_FLAG);
140*41004253Sirving-ch-lin #endif
141*41004253Sirving-ch-lin 			*rtff_save_flag = 0;
142a881aebcSirving-ch-lin 		}
143a881aebcSirving-ch-lin 
144*41004253Sirving-ch-lin 		if (has_sram) {
145*41004253Sirving-ch-lin 			mmio_clrbits_32(reg, SRAM_PDN);
146*41004253Sirving-ch-lin 			ret = mtcmos_wait_for_state(reg, SRAM_PDN_ACK, false);
147a881aebcSirving-ch-lin 			if (ret)
148a881aebcSirving-ch-lin 				goto exit;
149a881aebcSirving-ch-lin 		}
150a881aebcSirving-ch-lin 
151*41004253Sirving-ch-lin 		spm_mtcmos_ctrl_bus_prot(bp_table, bp_steps);
152a881aebcSirving-ch-lin 	}
153a881aebcSirving-ch-lin 
154a881aebcSirving-ch-lin exit:
155a881aebcSirving-ch-lin 	spin_unlock(&mtcmos_ctrl_lock);
156a881aebcSirving-ch-lin 	return ret;
157a881aebcSirving-ch-lin }
158a881aebcSirving-ch-lin 
spm_mtcmos_ctrl_ufs0(enum mtcmos_state state)159a881aebcSirving-ch-lin int spm_mtcmos_ctrl_ufs0(enum mtcmos_state state)
160a881aebcSirving-ch-lin {
161*41004253Sirving-ch-lin 	static int rtff_save_flag;
162*41004253Sirving-ch-lin 	const struct bus_protect *bp_table;
163*41004253Sirving-ch-lin 	uint32_t bp_steps;
164*41004253Sirving-ch-lin 
165*41004253Sirving-ch-lin 	if (state == STA_POWER_DOWN) {
166*41004253Sirving-ch-lin 		bp_table = &ufs0_bus_prot_set_table[0];
167*41004253Sirving-ch-lin 		bp_steps = ARRAY_SIZE(ufs0_bus_prot_set_table);
168*41004253Sirving-ch-lin 	} else {
169*41004253Sirving-ch-lin 		bp_table = &ufs0_bus_prot_clr_table[0];
170*41004253Sirving-ch-lin 		bp_steps = ARRAY_SIZE(ufs0_bus_prot_clr_table);
171*41004253Sirving-ch-lin 	}
172*41004253Sirving-ch-lin 
173*41004253Sirving-ch-lin 	return spm_mtcmos_ctrl(state, UFS0_PWR_CON, false, &rtff_save_flag,
174*41004253Sirving-ch-lin 			       bp_table, bp_steps);
175a881aebcSirving-ch-lin }
176a881aebcSirving-ch-lin 
spm_mtcmos_ctrl_ufs0_phy(enum mtcmos_state state)177a881aebcSirving-ch-lin int spm_mtcmos_ctrl_ufs0_phy(enum mtcmos_state state)
178a881aebcSirving-ch-lin {
179*41004253Sirving-ch-lin 	static int rtff_save_flag;
180*41004253Sirving-ch-lin 	const struct bus_protect *bp_table;
181*41004253Sirving-ch-lin 	uint32_t bp_steps;
182*41004253Sirving-ch-lin 
183*41004253Sirving-ch-lin 	if (state == STA_POWER_DOWN) {
184*41004253Sirving-ch-lin 		bp_table = &ufs0_phy_bus_prot_set_table[0];
185*41004253Sirving-ch-lin 		bp_steps = ARRAY_SIZE(ufs0_phy_bus_prot_set_table);
186*41004253Sirving-ch-lin 	} else {
187*41004253Sirving-ch-lin 		bp_table = &ufs0_phy_bus_prot_clr_table[0];
188*41004253Sirving-ch-lin 		bp_steps = ARRAY_SIZE(ufs0_phy_bus_prot_clr_table);
189*41004253Sirving-ch-lin 	}
190*41004253Sirving-ch-lin 
191*41004253Sirving-ch-lin 	return spm_mtcmos_ctrl(state, UFS0_PHY_PWR_CON, true, &rtff_save_flag,
192*41004253Sirving-ch-lin 			       bp_table, bp_steps);
193a881aebcSirving-ch-lin }
194