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