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