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
spm_semaphore_get(uint32_t base,uint32_t set_val)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
spm_semaphore_release(uint32_t base,uint32_t set_val)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
mminfra_hw_sema_ctrl(struct mminfra_hw_sema * hw_sema,bool is_get)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
is_mminfra_ready(struct mminfra_hw_voter * hw_voter)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
mminfra_hwv_power_ctrl(struct mminfra_hw_voter * hw_voter,bool is_on)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
mminfra_get_if_in_use(void)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
mminfra_put(void)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