1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2021, Linaro Limited 2 // Copyright (c) 2021, Linaro Limited 3 3 4 #include <linux/slab.h> 4 #include <linux/slab.h> 5 #include <linux/wait.h> 5 #include <linux/wait.h> 6 #include <linux/kernel.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> 7 #include <linux/module.h> 8 #include <linux/of.h> 8 #include <linux/of.h> 9 #include <linux/delay.h> 9 #include <linux/delay.h> 10 #include <linux/of_platform.h> 10 #include <linux/of_platform.h> 11 #include <linux/jiffies.h> 11 #include <linux/jiffies.h> 12 #include <linux/soc/qcom/apr.h> 12 #include <linux/soc/qcom/apr.h> 13 #include <dt-bindings/soc/qcom,gpr.h> 13 #include <dt-bindings/soc/qcom,gpr.h> 14 #include <dt-bindings/sound/qcom,q6dsp-lpass-p 14 #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> 15 #include "q6apm.h" << 16 #include "q6prm.h" 15 #include "q6prm.h" 17 #include "audioreach.h" 16 #include "audioreach.h" 18 17 19 struct q6prm { 18 struct q6prm { 20 struct device *dev; 19 struct device *dev; 21 gpr_device_t *gdev; 20 gpr_device_t *gdev; 22 wait_queue_head_t wait; 21 wait_queue_head_t wait; 23 struct gpr_ibasic_rsp_result_t result; 22 struct gpr_ibasic_rsp_result_t result; 24 struct mutex lock; 23 struct mutex lock; 25 }; 24 }; 26 25 27 #define PRM_CMD_REQUEST_HW_RSC 0x0100 26 #define PRM_CMD_REQUEST_HW_RSC 0x0100100F 28 #define PRM_CMD_RSP_REQUEST_HW_RSC 0x0200 27 #define PRM_CMD_RSP_REQUEST_HW_RSC 0x02001002 29 #define PRM_CMD_RELEASE_HW_RSC 0x0100 28 #define PRM_CMD_RELEASE_HW_RSC 0x01001010 30 #define PRM_CMD_RSP_RELEASE_HW_RSC 0x0200 29 #define PRM_CMD_RSP_RELEASE_HW_RSC 0x02001003 31 #define PARAM_ID_RSC_HW_CORE 0x0800 30 #define PARAM_ID_RSC_HW_CORE 0x08001032 32 #define PARAM_ID_RSC_LPASS_CORE 0x0800 31 #define PARAM_ID_RSC_LPASS_CORE 0x0800102B 33 #define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800 32 #define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C 34 33 35 struct prm_cmd_request_hw_core { 34 struct prm_cmd_request_hw_core { 36 struct apm_module_param_data param_dat 35 struct apm_module_param_data param_data; 37 uint32_t hw_clk_id; 36 uint32_t hw_clk_id; 38 } __packed; 37 } __packed; 39 38 40 struct prm_cmd_request_rsc { 39 struct prm_cmd_request_rsc { 41 struct apm_module_param_data param_dat 40 struct apm_module_param_data param_data; 42 uint32_t num_clk_id; 41 uint32_t num_clk_id; 43 struct audio_hw_clk_cfg clock_id; 42 struct audio_hw_clk_cfg clock_id; 44 } __packed; 43 } __packed; 45 44 46 struct prm_cmd_release_rsc { 45 struct prm_cmd_release_rsc { 47 struct apm_module_param_data param_dat 46 struct apm_module_param_data param_data; 48 uint32_t num_clk_id; 47 uint32_t num_clk_id; 49 struct audio_hw_clk_rel_cfg clock_id; 48 struct audio_hw_clk_rel_cfg clock_id; 50 } __packed; 49 } __packed; 51 50 52 static int q6prm_send_cmd_sync(struct q6prm *p 51 static int q6prm_send_cmd_sync(struct q6prm *prm, struct gpr_pkt *pkt, uint32_t rsp_opcode) 53 { 52 { 54 return audioreach_send_cmd_sync(prm->d 53 return audioreach_send_cmd_sync(prm->dev, prm->gdev, &prm->result, &prm->lock, 55 NULL, 54 NULL, &prm->wait, pkt, rsp_opcode); 56 } 55 } 57 56 58 static int q6prm_set_hw_core_req(struct device 57 static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool enable) 59 { 58 { 60 struct q6prm *prm = dev_get_drvdata(de 59 struct q6prm *prm = dev_get_drvdata(dev->parent); 61 struct apm_module_param_data *param_da 60 struct apm_module_param_data *param_data; 62 struct prm_cmd_request_hw_core *req; 61 struct prm_cmd_request_hw_core *req; 63 gpr_device_t *gdev = prm->gdev; 62 gpr_device_t *gdev = prm->gdev; 64 uint32_t opcode, rsp_opcode; 63 uint32_t opcode, rsp_opcode; 65 struct gpr_pkt *pkt; 64 struct gpr_pkt *pkt; 66 int rc; 65 int rc; 67 66 68 if (enable) { 67 if (enable) { 69 opcode = PRM_CMD_REQUEST_HW_RS 68 opcode = PRM_CMD_REQUEST_HW_RSC; 70 rsp_opcode = PRM_CMD_RSP_REQUE 69 rsp_opcode = PRM_CMD_RSP_REQUEST_HW_RSC; 71 } else { 70 } else { 72 opcode = PRM_CMD_RELEASE_HW_RS 71 opcode = PRM_CMD_RELEASE_HW_RSC; 73 rsp_opcode = PRM_CMD_RSP_RELEA 72 rsp_opcode = PRM_CMD_RSP_RELEASE_HW_RSC; 74 } 73 } 75 74 76 pkt = audioreach_alloc_cmd_pkt(sizeof( 75 pkt = audioreach_alloc_cmd_pkt(sizeof(*req), opcode, 0, gdev->svc.id, GPR_PRM_MODULE_IID); 77 if (IS_ERR(pkt)) 76 if (IS_ERR(pkt)) 78 return PTR_ERR(pkt); 77 return PTR_ERR(pkt); 79 78 80 req = (void *)pkt + GPR_HDR_SIZE + APM 79 req = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 81 80 82 param_data = &req->param_data; 81 param_data = &req->param_data; 83 82 84 param_data->module_instance_id = GPR_P 83 param_data->module_instance_id = GPR_PRM_MODULE_IID; 85 param_data->error_code = 0; 84 param_data->error_code = 0; 86 param_data->param_id = PARAM_ID_RSC_HW 85 param_data->param_id = PARAM_ID_RSC_HW_CORE; 87 param_data->param_size = sizeof(*req) 86 param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE; 88 87 89 req->hw_clk_id = hw_block_id; 88 req->hw_clk_id = hw_block_id; 90 89 91 rc = q6prm_send_cmd_sync(prm, pkt, rsp 90 rc = q6prm_send_cmd_sync(prm, pkt, rsp_opcode); 92 91 93 kfree(pkt); 92 kfree(pkt); 94 93 95 return rc; 94 return rc; 96 } 95 } 97 96 98 int q6prm_vote_lpass_core_hw(struct device *de 97 int q6prm_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, 99 const char *clien 98 const char *client_name, uint32_t *client_handle) 100 { 99 { 101 return q6prm_set_hw_core_req(dev, hw_b 100 return q6prm_set_hw_core_req(dev, hw_block_id, true); 102 101 103 } 102 } 104 EXPORT_SYMBOL_GPL(q6prm_vote_lpass_core_hw); 103 EXPORT_SYMBOL_GPL(q6prm_vote_lpass_core_hw); 105 104 106 int q6prm_unvote_lpass_core_hw(struct device * 105 int q6prm_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, uint32_t client_handle) 107 { 106 { 108 return q6prm_set_hw_core_req(dev, hw_b 107 return q6prm_set_hw_core_req(dev, hw_block_id, false); 109 } 108 } 110 EXPORT_SYMBOL_GPL(q6prm_unvote_lpass_core_hw); 109 EXPORT_SYMBOL_GPL(q6prm_unvote_lpass_core_hw); 111 110 112 static int q6prm_request_lpass_clock(struct de 111 static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root, 113 unsigned 112 unsigned int freq) 114 { 113 { 115 struct q6prm *prm = dev_get_drvdata(de 114 struct q6prm *prm = dev_get_drvdata(dev->parent); 116 struct apm_module_param_data *param_da 115 struct apm_module_param_data *param_data; 117 struct prm_cmd_request_rsc *req; 116 struct prm_cmd_request_rsc *req; 118 gpr_device_t *gdev = prm->gdev; 117 gpr_device_t *gdev = prm->gdev; 119 struct gpr_pkt *pkt; 118 struct gpr_pkt *pkt; 120 int rc; 119 int rc; 121 120 122 pkt = audioreach_alloc_cmd_pkt(sizeof( 121 pkt = audioreach_alloc_cmd_pkt(sizeof(*req), PRM_CMD_REQUEST_HW_RSC, 0, gdev->svc.id, 123 GPR_PRM 122 GPR_PRM_MODULE_IID); 124 if (IS_ERR(pkt)) 123 if (IS_ERR(pkt)) 125 return PTR_ERR(pkt); 124 return PTR_ERR(pkt); 126 125 127 req = (void *)pkt + GPR_HDR_SIZE + APM 126 req = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 128 127 129 param_data = &req->param_data; 128 param_data = &req->param_data; 130 129 131 param_data->module_instance_id = GPR_P 130 param_data->module_instance_id = GPR_PRM_MODULE_IID; 132 param_data->error_code = 0; 131 param_data->error_code = 0; 133 param_data->param_id = PARAM_ID_RSC_AU 132 param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK; 134 param_data->param_size = sizeof(*req) 133 param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE; 135 134 136 req->num_clk_id = 1; 135 req->num_clk_id = 1; 137 req->clock_id.clock_id = clk_id; 136 req->clock_id.clock_id = clk_id; 138 req->clock_id.clock_freq = freq; 137 req->clock_id.clock_freq = freq; 139 req->clock_id.clock_attri = clk_attr; 138 req->clock_id.clock_attri = clk_attr; 140 req->clock_id.clock_root = clk_root; 139 req->clock_id.clock_root = clk_root; 141 140 142 rc = q6prm_send_cmd_sync(prm, pkt, PRM 141 rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_REQUEST_HW_RSC); 143 142 144 kfree(pkt); 143 kfree(pkt); 145 144 146 return rc; 145 return rc; 147 } 146 } 148 147 149 static int q6prm_release_lpass_clock(struct de 148 static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root, 150 unsigned int freq) 149 unsigned int freq) 151 { 150 { 152 struct q6prm *prm = dev_get_drvdata(de 151 struct q6prm *prm = dev_get_drvdata(dev->parent); 153 struct apm_module_param_data *param_da 152 struct apm_module_param_data *param_data; 154 struct prm_cmd_release_rsc *rel; 153 struct prm_cmd_release_rsc *rel; 155 gpr_device_t *gdev = prm->gdev; 154 gpr_device_t *gdev = prm->gdev; 156 struct gpr_pkt *pkt; 155 struct gpr_pkt *pkt; 157 int rc; 156 int rc; 158 157 159 pkt = audioreach_alloc_cmd_pkt(sizeof( 158 pkt = audioreach_alloc_cmd_pkt(sizeof(*rel), PRM_CMD_RELEASE_HW_RSC, 0, gdev->svc.id, 160 GPR_PRM 159 GPR_PRM_MODULE_IID); 161 if (IS_ERR(pkt)) 160 if (IS_ERR(pkt)) 162 return PTR_ERR(pkt); 161 return PTR_ERR(pkt); 163 162 164 rel = (void *)pkt + GPR_HDR_SIZE + APM 163 rel = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 165 164 166 param_data = &rel->param_data; 165 param_data = &rel->param_data; 167 166 168 param_data->module_instance_id = GPR_P 167 param_data->module_instance_id = GPR_PRM_MODULE_IID; 169 param_data->error_code = 0; 168 param_data->error_code = 0; 170 param_data->param_id = PARAM_ID_RSC_AU 169 param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK; 171 param_data->param_size = sizeof(*rel) 170 param_data->param_size = sizeof(*rel) - APM_MODULE_PARAM_DATA_SIZE; 172 171 173 rel->num_clk_id = 1; 172 rel->num_clk_id = 1; 174 rel->clock_id.clock_id = clk_id; 173 rel->clock_id.clock_id = clk_id; 175 174 176 rc = q6prm_send_cmd_sync(prm, pkt, PRM 175 rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_RELEASE_HW_RSC); 177 176 178 kfree(pkt); 177 kfree(pkt); 179 178 180 return rc; 179 return rc; 181 } 180 } 182 181 183 int q6prm_set_lpass_clock(struct device *dev, 182 int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root, 184 unsigned int freq) 183 unsigned int freq) 185 { 184 { 186 if (freq) 185 if (freq) 187 return q6prm_request_lpass_clo !! 186 return q6prm_request_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq); 188 187 189 return q6prm_release_lpass_clock(dev, !! 188 return q6prm_release_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq); 190 } 189 } 191 EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock); 190 EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock); 192 191 193 static int prm_callback(struct gpr_resp_pkt *d 192 static int prm_callback(struct gpr_resp_pkt *data, void *priv, int op) 194 { 193 { 195 gpr_device_t *gdev = priv; 194 gpr_device_t *gdev = priv; 196 struct q6prm *prm = dev_get_drvdata(&g 195 struct q6prm *prm = dev_get_drvdata(&gdev->dev); 197 struct gpr_ibasic_rsp_result_t *result 196 struct gpr_ibasic_rsp_result_t *result; 198 struct gpr_hdr *hdr = &data->hdr; 197 struct gpr_hdr *hdr = &data->hdr; 199 198 200 switch (hdr->opcode) { 199 switch (hdr->opcode) { 201 case PRM_CMD_RSP_REQUEST_HW_RSC: 200 case PRM_CMD_RSP_REQUEST_HW_RSC: 202 case PRM_CMD_RSP_RELEASE_HW_RSC: 201 case PRM_CMD_RSP_RELEASE_HW_RSC: 203 result = data->payload; 202 result = data->payload; 204 prm->result.opcode = hdr->opco 203 prm->result.opcode = hdr->opcode; 205 prm->result.status = result->s 204 prm->result.status = result->status; 206 wake_up(&prm->wait); 205 wake_up(&prm->wait); 207 break; 206 break; 208 default: 207 default: 209 break; 208 break; 210 } 209 } 211 210 212 return 0; 211 return 0; 213 } 212 } 214 213 215 static int prm_probe(gpr_device_t *gdev) 214 static int prm_probe(gpr_device_t *gdev) 216 { 215 { 217 struct device *dev = &gdev->dev; 216 struct device *dev = &gdev->dev; 218 struct q6prm *cc; 217 struct q6prm *cc; 219 218 220 cc = devm_kzalloc(dev, sizeof(*cc), GF 219 cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); 221 if (!cc) 220 if (!cc) 222 return -ENOMEM; 221 return -ENOMEM; 223 222 224 cc->dev = dev; 223 cc->dev = dev; 225 cc->gdev = gdev; 224 cc->gdev = gdev; 226 mutex_init(&cc->lock); 225 mutex_init(&cc->lock); 227 init_waitqueue_head(&cc->wait); 226 init_waitqueue_head(&cc->wait); 228 dev_set_drvdata(dev, cc); 227 dev_set_drvdata(dev, cc); 229 228 230 if (!q6apm_is_adsp_ready()) << 231 return -EPROBE_DEFER; << 232 << 233 return devm_of_platform_populate(dev); 229 return devm_of_platform_populate(dev); 234 } 230 } 235 231 236 #ifdef CONFIG_OF 232 #ifdef CONFIG_OF 237 static const struct of_device_id prm_device_id 233 static const struct of_device_id prm_device_id[] = { 238 { .compatible = "qcom,q6prm" }, 234 { .compatible = "qcom,q6prm" }, 239 {}, 235 {}, 240 }; 236 }; 241 MODULE_DEVICE_TABLE(of, prm_device_id); 237 MODULE_DEVICE_TABLE(of, prm_device_id); 242 #endif 238 #endif 243 239 244 static gpr_driver_t prm_driver = { 240 static gpr_driver_t prm_driver = { 245 .probe = prm_probe, 241 .probe = prm_probe, 246 .gpr_callback = prm_callback, 242 .gpr_callback = prm_callback, 247 .driver = { 243 .driver = { 248 .name = "qcom-prm", 244 .name = "qcom-prm", 249 .of_match_table = of_match_ptr 245 .of_match_table = of_match_ptr(prm_device_id), 250 }, 246 }, 251 }; 247 }; 252 248 253 module_gpr_driver(prm_driver); 249 module_gpr_driver(prm_driver); 254 MODULE_DESCRIPTION("Q6 Proxy Resource Manager" !! 250 MODULE_DESCRIPTION("Audio Process Manager"); 255 MODULE_LICENSE("GPL"); 251 MODULE_LICENSE("GPL"); 256 252
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.