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