blob: 95b203a74b071be5bf790a401ce49cd72460b376 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/* 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
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/string.h>
16#include <linux/types.h>
17#include <linux/spinlock.h>
18#include <linux/mutex.h>
19#include <linux/sched.h>
20#include <linux/slab.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053021#include <dsp/q6core.h>
22#include <dsp/audio_cal_utils.h>
Laxminath Kasam38070be2017-08-17 18:21:59 +053023#include <dsp/apr_audio-v2.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053024#include <ipc/apr.h>
Laxminath Kasam38070be2017-08-17 18:21:59 +053025#include "adsp_err.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053026
27#define TIMEOUT_MS 1000
28/*
29 * AVS bring up in the modem is optimitized for the new
30 * Sub System Restart design and 100 milliseconds timeout
31 * is sufficient to make sure the Q6 will be ready.
32 */
33#define Q6_READY_TIMEOUT_MS 100
34
35enum {
36 META_CAL,
37 CUST_TOP_CAL,
38 CORE_MAX_CAL
39};
40
Laxminath Kasam38070be2017-08-17 18:21:59 +053041enum ver_query_status {
42 VER_QUERY_UNATTEMPTED,
43 VER_QUERY_UNSUPPORTED,
44 VER_QUERY_SUPPORTED
45};
46
47struct q6core_avcs_ver_info {
48 enum ver_query_status status;
49 struct avcs_fwk_ver_info ver_info;
50};
51
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053052struct q6core_str {
53 struct apr_svc *core_handle_q;
54 wait_queue_head_t bus_bw_req_wait;
55 wait_queue_head_t cmd_req_wait;
Laxminath Kasam38070be2017-08-17 18:21:59 +053056 wait_queue_head_t avcs_fwk_ver_req_wait;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053057 u32 bus_bw_resp_received;
58 enum cmd_flags {
59 FLAG_NONE,
60 FLAG_CMDRSP_LICENSE_RESULT
61 } cmd_resp_received_flag;
Laxminath Kasam38070be2017-08-17 18:21:59 +053062 u32 avcs_fwk_ver_resp_received;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053063 struct mutex cmd_lock;
Laxminath Kasam38070be2017-08-17 18:21:59 +053064 struct mutex ver_lock;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053065 union {
66 struct avcs_cmdrsp_get_license_validation_result
67 cmdrsp_license_result;
68 } cmd_resp_payload;
69 u32 param;
70 struct cal_type_data *cal_data[CORE_MAX_CAL];
71 uint32_t mem_map_cal_handle;
72 int32_t adsp_status;
Laxminath Kasam38070be2017-08-17 18:21:59 +053073 struct q6core_avcs_ver_info q6core_avcs_ver_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053074};
75
76static struct q6core_str q6core_lcl;
77
78struct generic_get_data_ {
79 int valid;
80 int size_in_ints;
81 int ints[];
82};
83static struct generic_get_data_ *generic_get_data;
84
Laxminath Kasam38070be2017-08-17 18:21:59 +053085static int parse_fwk_version_info(uint32_t *payload)
86{
87 size_t fwk_ver_size;
88 size_t svc_size;
89 int num_services;
90 int ret = 0;
91
92 pr_debug("%s: Payload info num services %d\n",
93 __func__, payload[4]);
94 /*
95 * payload1[4] is the number of services running on DSP
96 * Based on this info, we copy the payload into core
97 * avcs version info structure.
98 */
99 num_services = payload[4];
100 q6core_lcl.q6core_avcs_ver_info.ver_info.avcs_fwk_version.
101 num_services = num_services;
102 if (num_services > VSS_MAX_AVCS_NUM_SERVICES) {
103 pr_err("%s: num_services: %d greater than max services: %d\n",
104 __func__, num_services, VSS_MAX_AVCS_NUM_SERVICES);
105 ret = -EINVAL;
106 goto done;
107 }
108 fwk_ver_size = sizeof(struct avcs_get_fwk_version);
109 svc_size = num_services * sizeof(struct avs_svc_api_info);
110 /*
111 * Dynamically allocate memory for all
112 * the services based on num_services
113 */
114 q6core_lcl.q6core_avcs_ver_info.ver_info.services = NULL;
115 q6core_lcl.q6core_avcs_ver_info.ver_info.services =
116 kzalloc(svc_size, GFP_ATOMIC);
117 if (q6core_lcl.q6core_avcs_ver_info.ver_info.services == NULL) {
118 ret = -ENOMEM;
119 goto done;
120 }
121 /*
122 * memcpy is done twice because the memory allocated for
123 * q6core_lcl.q6core_avcs_ver_info.ver_info is not
124 * contiguous.
125 */
126 memcpy(&q6core_lcl.q6core_avcs_ver_info.ver_info,
127 (uint8_t *)payload, fwk_ver_size);
128 memcpy(q6core_lcl.q6core_avcs_ver_info.ver_info.services,
129 (uint8_t *)&payload[sizeof(struct avcs_get_fwk_version)/
130 sizeof(uint32_t)], svc_size);
131 ret = 0;
132done:
133 return ret;
134}
135
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530136static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
137{
138 uint32_t *payload1;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530139 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530140
141 if (data == NULL) {
142 pr_err("%s: data argument is null\n", __func__);
143 return -EINVAL;
144 }
145
146 pr_debug("%s: core msg: payload len = %u, apr resp opcode = 0x%x\n",
147 __func__,
148 data->payload_size, data->opcode);
149
150 switch (data->opcode) {
151
152 case APR_BASIC_RSP_RESULT:{
153
154 if (data->payload_size == 0) {
155 pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
156 __func__);
157 return 0;
158 }
159
160 payload1 = data->payload;
161
162 switch (payload1[0]) {
163
164 case AVCS_CMD_SHARED_MEM_UNMAP_REGIONS:
165 pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS status[0x%x]\n",
166 __func__, payload1[1]);
167 q6core_lcl.bus_bw_resp_received = 1;
168 wake_up(&q6core_lcl.bus_bw_req_wait);
169 break;
170 case AVCS_CMD_SHARED_MEM_MAP_REGIONS:
171 pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_MAP_REGIONS status[0x%x]\n",
172 __func__, payload1[1]);
173 q6core_lcl.bus_bw_resp_received = 1;
174 wake_up(&q6core_lcl.bus_bw_req_wait);
175 break;
176 case AVCS_CMD_REGISTER_TOPOLOGIES:
177 pr_debug("%s: Cmd = AVCS_CMD_REGISTER_TOPOLOGIES status[0x%x]\n",
178 __func__, payload1[1]);
179 /* -ADSP status to match Linux error standard */
180 q6core_lcl.adsp_status = -payload1[1];
181 q6core_lcl.bus_bw_resp_received = 1;
182 wake_up(&q6core_lcl.bus_bw_req_wait);
183 break;
184 case AVCS_CMD_DEREGISTER_TOPOLOGIES:
185 pr_debug("%s: Cmd = AVCS_CMD_DEREGISTER_TOPOLOGIES status[0x%x]\n",
186 __func__, payload1[1]);
187 q6core_lcl.bus_bw_resp_received = 1;
188 wake_up(&q6core_lcl.bus_bw_req_wait);
189 break;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530190 case AVCS_CMD_GET_FWK_VERSION:
191 pr_debug("%s: Cmd = AVCS_CMD_GET_FWK_VERSION status[%s]\n",
192 __func__, adsp_err_get_err_str(payload1[1]));
193 /* ADSP status to match Linux error standard */
194 q6core_lcl.adsp_status = -payload1[1];
195 if (payload1[1] == ADSP_EUNSUPPORTED)
196 q6core_lcl.q6core_avcs_ver_info.status =
197 VER_QUERY_UNSUPPORTED;
198 q6core_lcl.avcs_fwk_ver_resp_received = 1;
199 wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
200 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530201 default:
202 pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
203 __func__,
204 payload1[0], payload1[1], data->opcode);
205 break;
206 }
207 break;
208 }
209
210 case RESET_EVENTS:{
211 pr_debug("%s: Reset event received in Core service\n",
212 __func__);
Tanya Dixit861a8fa2017-09-12 15:38:21 +0530213 /*
214 * no reset for q6core_avcs_ver_info done as
215 * the data will not change after SSR
216 */
217 apr_reset(q6core_lcl.core_handle_q);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530218 q6core_lcl.core_handle_q = NULL;
219 break;
220 }
221 case AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS:
222 payload1 = data->payload;
223 pr_debug("%s: AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS handle %d\n",
224 __func__, payload1[0]);
225 q6core_lcl.mem_map_cal_handle = payload1[0];
226 q6core_lcl.bus_bw_resp_received = 1;
227 wake_up(&q6core_lcl.bus_bw_req_wait);
228 break;
229 case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
230 payload1 = data->payload;
231 q6core_lcl.param = payload1[0];
232 pr_debug("%s: Received ADSP get state response 0x%x\n",
233 __func__, q6core_lcl.param);
234 /* ensure .param is updated prior to .bus_bw_resp_received */
235 wmb();
236 q6core_lcl.bus_bw_resp_received = 1;
237 wake_up(&q6core_lcl.bus_bw_req_wait);
238 break;
239 case AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT:
240 payload1 = data->payload;
241 pr_debug("%s: cmd = LICENSE_VALIDATION_RESULT, result = 0x%x\n",
242 __func__, payload1[0]);
243 q6core_lcl.cmd_resp_payload.cmdrsp_license_result.result
244 = payload1[0];
245 q6core_lcl.cmd_resp_received_flag = FLAG_CMDRSP_LICENSE_RESULT;
246 wake_up(&q6core_lcl.cmd_req_wait);
247 break;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530248 case AVCS_CMDRSP_GET_FWK_VERSION:
249 pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
250 __func__);
251 payload1 = data->payload;
252 q6core_lcl.q6core_avcs_ver_info.status = VER_QUERY_SUPPORTED;
253 q6core_lcl.avcs_fwk_ver_resp_received = 1;
254 ret = parse_fwk_version_info(payload1);
255 if (ret < 0)
256 pr_err("%s: Failed to parse payload:%d\n",
257 __func__, ret);
258 wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
259 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530260 default:
261 pr_err("%s: Message id from adsp core svc: 0x%x\n",
262 __func__, data->opcode);
263 if (generic_get_data) {
264 generic_get_data->valid = 1;
265 generic_get_data->size_in_ints =
266 data->payload_size/sizeof(int);
267 pr_debug("callback size = %i\n",
268 data->payload_size);
269 memcpy(generic_get_data->ints, data->payload,
270 data->payload_size);
271 q6core_lcl.bus_bw_resp_received = 1;
272 wake_up(&q6core_lcl.bus_bw_req_wait);
273 break;
274 }
275 break;
276 }
277
278 return 0;
279}
280
281void ocm_core_open(void)
282{
283 if (q6core_lcl.core_handle_q == NULL)
284 q6core_lcl.core_handle_q = apr_register("ADSP", "CORE",
285 aprv2_core_fn_q, 0xFFFFFFFF, NULL);
286 pr_debug("%s: Open_q %pK\n", __func__, q6core_lcl.core_handle_q);
287 if (q6core_lcl.core_handle_q == NULL)
288 pr_err("%s: Unable to register CORE\n", __func__);
289}
290
291struct cal_block_data *cal_utils_get_cal_block_by_key(
292 struct cal_type_data *cal_type, uint32_t key)
293{
294 struct list_head *ptr, *next;
295 struct cal_block_data *cal_block = NULL;
296 struct audio_cal_info_metainfo *metainfo;
297
298 list_for_each_safe(ptr, next,
299 &cal_type->cal_blocks) {
300
301 cal_block = list_entry(ptr,
302 struct cal_block_data, list);
303 metainfo = (struct audio_cal_info_metainfo *)
304 cal_block->cal_info;
305 if (metainfo->nKey != key) {
306 pr_debug("%s: metainfo key mismatch!!! found:%x, needed:%x\n",
307 __func__, metainfo->nKey, key);
308 } else {
309 pr_debug("%s: metainfo key match found", __func__);
310 return cal_block;
311 }
312 }
313 return NULL;
314}
315
Laxminath Kasam38070be2017-08-17 18:21:59 +0530316static int q6core_send_get_avcs_fwk_ver_cmd(void)
317{
318 struct apr_hdr avcs_ver_cmd;
319 int ret;
320
321 avcs_ver_cmd.hdr_field =
322 APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
323 APR_PKT_VER);
324 avcs_ver_cmd.pkt_size = sizeof(struct apr_hdr);
325 avcs_ver_cmd.src_port = 0;
326 avcs_ver_cmd.dest_port = 0;
327 avcs_ver_cmd.token = 0;
328 avcs_ver_cmd.opcode = AVCS_CMD_GET_FWK_VERSION;
329
330 q6core_lcl.adsp_status = 0;
331 q6core_lcl.avcs_fwk_ver_resp_received = 0;
332
333 ret = apr_send_pkt(q6core_lcl.core_handle_q,
334 (uint32_t *) &avcs_ver_cmd);
335 if (ret < 0) {
336 pr_err("%s: failed to send apr packet, ret=%d\n", __func__,
337 ret);
338 goto done;
339 }
340
341 ret = wait_event_timeout(q6core_lcl.avcs_fwk_ver_req_wait,
342 (q6core_lcl.avcs_fwk_ver_resp_received == 1),
343 msecs_to_jiffies(TIMEOUT_MS));
344 if (!ret) {
345 pr_err("%s: wait_event timeout for AVCS fwk version info\n",
346 __func__);
347 ret = -ETIMEDOUT;
348 goto done;
349 }
350
351 if (q6core_lcl.adsp_status < 0) {
352 /*
353 * adsp_err_get_err_str expects a positive value but we store
354 * the DSP error as negative to match the Linux error standard.
355 * Pass in the negated value so adsp_err_get_err_str returns
356 * the correct string.
357 */
358 pr_err("%s: DSP returned error[%s]\n", __func__,
359 adsp_err_get_err_str(-q6core_lcl.adsp_status));
360 ret = adsp_err_get_lnx_err_code(q6core_lcl.adsp_status);
361 goto done;
362 }
363
364 ret = 0;
365
366done:
367 return ret;
368}
369
370int q6core_get_service_version(uint32_t service_id,
371 struct avcs_fwk_ver_info *ver_info,
372 size_t size)
373{
374 int i;
375 uint32_t num_services;
376 size_t svc_size;
377
378 svc_size = q6core_get_avcs_service_size(service_id);
379 if (svc_size != size) {
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +0530380 pr_err("%s: Expected size: %zu, Provided size: %zu\n",
Laxminath Kasam38070be2017-08-17 18:21:59 +0530381 __func__, svc_size, size);
382 return -EINVAL;
383 }
384
385 num_services =
386 q6core_lcl.q6core_avcs_ver_info.ver_info.
387 avcs_fwk_version.num_services;
388
389 if (ver_info == NULL) {
390 pr_err("%s: NULL parameter ver_info\n", __func__);
391 return -EINVAL;
392 }
393
394 memcpy(ver_info, &q6core_lcl.q6core_avcs_ver_info.
395 ver_info.avcs_fwk_version, sizeof(struct avcs_get_fwk_version));
396
397 if (service_id == AVCS_SERVICE_ID_ALL) {
398 memcpy(&ver_info->services[0], &q6core_lcl.
399 q6core_avcs_ver_info.ver_info.services[0],
400 (num_services * sizeof(struct avs_svc_api_info)));
401 } else {
402 for (i = 0; i < num_services; i++) {
403 if (q6core_lcl.q6core_avcs_ver_info.
404 ver_info.services[i].service_id == service_id) {
405 memcpy(&ver_info->services[0],
406 &q6core_lcl.q6core_avcs_ver_info.
407 ver_info.services[i], size);
408 break;
409 }
410 }
411 }
412
413 return 0;
414}
415EXPORT_SYMBOL(q6core_get_service_version);
416
417size_t q6core_get_avcs_service_size(uint32_t service_id)
418{
419 int ret = 0;
420 uint32_t num_services;
421
422 num_services =
423 q6core_lcl.q6core_avcs_ver_info.ver_info.
424 avcs_fwk_version.num_services;
425
426 mutex_lock(&(q6core_lcl.ver_lock));
427 pr_debug("%s: q6core_avcs_ver_info.status(%d)\n", __func__,
428 q6core_lcl.q6core_avcs_ver_info.status);
429
430 switch (q6core_lcl.q6core_avcs_ver_info.status) {
431 case VER_QUERY_SUPPORTED:
432 pr_debug("%s: AVCS FWK version query already attempted\n",
433 __func__);
434 ret = num_services * sizeof(struct avs_svc_api_info);
435 break;
436 case VER_QUERY_UNSUPPORTED:
437 ret = -EOPNOTSUPP;
438 break;
439 case VER_QUERY_UNATTEMPTED:
440 pr_debug("%s: Attempting AVCS FWK version query\n", __func__);
441 if (q6core_is_adsp_ready()) {
442 ret = q6core_send_get_avcs_fwk_ver_cmd();
443 if (ret == 0)
444 ret = num_services *
445 sizeof(struct avs_svc_api_info);
446 } else {
447 pr_err("%s: ADSP is not ready to query version\n",
448 __func__);
449 ret = -ENODEV;
450 }
451 break;
452 default:
453 pr_err("%s: Invalid version query status %d\n", __func__,
454 q6core_lcl.q6core_avcs_ver_info.status);
455 ret = -EINVAL;
456 break;
457 }
458 mutex_unlock(&(q6core_lcl.ver_lock));
459
460 if (service_id != AVCS_SERVICE_ID_ALL)
461 return sizeof(struct avs_svc_api_info);
462
463 return ret;
464}
465EXPORT_SYMBOL(q6core_get_avcs_service_size);
466
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530467int32_t core_set_license(uint32_t key, uint32_t module_id)
468{
469 struct avcs_cmd_set_license *cmd_setl = NULL;
470 struct cal_block_data *cal_block = NULL;
471 int rc = 0, packet_size = 0;
472
473 pr_debug("%s: key:0x%x, id:0x%x\n", __func__, key, module_id);
474
475 mutex_lock(&(q6core_lcl.cmd_lock));
476 if (q6core_lcl.cal_data[META_CAL] == NULL) {
477 pr_err("%s: cal_data not initialized yet!!\n", __func__);
478 rc = -EINVAL;
479 goto cmd_unlock;
480 }
481
482 mutex_lock(&((q6core_lcl.cal_data[META_CAL])->lock));
483 cal_block = cal_utils_get_cal_block_by_key(
484 q6core_lcl.cal_data[META_CAL], key);
485 if (cal_block == NULL ||
486 cal_block->cal_data.kvaddr == NULL ||
487 cal_block->cal_data.size <= 0) {
488 pr_err("%s: Invalid cal block to send", __func__);
489 rc = -EINVAL;
490 goto cal_data_unlock;
491 }
492
493 packet_size = sizeof(struct avcs_cmd_set_license) +
494 cal_block->cal_data.size;
495 /*round up total packet_size to next 4 byte boundary*/
496 packet_size = ((packet_size + 0x3)>>2)<<2;
497
498 cmd_setl = kzalloc(packet_size, GFP_KERNEL);
499 if (cmd_setl == NULL) {
500 rc = -ENOMEM;
501 goto cal_data_unlock;
502 }
503
504 ocm_core_open();
505 if (q6core_lcl.core_handle_q == NULL) {
506 pr_err("%s: apr registration for CORE failed\n", __func__);
507 rc = -ENODEV;
508 goto fail_cmd;
509 }
510
511 cmd_setl->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
512 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
513 cmd_setl->hdr.pkt_size = packet_size;
514 cmd_setl->hdr.src_port = 0;
515 cmd_setl->hdr.dest_port = 0;
516 cmd_setl->hdr.token = 0;
517 cmd_setl->hdr.opcode = AVCS_CMD_SET_LICENSE;
518 cmd_setl->id = module_id;
519 cmd_setl->overwrite = 1;
520 cmd_setl->size = cal_block->cal_data.size;
521 memcpy((uint8_t *)cmd_setl + sizeof(struct avcs_cmd_set_license),
522 cal_block->cal_data.kvaddr,
523 cal_block->cal_data.size);
524 pr_info("%s: Set license opcode=0x%x, id =0x%x, size = %d\n",
525 __func__, cmd_setl->hdr.opcode,
526 cmd_setl->id, cmd_setl->size);
527 rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)cmd_setl);
528 if (rc < 0)
529 pr_err("%s: SET_LICENSE failed op[0x%x]rc[%d]\n",
530 __func__, cmd_setl->hdr.opcode, rc);
531
532fail_cmd:
533 kfree(cmd_setl);
534cal_data_unlock:
535 mutex_unlock(&((q6core_lcl.cal_data[META_CAL])->lock));
536cmd_unlock:
537 mutex_unlock(&(q6core_lcl.cmd_lock));
538
539 return rc;
540}
541
542int32_t core_get_license_status(uint32_t module_id)
543{
544 struct avcs_cmd_get_license_validation_result get_lvr_cmd;
545 int ret = 0;
546
547 pr_debug("%s: module_id 0x%x", __func__, module_id);
548
549 mutex_lock(&(q6core_lcl.cmd_lock));
550 ocm_core_open();
551 if (q6core_lcl.core_handle_q == NULL) {
552 pr_err("%s: apr registration for CORE failed\n", __func__);
553 ret = -ENODEV;
554 goto fail_cmd;
555 }
556
557 get_lvr_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
558 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
559 get_lvr_cmd.hdr.pkt_size =
560 sizeof(struct avcs_cmd_get_license_validation_result);
561
562 get_lvr_cmd.hdr.src_port = 0;
563 get_lvr_cmd.hdr.dest_port = 0;
564 get_lvr_cmd.hdr.token = 0;
565 get_lvr_cmd.hdr.opcode = AVCS_CMD_GET_LICENSE_VALIDATION_RESULT;
566 get_lvr_cmd.id = module_id;
567
568
569 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &get_lvr_cmd);
570 if (ret < 0) {
571 pr_err("%s: license_validation request failed, err %d\n",
572 __func__, ret);
573 ret = -EREMOTE;
574 goto fail_cmd;
575 }
576
577 q6core_lcl.cmd_resp_received_flag &= ~(FLAG_CMDRSP_LICENSE_RESULT);
578 mutex_unlock(&(q6core_lcl.cmd_lock));
579 ret = wait_event_timeout(q6core_lcl.cmd_req_wait,
580 (q6core_lcl.cmd_resp_received_flag ==
581 FLAG_CMDRSP_LICENSE_RESULT),
582 msecs_to_jiffies(TIMEOUT_MS));
583 mutex_lock(&(q6core_lcl.cmd_lock));
584 if (!ret) {
585 pr_err("%s: wait_event timeout for CMDRSP_LICENSE_RESULT\n",
586 __func__);
587 ret = -ETIME;
588 goto fail_cmd;
589 }
590 q6core_lcl.cmd_resp_received_flag &= ~(FLAG_CMDRSP_LICENSE_RESULT);
591 ret = q6core_lcl.cmd_resp_payload.cmdrsp_license_result.result;
592
593fail_cmd:
594 mutex_unlock(&(q6core_lcl.cmd_lock));
595 pr_info("%s: cmdrsp_license_result.result = 0x%x for module 0x%x\n",
596 __func__, ret, module_id);
597 return ret;
598}
599
600uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
601{
602 struct adsp_dolby_manufacturer_id payload;
603 int rc = 0;
604
605 pr_debug("%s: manufacturer_id :%d\n", __func__, manufacturer_id);
606 mutex_lock(&(q6core_lcl.cmd_lock));
607 ocm_core_open();
608 if (q6core_lcl.core_handle_q) {
609 payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
610 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
611 payload.hdr.pkt_size =
612 sizeof(struct adsp_dolby_manufacturer_id);
613 payload.hdr.src_port = 0;
614 payload.hdr.dest_port = 0;
615 payload.hdr.token = 0;
616 payload.hdr.opcode = ADSP_CMD_SET_DOLBY_MANUFACTURER_ID;
617 payload.manufacturer_id = manufacturer_id;
618 pr_debug("%s: Send Dolby security opcode=0x%x manufacturer ID = %d\n",
619 __func__,
620 payload.hdr.opcode, payload.manufacturer_id);
621 rc = apr_send_pkt(q6core_lcl.core_handle_q,
622 (uint32_t *)&payload);
623 if (rc < 0)
624 pr_err("%s: SET_DOLBY_MANUFACTURER_ID failed op[0x%x]rc[%d]\n",
625 __func__, payload.hdr.opcode, rc);
626 }
627 mutex_unlock(&(q6core_lcl.cmd_lock));
628 return rc;
629}
630
631/**
632 * q6core_is_adsp_ready - check adsp ready status
633 *
634 * Returns true if adsp is ready otherwise returns false
635 */
636bool q6core_is_adsp_ready(void)
637{
638 int rc = 0;
639 bool ret = false;
640 struct apr_hdr hdr;
641
642 pr_debug("%s: enter\n", __func__);
643 memset(&hdr, 0, sizeof(hdr));
644 hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
645 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
646 hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
647 hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
648
649 mutex_lock(&(q6core_lcl.cmd_lock));
650 ocm_core_open();
651 if (q6core_lcl.core_handle_q) {
652 q6core_lcl.bus_bw_resp_received = 0;
653 rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
654 if (rc < 0) {
655 pr_err("%s: Get ADSP state APR packet send event %d\n",
656 __func__, rc);
657 goto bail;
658 }
659
660 rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
661 (q6core_lcl.bus_bw_resp_received == 1),
662 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
663 if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
664 /* ensure to read updated param by callback thread */
665 rmb();
666 ret = !!q6core_lcl.param;
667 }
668 }
669bail:
670 pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
671 mutex_unlock(&(q6core_lcl.cmd_lock));
672 return ret;
673}
674EXPORT_SYMBOL(q6core_is_adsp_ready);
675
676static int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
677 uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle)
678{
679 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
680 struct avs_shared_map_region_payload *mregions = NULL;
681 void *mmap_region_cmd = NULL;
682 void *payload = NULL;
683 int ret = 0;
684 int i = 0;
685 int cmd_size = 0;
686
687 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
688 + sizeof(struct avs_shared_map_region_payload)
689 * bufcnt;
690
691 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
692 if (mmap_region_cmd == NULL)
693 return -ENOMEM;
694
695 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
696 mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
697 APR_HDR_LEN(APR_HDR_SIZE),
698 APR_PKT_VER);
699 mmap_regions->hdr.pkt_size = cmd_size;
700 mmap_regions->hdr.src_port = 0;
701 mmap_regions->hdr.dest_port = 0;
702 mmap_regions->hdr.token = 0;
703 mmap_regions->hdr.opcode = AVCS_CMD_SHARED_MEM_MAP_REGIONS;
704 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
705 mmap_regions->num_regions = bufcnt & 0x00ff;
706 mmap_regions->property_flag = 0x00;
707
708 payload = ((u8 *) mmap_region_cmd +
709 sizeof(struct avs_cmd_shared_mem_map_regions));
710 mregions = (struct avs_shared_map_region_payload *)payload;
711
712 for (i = 0; i < bufcnt; i++) {
713 mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
714 mregions->shm_addr_msw =
715 msm_audio_populate_upper_32_bits(buf_add[i]);
716 mregions->mem_size_bytes = bufsz[i];
717 ++mregions;
718 }
719
720 pr_debug("%s: sending memory map, addr %pK, size %d, bufcnt = %d\n",
721 __func__, buf_add, bufsz[0], mmap_regions->num_regions);
722
723 *map_handle = 0;
724 q6core_lcl.bus_bw_resp_received = 0;
725 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
726 mmap_regions);
727 if (ret < 0) {
728 pr_err("%s: mmap regions failed %d\n",
729 __func__, ret);
730 ret = -EINVAL;
731 goto done;
732 }
733
734 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
735 (q6core_lcl.bus_bw_resp_received == 1),
736 msecs_to_jiffies(TIMEOUT_MS));
737 if (!ret) {
738 pr_err("%s: timeout. waited for memory map\n", __func__);
739 ret = -ETIME;
740 goto done;
741 }
742
743 *map_handle = q6core_lcl.mem_map_cal_handle;
744done:
745 kfree(mmap_region_cmd);
746 return ret;
747}
748
749static int q6core_memory_unmap_regions(uint32_t mem_map_handle)
750{
751 struct avs_cmd_shared_mem_unmap_regions unmap_regions;
752 int ret = 0;
753
754 memset(&unmap_regions, 0, sizeof(unmap_regions));
755 unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
756 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
757 unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
758 unmap_regions.hdr.src_svc = APR_SVC_ADSP_CORE;
759 unmap_regions.hdr.src_domain = APR_DOMAIN_APPS;
760 unmap_regions.hdr.src_port = 0;
761 unmap_regions.hdr.dest_svc = APR_SVC_ADSP_CORE;
762 unmap_regions.hdr.dest_domain = APR_DOMAIN_ADSP;
763 unmap_regions.hdr.dest_port = 0;
764 unmap_regions.hdr.token = 0;
765 unmap_regions.hdr.opcode = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS;
766 unmap_regions.mem_map_handle = mem_map_handle;
767
768 q6core_lcl.bus_bw_resp_received = 0;
769
770 pr_debug("%s: unmap regions map handle %d\n",
771 __func__, mem_map_handle);
772
773 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
774 &unmap_regions);
775 if (ret < 0) {
776 pr_err("%s: unmap regions failed %d\n",
777 __func__, ret);
778 ret = -EINVAL;
779 goto done;
780 }
781
782 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
783 (q6core_lcl.bus_bw_resp_received == 1),
784 msecs_to_jiffies(TIMEOUT_MS));
785 if (!ret) {
786 pr_err("%s: timeout. waited for memory_unmap\n",
787 __func__);
788 ret = -ETIME;
789 goto done;
790 }
791done:
792 return ret;
793}
794
795static int q6core_dereg_all_custom_topologies(void)
796{
797 int ret = 0;
798 struct avcs_cmd_deregister_topologies dereg_top;
799
800 memset(&dereg_top, 0, sizeof(dereg_top));
801 dereg_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
802 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
803 dereg_top.hdr.pkt_size = sizeof(dereg_top);
804 dereg_top.hdr.src_svc = APR_SVC_ADSP_CORE;
805 dereg_top.hdr.src_domain = APR_DOMAIN_APPS;
806 dereg_top.hdr.src_port = 0;
807 dereg_top.hdr.dest_svc = APR_SVC_ADSP_CORE;
808 dereg_top.hdr.dest_domain = APR_DOMAIN_ADSP;
809 dereg_top.hdr.dest_port = 0;
810 dereg_top.hdr.token = 0;
811 dereg_top.hdr.opcode = AVCS_CMD_DEREGISTER_TOPOLOGIES;
812 dereg_top.payload_addr_lsw = 0;
813 dereg_top.payload_addr_msw = 0;
814 dereg_top.mem_map_handle = 0;
815 dereg_top.payload_size = 0;
816 dereg_top.mode = AVCS_MODE_DEREGISTER_ALL_CUSTOM_TOPOLOGIES;
817
818 q6core_lcl.bus_bw_resp_received = 0;
819
820 pr_debug("%s: Deregister topologies mode %d\n",
821 __func__, dereg_top.mode);
822
823 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &dereg_top);
824 if (ret < 0) {
825 pr_err("%s: Deregister topologies failed %d\n",
826 __func__, ret);
827 goto done;
828 }
829
830 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
831 (q6core_lcl.bus_bw_resp_received == 1),
832 msecs_to_jiffies(TIMEOUT_MS));
833 if (!ret) {
834 pr_err("%s: wait_event timeout for Deregister topologies\n",
835 __func__);
836 goto done;
837 }
838done:
839 return ret;
840}
841
842static int q6core_send_custom_topologies(void)
843{
844 int ret = 0;
845 int ret2 = 0;
846 struct cal_block_data *cal_block = NULL;
847 struct avcs_cmd_register_topologies reg_top;
848
849 if (!q6core_is_adsp_ready()) {
850 pr_err("%s: ADSP is not ready!\n", __func__);
851 return -ENODEV;
852 }
853
854 memset(&reg_top, 0, sizeof(reg_top));
855 mutex_lock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
856 mutex_lock(&q6core_lcl.cmd_lock);
857
858 cal_block = cal_utils_get_only_cal_block(
859 q6core_lcl.cal_data[CUST_TOP_CAL]);
860 if (cal_block == NULL) {
861 pr_debug("%s: cal block is NULL!\n", __func__);
862 goto unlock;
863 }
864 if (cal_block->cal_data.size <= 0) {
865 pr_debug("%s: cal size is %zd not sending\n",
866 __func__, cal_block->cal_data.size);
867 goto unlock;
868 }
869
870 q6core_dereg_all_custom_topologies();
871
872 ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0,
873 (uint32_t *)&cal_block->map_data.map_size, 1,
874 &cal_block->map_data.q6map_handle);
875 if (!ret) {
876 pr_err("%s: q6core_map_memory_regions failed\n", __func__);
877 goto unlock;
878 }
879
880 reg_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
881 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
882 reg_top.hdr.pkt_size = sizeof(reg_top);
883 reg_top.hdr.src_svc = APR_SVC_ADSP_CORE;
884 reg_top.hdr.src_domain = APR_DOMAIN_APPS;
885 reg_top.hdr.src_port = 0;
886 reg_top.hdr.dest_svc = APR_SVC_ADSP_CORE;
887 reg_top.hdr.dest_domain = APR_DOMAIN_ADSP;
888 reg_top.hdr.dest_port = 0;
889 reg_top.hdr.token = 0;
890 reg_top.hdr.opcode = AVCS_CMD_REGISTER_TOPOLOGIES;
891 reg_top.payload_addr_lsw =
892 lower_32_bits(cal_block->cal_data.paddr);
893 reg_top.payload_addr_msw =
894 msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
895 reg_top.mem_map_handle = cal_block->map_data.q6map_handle;
896 reg_top.payload_size = cal_block->cal_data.size;
897
898 q6core_lcl.adsp_status = 0;
899 q6core_lcl.bus_bw_resp_received = 0;
900
901 pr_debug("%s: Register topologies addr %pK, size %zd, map handle %d\n",
902 __func__, &cal_block->cal_data.paddr, cal_block->cal_data.size,
903 cal_block->map_data.q6map_handle);
904
905 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &reg_top);
906 if (ret < 0) {
907 pr_err("%s: Register topologies failed %d\n",
908 __func__, ret);
909 goto unmap;
910 }
911
912 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
913 (q6core_lcl.bus_bw_resp_received == 1),
914 msecs_to_jiffies(TIMEOUT_MS));
915 if (!ret) {
916 pr_err("%s: wait_event timeout for Register topologies\n",
917 __func__);
918 goto unmap;
919 }
920
921 if (q6core_lcl.adsp_status < 0)
922 ret = q6core_lcl.adsp_status;
923unmap:
924 ret2 = q6core_memory_unmap_regions(cal_block->map_data.q6map_handle);
925 if (!ret2) {
926 pr_err("%s: q6core_memory_unmap_regions failed for map handle %d\n",
927 __func__, cal_block->map_data.q6map_handle);
928 ret = ret2;
929 goto unlock;
930 }
931
932unlock:
933 mutex_unlock(&q6core_lcl.cmd_lock);
934 mutex_unlock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
935
936 return ret;
937}
938
939static int get_cal_type_index(int32_t cal_type)
940{
941 int ret = -EINVAL;
942
943 switch (cal_type) {
944 case AUDIO_CORE_METAINFO_CAL_TYPE:
945 ret = META_CAL;
946 break;
947 case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE:
948 ret = CUST_TOP_CAL;
949 break;
950 default:
951 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
952 }
953 return ret;
954}
955
956static int q6core_alloc_cal(int32_t cal_type,
957 size_t data_size, void *data)
958{
959 int ret = 0;
960 int cal_index;
961
962 cal_index = get_cal_type_index(cal_type);
963 if (cal_index < 0) {
964 pr_err("%s: could not get cal index %d!\n",
965 __func__, cal_index);
966 ret = -EINVAL;
967 goto done;
968 }
969
970
971 ret = cal_utils_alloc_cal(data_size, data,
972 q6core_lcl.cal_data[cal_index], 0, NULL);
973 if (ret < 0) {
974 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
975 __func__, ret, cal_type);
976 goto done;
977 }
978done:
979 return ret;
980}
981
982static int q6core_dealloc_cal(int32_t cal_type,
983 size_t data_size, void *data)
984{
985 int ret = 0;
986 int cal_index;
987
988 cal_index = get_cal_type_index(cal_type);
989 if (cal_index < 0) {
990 pr_err("%s: could not get cal index %d!\n",
991 __func__, cal_index);
992 ret = -EINVAL;
993 goto done;
994 }
995
996
997 ret = cal_utils_dealloc_cal(data_size, data,
998 q6core_lcl.cal_data[cal_index]);
999 if (ret < 0) {
1000 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
1001 __func__, ret, cal_type);
1002 goto done;
1003 }
1004done:
1005 return ret;
1006}
1007
1008static int q6core_set_cal(int32_t cal_type,
1009 size_t data_size, void *data)
1010{
1011 int ret = 0;
1012 int cal_index;
1013
1014 cal_index = get_cal_type_index(cal_type);
1015 if (cal_index < 0) {
1016 pr_err("%s: could not get cal index %d!\n",
1017 __func__, cal_index);
1018 ret = -EINVAL;
1019 goto done;
1020 }
1021
1022
1023 ret = cal_utils_set_cal(data_size, data,
1024 q6core_lcl.cal_data[cal_index], 0, NULL);
1025 if (ret < 0) {
1026 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
1027 __func__, ret, cal_type);
1028 goto done;
1029 }
1030
1031 if (cal_index == CUST_TOP_CAL)
1032 ret = q6core_send_custom_topologies();
1033done:
1034 return ret;
1035}
1036
1037static void q6core_delete_cal_data(void)
1038{
1039 pr_debug("%s:\n", __func__);
1040
1041 cal_utils_destroy_cal_types(CORE_MAX_CAL, q6core_lcl.cal_data);
1042}
1043
1044
1045static int q6core_init_cal_data(void)
1046{
1047 int ret = 0;
1048 struct cal_type_info cal_type_info[] = {
1049 {{AUDIO_CORE_METAINFO_CAL_TYPE,
1050 {q6core_alloc_cal, q6core_dealloc_cal, NULL,
1051 q6core_set_cal, NULL, NULL} },
1052 {NULL, NULL, cal_utils_match_buf_num} },
1053
1054 {{CORE_CUSTOM_TOPOLOGIES_CAL_TYPE,
1055 {q6core_alloc_cal, q6core_dealloc_cal, NULL,
1056 q6core_set_cal, NULL, NULL} },
1057 {NULL, NULL, cal_utils_match_buf_num} }
1058 };
1059 pr_debug("%s:\n", __func__);
1060
1061 ret = cal_utils_create_cal_types(CORE_MAX_CAL,
1062 q6core_lcl.cal_data, cal_type_info);
1063 if (ret < 0) {
1064 pr_err("%s: could not create cal type!\n",
1065 __func__);
1066 goto err;
1067 }
1068
1069 return ret;
1070err:
1071 q6core_delete_cal_data();
1072 return ret;
1073}
1074
1075static int __init core_init(void)
1076{
Laxminath Kasam38070be2017-08-17 18:21:59 +05301077 memset(&q6core_lcl, 0, sizeof(struct q6core_str));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301078 init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301079 init_waitqueue_head(&q6core_lcl.cmd_req_wait);
Laxminath Kasam38070be2017-08-17 18:21:59 +05301080 init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301081 q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
1082 mutex_init(&q6core_lcl.cmd_lock);
Laxminath Kasam38070be2017-08-17 18:21:59 +05301083 mutex_init(&q6core_lcl.ver_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301084
1085 q6core_init_cal_data();
Laxminath Kasam38070be2017-08-17 18:21:59 +05301086
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301087 return 0;
1088}
1089module_init(core_init);
1090
1091static void __exit core_exit(void)
1092{
1093 mutex_destroy(&q6core_lcl.cmd_lock);
Laxminath Kasam38070be2017-08-17 18:21:59 +05301094 mutex_destroy(&q6core_lcl.ver_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301095 q6core_delete_cal_data();
1096}
1097module_exit(core_exit);
1098MODULE_DESCRIPTION("ADSP core driver");
1099MODULE_LICENSE("GPL v2");