xref: /rk3399_ARM-atf/plat/mediatek/drivers/mminfra/mt8196/mminfra.c (revision c33b98d7b84d58e9177da37614e22ff576496f08)
1*c33b98d7SYidi Lin /*
2*c33b98d7SYidi Lin  * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3*c33b98d7SYidi Lin  *
4*c33b98d7SYidi Lin  * SPDX-License-Identifier: BSD-3-Clause
5*c33b98d7SYidi Lin  */
6*c33b98d7SYidi Lin 
7*c33b98d7SYidi Lin #include <common/debug.h>
8*c33b98d7SYidi Lin #include <drivers/delay_timer.h>
9*c33b98d7SYidi Lin #include <lib/mmio.h>
10*c33b98d7SYidi Lin 
11*c33b98d7SYidi Lin #include <drivers/mminfra_public.h>
12*c33b98d7SYidi Lin #include <mminfra.h>
13*c33b98d7SYidi Lin #include <mtk_mmap_pool.h>
14*c33b98d7SYidi Lin 
15*c33b98d7SYidi Lin static const mmap_region_t mminfra_plat_mmap[] MTK_MMAP_SECTION = {
16*c33b98d7SYidi Lin 	MAP_REGION_FLAT(MMINFRA_HW_VOTER_BASE, PAGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
17*c33b98d7SYidi Lin 	{0}
18*c33b98d7SYidi Lin };
19*c33b98d7SYidi Lin DECLARE_MTK_MMAP_REGIONS(mminfra_plat_mmap);
20*c33b98d7SYidi Lin 
21*c33b98d7SYidi Lin static struct mtk_mminfra_pwr_ctrl mminfra_pwr_ctrl = {
22*c33b98d7SYidi Lin 	.hw_voter = {
23*c33b98d7SYidi Lin 		.base = MMINFRA_HW_VOTER_BASE,
24*c33b98d7SYidi Lin 		.set_ofs = 0x104,
25*c33b98d7SYidi Lin 		.clr_ofs = 0x108,
26*c33b98d7SYidi Lin 		.en_ofs = 0x100,
27*c33b98d7SYidi Lin 		.en_shift = 0x1,
28*c33b98d7SYidi Lin 		.done_bits = VLP_AO_RSVD6,
29*c33b98d7SYidi Lin 	},
30*c33b98d7SYidi Lin 	.hw_sema = {
31*c33b98d7SYidi Lin 		.base = SPM_BASE,
32*c33b98d7SYidi Lin 		.offset = SPM_SEMAPHORE_M1,
33*c33b98d7SYidi Lin 		.offset_all = {
34*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M0,
35*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M1,
36*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M2,
37*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M3,
38*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M4,
39*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M5,
40*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M6,
41*c33b98d7SYidi Lin 			SPM_SEMAPHORE_M7,
42*c33b98d7SYidi Lin 		},
43*c33b98d7SYidi Lin 		.set_val = SPM_SEMA_MMINFRA,
44*c33b98d7SYidi Lin 	},
45*c33b98d7SYidi Lin 	.active = true,
46*c33b98d7SYidi Lin 	.ref_cnt = 0,
47*c33b98d7SYidi Lin };
48*c33b98d7SYidi Lin 
49*c33b98d7SYidi Lin static int spm_semaphore_get(uint32_t base, uint32_t set_val)
50*c33b98d7SYidi Lin {
51*c33b98d7SYidi Lin 	int  cnt = SEMA_RETRY_CNT;
52*c33b98d7SYidi Lin 	uint32_t val;
53*c33b98d7SYidi Lin 
54*c33b98d7SYidi Lin 	val = mmio_read_32(base);
55*c33b98d7SYidi Lin 	if ((val & set_val) == set_val) {
56*c33b98d7SYidi Lin 		mminfra_err("hw_sem was already got, base:0x%x=0x%x, set_val:0x%x\n",
57*c33b98d7SYidi Lin 			    base, val, set_val);
58*c33b98d7SYidi Lin 		return -1;
59*c33b98d7SYidi Lin 	}
60*c33b98d7SYidi Lin 
61*c33b98d7SYidi Lin 	while (cnt > 0) {
62*c33b98d7SYidi Lin 		mmio_write_32(base, set_val);
63*c33b98d7SYidi Lin 		udelay(10);
64*c33b98d7SYidi Lin 		if ((mmio_read_32(base) & set_val) == set_val)
65*c33b98d7SYidi Lin 			return 0;
66*c33b98d7SYidi Lin 		cnt--;
67*c33b98d7SYidi Lin 	}
68*c33b98d7SYidi Lin 
69*c33b98d7SYidi Lin 	mminfra_err("timeout! base:0x%x, set_val:0x%x\n", base, set_val);
70*c33b98d7SYidi Lin 	return -1;
71*c33b98d7SYidi Lin }
72*c33b98d7SYidi Lin 
73*c33b98d7SYidi Lin static int spm_semaphore_release(uint32_t base, uint32_t set_val)
74*c33b98d7SYidi Lin {
75*c33b98d7SYidi Lin 	int cnt = SEMA_RETRY_CNT;
76*c33b98d7SYidi Lin 	uint32_t val;
77*c33b98d7SYidi Lin 
78*c33b98d7SYidi Lin 	val = mmio_read_32(base);
79*c33b98d7SYidi Lin 	if ((val & set_val) != set_val) {
80*c33b98d7SYidi Lin 		mminfra_err("hw_sem was already released, base:0x%x=0x%x, set_val:0x%x\n",
81*c33b98d7SYidi Lin 			    base, val, set_val);
82*c33b98d7SYidi Lin 		return -1;
83*c33b98d7SYidi Lin 	}
84*c33b98d7SYidi Lin 	do {
85*c33b98d7SYidi Lin 		mmio_write_32(base, set_val);
86*c33b98d7SYidi Lin 		udelay(10);
87*c33b98d7SYidi Lin 		if (cnt-- < 0) {
88*c33b98d7SYidi Lin 			if ((mmio_read_32(base) & set_val) != set_val)
89*c33b98d7SYidi Lin 				return 0;
90*c33b98d7SYidi Lin 			mminfra_err("timeout! base:0x%x, set_val:0x%x\n", base, set_val);
91*c33b98d7SYidi Lin 			return -1;
92*c33b98d7SYidi Lin 		}
93*c33b98d7SYidi Lin 	} while ((mmio_read_32(base) & set_val) == set_val);
94*c33b98d7SYidi Lin 
95*c33b98d7SYidi Lin 	return 0;
96*c33b98d7SYidi Lin }
97*c33b98d7SYidi Lin 
98*c33b98d7SYidi Lin static int mminfra_hw_sema_ctrl(struct mminfra_hw_sema *hw_sema, bool is_get)
99*c33b98d7SYidi Lin {
100*c33b98d7SYidi Lin 	int i, ret;
101*c33b98d7SYidi Lin 
102*c33b98d7SYidi Lin 	if (!hw_sema)
103*c33b98d7SYidi Lin 		return 0;
104*c33b98d7SYidi Lin 
105*c33b98d7SYidi Lin 	if (is_get)
106*c33b98d7SYidi Lin 		ret = spm_semaphore_get(hw_sema->base + hw_sema->offset, hw_sema->set_val);
107*c33b98d7SYidi Lin 	else
108*c33b98d7SYidi Lin 		ret = spm_semaphore_release(hw_sema->base + hw_sema->offset, hw_sema->set_val);
109*c33b98d7SYidi Lin 
110*c33b98d7SYidi Lin 	if (ret)
111*c33b98d7SYidi Lin 		for (i = 0; i < SPM_SEMA_MMINFRA_NR; i++)
112*c33b98d7SYidi Lin 			mminfra_err("0x%x=0x%x\n", hw_sema->base + hw_sema->offset_all[i],
113*c33b98d7SYidi Lin 				    mmio_read_32(hw_sema->base + hw_sema->offset_all[i]));
114*c33b98d7SYidi Lin 
115*c33b98d7SYidi Lin 	return ret;
116*c33b98d7SYidi Lin }
117*c33b98d7SYidi Lin 
118*c33b98d7SYidi Lin static bool is_mminfra_ready(struct mminfra_hw_voter *hw_voter)
119*c33b98d7SYidi Lin {
120*c33b98d7SYidi Lin 	if (!hw_voter)
121*c33b98d7SYidi Lin 		return false;
122*c33b98d7SYidi Lin 
123*c33b98d7SYidi Lin 	return !!(mmio_read_32(hw_voter->done_bits) & MMINFRA_DONE);
124*c33b98d7SYidi Lin }
125*c33b98d7SYidi Lin 
126*c33b98d7SYidi Lin static int mminfra_hwv_power_ctrl(struct mminfra_hw_voter *hw_voter, bool is_on)
127*c33b98d7SYidi Lin {
128*c33b98d7SYidi Lin 	uint32_t vote_ofs, vote_mask, vote_ack;
129*c33b98d7SYidi Lin 	uint32_t val = 0, cnt;
130*c33b98d7SYidi Lin 
131*c33b98d7SYidi Lin 	vote_mask = BIT(hw_voter->en_shift);
132*c33b98d7SYidi Lin 	vote_ofs = is_on ? hw_voter->set_ofs : hw_voter->clr_ofs;
133*c33b98d7SYidi Lin 	vote_ack = is_on ? vote_mask : 0x0;
134*c33b98d7SYidi Lin 
135*c33b98d7SYidi Lin 	/* Vote on off */
136*c33b98d7SYidi Lin 	cnt = 0;
137*c33b98d7SYidi Lin 	do {
138*c33b98d7SYidi Lin 		mmio_write_32(hw_voter->base + vote_ofs, vote_mask);
139*c33b98d7SYidi Lin 		udelay(MTK_POLL_HWV_VOTE_US);
140*c33b98d7SYidi Lin 		val = mmio_read_32(hw_voter->base + hw_voter->en_ofs);
141*c33b98d7SYidi Lin 		if ((val & vote_mask) == vote_ack)
142*c33b98d7SYidi Lin 			break;
143*c33b98d7SYidi Lin 
144*c33b98d7SYidi Lin 		if (cnt > MTK_POLL_HWV_VOTE_CNT) {
145*c33b98d7SYidi Lin 			mminfra_err("vote mminfra timeout, is_on:%d, 0x%x=0x%x\n",
146*c33b98d7SYidi Lin 				    is_on, hw_voter->base + hw_voter->en_ofs, val);
147*c33b98d7SYidi Lin 			return -1;
148*c33b98d7SYidi Lin 		}
149*c33b98d7SYidi Lin 		cnt++;
150*c33b98d7SYidi Lin 	} while (1);
151*c33b98d7SYidi Lin 
152*c33b98d7SYidi Lin 	if (!is_on)
153*c33b98d7SYidi Lin 		return 0;
154*c33b98d7SYidi Lin 
155*c33b98d7SYidi Lin 	/* Confirm done bits */
156*c33b98d7SYidi Lin 	cnt = 0;
157*c33b98d7SYidi Lin 	while (cnt < MTK_POLL_DONE_RETRY) {
158*c33b98d7SYidi Lin 		if (is_mminfra_ready(hw_voter))
159*c33b98d7SYidi Lin 			return 0;
160*c33b98d7SYidi Lin 		udelay(MTK_POLL_DONE_DELAY_US);
161*c33b98d7SYidi Lin 		cnt++;
162*c33b98d7SYidi Lin 	}
163*c33b98d7SYidi Lin 
164*c33b98d7SYidi Lin 	mminfra_err("polling mminfra done timeout, 0x%x=0x%x\n",
165*c33b98d7SYidi Lin 		    hw_voter->done_bits, val);
166*c33b98d7SYidi Lin 	return -1;
167*c33b98d7SYidi Lin }
168*c33b98d7SYidi Lin 
169*c33b98d7SYidi Lin int mminfra_get_if_in_use(void)
170*c33b98d7SYidi Lin {
171*c33b98d7SYidi Lin 	int ret, is_on = MMINFRA_RET_POWER_OFF;
172*c33b98d7SYidi Lin 
173*c33b98d7SYidi Lin 	if (!mminfra_pwr_ctrl.active) {
174*c33b98d7SYidi Lin 		mminfra_err("not ready\n");
175*c33b98d7SYidi Lin 		return MMINFRA_RET_POWER_OFF;
176*c33b98d7SYidi Lin 	}
177*c33b98d7SYidi Lin 
178*c33b98d7SYidi Lin 	spin_lock(&mminfra_pwr_ctrl.lock);
179*c33b98d7SYidi Lin 	if (mminfra_pwr_ctrl.ref_cnt > 0) {
180*c33b98d7SYidi Lin 		mminfra_pwr_ctrl.ref_cnt++;
181*c33b98d7SYidi Lin 		is_on = MMINFRA_RET_POWER_ON;
182*c33b98d7SYidi Lin 		spin_unlock(&mminfra_pwr_ctrl.lock);
183*c33b98d7SYidi Lin 		return is_on;
184*c33b98d7SYidi Lin 	}
185*c33b98d7SYidi Lin 
186*c33b98d7SYidi Lin 	ret = mminfra_hw_sema_ctrl(&mminfra_pwr_ctrl.hw_sema, true);
187*c33b98d7SYidi Lin 	if (ret)
188*c33b98d7SYidi Lin 		goto err;
189*c33b98d7SYidi Lin 
190*c33b98d7SYidi Lin 	/* Check if mminfra is in use */
191*c33b98d7SYidi Lin 	if (is_mminfra_ready(&mminfra_pwr_ctrl.hw_voter)) {
192*c33b98d7SYidi Lin 		ret = mminfra_hwv_power_ctrl(&mminfra_pwr_ctrl.hw_voter, true);
193*c33b98d7SYidi Lin 		if (ret) {
194*c33b98d7SYidi Lin 			mminfra_err("vote for mminfra fail, ret=%d\n", ret);
195*c33b98d7SYidi Lin 			goto err;
196*c33b98d7SYidi Lin 		}
197*c33b98d7SYidi Lin 		mminfra_pwr_ctrl.ref_cnt++;
198*c33b98d7SYidi Lin 		is_on = MMINFRA_RET_POWER_ON;
199*c33b98d7SYidi Lin 	} else {
200*c33b98d7SYidi Lin 		is_on = MMINFRA_RET_POWER_OFF;
201*c33b98d7SYidi Lin 	}
202*c33b98d7SYidi Lin 
203*c33b98d7SYidi Lin 	ret = mminfra_hw_sema_ctrl(&mminfra_pwr_ctrl.hw_sema, false);
204*c33b98d7SYidi Lin 	if (ret)
205*c33b98d7SYidi Lin 		goto err;
206*c33b98d7SYidi Lin 	ret = is_on; /* Return power is on or off. */
207*c33b98d7SYidi Lin err:
208*c33b98d7SYidi Lin 	spin_unlock(&mminfra_pwr_ctrl.lock);
209*c33b98d7SYidi Lin 	return ret;
210*c33b98d7SYidi Lin }
211*c33b98d7SYidi Lin 
212*c33b98d7SYidi Lin int mminfra_put(void)
213*c33b98d7SYidi Lin {
214*c33b98d7SYidi Lin 	if (!mminfra_pwr_ctrl.active) {
215*c33b98d7SYidi Lin 		mminfra_err("not ready\n");
216*c33b98d7SYidi Lin 		return 0;
217*c33b98d7SYidi Lin 	}
218*c33b98d7SYidi Lin 
219*c33b98d7SYidi Lin 	spin_lock(&mminfra_pwr_ctrl.lock);
220*c33b98d7SYidi Lin 	mminfra_pwr_ctrl.ref_cnt--;
221*c33b98d7SYidi Lin 	if (mminfra_pwr_ctrl.ref_cnt > 0)
222*c33b98d7SYidi Lin 		goto out;
223*c33b98d7SYidi Lin 
224*c33b98d7SYidi Lin 	mminfra_hwv_power_ctrl(&mminfra_pwr_ctrl.hw_voter, false);
225*c33b98d7SYidi Lin out:
226*c33b98d7SYidi Lin 	spin_unlock(&mminfra_pwr_ctrl.lock);
227*c33b98d7SYidi Lin 	return 0;
228*c33b98d7SYidi Lin }
229