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