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 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 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 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 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 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 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 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