q6core.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/string.h>
  15. #include <linux/types.h>
  16. #include <linux/spinlock.h>
  17. #include <linux/mutex.h>
  18. #include <linux/sched.h>
  19. #include <linux/slab.h>
  20. #include <mach/msm_smd.h>
  21. #include <mach/qdsp6v2/apr.h>
  22. #include <mach/ocmem.h>
  23. #include <sound/q6core.h>
  24. #define TIMEOUT_MS 1000
  25. #define Q6_READY_TIMEOUT_MS 100
  26. struct q6core_str {
  27. struct apr_svc *core_handle_q;
  28. wait_queue_head_t bus_bw_req_wait;
  29. u32 bus_bw_resp_received;
  30. struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
  31. u32 param;
  32. };
  33. static struct q6core_str q6core_lcl;
  34. static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
  35. {
  36. uint32_t *payload1;
  37. uint32_t nseg;
  38. int i, j;
  39. if (data == NULL) {
  40. pr_err("%s: data argument is null\n", __func__);
  41. return -EINVAL;
  42. }
  43. pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
  44. data->payload_size, data->opcode);
  45. switch (data->opcode) {
  46. case APR_BASIC_RSP_RESULT:{
  47. if (data->payload_size == 0) {
  48. pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
  49. __func__);
  50. return 0;
  51. }
  52. payload1 = data->payload;
  53. switch (payload1[0]) {
  54. case AVCS_CMD_GET_LOW_POWER_SEGMENTS_INFO:
  55. pr_info("%s: Cmd = AVCS_CMD_GET_LOW_POWER_SEGMENTS_INFO status[0x%x]\n",
  56. __func__, payload1[1]);
  57. break;
  58. default:
  59. pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
  60. payload1[0], payload1[1]);
  61. break;
  62. }
  63. break;
  64. }
  65. case AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO:
  66. payload1 = data->payload;
  67. pr_info("%s: cmd = AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO num_segments = 0x%x\n",
  68. __func__, payload1[0]);
  69. nseg = payload1[0];
  70. q6core_lcl.lp_ocm_payload.num_segments = nseg;
  71. q6core_lcl.lp_ocm_payload.bandwidth = payload1[1];
  72. for (i = 0, j = 2; i < nseg; i++) {
  73. q6core_lcl.lp_ocm_payload.mem_segment[i].type =
  74. (payload1[j] & 0xffff);
  75. q6core_lcl.lp_ocm_payload.mem_segment[i].category =
  76. ((payload1[j++] >> 16) & 0xffff);
  77. q6core_lcl.lp_ocm_payload.mem_segment[i].size =
  78. payload1[j++];
  79. q6core_lcl.lp_ocm_payload.
  80. mem_segment[i].start_address_lsw =
  81. payload1[j++];
  82. q6core_lcl.lp_ocm_payload.
  83. mem_segment[i].start_address_msw =
  84. payload1[j++];
  85. }
  86. q6core_lcl.bus_bw_resp_received = 1;
  87. wake_up(&q6core_lcl.bus_bw_req_wait);
  88. break;
  89. case RESET_EVENTS:{
  90. pr_debug("Reset event received in Core service");
  91. apr_reset(q6core_lcl.core_handle_q);
  92. q6core_lcl.core_handle_q = NULL;
  93. break;
  94. }
  95. case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
  96. payload1 = data->payload;
  97. q6core_lcl.param = payload1[0];
  98. pr_debug("%s: Received ADSP get state response 0x%x\n",
  99. __func__, q6core_lcl.param);
  100. /* ensure .param is updated prior to .bus_bw_resp_received */
  101. wmb();
  102. q6core_lcl.bus_bw_resp_received = 1;
  103. wake_up(&q6core_lcl.bus_bw_req_wait);
  104. break;
  105. default:
  106. pr_err("Message id from adsp core svc: %d\n", data->opcode);
  107. break;
  108. }
  109. return 0;
  110. }
  111. void ocm_core_open(void)
  112. {
  113. if (q6core_lcl.core_handle_q == NULL)
  114. q6core_lcl.core_handle_q = apr_register("ADSP", "CORE",
  115. aprv2_core_fn_q, 0xFFFFFFFF, NULL);
  116. pr_debug("Open_q %p\n", q6core_lcl.core_handle_q);
  117. if (q6core_lcl.core_handle_q == NULL)
  118. pr_err("%s: Unable to register CORE\n", __func__);
  119. }
  120. uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
  121. {
  122. struct adsp_dolby_manufacturer_id payload;
  123. int rc = 0;
  124. pr_debug("%s manufacturer_id :%d\n", __func__, manufacturer_id);
  125. ocm_core_open();
  126. if (q6core_lcl.core_handle_q) {
  127. payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
  128. APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
  129. payload.hdr.pkt_size =
  130. sizeof(struct adsp_dolby_manufacturer_id);
  131. payload.hdr.src_port = 0;
  132. payload.hdr.dest_port = 0;
  133. payload.hdr.token = 0;
  134. payload.hdr.opcode = ADSP_CMD_SET_DOLBY_MANUFACTURER_ID;
  135. payload.manufacturer_id = manufacturer_id;
  136. pr_debug("Send Dolby security opcode=%x manufacturer ID = %d\n",
  137. payload.hdr.opcode, payload.manufacturer_id);
  138. rc = apr_send_pkt(q6core_lcl.core_handle_q,
  139. (uint32_t *)&payload);
  140. if (rc < 0)
  141. pr_err("%s: SET_DOLBY_MANUFACTURER_ID failed op[0x%x]rc[%d]\n",
  142. __func__, payload.hdr.opcode, rc);
  143. }
  144. return rc;
  145. }
  146. int core_get_low_power_segments(
  147. struct avcs_cmd_rsp_get_low_power_segments_info_t **lp_memseg)
  148. {
  149. struct avcs_cmd_get_low_power_segments_info lp_ocm_cmd;
  150. int ret = 0;
  151. pr_debug("%s: ", __func__);
  152. ocm_core_open();
  153. if (q6core_lcl.core_handle_q == NULL) {
  154. pr_info("%s: apr registration for CORE failed\n", __func__);
  155. return -ENODEV;
  156. }
  157. lp_ocm_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
  158. APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
  159. lp_ocm_cmd.hdr.pkt_size =
  160. sizeof(struct avcs_cmd_get_low_power_segments_info);
  161. lp_ocm_cmd.hdr.src_port = 0;
  162. lp_ocm_cmd.hdr.dest_port = 0;
  163. lp_ocm_cmd.hdr.token = 0;
  164. lp_ocm_cmd.hdr.opcode = AVCS_CMD_GET_LOW_POWER_SEGMENTS_INFO;
  165. ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &lp_ocm_cmd);
  166. if (ret < 0) {
  167. pr_err("%s: CORE low power segment request failed\n", __func__);
  168. goto fail_cmd;
  169. }
  170. ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
  171. (q6core_lcl.bus_bw_resp_received == 1),
  172. msecs_to_jiffies(TIMEOUT_MS));
  173. if (!ret) {
  174. pr_err("%s: wait_event timeout for GET_LOW_POWER_SEGMENTS\n",
  175. __func__);
  176. ret = -ETIME;
  177. goto fail_cmd;
  178. }
  179. *lp_memseg = &q6core_lcl.lp_ocm_payload;
  180. return 0;
  181. fail_cmd:
  182. return ret;
  183. }
  184. bool q6core_is_adsp_ready(void)
  185. {
  186. int rc;
  187. bool ret = false;
  188. struct apr_hdr hdr;
  189. pr_debug("%s: enter\n", __func__);
  190. memset(&hdr, 0, sizeof(hdr));
  191. hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
  192. APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
  193. hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
  194. hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
  195. ocm_core_open();
  196. if (q6core_lcl.core_handle_q) {
  197. q6core_lcl.bus_bw_resp_received = 0;
  198. rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
  199. if (rc < 0) {
  200. pr_err("%s: Get ADSP state APR packet send event %d\n",
  201. __func__, rc);
  202. goto bail;
  203. }
  204. rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
  205. (q6core_lcl.bus_bw_resp_received == 1),
  206. msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
  207. if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
  208. /* ensure to read updated param by callback thread */
  209. rmb();
  210. ret = !!q6core_lcl.param;
  211. }
  212. }
  213. bail:
  214. pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
  215. return ret;
  216. }
  217. static int __init core_init(void)
  218. {
  219. init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
  220. q6core_lcl.bus_bw_resp_received = 0;
  221. q6core_lcl.core_handle_q = NULL;
  222. return 0;
  223. }
  224. module_init(core_init);
  225. static void __exit core_exit(void)
  226. {
  227. }
  228. module_exit(core_exit);
  229. MODULE_DESCRIPTION("ADSP core driver");
  230. MODULE_LICENSE("GPL v2");