blob: 7b83fed23c0995f80c27accd3472c97aea762c15 [file] [log] [blame]
developer91bb08d2022-09-07 18:41:59 +08001/*
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
14struct 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
24static struct mt_lp_res_req_m plat_mt_rqm;
25static spinlock_t mt_lp_rq_lock;
26
27static 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
52static 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
74int 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
96int 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
134int 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
182int 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}