xref: /rk3399_ARM-atf/plat/mediatek/common/lpm_v2/mt_lp_rq.c (revision cf2df874cd09305ac7282fadb0fef6be597dfffb)
1 /*
2  * Copyright (c) 2025, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdint.h>
8 #include <string.h>
9 
10 #include <common/debug.h>
11 #include <drivers/console.h>
12 #include <lib/spinlock.h>
13 
14 #include <lpm_v2/mt_lp_rm.h>
15 #include <lpm_v2/mt_lp_rqm.h>
16 
17 struct _mt_lp_res_req_m_ {
18 	unsigned int uname[MT_LP_RQ_USER_MAX];
19 	unsigned int user_num;
20 	unsigned int user_valid;
21 	unsigned int resource_num;
22 	unsigned int generic_resource_req;
23 	unsigned int flag;
24 	struct mt_resource_req_manager *plat_rqm;
25 };
26 
27 static struct _mt_lp_res_req_m_ plat_mt_rqm;
28 static spinlock_t mt_lp_rq_lock;
29 
30 static int mt_lp_resource_update_and_set(struct mt_lp_resource_user *this);
31 
mt_lp_resource_request(struct mt_lp_resource_user * this,unsigned int resource)32 static int mt_lp_resource_request(struct mt_lp_resource_user *this,
33 				  unsigned int resource)
34 {
35 	int i;
36 	struct mt_lp_res_req *const *rs;
37 	int ret;
38 
39 	if ((this == NULL) || (resource == 0) || (resource > MT_LP_RQ_ALL)) {
40 		ERROR("invalid request(%x)\n", resource);
41 		return MT_LP_RQ_STA_BAD;
42 	}
43 
44 	spin_lock(&mt_lp_rq_lock);
45 
46 	rs = (plat_mt_rqm.plat_rqm)->res;
47 	for (i = 0; i < plat_mt_rqm.resource_num; i++) {
48 		if ((resource & rs[i]->res_id) != 0)
49 			rs[i]->res_usage |= this->umask;
50 	}
51 
52 	plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE;
53 	spin_unlock(&mt_lp_rq_lock);
54 
55 	ret = mt_lp_resource_update_and_set(this);
56 
57 	return ret;
58 }
59 
mt_lp_resource_release(struct mt_lp_resource_user * this)60 static int mt_lp_resource_release(struct mt_lp_resource_user *this)
61 {
62 	int i;
63 	struct mt_lp_res_req *const *rs;
64 	int ret;
65 
66 	if (this == NULL)
67 		return MT_LP_RQ_STA_BAD;
68 
69 	spin_lock(&mt_lp_rq_lock);
70 
71 	rs = (plat_mt_rqm.plat_rqm)->res;
72 	for (i = 0; i < plat_mt_rqm.resource_num; i++)
73 		rs[i]->res_usage &= ~(this->umask);
74 
75 	plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE;
76 	spin_unlock(&mt_lp_rq_lock);
77 
78 	ret = mt_lp_resource_update_and_set(this);
79 
80 	return ret;
81 }
82 
mt_lp_resource_request_manager_register(struct mt_resource_req_manager * rm)83 int mt_lp_resource_request_manager_register(struct mt_resource_req_manager *rm)
84 {
85 	unsigned int count;
86 	struct mt_lp_res_req *const *rs;
87 
88 	if (!rm || !(rm->res) || (plat_mt_rqm.plat_rqm != NULL))
89 		return MT_LP_RQ_STA_BAD;
90 
91 	rs = rm->res;
92 	count = 0;
93 	while (*rs != NULL) {
94 		count++;
95 		rs++;
96 	}
97 
98 	plat_mt_rqm.plat_rqm = rm;
99 	plat_mt_rqm.resource_num = count;
100 
101 	return MT_LP_RQ_STA_OK;
102 }
103 
104 
mt_lp_resource_user_register(char * user,struct mt_lp_resource_user * ru)105 int mt_lp_resource_user_register(char *user, struct mt_lp_resource_user *ru)
106 {
107 	int i, len;
108 	unsigned int uname;
109 
110 	if ((plat_mt_rqm.plat_rqm == NULL) || (user == NULL))
111 		goto invalid;
112 
113 	len = strnlen(user, MT_LP_RQ_USER_NAME_LEN);
114 
115 	uname = 0;
116 	for (i = 0; i < len; i++)
117 		uname |= (user[i] << (MT_LP_RQ_USER_CHAR_U * i));
118 
119 	spin_lock(&mt_lp_rq_lock);
120 
121 	if (plat_mt_rqm.user_num >= MT_LP_RQ_USER_MAX) {
122 		spin_unlock(&mt_lp_rq_lock);
123 		goto invalid;
124 	}
125 
126 	i = plat_mt_rqm.user_num;
127 	plat_mt_rqm.user_num += 1;
128 	plat_mt_rqm.uname[i] = uname;
129 	plat_mt_rqm.user_valid |= BIT(i);
130 	spin_unlock(&mt_lp_rq_lock);
131 
132 	ru->umask = BIT(i);
133 	ru->uid = i;
134 	ru->request = mt_lp_resource_request;
135 	ru->release = mt_lp_resource_release;
136 	INFO("%s register by %s, uid = %d\n", __func__, user, ru->uid);
137 
138 	return MT_LP_RQ_STA_OK;
139 
140 invalid:
141 	ru->uid = MT_LP_RQ_USER_INVALID;
142 	ru->umask = 0;
143 	ru->request = NULL;
144 	ru->release = NULL;
145 	return MT_LP_RQ_STA_BAD;
146 }
147 
mt_lp_rq_get_status(int type,void * p)148 int mt_lp_rq_get_status(int type, void *p)
149 {
150 	int i;
151 	unsigned int update_sta = 0;
152 	struct mt_lp_res_req *const *rs;
153 	struct resource_req_status *rq_sta = (struct resource_req_status *)p;
154 
155 	spin_lock(&mt_lp_rq_lock);
156 
157 	if (plat_mt_rqm.flag) {
158 		rs = (plat_mt_rqm.plat_rqm)->res;
159 		for (i = 0; i < plat_mt_rqm.resource_num; i++) {
160 			if ((rs[i]->res_usage & plat_mt_rqm.user_valid) != 0)
161 				update_sta |= rs[i]->res_rq;
162 		}
163 
164 		plat_mt_rqm.generic_resource_req = update_sta;
165 		plat_mt_rqm.flag = MT_LP_RQ_FLAG_DONE;
166 	}
167 
168 	switch (type) {
169 	case PLAT_RQ_REQ_USAGE:
170 		rs = (plat_mt_rqm.plat_rqm)->res;
171 		rq_sta->val = plat_mt_rqm.generic_resource_req;
172 		if (rq_sta->id < plat_mt_rqm.resource_num)
173 			rq_sta->val = rs[rq_sta->id]->res_usage;
174 		break;
175 	case PLAT_RQ_USER_NUM:
176 		rq_sta->val = plat_mt_rqm.user_num;
177 		break;
178 	case PLAT_RQ_USER_VALID:
179 		rq_sta->val = plat_mt_rqm.user_valid;
180 		break;
181 	case PLAT_RQ_PER_USER_NAME:
182 		rq_sta->val = (rq_sta->id < plat_mt_rqm.user_num) ?
183 			      plat_mt_rqm.uname[rq_sta->id] : 0;
184 		break;
185 	case PLAT_RQ_REQ_NUM:
186 		rq_sta->val = plat_mt_rqm.resource_num;
187 		break;
188 	default:
189 		break;
190 	}
191 
192 	spin_unlock(&mt_lp_rq_lock);
193 
194 	return MT_LP_RQ_STA_OK;
195 }
196 
mt_lp_rq_update_status(int type,void * p)197 int mt_lp_rq_update_status(int type, void *p)
198 {
199 	unsigned int user;
200 	struct resource_req_status *rq_sta = (struct resource_req_status *)p;
201 
202 	spin_lock(&mt_lp_rq_lock);
203 
204 	switch (type) {
205 	case PLAT_RQ_USER_VALID:
206 		if (rq_sta->id >= plat_mt_rqm.user_num)
207 			break;
208 		user = BIT(rq_sta->id);
209 		plat_mt_rqm.user_valid = (rq_sta->val == 0) ?
210 					 (plat_mt_rqm.user_valid & ~(user)) :
211 					 (plat_mt_rqm.user_valid | user);
212 		plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE;
213 		break;
214 	default:
215 		break;
216 	}
217 
218 	spin_unlock(&mt_lp_rq_lock);
219 
220 	return MT_LP_RQ_STA_OK;
221 }
222 
mt_lp_resource_update_and_set(struct mt_lp_resource_user * this)223 static int mt_lp_resource_update_and_set(struct mt_lp_resource_user *this)
224 {
225 	unsigned int ret = MT_LP_RQ_STA_OK;
226 	struct resource_req_status generic_spm_resource_req = {
227 		.id = MT_LP_RQ_ID_ALL_USAGE,
228 		.val = 0,
229 	};
230 
231 	mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE, &generic_spm_resource_req);
232 	ret = mt_lp_rm_do_hwctrl(PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE, 1,
233 				 &generic_spm_resource_req.val);
234 
235 	if (ret)
236 		ret = MT_LP_RQ_STA_BAD;
237 
238 	return ret;
239 }
240