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