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