q6prm.c 6.5 KB

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