blob: 2cf511716693722770349b84e6c9afbad3f24f39 [file] [log] [blame]
Vignesh Kulothungan65b7a172017-12-12 17:33:24 -08001/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302 *
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>
Vignesh Kulothungana3f8bf62018-02-21 14:17:48 -080021#include <linux/sysfs.h>
22#include <linux/kobject.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053023#include <dsp/q6core.h>
24#include <dsp/audio_cal_utils.h>
Laxminath Kasam38070be2017-08-17 18:21:59 +053025#include <dsp/apr_audio-v2.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053026#include <ipc/apr.h>
Laxminath Kasam38070be2017-08-17 18:21:59 +053027#include "adsp_err.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053028
29#define TIMEOUT_MS 1000
30/*
31 * AVS bring up in the modem is optimitized for the new
32 * Sub System Restart design and 100 milliseconds timeout
33 * is sufficient to make sure the Q6 will be ready.
34 */
35#define Q6_READY_TIMEOUT_MS 100
36
37enum {
38 META_CAL,
39 CUST_TOP_CAL,
40 CORE_MAX_CAL
41};
42
Laxminath Kasam38070be2017-08-17 18:21:59 +053043enum ver_query_status {
44 VER_QUERY_UNATTEMPTED,
45 VER_QUERY_UNSUPPORTED,
46 VER_QUERY_SUPPORTED
47};
48
49struct q6core_avcs_ver_info {
50 enum ver_query_status status;
Siena Richard2d0102d2017-09-05 11:15:45 -070051 struct avcs_fwk_ver_info *ver_info;
Laxminath Kasam38070be2017-08-17 18:21:59 +053052};
53
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053054struct q6core_str {
55 struct apr_svc *core_handle_q;
56 wait_queue_head_t bus_bw_req_wait;
57 wait_queue_head_t cmd_req_wait;
Laxminath Kasam38070be2017-08-17 18:21:59 +053058 wait_queue_head_t avcs_fwk_ver_req_wait;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053059 u32 bus_bw_resp_received;
60 enum cmd_flags {
61 FLAG_NONE,
62 FLAG_CMDRSP_LICENSE_RESULT
63 } cmd_resp_received_flag;
Laxminath Kasam38070be2017-08-17 18:21:59 +053064 u32 avcs_fwk_ver_resp_received;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053065 struct mutex cmd_lock;
Laxminath Kasam38070be2017-08-17 18:21:59 +053066 struct mutex ver_lock;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053067 union {
68 struct avcs_cmdrsp_get_license_validation_result
69 cmdrsp_license_result;
70 } cmd_resp_payload;
71 u32 param;
72 struct cal_type_data *cal_data[CORE_MAX_CAL];
73 uint32_t mem_map_cal_handle;
74 int32_t adsp_status;
Laxminath Kasam38070be2017-08-17 18:21:59 +053075 struct q6core_avcs_ver_info q6core_avcs_ver_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053076};
77
78static struct q6core_str q6core_lcl;
79
80struct generic_get_data_ {
81 int valid;
82 int size_in_ints;
83 int ints[];
84};
85static struct generic_get_data_ *generic_get_data;
86
Vignesh Kulothungana3f8bf62018-02-21 14:17:48 -080087static DEFINE_MUTEX(kset_lock);
88static struct kset *audio_uevent_kset;
89
90static int q6core_init_uevent_kset(void)
91{
92 int ret = 0;
93
94 mutex_lock(&kset_lock);
95 if (audio_uevent_kset)
96 goto done;
97
98 /* Create a kset under /sys/kernel/ */
99 audio_uevent_kset = kset_create_and_add("q6audio", NULL, kernel_kobj);
100 if (!audio_uevent_kset) {
101 pr_err("%s: error creating uevent kernel set", __func__);
102 ret = -EINVAL;
103 }
104done:
105 mutex_unlock(&kset_lock);
106 return ret;
107}
108
109static void q6core_destroy_uevent_kset(void)
110{
111 if (audio_uevent_kset) {
112 kset_unregister(audio_uevent_kset);
113 audio_uevent_kset = NULL;
114 }
115}
116
117/**
118 * q6core_init_uevent_data - initialize kernel object required to send uevents.
119 *
120 * @uevent_data: uevent data (dynamically allocated memory).
121 * @name: name of the kernel object.
122 *
123 * Returns 0 on success or error otherwise.
124 */
125int q6core_init_uevent_data(struct audio_uevent_data *uevent_data, char *name)
126{
127 int ret = -EINVAL;
128
129 if (!uevent_data || !name)
130 return ret;
131
132 ret = q6core_init_uevent_kset();
133 if (ret)
134 return ret;
135
136 /* Set kset for kobject before initializing the kobject */
137 uevent_data->kobj.kset = audio_uevent_kset;
138
139 /* Initialize kobject and add it to kernel */
140 ret = kobject_init_and_add(&uevent_data->kobj, &uevent_data->ktype,
141 NULL, "%s", name);
142 if (ret) {
143 pr_err("%s: error initializing uevent kernel object: %d",
144 __func__, ret);
145 kobject_put(&uevent_data->kobj);
146 return ret;
147 }
148
149 /* Send kobject add event to the system */
150 kobject_uevent(&uevent_data->kobj, KOBJ_ADD);
151
152 return ret;
153}
154EXPORT_SYMBOL(q6core_init_uevent_data);
155
156/**
157 * q6core_destroy_uevent_data - destroy kernel object.
158 *
159 * @uevent_data: uevent data.
160 */
161void q6core_destroy_uevent_data(struct audio_uevent_data *uevent_data)
162{
163 if (uevent_data)
164 kobject_put(&uevent_data->kobj);
165}
166EXPORT_SYMBOL(q6core_destroy_uevent_data);
167
168/**
169 * q6core_send_uevent - send uevent to userspace.
170 *
171 * @uevent_data: uevent data.
172 * @event: event to send.
173 *
174 * Returns 0 on success or error otherwise.
175 */
176int q6core_send_uevent(struct audio_uevent_data *uevent_data, char *event)
177{
178 char *env[] = { event, NULL };
179
180 if (!event || !uevent_data)
181 return -EINVAL;
182
183 return kobject_uevent_env(&uevent_data->kobj, KOBJ_CHANGE, env);
184}
185EXPORT_SYMBOL(q6core_send_uevent);
186
Laxminath Kasam38070be2017-08-17 18:21:59 +0530187static int parse_fwk_version_info(uint32_t *payload)
188{
Siena Richard2d0102d2017-09-05 11:15:45 -0700189 size_t ver_size;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530190 int num_services;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530191
192 pr_debug("%s: Payload info num services %d\n",
193 __func__, payload[4]);
Siena Richard2d0102d2017-09-05 11:15:45 -0700194
Laxminath Kasam38070be2017-08-17 18:21:59 +0530195 /*
196 * payload1[4] is the number of services running on DSP
197 * Based on this info, we copy the payload into core
198 * avcs version info structure.
199 */
200 num_services = payload[4];
Laxminath Kasam38070be2017-08-17 18:21:59 +0530201 if (num_services > VSS_MAX_AVCS_NUM_SERVICES) {
202 pr_err("%s: num_services: %d greater than max services: %d\n",
203 __func__, num_services, VSS_MAX_AVCS_NUM_SERVICES);
Siena Richard2d0102d2017-09-05 11:15:45 -0700204 return -EINVAL;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530205 }
Siena Richard2d0102d2017-09-05 11:15:45 -0700206
Laxminath Kasam38070be2017-08-17 18:21:59 +0530207 /*
208 * Dynamically allocate memory for all
209 * the services based on num_services
210 */
Siena Richard2d0102d2017-09-05 11:15:45 -0700211 ver_size = sizeof(struct avcs_get_fwk_version) +
212 num_services * sizeof(struct avs_svc_api_info);
Aditya Bavanari9ae2dde2018-01-09 11:35:29 +0530213
Siena Richard2d0102d2017-09-05 11:15:45 -0700214 q6core_lcl.q6core_avcs_ver_info.ver_info =
215 kzalloc(ver_size, GFP_ATOMIC);
216 if (q6core_lcl.q6core_avcs_ver_info.ver_info == NULL)
217 return -ENOMEM;
218
219 memcpy(q6core_lcl.q6core_avcs_ver_info.ver_info, (uint8_t *) payload,
220 ver_size);
221 return 0;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530222}
223
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530224static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
225{
226 uint32_t *payload1;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530227 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530228
229 if (data == NULL) {
230 pr_err("%s: data argument is null\n", __func__);
231 return -EINVAL;
232 }
233
234 pr_debug("%s: core msg: payload len = %u, apr resp opcode = 0x%x\n",
235 __func__,
236 data->payload_size, data->opcode);
237
238 switch (data->opcode) {
239
240 case APR_BASIC_RSP_RESULT:{
241
242 if (data->payload_size == 0) {
243 pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
244 __func__);
245 return 0;
246 }
247
248 payload1 = data->payload;
249
250 switch (payload1[0]) {
251
252 case AVCS_CMD_SHARED_MEM_UNMAP_REGIONS:
253 pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS status[0x%x]\n",
254 __func__, payload1[1]);
255 q6core_lcl.bus_bw_resp_received = 1;
256 wake_up(&q6core_lcl.bus_bw_req_wait);
257 break;
258 case AVCS_CMD_SHARED_MEM_MAP_REGIONS:
259 pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_MAP_REGIONS status[0x%x]\n",
260 __func__, payload1[1]);
261 q6core_lcl.bus_bw_resp_received = 1;
262 wake_up(&q6core_lcl.bus_bw_req_wait);
263 break;
264 case AVCS_CMD_REGISTER_TOPOLOGIES:
265 pr_debug("%s: Cmd = AVCS_CMD_REGISTER_TOPOLOGIES status[0x%x]\n",
266 __func__, payload1[1]);
267 /* -ADSP status to match Linux error standard */
268 q6core_lcl.adsp_status = -payload1[1];
269 q6core_lcl.bus_bw_resp_received = 1;
270 wake_up(&q6core_lcl.bus_bw_req_wait);
271 break;
272 case AVCS_CMD_DEREGISTER_TOPOLOGIES:
273 pr_debug("%s: Cmd = AVCS_CMD_DEREGISTER_TOPOLOGIES status[0x%x]\n",
274 __func__, payload1[1]);
275 q6core_lcl.bus_bw_resp_received = 1;
276 wake_up(&q6core_lcl.bus_bw_req_wait);
277 break;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530278 case AVCS_CMD_GET_FWK_VERSION:
279 pr_debug("%s: Cmd = AVCS_CMD_GET_FWK_VERSION status[%s]\n",
280 __func__, adsp_err_get_err_str(payload1[1]));
281 /* ADSP status to match Linux error standard */
282 q6core_lcl.adsp_status = -payload1[1];
283 if (payload1[1] == ADSP_EUNSUPPORTED)
284 q6core_lcl.q6core_avcs_ver_info.status =
285 VER_QUERY_UNSUPPORTED;
286 q6core_lcl.avcs_fwk_ver_resp_received = 1;
287 wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
288 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530289 default:
290 pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
291 __func__,
292 payload1[0], payload1[1], data->opcode);
293 break;
294 }
295 break;
296 }
297
298 case RESET_EVENTS:{
299 pr_debug("%s: Reset event received in Core service\n",
300 __func__);
Tanya Dixit861a8fa2017-09-12 15:38:21 +0530301 /*
302 * no reset for q6core_avcs_ver_info done as
303 * the data will not change after SSR
304 */
305 apr_reset(q6core_lcl.core_handle_q);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530306 q6core_lcl.core_handle_q = NULL;
307 break;
308 }
309 case AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS:
310 payload1 = data->payload;
311 pr_debug("%s: AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS handle %d\n",
312 __func__, payload1[0]);
313 q6core_lcl.mem_map_cal_handle = payload1[0];
314 q6core_lcl.bus_bw_resp_received = 1;
315 wake_up(&q6core_lcl.bus_bw_req_wait);
316 break;
317 case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
318 payload1 = data->payload;
319 q6core_lcl.param = payload1[0];
320 pr_debug("%s: Received ADSP get state response 0x%x\n",
321 __func__, q6core_lcl.param);
322 /* ensure .param is updated prior to .bus_bw_resp_received */
323 wmb();
324 q6core_lcl.bus_bw_resp_received = 1;
325 wake_up(&q6core_lcl.bus_bw_req_wait);
326 break;
327 case AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT:
328 payload1 = data->payload;
329 pr_debug("%s: cmd = LICENSE_VALIDATION_RESULT, result = 0x%x\n",
330 __func__, payload1[0]);
331 q6core_lcl.cmd_resp_payload.cmdrsp_license_result.result
332 = payload1[0];
333 q6core_lcl.cmd_resp_received_flag = FLAG_CMDRSP_LICENSE_RESULT;
334 wake_up(&q6core_lcl.cmd_req_wait);
335 break;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530336 case AVCS_CMDRSP_GET_FWK_VERSION:
337 pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
338 __func__);
339 payload1 = data->payload;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530340 ret = parse_fwk_version_info(payload1);
Vignesh Kulothungan65b7a172017-12-12 17:33:24 -0800341 if (ret < 0) {
342 q6core_lcl.adsp_status = ret;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530343 pr_err("%s: Failed to parse payload:%d\n",
344 __func__, ret);
Vignesh Kulothungan65b7a172017-12-12 17:33:24 -0800345 } else {
346 q6core_lcl.q6core_avcs_ver_info.status =
347 VER_QUERY_SUPPORTED;
348 }
Aditya Bavanari9ae2dde2018-01-09 11:35:29 +0530349 q6core_lcl.avcs_fwk_ver_resp_received = 1;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530350 wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
351 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530352 default:
353 pr_err("%s: Message id from adsp core svc: 0x%x\n",
354 __func__, data->opcode);
355 if (generic_get_data) {
356 generic_get_data->valid = 1;
357 generic_get_data->size_in_ints =
358 data->payload_size/sizeof(int);
359 pr_debug("callback size = %i\n",
360 data->payload_size);
361 memcpy(generic_get_data->ints, data->payload,
362 data->payload_size);
363 q6core_lcl.bus_bw_resp_received = 1;
364 wake_up(&q6core_lcl.bus_bw_req_wait);
365 break;
366 }
367 break;
368 }
369
370 return 0;
371}
372
373void ocm_core_open(void)
374{
375 if (q6core_lcl.core_handle_q == NULL)
376 q6core_lcl.core_handle_q = apr_register("ADSP", "CORE",
377 aprv2_core_fn_q, 0xFFFFFFFF, NULL);
378 pr_debug("%s: Open_q %pK\n", __func__, q6core_lcl.core_handle_q);
379 if (q6core_lcl.core_handle_q == NULL)
Laxminath Kasamc1880702018-04-04 10:59:57 +0530380 pr_err_ratelimited("%s: Unable to register CORE\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530381}
382
383struct cal_block_data *cal_utils_get_cal_block_by_key(
384 struct cal_type_data *cal_type, uint32_t key)
385{
386 struct list_head *ptr, *next;
387 struct cal_block_data *cal_block = NULL;
388 struct audio_cal_info_metainfo *metainfo;
389
390 list_for_each_safe(ptr, next,
391 &cal_type->cal_blocks) {
392
393 cal_block = list_entry(ptr,
394 struct cal_block_data, list);
395 metainfo = (struct audio_cal_info_metainfo *)
396 cal_block->cal_info;
397 if (metainfo->nKey != key) {
398 pr_debug("%s: metainfo key mismatch!!! found:%x, needed:%x\n",
399 __func__, metainfo->nKey, key);
400 } else {
401 pr_debug("%s: metainfo key match found", __func__);
402 return cal_block;
403 }
404 }
405 return NULL;
406}
407
Laxminath Kasam38070be2017-08-17 18:21:59 +0530408static int q6core_send_get_avcs_fwk_ver_cmd(void)
409{
410 struct apr_hdr avcs_ver_cmd;
411 int ret;
412
413 avcs_ver_cmd.hdr_field =
414 APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
415 APR_PKT_VER);
416 avcs_ver_cmd.pkt_size = sizeof(struct apr_hdr);
417 avcs_ver_cmd.src_port = 0;
418 avcs_ver_cmd.dest_port = 0;
419 avcs_ver_cmd.token = 0;
420 avcs_ver_cmd.opcode = AVCS_CMD_GET_FWK_VERSION;
421
422 q6core_lcl.adsp_status = 0;
423 q6core_lcl.avcs_fwk_ver_resp_received = 0;
424
425 ret = apr_send_pkt(q6core_lcl.core_handle_q,
426 (uint32_t *) &avcs_ver_cmd);
427 if (ret < 0) {
428 pr_err("%s: failed to send apr packet, ret=%d\n", __func__,
429 ret);
430 goto done;
431 }
432
433 ret = wait_event_timeout(q6core_lcl.avcs_fwk_ver_req_wait,
434 (q6core_lcl.avcs_fwk_ver_resp_received == 1),
435 msecs_to_jiffies(TIMEOUT_MS));
436 if (!ret) {
437 pr_err("%s: wait_event timeout for AVCS fwk version info\n",
438 __func__);
439 ret = -ETIMEDOUT;
440 goto done;
441 }
442
443 if (q6core_lcl.adsp_status < 0) {
444 /*
445 * adsp_err_get_err_str expects a positive value but we store
446 * the DSP error as negative to match the Linux error standard.
447 * Pass in the negated value so adsp_err_get_err_str returns
448 * the correct string.
449 */
450 pr_err("%s: DSP returned error[%s]\n", __func__,
451 adsp_err_get_err_str(-q6core_lcl.adsp_status));
452 ret = adsp_err_get_lnx_err_code(q6core_lcl.adsp_status);
453 goto done;
454 }
455
456 ret = 0;
457
458done:
459 return ret;
460}
461
462int q6core_get_service_version(uint32_t service_id,
463 struct avcs_fwk_ver_info *ver_info,
464 size_t size)
465{
Siena Richard2d0102d2017-09-05 11:15:45 -0700466 struct avcs_fwk_ver_info *cached_ver_info = NULL;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530467 int i;
468 uint32_t num_services;
Siena Richard2d0102d2017-09-05 11:15:45 -0700469 size_t ver_size;
470 int ret;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530471
472 if (ver_info == NULL) {
Siena Richard2d0102d2017-09-05 11:15:45 -0700473 pr_err("%s: ver_info is NULL\n", __func__);
Laxminath Kasam38070be2017-08-17 18:21:59 +0530474 return -EINVAL;
475 }
476
Siena Richard2d0102d2017-09-05 11:15:45 -0700477 ret = q6core_get_fwk_version_size(service_id);
478 if (ret < 0) {
479 pr_err("%s: Failed to get service size for service id %d with error %d\n",
480 __func__, service_id, ret);
481 return ret;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530482 }
483
Siena Richard2d0102d2017-09-05 11:15:45 -0700484 ver_size = ret;
485 if (ver_size != size) {
486 pr_err("%s: Expected size %zu and provided size %zu do not match\n",
487 __func__, ver_size, size);
488 return -EINVAL;
489 }
490
491 cached_ver_info = q6core_lcl.q6core_avcs_ver_info.ver_info;
492 num_services = cached_ver_info->avcs_fwk_version.num_services;
493
494 if (service_id == AVCS_SERVICE_ID_ALL) {
495 memcpy(ver_info, cached_ver_info, ver_size);
496 return 0;
497 }
498
499 ver_info->avcs_fwk_version = cached_ver_info->avcs_fwk_version;
500 for (i = 0; i < num_services; i++) {
501 if (cached_ver_info->services[i].service_id == service_id) {
502 ver_info->services[0] = cached_ver_info->services[i];
503 return 0;
504 }
505 }
506 pr_err("%s: No service matching service ID %d\n", __func__, service_id);
507 return -EINVAL;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530508}
509EXPORT_SYMBOL(q6core_get_service_version);
510
Siena Richard2d0102d2017-09-05 11:15:45 -0700511size_t q6core_get_fwk_version_size(uint32_t service_id)
Laxminath Kasam38070be2017-08-17 18:21:59 +0530512{
513 int ret = 0;
514 uint32_t num_services;
515
Laxminath Kasam38070be2017-08-17 18:21:59 +0530516 mutex_lock(&(q6core_lcl.ver_lock));
517 pr_debug("%s: q6core_avcs_ver_info.status(%d)\n", __func__,
518 q6core_lcl.q6core_avcs_ver_info.status);
519
520 switch (q6core_lcl.q6core_avcs_ver_info.status) {
521 case VER_QUERY_SUPPORTED:
522 pr_debug("%s: AVCS FWK version query already attempted\n",
523 __func__);
Laxminath Kasam38070be2017-08-17 18:21:59 +0530524 break;
525 case VER_QUERY_UNSUPPORTED:
526 ret = -EOPNOTSUPP;
527 break;
528 case VER_QUERY_UNATTEMPTED:
529 pr_debug("%s: Attempting AVCS FWK version query\n", __func__);
530 if (q6core_is_adsp_ready()) {
531 ret = q6core_send_get_avcs_fwk_ver_cmd();
Laxminath Kasam38070be2017-08-17 18:21:59 +0530532 } else {
533 pr_err("%s: ADSP is not ready to query version\n",
534 __func__);
535 ret = -ENODEV;
536 }
537 break;
538 default:
539 pr_err("%s: Invalid version query status %d\n", __func__,
540 q6core_lcl.q6core_avcs_ver_info.status);
541 ret = -EINVAL;
542 break;
543 }
544 mutex_unlock(&(q6core_lcl.ver_lock));
545
Siena Richard2d0102d2017-09-05 11:15:45 -0700546 if (ret)
547 goto done;
Laxminath Kasam38070be2017-08-17 18:21:59 +0530548
Aditya Bavanari9ae2dde2018-01-09 11:35:29 +0530549 if (q6core_lcl.q6core_avcs_ver_info.ver_info != NULL) {
550 num_services = q6core_lcl.q6core_avcs_ver_info.ver_info
551 ->avcs_fwk_version.num_services;
552 } else {
553 pr_err("%s: ver_info is NULL\n", __func__);
554 ret = -EINVAL;
555 goto done;
556 }
Siena Richard2d0102d2017-09-05 11:15:45 -0700557
558 ret = sizeof(struct avcs_get_fwk_version);
559 if (service_id == AVCS_SERVICE_ID_ALL)
560 ret += num_services * sizeof(struct avs_svc_api_info);
561 else
562 ret += sizeof(struct avs_svc_api_info);
563done:
Laxminath Kasam38070be2017-08-17 18:21:59 +0530564 return ret;
565}
Siena Richard2d0102d2017-09-05 11:15:45 -0700566EXPORT_SYMBOL(q6core_get_fwk_version_size);
Laxminath Kasam38070be2017-08-17 18:21:59 +0530567
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530568/**
569 * core_set_license -
570 * command to set license for module
571 *
572 * @key: license key hash
573 * @module_id: DSP Module ID
574 *
575 * Returns 0 on success or error on failure
576 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530577int32_t core_set_license(uint32_t key, uint32_t module_id)
578{
579 struct avcs_cmd_set_license *cmd_setl = NULL;
580 struct cal_block_data *cal_block = NULL;
581 int rc = 0, packet_size = 0;
582
583 pr_debug("%s: key:0x%x, id:0x%x\n", __func__, key, module_id);
584
585 mutex_lock(&(q6core_lcl.cmd_lock));
586 if (q6core_lcl.cal_data[META_CAL] == NULL) {
587 pr_err("%s: cal_data not initialized yet!!\n", __func__);
588 rc = -EINVAL;
589 goto cmd_unlock;
590 }
591
592 mutex_lock(&((q6core_lcl.cal_data[META_CAL])->lock));
593 cal_block = cal_utils_get_cal_block_by_key(
594 q6core_lcl.cal_data[META_CAL], key);
595 if (cal_block == NULL ||
596 cal_block->cal_data.kvaddr == NULL ||
597 cal_block->cal_data.size <= 0) {
598 pr_err("%s: Invalid cal block to send", __func__);
599 rc = -EINVAL;
600 goto cal_data_unlock;
601 }
602
603 packet_size = sizeof(struct avcs_cmd_set_license) +
604 cal_block->cal_data.size;
605 /*round up total packet_size to next 4 byte boundary*/
606 packet_size = ((packet_size + 0x3)>>2)<<2;
607
608 cmd_setl = kzalloc(packet_size, GFP_KERNEL);
609 if (cmd_setl == NULL) {
610 rc = -ENOMEM;
611 goto cal_data_unlock;
612 }
613
614 ocm_core_open();
615 if (q6core_lcl.core_handle_q == NULL) {
616 pr_err("%s: apr registration for CORE failed\n", __func__);
617 rc = -ENODEV;
618 goto fail_cmd;
619 }
620
621 cmd_setl->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
622 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
623 cmd_setl->hdr.pkt_size = packet_size;
624 cmd_setl->hdr.src_port = 0;
625 cmd_setl->hdr.dest_port = 0;
626 cmd_setl->hdr.token = 0;
627 cmd_setl->hdr.opcode = AVCS_CMD_SET_LICENSE;
628 cmd_setl->id = module_id;
629 cmd_setl->overwrite = 1;
630 cmd_setl->size = cal_block->cal_data.size;
631 memcpy((uint8_t *)cmd_setl + sizeof(struct avcs_cmd_set_license),
632 cal_block->cal_data.kvaddr,
633 cal_block->cal_data.size);
634 pr_info("%s: Set license opcode=0x%x, id =0x%x, size = %d\n",
635 __func__, cmd_setl->hdr.opcode,
636 cmd_setl->id, cmd_setl->size);
637 rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)cmd_setl);
638 if (rc < 0)
639 pr_err("%s: SET_LICENSE failed op[0x%x]rc[%d]\n",
640 __func__, cmd_setl->hdr.opcode, rc);
641
642fail_cmd:
643 kfree(cmd_setl);
644cal_data_unlock:
645 mutex_unlock(&((q6core_lcl.cal_data[META_CAL])->lock));
646cmd_unlock:
647 mutex_unlock(&(q6core_lcl.cmd_lock));
648
649 return rc;
650}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530651EXPORT_SYMBOL(core_set_license);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530652
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530653/**
654 * core_get_license_status -
655 * command to retrieve license status for module
656 *
657 * @module_id: DSP Module ID
658 *
659 * Returns 0 on success or error on failure
660 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530661int32_t core_get_license_status(uint32_t module_id)
662{
663 struct avcs_cmd_get_license_validation_result get_lvr_cmd;
664 int ret = 0;
665
666 pr_debug("%s: module_id 0x%x", __func__, module_id);
667
668 mutex_lock(&(q6core_lcl.cmd_lock));
669 ocm_core_open();
670 if (q6core_lcl.core_handle_q == NULL) {
671 pr_err("%s: apr registration for CORE failed\n", __func__);
672 ret = -ENODEV;
673 goto fail_cmd;
674 }
675
676 get_lvr_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
677 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
678 get_lvr_cmd.hdr.pkt_size =
679 sizeof(struct avcs_cmd_get_license_validation_result);
680
681 get_lvr_cmd.hdr.src_port = 0;
682 get_lvr_cmd.hdr.dest_port = 0;
683 get_lvr_cmd.hdr.token = 0;
684 get_lvr_cmd.hdr.opcode = AVCS_CMD_GET_LICENSE_VALIDATION_RESULT;
685 get_lvr_cmd.id = module_id;
686
687
688 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &get_lvr_cmd);
689 if (ret < 0) {
690 pr_err("%s: license_validation request failed, err %d\n",
691 __func__, ret);
692 ret = -EREMOTE;
693 goto fail_cmd;
694 }
695
696 q6core_lcl.cmd_resp_received_flag &= ~(FLAG_CMDRSP_LICENSE_RESULT);
697 mutex_unlock(&(q6core_lcl.cmd_lock));
698 ret = wait_event_timeout(q6core_lcl.cmd_req_wait,
699 (q6core_lcl.cmd_resp_received_flag ==
700 FLAG_CMDRSP_LICENSE_RESULT),
701 msecs_to_jiffies(TIMEOUT_MS));
702 mutex_lock(&(q6core_lcl.cmd_lock));
703 if (!ret) {
704 pr_err("%s: wait_event timeout for CMDRSP_LICENSE_RESULT\n",
705 __func__);
706 ret = -ETIME;
707 goto fail_cmd;
708 }
709 q6core_lcl.cmd_resp_received_flag &= ~(FLAG_CMDRSP_LICENSE_RESULT);
710 ret = q6core_lcl.cmd_resp_payload.cmdrsp_license_result.result;
711
712fail_cmd:
713 mutex_unlock(&(q6core_lcl.cmd_lock));
714 pr_info("%s: cmdrsp_license_result.result = 0x%x for module 0x%x\n",
715 __func__, ret, module_id);
716 return ret;
717}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530718EXPORT_SYMBOL(core_get_license_status);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530719
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530720/**
721 * core_set_dolby_manufacturer_id -
722 * command to set dolby manufacturer id
723 *
724 * @manufacturer_id: Dolby manufacturer id
725 *
726 * Returns 0 on success or error on failure
727 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530728uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
729{
730 struct adsp_dolby_manufacturer_id payload;
731 int rc = 0;
732
733 pr_debug("%s: manufacturer_id :%d\n", __func__, manufacturer_id);
734 mutex_lock(&(q6core_lcl.cmd_lock));
735 ocm_core_open();
736 if (q6core_lcl.core_handle_q) {
737 payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
738 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
739 payload.hdr.pkt_size =
740 sizeof(struct adsp_dolby_manufacturer_id);
741 payload.hdr.src_port = 0;
742 payload.hdr.dest_port = 0;
743 payload.hdr.token = 0;
744 payload.hdr.opcode = ADSP_CMD_SET_DOLBY_MANUFACTURER_ID;
745 payload.manufacturer_id = manufacturer_id;
746 pr_debug("%s: Send Dolby security opcode=0x%x manufacturer ID = %d\n",
747 __func__,
748 payload.hdr.opcode, payload.manufacturer_id);
749 rc = apr_send_pkt(q6core_lcl.core_handle_q,
750 (uint32_t *)&payload);
751 if (rc < 0)
752 pr_err("%s: SET_DOLBY_MANUFACTURER_ID failed op[0x%x]rc[%d]\n",
753 __func__, payload.hdr.opcode, rc);
754 }
755 mutex_unlock(&(q6core_lcl.cmd_lock));
756 return rc;
757}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530758EXPORT_SYMBOL(core_set_dolby_manufacturer_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530759
760/**
761 * q6core_is_adsp_ready - check adsp ready status
762 *
763 * Returns true if adsp is ready otherwise returns false
764 */
765bool q6core_is_adsp_ready(void)
766{
767 int rc = 0;
768 bool ret = false;
769 struct apr_hdr hdr;
770
771 pr_debug("%s: enter\n", __func__);
772 memset(&hdr, 0, sizeof(hdr));
773 hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
774 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
775 hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
776 hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
777
778 mutex_lock(&(q6core_lcl.cmd_lock));
779 ocm_core_open();
780 if (q6core_lcl.core_handle_q) {
781 q6core_lcl.bus_bw_resp_received = 0;
782 rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
783 if (rc < 0) {
Laxminath Kasamc1880702018-04-04 10:59:57 +0530784 pr_err_ratelimited("%s: Get ADSP state APR packet send event %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530785 __func__, rc);
786 goto bail;
787 }
788
789 rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
790 (q6core_lcl.bus_bw_resp_received == 1),
791 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
792 if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
793 /* ensure to read updated param by callback thread */
794 rmb();
795 ret = !!q6core_lcl.param;
796 }
797 }
798bail:
799 pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
800 mutex_unlock(&(q6core_lcl.cmd_lock));
801 return ret;
802}
803EXPORT_SYMBOL(q6core_is_adsp_ready);
804
805static int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
806 uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle)
807{
808 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
809 struct avs_shared_map_region_payload *mregions = NULL;
810 void *mmap_region_cmd = NULL;
811 void *payload = NULL;
812 int ret = 0;
813 int i = 0;
814 int cmd_size = 0;
815
816 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
817 + sizeof(struct avs_shared_map_region_payload)
818 * bufcnt;
819
820 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
821 if (mmap_region_cmd == NULL)
822 return -ENOMEM;
823
824 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
825 mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
826 APR_HDR_LEN(APR_HDR_SIZE),
827 APR_PKT_VER);
828 mmap_regions->hdr.pkt_size = cmd_size;
829 mmap_regions->hdr.src_port = 0;
830 mmap_regions->hdr.dest_port = 0;
831 mmap_regions->hdr.token = 0;
832 mmap_regions->hdr.opcode = AVCS_CMD_SHARED_MEM_MAP_REGIONS;
833 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
834 mmap_regions->num_regions = bufcnt & 0x00ff;
835 mmap_regions->property_flag = 0x00;
836
837 payload = ((u8 *) mmap_region_cmd +
838 sizeof(struct avs_cmd_shared_mem_map_regions));
839 mregions = (struct avs_shared_map_region_payload *)payload;
840
841 for (i = 0; i < bufcnt; i++) {
842 mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
843 mregions->shm_addr_msw =
844 msm_audio_populate_upper_32_bits(buf_add[i]);
845 mregions->mem_size_bytes = bufsz[i];
846 ++mregions;
847 }
848
849 pr_debug("%s: sending memory map, addr %pK, size %d, bufcnt = %d\n",
850 __func__, buf_add, bufsz[0], mmap_regions->num_regions);
851
852 *map_handle = 0;
853 q6core_lcl.bus_bw_resp_received = 0;
854 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
855 mmap_regions);
856 if (ret < 0) {
857 pr_err("%s: mmap regions failed %d\n",
858 __func__, ret);
859 ret = -EINVAL;
860 goto done;
861 }
862
863 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
864 (q6core_lcl.bus_bw_resp_received == 1),
865 msecs_to_jiffies(TIMEOUT_MS));
866 if (!ret) {
867 pr_err("%s: timeout. waited for memory map\n", __func__);
868 ret = -ETIME;
869 goto done;
870 }
871
872 *map_handle = q6core_lcl.mem_map_cal_handle;
873done:
874 kfree(mmap_region_cmd);
875 return ret;
876}
877
878static int q6core_memory_unmap_regions(uint32_t mem_map_handle)
879{
880 struct avs_cmd_shared_mem_unmap_regions unmap_regions;
881 int ret = 0;
882
883 memset(&unmap_regions, 0, sizeof(unmap_regions));
884 unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
885 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
886 unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
887 unmap_regions.hdr.src_svc = APR_SVC_ADSP_CORE;
888 unmap_regions.hdr.src_domain = APR_DOMAIN_APPS;
889 unmap_regions.hdr.src_port = 0;
890 unmap_regions.hdr.dest_svc = APR_SVC_ADSP_CORE;
891 unmap_regions.hdr.dest_domain = APR_DOMAIN_ADSP;
892 unmap_regions.hdr.dest_port = 0;
893 unmap_regions.hdr.token = 0;
894 unmap_regions.hdr.opcode = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS;
895 unmap_regions.mem_map_handle = mem_map_handle;
896
897 q6core_lcl.bus_bw_resp_received = 0;
898
899 pr_debug("%s: unmap regions map handle %d\n",
900 __func__, mem_map_handle);
901
902 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
903 &unmap_regions);
904 if (ret < 0) {
905 pr_err("%s: unmap regions failed %d\n",
906 __func__, ret);
907 ret = -EINVAL;
908 goto done;
909 }
910
911 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
912 (q6core_lcl.bus_bw_resp_received == 1),
913 msecs_to_jiffies(TIMEOUT_MS));
914 if (!ret) {
915 pr_err("%s: timeout. waited for memory_unmap\n",
916 __func__);
917 ret = -ETIME;
918 goto done;
919 }
920done:
921 return ret;
922}
923
924static int q6core_dereg_all_custom_topologies(void)
925{
926 int ret = 0;
927 struct avcs_cmd_deregister_topologies dereg_top;
928
929 memset(&dereg_top, 0, sizeof(dereg_top));
930 dereg_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
931 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
932 dereg_top.hdr.pkt_size = sizeof(dereg_top);
933 dereg_top.hdr.src_svc = APR_SVC_ADSP_CORE;
934 dereg_top.hdr.src_domain = APR_DOMAIN_APPS;
935 dereg_top.hdr.src_port = 0;
936 dereg_top.hdr.dest_svc = APR_SVC_ADSP_CORE;
937 dereg_top.hdr.dest_domain = APR_DOMAIN_ADSP;
938 dereg_top.hdr.dest_port = 0;
939 dereg_top.hdr.token = 0;
940 dereg_top.hdr.opcode = AVCS_CMD_DEREGISTER_TOPOLOGIES;
941 dereg_top.payload_addr_lsw = 0;
942 dereg_top.payload_addr_msw = 0;
943 dereg_top.mem_map_handle = 0;
944 dereg_top.payload_size = 0;
945 dereg_top.mode = AVCS_MODE_DEREGISTER_ALL_CUSTOM_TOPOLOGIES;
946
947 q6core_lcl.bus_bw_resp_received = 0;
948
949 pr_debug("%s: Deregister topologies mode %d\n",
950 __func__, dereg_top.mode);
951
952 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &dereg_top);
953 if (ret < 0) {
954 pr_err("%s: Deregister topologies failed %d\n",
955 __func__, ret);
956 goto done;
957 }
958
959 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
960 (q6core_lcl.bus_bw_resp_received == 1),
961 msecs_to_jiffies(TIMEOUT_MS));
962 if (!ret) {
963 pr_err("%s: wait_event timeout for Deregister topologies\n",
964 __func__);
965 goto done;
966 }
967done:
968 return ret;
969}
970
971static int q6core_send_custom_topologies(void)
972{
973 int ret = 0;
974 int ret2 = 0;
975 struct cal_block_data *cal_block = NULL;
976 struct avcs_cmd_register_topologies reg_top;
977
978 if (!q6core_is_adsp_ready()) {
979 pr_err("%s: ADSP is not ready!\n", __func__);
980 return -ENODEV;
981 }
982
983 memset(&reg_top, 0, sizeof(reg_top));
984 mutex_lock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
985 mutex_lock(&q6core_lcl.cmd_lock);
986
987 cal_block = cal_utils_get_only_cal_block(
988 q6core_lcl.cal_data[CUST_TOP_CAL]);
989 if (cal_block == NULL) {
990 pr_debug("%s: cal block is NULL!\n", __func__);
991 goto unlock;
992 }
993 if (cal_block->cal_data.size <= 0) {
994 pr_debug("%s: cal size is %zd not sending\n",
995 __func__, cal_block->cal_data.size);
996 goto unlock;
997 }
998
999 q6core_dereg_all_custom_topologies();
1000
1001 ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0,
1002 (uint32_t *)&cal_block->map_data.map_size, 1,
1003 &cal_block->map_data.q6map_handle);
1004 if (!ret) {
1005 pr_err("%s: q6core_map_memory_regions failed\n", __func__);
1006 goto unlock;
1007 }
1008
1009 reg_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1010 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1011 reg_top.hdr.pkt_size = sizeof(reg_top);
1012 reg_top.hdr.src_svc = APR_SVC_ADSP_CORE;
1013 reg_top.hdr.src_domain = APR_DOMAIN_APPS;
1014 reg_top.hdr.src_port = 0;
1015 reg_top.hdr.dest_svc = APR_SVC_ADSP_CORE;
1016 reg_top.hdr.dest_domain = APR_DOMAIN_ADSP;
1017 reg_top.hdr.dest_port = 0;
1018 reg_top.hdr.token = 0;
1019 reg_top.hdr.opcode = AVCS_CMD_REGISTER_TOPOLOGIES;
1020 reg_top.payload_addr_lsw =
1021 lower_32_bits(cal_block->cal_data.paddr);
1022 reg_top.payload_addr_msw =
1023 msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
1024 reg_top.mem_map_handle = cal_block->map_data.q6map_handle;
1025 reg_top.payload_size = cal_block->cal_data.size;
1026
1027 q6core_lcl.adsp_status = 0;
1028 q6core_lcl.bus_bw_resp_received = 0;
1029
1030 pr_debug("%s: Register topologies addr %pK, size %zd, map handle %d\n",
1031 __func__, &cal_block->cal_data.paddr, cal_block->cal_data.size,
1032 cal_block->map_data.q6map_handle);
1033
1034 ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &reg_top);
1035 if (ret < 0) {
1036 pr_err("%s: Register topologies failed %d\n",
1037 __func__, ret);
1038 goto unmap;
1039 }
1040
1041 ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
1042 (q6core_lcl.bus_bw_resp_received == 1),
1043 msecs_to_jiffies(TIMEOUT_MS));
1044 if (!ret) {
1045 pr_err("%s: wait_event timeout for Register topologies\n",
1046 __func__);
1047 goto unmap;
1048 }
1049
1050 if (q6core_lcl.adsp_status < 0)
1051 ret = q6core_lcl.adsp_status;
1052unmap:
1053 ret2 = q6core_memory_unmap_regions(cal_block->map_data.q6map_handle);
1054 if (!ret2) {
1055 pr_err("%s: q6core_memory_unmap_regions failed for map handle %d\n",
1056 __func__, cal_block->map_data.q6map_handle);
1057 ret = ret2;
1058 goto unlock;
1059 }
1060
1061unlock:
1062 mutex_unlock(&q6core_lcl.cmd_lock);
1063 mutex_unlock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
1064
1065 return ret;
1066}
1067
1068static int get_cal_type_index(int32_t cal_type)
1069{
1070 int ret = -EINVAL;
1071
1072 switch (cal_type) {
1073 case AUDIO_CORE_METAINFO_CAL_TYPE:
1074 ret = META_CAL;
1075 break;
1076 case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE:
1077 ret = CUST_TOP_CAL;
1078 break;
1079 default:
1080 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
1081 }
1082 return ret;
1083}
1084
1085static int q6core_alloc_cal(int32_t cal_type,
1086 size_t data_size, void *data)
1087{
1088 int ret = 0;
1089 int cal_index;
1090
1091 cal_index = get_cal_type_index(cal_type);
1092 if (cal_index < 0) {
1093 pr_err("%s: could not get cal index %d!\n",
1094 __func__, cal_index);
1095 ret = -EINVAL;
1096 goto done;
1097 }
1098
1099
1100 ret = cal_utils_alloc_cal(data_size, data,
1101 q6core_lcl.cal_data[cal_index], 0, NULL);
1102 if (ret < 0) {
1103 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
1104 __func__, ret, cal_type);
1105 goto done;
1106 }
1107done:
1108 return ret;
1109}
1110
1111static int q6core_dealloc_cal(int32_t cal_type,
1112 size_t data_size, void *data)
1113{
1114 int ret = 0;
1115 int cal_index;
1116
1117 cal_index = get_cal_type_index(cal_type);
1118 if (cal_index < 0) {
1119 pr_err("%s: could not get cal index %d!\n",
1120 __func__, cal_index);
1121 ret = -EINVAL;
1122 goto done;
1123 }
1124
1125
1126 ret = cal_utils_dealloc_cal(data_size, data,
1127 q6core_lcl.cal_data[cal_index]);
1128 if (ret < 0) {
1129 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
1130 __func__, ret, cal_type);
1131 goto done;
1132 }
1133done:
1134 return ret;
1135}
1136
1137static int q6core_set_cal(int32_t cal_type,
1138 size_t data_size, void *data)
1139{
1140 int ret = 0;
1141 int cal_index;
1142
1143 cal_index = get_cal_type_index(cal_type);
1144 if (cal_index < 0) {
1145 pr_err("%s: could not get cal index %d!\n",
1146 __func__, cal_index);
1147 ret = -EINVAL;
1148 goto done;
1149 }
1150
1151
1152 ret = cal_utils_set_cal(data_size, data,
1153 q6core_lcl.cal_data[cal_index], 0, NULL);
1154 if (ret < 0) {
1155 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
1156 __func__, ret, cal_type);
1157 goto done;
1158 }
1159
1160 if (cal_index == CUST_TOP_CAL)
1161 ret = q6core_send_custom_topologies();
1162done:
1163 return ret;
1164}
1165
1166static void q6core_delete_cal_data(void)
1167{
1168 pr_debug("%s:\n", __func__);
1169
1170 cal_utils_destroy_cal_types(CORE_MAX_CAL, q6core_lcl.cal_data);
1171}
1172
1173
1174static int q6core_init_cal_data(void)
1175{
1176 int ret = 0;
1177 struct cal_type_info cal_type_info[] = {
1178 {{AUDIO_CORE_METAINFO_CAL_TYPE,
1179 {q6core_alloc_cal, q6core_dealloc_cal, NULL,
1180 q6core_set_cal, NULL, NULL} },
1181 {NULL, NULL, cal_utils_match_buf_num} },
1182
1183 {{CORE_CUSTOM_TOPOLOGIES_CAL_TYPE,
1184 {q6core_alloc_cal, q6core_dealloc_cal, NULL,
1185 q6core_set_cal, NULL, NULL} },
1186 {NULL, NULL, cal_utils_match_buf_num} }
1187 };
1188 pr_debug("%s:\n", __func__);
1189
1190 ret = cal_utils_create_cal_types(CORE_MAX_CAL,
1191 q6core_lcl.cal_data, cal_type_info);
1192 if (ret < 0) {
1193 pr_err("%s: could not create cal type!\n",
1194 __func__);
1195 goto err;
1196 }
1197
1198 return ret;
1199err:
1200 q6core_delete_cal_data();
1201 return ret;
1202}
1203
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301204int __init core_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301205{
Laxminath Kasam38070be2017-08-17 18:21:59 +05301206 memset(&q6core_lcl, 0, sizeof(struct q6core_str));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301207 init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301208 init_waitqueue_head(&q6core_lcl.cmd_req_wait);
Laxminath Kasam38070be2017-08-17 18:21:59 +05301209 init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301210 q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
1211 mutex_init(&q6core_lcl.cmd_lock);
Laxminath Kasam38070be2017-08-17 18:21:59 +05301212 mutex_init(&q6core_lcl.ver_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301213
1214 q6core_init_cal_data();
Vignesh Kulothungana3f8bf62018-02-21 14:17:48 -08001215 q6core_init_uevent_kset();
Laxminath Kasam38070be2017-08-17 18:21:59 +05301216
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301217 return 0;
1218}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301219
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05301220void core_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301221{
1222 mutex_destroy(&q6core_lcl.cmd_lock);
Laxminath Kasam38070be2017-08-17 18:21:59 +05301223 mutex_destroy(&q6core_lcl.ver_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301224 q6core_delete_cal_data();
Vignesh Kulothungana3f8bf62018-02-21 14:17:48 -08001225 q6core_destroy_uevent_kset();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301226}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301227MODULE_DESCRIPTION("ADSP core driver");
1228MODULE_LICENSE("GPL v2");