Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2021, Linaro Limited
0003 
0004 #include <linux/slab.h>
0005 #include <linux/wait.h>
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/of.h>
0009 #include <linux/delay.h>
0010 #include <linux/of_platform.h>
0011 #include <linux/jiffies.h>
0012 #include <linux/soc/qcom/apr.h>
0013 #include <dt-bindings/soc/qcom,gpr.h>
0014 #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
0015 #include "q6prm.h"
0016 #include "audioreach.h"
0017 
0018 struct q6prm {
0019     struct device *dev;
0020     gpr_device_t *gdev;
0021     wait_queue_head_t wait;
0022     struct gpr_ibasic_rsp_result_t result;
0023     struct mutex lock;
0024 };
0025 
0026 #define PRM_CMD_REQUEST_HW_RSC      0x0100100F
0027 #define PRM_CMD_RSP_REQUEST_HW_RSC  0x02001002
0028 #define PRM_CMD_RELEASE_HW_RSC      0x01001010
0029 #define PRM_CMD_RSP_RELEASE_HW_RSC  0x02001003
0030 #define PARAM_ID_RSC_HW_CORE        0x08001032
0031 #define PARAM_ID_RSC_LPASS_CORE     0x0800102B
0032 #define PARAM_ID_RSC_AUDIO_HW_CLK   0x0800102C
0033 
0034 struct prm_cmd_request_hw_core {
0035     struct apm_module_param_data param_data;
0036     uint32_t hw_clk_id;
0037 } __packed;
0038 
0039 struct prm_cmd_request_rsc {
0040     struct apm_module_param_data param_data;
0041     uint32_t num_clk_id;
0042     struct audio_hw_clk_cfg clock_id;
0043 } __packed;
0044 
0045 struct prm_cmd_release_rsc {
0046     struct apm_module_param_data param_data;
0047     uint32_t num_clk_id;
0048     struct audio_hw_clk_rel_cfg clock_id;
0049 } __packed;
0050 
0051 static int q6prm_send_cmd_sync(struct q6prm *prm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
0052 {
0053     return audioreach_send_cmd_sync(prm->dev, prm->gdev, &prm->result, &prm->lock,
0054                     NULL, &prm->wait, pkt, rsp_opcode);
0055 }
0056 
0057 static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool enable)
0058 {
0059     struct q6prm *prm = dev_get_drvdata(dev->parent);
0060     struct apm_module_param_data *param_data;
0061     struct prm_cmd_request_hw_core *req;
0062     gpr_device_t *gdev = prm->gdev;
0063     uint32_t opcode, rsp_opcode;
0064     struct gpr_pkt *pkt;
0065     int rc;
0066 
0067     if (enable) {
0068         opcode = PRM_CMD_REQUEST_HW_RSC;
0069         rsp_opcode = PRM_CMD_RSP_REQUEST_HW_RSC;
0070     } else {
0071         opcode = PRM_CMD_RELEASE_HW_RSC;
0072         rsp_opcode = PRM_CMD_RSP_RELEASE_HW_RSC;
0073     }
0074 
0075     pkt = audioreach_alloc_cmd_pkt(sizeof(*req), opcode, 0, gdev->svc.id, GPR_PRM_MODULE_IID);
0076     if (IS_ERR(pkt))
0077         return PTR_ERR(pkt);
0078 
0079     req = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0080 
0081     param_data = &req->param_data;
0082 
0083     param_data->module_instance_id = GPR_PRM_MODULE_IID;
0084     param_data->error_code = 0;
0085     param_data->param_id = PARAM_ID_RSC_HW_CORE;
0086     param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE;
0087 
0088     req->hw_clk_id = hw_block_id;
0089 
0090     rc = q6prm_send_cmd_sync(prm, pkt, rsp_opcode);
0091 
0092     kfree(pkt);
0093 
0094     return rc;
0095 }
0096 
0097 int q6prm_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
0098                  const char *client_name, uint32_t *client_handle)
0099 {
0100     return q6prm_set_hw_core_req(dev, hw_block_id, true);
0101 
0102 }
0103 EXPORT_SYMBOL_GPL(q6prm_vote_lpass_core_hw);
0104 
0105 int q6prm_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, uint32_t client_handle)
0106 {
0107     return q6prm_set_hw_core_req(dev, hw_block_id, false);
0108 }
0109 EXPORT_SYMBOL_GPL(q6prm_unvote_lpass_core_hw);
0110 
0111 static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
0112                      unsigned int freq)
0113 {
0114     struct q6prm *prm = dev_get_drvdata(dev->parent);
0115     struct apm_module_param_data *param_data;
0116     struct prm_cmd_request_rsc *req;
0117     gpr_device_t *gdev = prm->gdev;
0118     struct gpr_pkt *pkt;
0119     int rc;
0120 
0121     pkt = audioreach_alloc_cmd_pkt(sizeof(*req), PRM_CMD_REQUEST_HW_RSC, 0, gdev->svc.id,
0122                        GPR_PRM_MODULE_IID);
0123     if (IS_ERR(pkt))
0124         return PTR_ERR(pkt);
0125 
0126     req = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0127 
0128     param_data = &req->param_data;
0129 
0130     param_data->module_instance_id = GPR_PRM_MODULE_IID;
0131     param_data->error_code = 0;
0132     param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK;
0133     param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE;
0134 
0135     req->num_clk_id = 1;
0136     req->clock_id.clock_id = clk_id;
0137     req->clock_id.clock_freq = freq;
0138     req->clock_id.clock_attri = clk_attr;
0139     req->clock_id.clock_root = clk_root;
0140 
0141     rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_REQUEST_HW_RSC);
0142 
0143     kfree(pkt);
0144 
0145     return rc;
0146 }
0147 
0148 static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
0149               unsigned int freq)
0150 {
0151     struct q6prm *prm = dev_get_drvdata(dev->parent);
0152     struct apm_module_param_data *param_data;
0153     struct prm_cmd_release_rsc *rel;
0154     gpr_device_t *gdev = prm->gdev;
0155     struct gpr_pkt *pkt;
0156     int rc;
0157 
0158     pkt = audioreach_alloc_cmd_pkt(sizeof(*rel), PRM_CMD_RELEASE_HW_RSC, 0, gdev->svc.id,
0159                        GPR_PRM_MODULE_IID);
0160     if (IS_ERR(pkt))
0161         return PTR_ERR(pkt);
0162 
0163     rel = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0164 
0165     param_data = &rel->param_data;
0166 
0167     param_data->module_instance_id = GPR_PRM_MODULE_IID;
0168     param_data->error_code = 0;
0169     param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK;
0170     param_data->param_size = sizeof(*rel) - APM_MODULE_PARAM_DATA_SIZE;
0171 
0172     rel->num_clk_id = 1;
0173     rel->clock_id.clock_id = clk_id;
0174 
0175     rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_RELEASE_HW_RSC);
0176 
0177     kfree(pkt);
0178 
0179     return rc;
0180 }
0181 
0182 int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
0183               unsigned int freq)
0184 {
0185     if (freq)
0186         return q6prm_request_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq);
0187 
0188     return q6prm_release_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq);
0189 }
0190 EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock);
0191 
0192 static int prm_callback(struct gpr_resp_pkt *data, void *priv, int op)
0193 {
0194     gpr_device_t *gdev = priv;
0195     struct q6prm *prm = dev_get_drvdata(&gdev->dev);
0196     struct gpr_ibasic_rsp_result_t *result;
0197     struct gpr_hdr *hdr = &data->hdr;
0198 
0199     switch (hdr->opcode) {
0200     case PRM_CMD_RSP_REQUEST_HW_RSC:
0201     case PRM_CMD_RSP_RELEASE_HW_RSC:
0202         result = data->payload;
0203         prm->result.opcode = hdr->opcode;
0204         prm->result.status = result->status;
0205         wake_up(&prm->wait);
0206         break;
0207     default:
0208         break;
0209     }
0210 
0211     return 0;
0212 }
0213 
0214 static int prm_probe(gpr_device_t *gdev)
0215 {
0216     struct device *dev = &gdev->dev;
0217     struct q6prm *cc;
0218 
0219     cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
0220     if (!cc)
0221         return -ENOMEM;
0222 
0223     cc->dev = dev;
0224     cc->gdev = gdev;
0225     mutex_init(&cc->lock);
0226     init_waitqueue_head(&cc->wait);
0227     dev_set_drvdata(dev, cc);
0228 
0229     return devm_of_platform_populate(dev);
0230 }
0231 
0232 #ifdef CONFIG_OF
0233 static const struct of_device_id prm_device_id[]  = {
0234     { .compatible = "qcom,q6prm" },
0235     {},
0236 };
0237 MODULE_DEVICE_TABLE(of, prm_device_id);
0238 #endif
0239 
0240 static gpr_driver_t prm_driver = {
0241     .probe = prm_probe,
0242     .gpr_callback = prm_callback,
0243     .driver = {
0244         .name = "qcom-prm",
0245         .of_match_table = of_match_ptr(prm_device_id),
0246     },
0247 };
0248 
0249 module_gpr_driver(prm_driver);
0250 MODULE_DESCRIPTION("Audio Process Manager");
0251 MODULE_LICENSE("GPL");