blob: 8df449e499e78f035d84fb2a6373a3af0221b3c4 [file] [log] [blame]
Meng Wang688a8672019-01-29 13:43:33 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -07003 * Copyright (c) 2013-2019, Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5#include <linux/fs.h>
6#include <linux/mutex.h>
7#include <linux/wait.h>
8#include <linux/miscdevice.h>
9#include <linux/uaccess.h>
10#include <linux/sched.h>
11#include <linux/miscdevice.h>
12#include <linux/delay.h>
13#include <linux/spinlock.h>
14#include <linux/slab.h>
15#include <linux/debugfs.h>
16#include <linux/time.h>
17#include <linux/atomic.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053018#include <sound/lsm_params.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053019#include <asm/ioctls.h>
20#include <linux/memory.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053021#include <dsp/msm_audio_ion.h>
22#include <dsp/apr_audio-v2.h>
23#include <dsp/q6core.h>
24#include <dsp/q6lsm.h>
25#include <dsp/q6afe-v2.h>
Vignesh Kulothungana65e3012018-01-24 18:03:12 -080026#include <dsp/q6common.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053027#include <dsp/audio_cal_utils.h>
28#include "adsp_err.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053029
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -070030#define APR_TIMEOUT (HZ)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053031#define LSM_SAMPLE_RATE 16000
32#define QLSM_PARAM_ID_MINOR_VERSION 1
33#define QLSM_PARAM_ID_MINOR_VERSION_2 2
34
35static int lsm_afe_port;
36
37enum {
38 LSM_CUSTOM_TOP_IDX,
39 LSM_TOP_IDX,
40 LSM_CAL_IDX,
41 LSM_MAX_CAL_IDX
42};
43
44enum {
45 CMD_STATE_CLEARED = 0,
46 CMD_STATE_WAIT_RESP = 1,
47};
48
49enum {
50 LSM_INVALID_SESSION_ID = 0,
51 LSM_MIN_SESSION_ID = 1,
52 LSM_MAX_SESSION_ID = 8,
53 LSM_CONTROL_SESSION = 0x0F,
54};
55
56#define CHECK_SESSION(x) (x < LSM_MIN_SESSION_ID || x > LSM_MAX_SESSION_ID)
57struct lsm_common {
58 void *apr;
59 atomic_t apr_users;
60 struct lsm_client common_client[LSM_MAX_SESSION_ID + 1];
61
62 int set_custom_topology;
63 struct cal_type_data *cal_data[LSM_MAX_CAL_IDX];
64
65 struct mutex apr_lock;
66};
67
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053068static struct lsm_common lsm_common;
Laxminath Kasam9c09cbd2018-06-30 19:57:10 +053069static DEFINE_MUTEX(session_lock);
70
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053071/*
72 * mmap_handle_p can point either client->sound_model.mem_map_handle or
73 * lsm_common.mmap_handle_for_cal.
74 * mmap_lock must be held while accessing this.
75 */
76static spinlock_t mmap_lock;
77static uint32_t *mmap_handle_p;
78
79static spinlock_t lsm_session_lock;
80static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
81
82static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +053083static int q6lsm_send_cal(struct lsm_client *client,
84 u32 set_params_opcode, struct lsm_params_info_v2 *p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053085static int q6lsm_memory_map_regions(struct lsm_client *client,
86 dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
87 uint32_t *mmap_p);
88static int q6lsm_memory_unmap_regions(struct lsm_client *client,
89 uint32_t handle);
90
Xiaoyu Ye845b66f2019-04-15 15:44:28 -070091struct lsm_client_afe_data {
92 uint64_t fe_id;
93 uint16_t unprocessed_data;
94};
95
96static struct lsm_client_afe_data lsm_client_afe_data[LSM_MAX_SESSION_ID + 1];
97
Laxminath Kasam9c09cbd2018-06-30 19:57:10 +053098static int q6lsm_get_session_id_from_lsm_client(struct lsm_client *client)
99{
100 int n;
101
102 for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
103 if (lsm_session[n] == client)
104 return n;
105 }
Xiaoyu Ye56c0d092019-10-09 21:57:42 -0700106 pr_err("%s: cannot find matching lsm client.\n", __func__);
Laxminath Kasam9c09cbd2018-06-30 19:57:10 +0530107 return LSM_INVALID_SESSION_ID;
108}
109
110static bool q6lsm_is_valid_lsm_client(struct lsm_client *client)
111{
112 return q6lsm_get_session_id_from_lsm_client(client) ? 1 : 0;
113}
114
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530115static int q6lsm_callback(struct apr_client_data *data, void *priv)
116{
117 struct lsm_client *client = (struct lsm_client *)priv;
118 uint32_t token;
119 uint32_t *payload;
120
121 if (!client || !data) {
122 pr_err("%s: client %pK data %pK\n",
123 __func__, client, data);
124 WARN_ON(1);
125 return -EINVAL;
126 }
127
128 if (data->opcode == RESET_EVENTS) {
129 pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
130 __func__, data->opcode, data->reset_event,
131 data->reset_proc);
132
Laxminath Kasam9c09cbd2018-06-30 19:57:10 +0530133 mutex_lock(&session_lock);
134 if (!client || !q6lsm_is_valid_lsm_client(client)) {
135 pr_err("%s: client already freed/invalid, return\n",
136 __func__);
137 mutex_unlock(&session_lock);
138 return 0;
139 }
Xiaoyu Yefb90eb62017-10-10 12:26:08 -0700140 apr_reset(client->apr);
141 client->apr = NULL;
142 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
143 wake_up(&client->cmd_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530144 cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
145 lsm_common.cal_data);
146 mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
147 lsm_common.set_custom_topology = 1;
148 mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
Laxminath Kasam9c09cbd2018-06-30 19:57:10 +0530149 mutex_unlock(&session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530150 return 0;
151 }
152
153 payload = data->payload;
154 pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n"
155 "payload [0] = 0x%x\n", __func__, client->session,
156 data->opcode, data->token, data->payload_size, payload[0]);
157 if (data->opcode == LSM_DATA_EVENT_READ_DONE) {
158 struct lsm_cmd_read_done read_done;
159
160 token = data->token;
Kunlei Zhang16e53592019-01-23 17:18:19 +0800161 if (data->payload_size > sizeof(read_done) ||
162 data->payload_size < 6 * sizeof(payload[0])) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530163 pr_err("%s: read done error payload size %d expected size %zd\n",
164 __func__, data->payload_size,
165 sizeof(read_done));
166 return -EINVAL;
167 }
168 pr_debug("%s: opcode %x status %x lsw %x msw %x mem_map handle %x\n",
169 __func__, data->opcode, payload[0], payload[1],
170 payload[2], payload[3]);
171 read_done.status = payload[0];
172 read_done.buf_addr_lsw = payload[1];
173 read_done.buf_addr_msw = payload[2];
174 read_done.mem_map_handle = payload[3];
175 read_done.total_size = payload[4];
176 read_done.offset = payload[5];
177 if (client->cb)
178 client->cb(data->opcode, data->token,
179 (void *)&read_done,
Kunlei Zhang16e53592019-01-23 17:18:19 +0800180 sizeof(read_done),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530181 client->priv);
182 return 0;
183 } else if (data->opcode == APR_BASIC_RSP_RESULT) {
184 token = data->token;
185 switch (payload[0]) {
186 case LSM_SESSION_CMD_START:
187 case LSM_SESSION_CMD_STOP:
188 case LSM_SESSION_CMD_SET_PARAMS:
189 case LSM_SESSION_CMD_OPEN_TX:
190 case LSM_SESSION_CMD_CLOSE_TX:
191 case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
192 case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
193 case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
194 case LSM_SESSION_CMD_EOB:
195 case LSM_SESSION_CMD_READ:
196 case LSM_SESSION_CMD_OPEN_TX_V2:
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530197 case LSM_SESSION_CMD_OPEN_TX_V3:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530198 case LSM_CMD_ADD_TOPOLOGIES:
199 case LSM_SESSION_CMD_SET_PARAMS_V2:
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800200 case LSM_SESSION_CMD_SET_PARAMS_V3:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530201 if (token != client->session &&
202 payload[0] !=
203 LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
204 pr_err("%s: Invalid session %d receivced expected %d\n",
205 __func__, token, client->session);
206 return -EINVAL;
207 }
Kunlei Zhang16e53592019-01-23 17:18:19 +0800208 if (data->payload_size < 2 * sizeof(payload[0])) {
209 pr_err("%s: payload has invalid size[%d]\n",
210 __func__, data->payload_size);
211 return -EINVAL;
212 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530213 client->cmd_err_code = payload[1];
214 if (client->cmd_err_code)
215 pr_err("%s: cmd 0x%x failed status %d\n",
216 __func__, payload[0], client->cmd_err_code);
217 if (atomic_cmpxchg(&client->cmd_state,
218 CMD_STATE_WAIT_RESP,
219 CMD_STATE_CLEARED) ==
220 CMD_STATE_WAIT_RESP)
221 wake_up(&client->cmd_wait);
222 break;
223 default:
224 pr_debug("%s: Unknown command 0x%x\n",
225 __func__, payload[0]);
226 break;
227 }
228 return 0;
229 }
230
231 if (client->cb)
232 client->cb(data->opcode, data->token, data->payload,
Kunlei Zhang16e53592019-01-23 17:18:19 +0800233 data->payload_size, client->priv);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530234
235 return 0;
236}
237
238static int q6lsm_session_alloc(struct lsm_client *client)
239{
240 unsigned long flags;
241 int n, ret = -ENOMEM;
242
243 spin_lock_irqsave(&lsm_session_lock, flags);
244 for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
245 if (!lsm_session[n]) {
246 lsm_session[n] = client;
247 ret = n;
248 break;
249 }
250 }
251 spin_unlock_irqrestore(&lsm_session_lock, flags);
252 pr_debug("%s: Alloc Session %d", __func__, n);
253 return ret;
254}
255
256static void q6lsm_session_free(struct lsm_client *client)
257{
258 unsigned long flags;
259
260 pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
261 spin_lock_irqsave(&lsm_session_lock, flags);
Meng Wang249b1f92018-03-30 09:21:47 +0800262 lsm_session[client->session] = NULL;
Xiaoyu Ye845b66f2019-04-15 15:44:28 -0700263 lsm_client_afe_data[client->session].fe_id = 0;
264 lsm_client_afe_data[client->session].unprocessed_data = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530265 spin_unlock_irqrestore(&lsm_session_lock, flags);
266 client->session = LSM_INVALID_SESSION_ID;
267}
268
269static void *q6lsm_mmap_apr_reg(void)
270{
271 if (atomic_inc_return(&lsm_common.apr_users) == 1) {
272 lsm_common.apr =
273 apr_register("ADSP", "LSM", q6lsm_mmapcallback,
274 0x0FFFFFFFF, &lsm_common);
275 if (!lsm_common.apr) {
276 pr_debug("%s: Unable to register APR LSM common port\n",
277 __func__);
278 atomic_dec(&lsm_common.apr_users);
279 }
280 }
281 return lsm_common.apr;
282}
283
284static int q6lsm_mmap_apr_dereg(void)
285{
Meng Wangc893cd22019-09-09 09:27:45 +0800286 if (lsm_common.apr) {
287 if (atomic_read(&lsm_common.apr_users) <= 0) {
288 WARN("%s: APR common port already closed\n", __func__);
289 } else {
290 if (atomic_dec_return(&lsm_common.apr_users) == 0) {
291 apr_deregister(lsm_common.apr);
292 pr_debug("%s: APR De-Register common port\n",
293 __func__);
294 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530295 }
296 }
297 return 0;
298}
299
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530300/**
301 * q6lsm_client_alloc -
302 * Allocate session for LSM client
303 *
304 * @cb: callback fn
305 * @priv: private data
306 *
307 * Returns LSM client handle on success or NULL on failure
308 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530309struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv)
310{
311 struct lsm_client *client;
312 int n;
313
314 client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
315 if (!client)
316 return NULL;
317 n = q6lsm_session_alloc(client);
318 if (n <= 0) {
319 kfree(client);
320 return NULL;
321 }
322 client->session = n;
323 client->cb = cb;
324 client->priv = priv;
325 if (CHECK_SESSION(client->session)) {
326 pr_err("%s: Client session %d\n",
327 __func__, client->session);
328 kfree(client);
329 return NULL;
330 }
pavanc8a81c4a2018-06-06 12:13:17 +0530331
332 init_waitqueue_head(&client->cmd_wait);
333 mutex_init(&client->cmd_lock);
334 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
335
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530336 pr_debug("%s: Client Session %d\n", __func__, client->session);
337 client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
338 ((client->session) << 8 | client->session),
339 client);
340
341 if (client->apr == NULL) {
342 pr_err("%s: Registration with APR failed\n", __func__);
343 goto fail;
344 }
345
346 pr_debug("%s: Registering the common port with APR\n", __func__);
347 client->mmap_apr = q6lsm_mmap_apr_reg();
348 if (!client->mmap_apr) {
349 pr_err("%s: APR registration failed\n", __func__);
350 goto fail;
351 }
352
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530353 pr_debug("%s: New client allocated\n", __func__);
354 return client;
355fail:
356 q6lsm_client_free(client);
357 return NULL;
358}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530359EXPORT_SYMBOL(q6lsm_client_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530360
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530361/**
362 * q6lsm_client_free -
363 * Performs LSM client free
364 *
365 * @client: LSM client handle
366 *
367 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530368void q6lsm_client_free(struct lsm_client *client)
369{
370 if (!client)
371 return;
372 if (CHECK_SESSION(client->session)) {
373 pr_err("%s: Invalid Session %d\n", __func__, client->session);
374 return;
375 }
376 apr_deregister(client->apr);
Meng Wanga801ad82019-10-15 11:19:11 +0800377 q6lsm_mmap_apr_dereg();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530378 client->mmap_apr = NULL;
Meng Wang818d4e92019-08-26 16:49:28 +0800379 mutex_lock(&session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530380 q6lsm_session_free(client);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530381 mutex_destroy(&client->cmd_lock);
382 kfree(client);
383 client = NULL;
Laxminath Kasam9c09cbd2018-06-30 19:57:10 +0530384 mutex_unlock(&session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530385}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530386EXPORT_SYMBOL(q6lsm_client_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530387
388/*
389 * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
390 * other thread's wait.
391 * If mmap_handle_p != NULL, disable irq and spin lock to
392 * protect mmap_handle_p
393 */
394static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
395 void *data, bool wait, uint32_t *mmap_p)
396{
397 int ret;
398 unsigned long flags = 0;
399 struct apr_hdr *msg_hdr = (struct apr_hdr *) data;
400
Xiaoyu Yefb90eb62017-10-10 12:26:08 -0700401 if (!handle) {
402 pr_err("%s: handle is NULL\n", __func__);
403 return -EINVAL;
404 }
405
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530406 pr_debug("%s: enter wait %d\n", __func__, wait);
407 if (wait)
408 mutex_lock(&lsm_common.apr_lock);
409 if (mmap_p) {
410 WARN_ON(!wait);
411 spin_lock_irqsave(&mmap_lock, flags);
412 mmap_handle_p = mmap_p;
413 }
414 atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
415 client->cmd_err_code = 0;
416 ret = apr_send_pkt(handle, data);
417 if (mmap_p)
418 spin_unlock_irqrestore(&mmap_lock, flags);
419
420 if (ret < 0) {
421 pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
422 } else if (wait) {
423 ret = wait_event_timeout(client->cmd_wait,
424 (atomic_read(&client->cmd_state) ==
425 CMD_STATE_CLEARED),
426 APR_TIMEOUT);
427 if (likely(ret)) {
428 /* q6 returned error */
429 if (client->cmd_err_code) {
430 pr_err("%s: DSP returned error[%s]\n",
431 __func__, adsp_err_get_err_str(
432 client->cmd_err_code));
433 ret = adsp_err_get_lnx_err_code(
434 client->cmd_err_code);
435 } else {
436 ret = 0;
437 }
438 } else {
439 pr_err("%s: wait timedout, apr_opcode = 0x%x, size = %d\n",
440 __func__, msg_hdr->opcode, msg_hdr->pkt_size);
441 /* ret = 0 means wait timed out */
442 ret = -ETIMEDOUT;
443 }
444 } else {
445 ret = 0;
446 }
447 if (wait)
448 mutex_unlock(&lsm_common.apr_lock);
449
Meng Wangfae34042019-09-03 17:12:59 +0800450 if (mmap_p && *mmap_p == 0)
451 ret = -ENOMEM;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530452 pr_debug("%s: leave ret %d\n", __func__, ret);
453 return ret;
454}
455
456static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
457 uint32_t pkt_size, bool cmd_flg)
458{
459 pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
460 pkt_size, cmd_flg, client->session);
461 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
462 APR_HDR_LEN(sizeof(struct apr_hdr)),
463 APR_PKT_VER);
464 hdr->src_svc = APR_SVC_LSM;
465 hdr->src_domain = APR_DOMAIN_APPS;
466 hdr->dest_svc = APR_SVC_LSM;
467 hdr->dest_domain = APR_DOMAIN_ADSP;
468 hdr->src_port = ((client->session << 8) & 0xFF00) | client->session;
469 hdr->dest_port = ((client->session << 8) & 0xFF00) | client->session;
470 hdr->pkt_size = pkt_size;
471 if (cmd_flg)
472 hdr->token = client->session;
473}
474
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800475static int q6lsm_pack_params(u8 *dest, struct param_hdr_v3 *param_info,
476 u8 *param_data, size_t *final_length,
477 u32 set_param_opcode)
478{
479 bool iid_supported = q6common_is_instance_id_supported();
480 union param_hdrs *param_hdr = NULL;
481 u32 param_size = param_info->param_size;
482 size_t hdr_size;
483 size_t provided_size = *final_length;
484
485 hdr_size = iid_supported ? sizeof(struct param_hdr_v3) :
486 sizeof(struct param_hdr_v2);
487 if (provided_size < hdr_size) {
488 pr_err("%s: Provided size %zu is not large enough, need %zu\n",
489 __func__, provided_size, hdr_size);
490 return -EINVAL;
491 }
492
493 if (iid_supported) {
494 memcpy(dest, param_info, hdr_size);
495 } else {
496 /* MID, PID and structure size are the same in V1 and V2 */
497 param_hdr = (union param_hdrs *) dest;
498 param_hdr->v2.module_id = param_info->module_id;
499 param_hdr->v2.param_id = param_info->param_id;
500
501 switch (set_param_opcode) {
502 case LSM_SESSION_CMD_SET_PARAMS_V2:
503 param_hdr->v2.param_size = param_size;
504 break;
505 case LSM_SESSION_CMD_SET_PARAMS:
506 default:
507 if (param_size > U16_MAX) {
508 pr_err("%s: Invalid param size %d\n", __func__,
509 param_size);
510 return -EINVAL;
511 }
512
513 param_hdr->v1.param_size = param_size;
514 param_hdr->v1.reserved = 0;
515 break;
516 }
517 }
518
519 *final_length = hdr_size;
520
521 if (param_data != NULL) {
522 if (provided_size < hdr_size + param_size) {
523 pr_err("%s: Provided size %zu is not large enough, need %zu\n",
524 __func__, provided_size, hdr_size + param_size);
525 return -EINVAL;
526 }
527 memcpy(dest + hdr_size, param_data, param_size);
528 *final_length += param_size;
529 }
530 return 0;
531}
532
533static int q6lsm_set_params_v2(struct lsm_client *client,
534 struct mem_mapping_hdr *mem_hdr,
535 uint8_t *param_data, uint32_t param_size,
536 uint32_t set_param_opcode)
537{
538 struct lsm_session_cmd_set_params_v2 *lsm_set_param = NULL;
539 uint32_t pkt_size = 0;
540 int ret;
541
542 pkt_size = sizeof(struct lsm_session_cmd_set_params_v2);
543 /* Only include param size in packet size when inband */
544 if (param_data != NULL)
545 pkt_size += param_size;
546
547 lsm_set_param = kzalloc(pkt_size, GFP_KERNEL);
548 if (!lsm_set_param)
549 return -ENOMEM;
550
551 q6lsm_add_hdr(client, &lsm_set_param->apr_hdr, pkt_size, true);
552 lsm_set_param->apr_hdr.opcode = set_param_opcode;
553 lsm_set_param->payload_size = param_size;
554
555 if (mem_hdr != NULL) {
556 lsm_set_param->mem_hdr = *mem_hdr;
557 } else if (param_data != NULL) {
558 memcpy(lsm_set_param->param_data, param_data, param_size);
559 } else {
560 pr_err("%s: Received NULL pointers for both memory header and data\n",
561 __func__);
562 ret = -EINVAL;
563 goto done;
564 }
565
566 ret = q6lsm_apr_send_pkt(client, client->apr, lsm_set_param, true,
567 NULL);
568done:
569 kfree(lsm_set_param);
570 return ret;
571}
572
573static int q6lsm_set_params_v3(struct lsm_client *client,
574 struct mem_mapping_hdr *mem_hdr,
575 uint8_t *param_data, uint32_t param_size)
576{
577 struct lsm_session_cmd_set_params_v3 *lsm_set_param = NULL;
578 uint16_t pkt_size = 0;
579 int ret = 0;
580
581 pkt_size = sizeof(struct lsm_session_cmd_set_params_v3);
582 /* Only include param size in packet size when inband */
583 if (param_data != NULL)
584 pkt_size += param_size;
585
586 lsm_set_param = kzalloc(pkt_size, GFP_KERNEL);
587 if (!lsm_set_param)
588 return -ENOMEM;
589
590 q6lsm_add_hdr(client, &lsm_set_param->apr_hdr, pkt_size, true);
591 lsm_set_param->apr_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS_V3;
592 lsm_set_param->payload_size = param_size;
593
594 if (mem_hdr != NULL) {
595 lsm_set_param->mem_hdr = *mem_hdr;
596 } else if (param_data != NULL) {
597 memcpy(lsm_set_param->param_data, param_data, param_size);
598 } else {
599 pr_err("%s: Received NULL pointers for both memory header and data\n",
600 __func__);
601 ret = -EINVAL;
602 goto done;
603 }
604
605 ret = q6lsm_apr_send_pkt(client, client->apr, lsm_set_param, true,
606 NULL);
607done:
608 kfree(lsm_set_param);
609 return ret;
610}
611
612static int q6lsm_set_params(struct lsm_client *client,
613 struct mem_mapping_hdr *mem_hdr,
614 uint8_t *param_data, uint32_t param_size,
615 uint32_t set_param_opcode)
616
617{
618 if (q6common_is_instance_id_supported())
619 return q6lsm_set_params_v3(client, mem_hdr, param_data,
620 param_size);
621 else
622 return q6lsm_set_params_v2(client, mem_hdr, param_data,
623 param_size, set_param_opcode);
624}
625
626static int q6lsm_pack_and_set_params(struct lsm_client *client,
627 struct param_hdr_v3 *param_info,
628 uint8_t *param_data,
629 uint32_t set_param_opcode)
630
631{
632 u8 *packed_data = NULL;
633 size_t total_size = 0;
634 int ret = 0;
635
636 total_size = sizeof(union param_hdrs) + param_info->param_size;
637 packed_data = kzalloc(total_size, GFP_KERNEL);
638 if (!packed_data)
639 return -ENOMEM;
640
641 ret = q6lsm_pack_params(packed_data, param_info, param_data,
642 &total_size, set_param_opcode);
643 if (ret)
644 goto done;
645
646 ret = q6lsm_set_params(client, NULL, packed_data, total_size,
647 set_param_opcode);
648
649done:
650 kfree(packed_data);
651 return ret;
652}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530653
654static int q6lsm_send_custom_topologies(struct lsm_client *client)
655{
656 int rc;
657 struct cal_block_data *cal_block = NULL;
658 struct lsm_custom_topologies cstm_top;
659
660 if (lsm_common.cal_data[LSM_CUSTOM_TOP_IDX] == NULL) {
661 pr_err("%s: LSM_CUSTOM_TOP_IDX invalid\n", __func__);
662 rc = -EINVAL;
663 goto done;
664 }
665
666 lsm_common.set_custom_topology = 0;
667
668 mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
669 cal_block = cal_utils_get_only_cal_block(
670 lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]);
671 if (!cal_block) {
672 pr_err("%s: Cal block for LSM_CUSTOM_TOP_IDX not found\n",
673 __func__);
674 rc = -EINVAL;
675 goto unlock;
676 }
677
678 if (cal_block->cal_data.size <= 0) {
679 pr_err("%s: Invalid size for LSM_CUSTOM_TOP %zd\n",
680 __func__, cal_block->cal_data.size);
681 rc = -EINVAL;
682 goto unlock;
683 }
684
685 memset(&cstm_top, 0, sizeof(cstm_top));
686 /* Map the memory for out-of-band data */
687 rc = q6lsm_memory_map_regions(client, cal_block->cal_data.paddr,
688 cal_block->map_data.map_size,
689 &cal_block->map_data.q6map_handle);
690 if (rc < 0) {
691 pr_err("%s: Failed to map custom topologied, err = %d\n",
692 __func__, rc);
693 goto unlock;
694 }
695
696 q6lsm_add_hdr(client, &cstm_top.hdr,
697 sizeof(cstm_top), true);
698 cstm_top.hdr.opcode = LSM_CMD_ADD_TOPOLOGIES;
699
700 /*
701 * For ADD_TOPOLOGIES, the dest_port should be 0
702 * Note that source port cannot be zero as it is used
703 * to route the response to a specific client registered
704 * on APR
705 */
706 cstm_top.hdr.dest_port = 0;
707
708 cstm_top.data_payload_addr_lsw =
709 lower_32_bits(cal_block->cal_data.paddr);
710 cstm_top.data_payload_addr_msw =
711 msm_audio_populate_upper_32_bits(
712 cal_block->cal_data.paddr);
713 cstm_top.mem_map_handle = cal_block->map_data.q6map_handle;
714 cstm_top.buffer_size = cal_block->cal_data.size;
715
716 rc = q6lsm_apr_send_pkt(client, client->apr,
717 &cstm_top, true, NULL);
718 if (rc)
719 pr_err("%s: Failed to add custom top, err = %d\n",
720 __func__, rc);
721 /* go ahead and unmap even if custom top failed */
722 rc = q6lsm_memory_unmap_regions(client,
723 cal_block->map_data.q6map_handle);
724 if (rc) {
725 pr_err("%s: Failed to unmap, err = %d\n",
726 __func__, rc);
727 /* Even if mem unmap failed, treat the cmd as success */
728 rc = 0;
729 }
730
731unlock:
732 mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
733done:
734 return rc;
735}
736
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530737static int q6lsm_get_topology_for_app_type(struct lsm_client *client,
738 int app_type, uint32_t *topology)
739{
740 int rc = -EINVAL;
741 struct cal_block_data *cal_block = NULL;
742 struct audio_cal_info_lsm_top *lsm_top;
743 struct list_head *ptr;
744
745 if (lsm_common.cal_data[LSM_TOP_IDX] == NULL) {
746 pr_err("%s: LSM_TOP_IDX invalid\n", __func__);
747 return rc;
748 }
749
750 mutex_lock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
751 list_for_each(ptr, &lsm_common.cal_data[LSM_TOP_IDX]->cal_blocks) {
752 cal_block = list_entry(ptr, struct cal_block_data, list);
753 if (!cal_block) {
754 pr_err("%s: Cal block for LSM_TOP_IDX not found\n",
755 __func__);
756 break;
757 }
758
759 lsm_top = (struct audio_cal_info_lsm_top *) cal_block->cal_info;
760 if (!lsm_top) {
761 pr_err("%s: cal_info for LSM_TOP_IDX not found\n",
762 __func__);
763 break;
764 }
765
766 pr_debug("%s: checking topology 0x%x, app_type 0x%x\n",
767 __func__, lsm_top->topology, lsm_top->app_type);
768
769 if (app_type == 0 || lsm_top->app_type == app_type) {
770 *topology = lsm_top->topology;
771 rc = 0;
772 break;
773 }
774 }
775 mutex_unlock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
776
777 pr_debug("%s: found topology_id = 0x%x, app_type = 0x%x\n",
778 __func__, *topology, app_type);
779
780 return rc;
781}
782
783static int q6lsm_do_open_v3(struct lsm_client *client)
784{
785 int rc, app_type;
786 struct lsm_stream_cmd_open_tx_v3 *open_v3;
Dhananjay Kumar66ae4132018-06-28 19:24:46 +0530787 size_t cmd_size = 0;
788 int stage_idx = LSM_STAGE_INDEX_FIRST;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530789 uint32_t topology_id = 0, *uint32_ptr = NULL;
790
791 cmd_size = sizeof(struct lsm_stream_cmd_open_tx_v3);
792 cmd_size += client->num_stages * sizeof(struct lsm_stream_stage_info);
793 open_v3 = kzalloc(cmd_size, GFP_KERNEL);
794 if (!open_v3)
795 return -ENOMEM;
796
797 q6lsm_add_hdr(client, &open_v3->hdr, cmd_size, true);
798 open_v3->hdr.opcode = LSM_SESSION_CMD_OPEN_TX_V3;
799 open_v3->num_stages = client->num_stages;
800 uint32_ptr = &open_v3->num_stages;
801 uint32_ptr++;
802
803 for (; stage_idx < client->num_stages; stage_idx++) {
804 app_type = client->stage_cfg[stage_idx].app_type;
805 rc = q6lsm_get_topology_for_app_type(client, app_type, &topology_id);
806 if (rc) {
807 pr_err("%s: failed to get topology for stage %d\n",
808 __func__, stage_idx);
809 return -EINVAL;
810 }
811 *uint32_ptr++ = topology_id;
812 *uint32_ptr++ = client->stage_cfg[stage_idx].lpi_enable;
813 }
814
815 rc = q6lsm_apr_send_pkt(client, client->apr, open_v3, true, NULL);
816 if (rc)
817 pr_err("%s: open_v3 failed, err = %d\n", __func__, rc);
818 else
819 client->use_topology = true;
820
821 kfree(open_v3);
822 return rc;
823
824}
825
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530826static int q6lsm_do_open_v2(struct lsm_client *client,
827 uint16_t app_id)
828{
829 int rc;
830 struct cal_block_data *cal_block = NULL;
831 struct audio_cal_info_lsm_top *lsm_top;
832 struct lsm_stream_cmd_open_tx_v2 open_v2;
833
834 if (lsm_common.cal_data[LSM_TOP_IDX] == NULL) {
835 pr_err("%s: LSM_TOP_IDX invalid\n", __func__);
836 rc = -EINVAL;
837 goto done;
838 }
839
840 mutex_lock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
841 cal_block = cal_utils_get_only_cal_block(
842 lsm_common.cal_data[LSM_TOP_IDX]);
843 if (!cal_block) {
844 pr_err("%s: Cal block for LSM_TOP_IDX not found\n",
845 __func__);
846 rc = -EINVAL;
847 goto unlock;
848 }
849
850 lsm_top = (struct audio_cal_info_lsm_top *)
851 cal_block->cal_info;
852 if (!lsm_top) {
853 pr_err("%s: cal_info for LSM_TOP_IDX not found\n",
854 __func__);
855 rc = -EINVAL;
856 goto unlock;
857 }
858
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530859 pr_debug("%s: topology_id = 0x%x, app_type = 0x%x\n",
860 __func__, lsm_top->topology, lsm_top->app_type);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530861
862 if (lsm_top->topology == 0) {
863 pr_err("%s: toplogy id not sent for app_type 0x%x\n",
864 __func__, lsm_top->app_type);
865 rc = -EINVAL;
866 goto unlock;
867 }
868
869 client->app_id = lsm_top->app_type;
870 memset(&open_v2, 0, sizeof(open_v2));
871 q6lsm_add_hdr(client, &open_v2.hdr,
872 sizeof(open_v2), true);
873 open_v2.topology_id = lsm_top->topology;
874 open_v2.hdr.opcode = LSM_SESSION_CMD_OPEN_TX_V2;
875
876 rc = q6lsm_apr_send_pkt(client, client->apr,
877 &open_v2, true, NULL);
878 if (rc)
879 pr_err("%s: open_v2 failed, err = %d\n",
880 __func__, rc);
881 else
882 client->use_topology = true;
883unlock:
884 mutex_unlock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
885done:
886 return rc;
887
888}
889
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530890/**
891 * q6lsm_sm_set_param_data -
892 * Update sound model param data
893 *
894 * @client: LSM client handle
895 * @p_info: param info
896 * @offset: pointer to retrieve size
897 *
898 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530899void q6lsm_sm_set_param_data(struct lsm_client *client,
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530900 struct lsm_params_info_v2 *p_info,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530901 size_t *offset)
902{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800903 struct param_hdr_v3 param_hdr;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530904 int ret;
905 struct lsm_sound_model *sm;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530906
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530907 sm = &client->stage_cfg[p_info->stage_idx].sound_model;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800908 memset(&param_hdr, 0, sizeof(param_hdr));
909
910 param_hdr.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530911 param_hdr.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800912 param_hdr.param_id = p_info->param_id;
Dhananjay Kumar66ae4132018-06-28 19:24:46 +0530913 param_hdr.param_size = p_info->param_size;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800914
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530915 ret = q6lsm_pack_params(sm->data, &param_hdr,
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800916 NULL, offset, LSM_SESSION_CMD_SET_PARAMS_V2);
917 if (ret)
918 pr_err("%s: Failed to pack params, error %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530919}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530920EXPORT_SYMBOL(q6lsm_sm_set_param_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530921
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530922/**
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530923 * q6lsm_support_multi_stage_detection -
924 * check for multi-stage support in adsp lsm framework service
925 *
926 * Returns true if multi-stage support available, else false
927 */
928bool q6lsm_adsp_supports_multi_stage_detection(void)
929{
930 return q6core_get_avcs_api_version_per_service(
931 APRV2_IDS_SERVICE_ID_ADSP_LSM_V) >= LSM_API_VERSION_V3;
932}
933EXPORT_SYMBOL(q6lsm_adsp_supports_multi_stage_detection);
934
935/**
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530936 * q6lsm_open -
937 * command to open LSM session
938 *
939 * @client: LSM client handle
940 * @app_id: App ID for LSM
941 *
942 * Returns 0 on success or error on failure
943 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530944int q6lsm_open(struct lsm_client *client, uint16_t app_id)
945{
946 int rc = 0;
947 struct lsm_stream_cmd_open_tx open;
948
949 /* Add Custom topologies if needed */
950 if (lsm_common.set_custom_topology) {
951 rc = q6lsm_send_custom_topologies(client);
952 if (rc)
953 pr_err("%s: Failed to send cust_top, err = %d\n",
954 __func__, rc);
955 }
956
957 /* Try to open with topology first */
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530958 if ((client->stage_cfg[LSM_STAGE_INDEX_FIRST].app_type != 0) &&
959 q6lsm_adsp_supports_multi_stage_detection())
960 rc = q6lsm_do_open_v3(client);
961 else
962 rc = q6lsm_do_open_v2(client, app_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530963 if (!rc)
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +0530964 /* open_v2/v3 was successful */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530965 goto done;
966
967 pr_debug("%s: try without topology\n",
968 __func__);
969
970 memset(&open, 0, sizeof(open));
971 q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
972 switch (client->app_id) {
973 case LSM_VOICE_WAKEUP_APP_ID_V2:
974 open.app_id = client->app_id;
975 break;
976 default:
977 pr_err("%s: default err 0x%x\n", __func__, client->app_id);
978 rc = -EINVAL;
979 break;
980 }
981
982 open.sampling_rate = LSM_SAMPLE_RATE;
983 open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
984 rc = q6lsm_apr_send_pkt(client, client->apr,
985 &open, true, NULL);
986 if (rc)
987 pr_err("%s: Open failed opcode 0x%x, rc %d\n",
988 __func__, open.hdr.opcode, rc);
989 else
990 client->use_topology = false;
991done:
992 pr_debug("%s: leave %d\n", __func__, rc);
993 return rc;
994}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530995EXPORT_SYMBOL(q6lsm_open);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530996
Vignesh Kulothungana65e3012018-01-24 18:03:12 -0800997static int q6lsm_send_confidence_levels(struct lsm_client *client,
998 struct param_hdr_v3 *param_info,
999 uint32_t set_param_opcode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301000{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001001 struct lsm_param_confidence_levels *conf_levels = NULL;
1002 uint32_t num_conf_levels = client->num_confidence_levels;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301003 uint8_t i = 0;
1004 uint8_t padd_size = 0;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001005 uint32_t param_size = 0;
1006 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301007
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001008 /* Data must be 4 byte aligned so add any necessary padding. */
1009 padd_size = (4 - (num_conf_levels % 4)) - 1;
1010 param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
1011 sizeof(uint8_t);
1012 param_info->param_size = param_size;
1013 pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301014
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001015 conf_levels = kzalloc(param_size, GFP_KERNEL);
1016 if (!conf_levels)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301017 return -ENOMEM;
1018
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001019 conf_levels->num_confidence_levels = num_conf_levels;
1020 pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301021
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001022 memcpy(conf_levels->confidence_levels, client->confidence_levels,
1023 num_conf_levels);
1024 for (i = 0; i < num_conf_levels; i++)
1025 pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
1026 conf_levels->confidence_levels[i]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301027
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001028 rc = q6lsm_pack_and_set_params(client, param_info,
1029 (uint8_t *) conf_levels,
1030 set_param_opcode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301031 if (rc)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001032 pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
1033 __func__, rc);
1034 kfree(conf_levels);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301035 return rc;
1036}
1037
1038static int q6lsm_send_param_opmode(struct lsm_client *client,
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001039 struct param_hdr_v3 *param_info,
1040 u32 set_param_opcode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301041{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001042 struct lsm_param_op_mode op_mode;
1043 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301044
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001045 memset(&op_mode, 0, sizeof(op_mode));
1046 param_info->param_size = sizeof(op_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301047
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001048 op_mode.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1049 op_mode.mode = client->mode;
1050 pr_debug("%s: mode = 0x%x", __func__, op_mode.mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301051
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001052 rc = q6lsm_pack_and_set_params(client, param_info, (uint8_t *) &op_mode,
1053 set_param_opcode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301054 if (rc)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001055 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301056
1057 pr_debug("%s: leave %d\n", __func__, rc);
1058 return rc;
1059}
1060
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301061/**
1062 * set_lsm_port -
1063 * Update LSM AFE port
1064 *
1065 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301066void set_lsm_port(int lsm_port)
1067{
1068 lsm_afe_port = lsm_port;
1069}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301070EXPORT_SYMBOL(set_lsm_port);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301071
1072int get_lsm_port(void)
1073{
1074 return lsm_afe_port;
1075}
1076
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301077/**
Xiaoyu Ye845b66f2019-04-15 15:44:28 -07001078 * q6lsm_set_afe_data_format -
1079 * command to set afe data format
1080 *
1081 * @fe_id: FrontEnd DAI link ID
1082 * @afe_data_format: afe data format
1083 *
1084 * Returns 0 on success or -EINVAL on failure
1085 */
1086int q6lsm_set_afe_data_format(uint64_t fe_id, uint16_t afe_data_format)
1087{
1088 int n = 0;
1089
1090 if (0 != afe_data_format && 1 != afe_data_format)
1091 goto done;
1092
1093 pr_debug("%s: afe data is %s\n", __func__,
1094 afe_data_format ? "unprocessed" : "processed");
1095
1096 for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
1097 if (0 == lsm_client_afe_data[n].fe_id) {
1098 lsm_client_afe_data[n].fe_id = fe_id;
1099 lsm_client_afe_data[n].unprocessed_data =
1100 afe_data_format;
1101 pr_debug("%s: session ID is %d, fe_id is %d\n",
1102 __func__, n, fe_id);
1103 return 0;
1104 }
1105 }
1106
1107 pr_err("%s: all lsm sessions are taken\n", __func__);
1108done:
1109 return -EINVAL;
1110}
1111EXPORT_SYMBOL(q6lsm_set_afe_data_format);
1112
1113/**
1114 * q6lsm_get_afe_data_format -
1115 * command to get afe data format
1116 *
1117 * @fe_id: FrontEnd DAI link ID
1118 * @afe_data_format: afe data format
1119 *
1120 */
1121void q6lsm_get_afe_data_format(uint64_t fe_id, uint16_t *afe_data_format)
1122{
1123 int n = 0;
1124
1125 if (NULL == afe_data_format) {
1126 pr_err("%s: Pointer afe_data_format is NULL\n", __func__);
1127 return;
1128 }
1129
1130 for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
1131 if (fe_id == lsm_client_afe_data[n].fe_id) {
1132 *afe_data_format =
1133 lsm_client_afe_data[n].unprocessed_data;
1134 pr_debug("%s: session: %d, fe_id: %d, afe data: %s\n",
1135 __func__, n, fe_id,
1136 *afe_data_format ? "unprocessed" : "processed");
1137 return;
1138 }
1139 }
1140}
1141EXPORT_SYMBOL(q6lsm_get_afe_data_format);
1142
1143/**
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301144 * q6lsm_set_port_connected -
1145 * command to set LSM port connected
1146 *
1147 * @client: LSM client handle
1148 *
1149 * Returns 0 on success or error on failure
1150 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301151int q6lsm_set_port_connected(struct lsm_client *client)
1152{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001153 struct lsm_param_connect_to_port connect_port;
1154 struct param_hdr_v3 connectport_hdr;
1155 u32 set_param_opcode = 0;
1156 int rc = 0;
1157
1158 memset(&connect_port, 0, sizeof(connect_port));
1159 memset(&connectport_hdr, 0, sizeof(connectport_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301160
1161 if (client->use_topology) {
1162 set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001163 connectport_hdr.module_id = LSM_MODULE_ID_FRAMEWORK;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301164 } else {
1165 set_param_opcode = LSM_SESSION_CMD_SET_PARAMS;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001166 connectport_hdr.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301167 }
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001168 connectport_hdr.instance_id = INSTANCE_ID_0;
1169 connectport_hdr.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
1170 connectport_hdr.param_size = sizeof(connect_port);
1171
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301172 client->connect_to_port = get_lsm_port();
Xiaoyu Ye845b66f2019-04-15 15:44:28 -07001173 if (ADM_LSM_PORT_ID != client->connect_to_port)
1174 q6lsm_get_afe_data_format(client->fe_id,
1175 &client->unprocessed_data);
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001176 connect_port.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1177 connect_port.port_id = client->connect_to_port;
Xiaoyu Ye845b66f2019-04-15 15:44:28 -07001178 connect_port.unprocessed_data = client->unprocessed_data;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301179
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001180 rc = q6lsm_pack_and_set_params(client, &connectport_hdr,
1181 (uint8_t *) &connect_port,
1182 set_param_opcode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301183 if (rc)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001184 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
Xiaoyu Ye845b66f2019-04-15 15:44:28 -07001185
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301186 return rc;
1187}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301188EXPORT_SYMBOL(q6lsm_set_port_connected);
1189
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301190static int q6lsm_send_param_polling_enable(struct lsm_client *client,
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001191 bool poll_en,
1192 struct param_hdr_v3 *param_info,
1193 u32 set_param_opcode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301194{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001195 struct lsm_param_poll_enable polling_enable;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301196 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301197
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001198 memset(&polling_enable, 0, sizeof(polling_enable));
1199 param_info->param_size = sizeof(polling_enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301200
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001201 polling_enable.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1202 polling_enable.polling_enable = (poll_en) ? 1 : 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301203
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001204 rc = q6lsm_pack_and_set_params(client, param_info,
1205 (uint8_t *) &polling_enable,
1206 set_param_opcode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301207 if (rc)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001208 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301209 return rc;
1210}
1211
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301212/**
1213 * q6lsm_set_fwk_mode_cfg -
1214 * command to set LSM fwk mode cfg
1215 *
1216 * @client: LSM client handle
1217 * @event_mode: mode for fwk cfg
1218 *
1219 * Returns 0 on success or error on failure
1220 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301221int q6lsm_set_fwk_mode_cfg(struct lsm_client *client,
1222 uint32_t event_mode)
1223{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001224 struct lsm_param_fwk_mode_cfg fwk_mode_cfg;
1225 struct param_hdr_v3 fwk_mode_cfg_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301226 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301227
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001228 memset(&fwk_mode_cfg, 0, sizeof(fwk_mode_cfg));
1229 memset(&fwk_mode_cfg_hdr, 0, sizeof(fwk_mode_cfg_hdr));
1230
1231 if (!client->use_topology) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301232 pr_debug("%s: Ignore sending event mode\n", __func__);
1233 return rc;
1234 }
1235
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001236 fwk_mode_cfg_hdr.module_id = LSM_MODULE_ID_FRAMEWORK;
1237 fwk_mode_cfg_hdr.instance_id = INSTANCE_ID_0;
1238 fwk_mode_cfg_hdr.param_id = LSM_PARAM_ID_FWK_MODE_CONFIG;
1239 fwk_mode_cfg_hdr.param_size = sizeof(fwk_mode_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301240
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001241 fwk_mode_cfg.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1242 fwk_mode_cfg.mode = event_mode;
1243 pr_debug("%s: mode = %d\n", __func__, fwk_mode_cfg.mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301244
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001245 rc = q6lsm_pack_and_set_params(client, &fwk_mode_cfg_hdr,
1246 (uint8_t *) &fwk_mode_cfg,
1247 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301248 if (rc)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001249 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301250 return rc;
1251}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301252EXPORT_SYMBOL(q6lsm_set_fwk_mode_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301253
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001254static int q6lsm_arrange_mch_map(uint8_t *ch_map, int ch_cnt)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301255{
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001256 int ch_idx;
1257 u8 mch_map[LSM_V3P0_MAX_NUM_CHANNELS] = {
1258 PCM_CHANNEL_FL, PCM_CHANNEL_FR, PCM_CHANNEL_FC,
1259 PCM_CHANNEL_LS, PCM_CHANNEL_RS, PCM_CHANNEL_LFE,
1260 PCM_CHANNEL_LB, PCM_CHANNEL_RB, PCM_CHANNEL_CS};
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301261
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301262
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001263 if (ch_cnt > LSM_V3P0_MAX_NUM_CHANNELS) {
1264 pr_err("%s: invalid num_chan %d\n", __func__, ch_cnt);
1265 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301266 }
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001267
1268 if (ch_cnt == 1) {
1269 ch_map[0] = PCM_CHANNEL_FC;
1270 } else if (ch_cnt == 4) {
1271 ch_map[0] = PCM_CHANNEL_FL;
1272 ch_map[1] = PCM_CHANNEL_FR;
1273 ch_map[2] = PCM_CHANNEL_LS;
1274 ch_map[3] = PCM_CHANNEL_RS;
1275 } else {
1276 for (ch_idx = 0; ch_idx < ch_cnt; ch_idx++)
1277 ch_map[ch_idx] = mch_map[ch_idx];
1278 }
1279
1280 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301281}
1282
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301283/**
1284 * q6lsm_set_media_fmt_params -
1285 * command to set LSM media fmt params
1286 *
1287 * @client: LSM client handle
1288 *
1289 * Returns 0 on success or error on failure
1290 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301291int q6lsm_set_media_fmt_params(struct lsm_client *client)
1292{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001293 struct lsm_param_media_fmt media_fmt;
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001294 struct lsm_hw_params in_param = client->in_hw_params;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001295 struct param_hdr_v3 media_fmt_hdr;
1296 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301297
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001298 memset(&media_fmt, 0, sizeof(media_fmt));
1299 memset(&media_fmt_hdr, 0, sizeof(media_fmt_hdr));
1300
1301 if (!client->use_topology) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301302 pr_debug("%s: Ignore sending media format\n", __func__);
1303 goto err_ret;
1304 }
1305
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001306 media_fmt_hdr.module_id = LSM_MODULE_ID_FRAMEWORK;
1307 media_fmt_hdr.instance_id = INSTANCE_ID_0;
1308 media_fmt_hdr.param_id = LSM_PARAM_ID_MEDIA_FMT;
1309 media_fmt_hdr.param_size = sizeof(media_fmt);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301310
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001311 media_fmt.minor_version = QLSM_PARAM_ID_MINOR_VERSION_2;
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001312 media_fmt.sample_rate = in_param.sample_rate;
1313 media_fmt.num_channels = in_param.num_chs;
1314 media_fmt.bit_width = in_param.sample_size;
1315 rc = q6lsm_arrange_mch_map(media_fmt.channel_mapping,
1316 media_fmt.num_channels);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301317 if (rc)
1318 goto err_ret;
1319
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001320 pr_debug("%s: sample rate= %d, channels %d bit width %d\n", __func__,
1321 media_fmt.sample_rate, media_fmt.num_channels,
1322 media_fmt.bit_width);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301323
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001324 rc = q6lsm_pack_and_set_params(client, &media_fmt_hdr,
1325 (uint8_t *) &media_fmt,
1326 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301327 if (rc)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001328 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301329err_ret:
1330 return rc;
1331}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301332EXPORT_SYMBOL(q6lsm_set_media_fmt_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301333
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07001334/*
1335 * q6lsm_set_media_fmt_v2_params -
1336 * command to set LSM media fmt (version2) params
1337 *
1338 * @client: LSM client handle
1339 *
1340 * Returns 0 on success or error on failure
1341 */
1342int q6lsm_set_media_fmt_v2_params(struct lsm_client *client)
1343{
1344 u8 *param_buf;
1345 struct lsm_param_media_fmt_v2 *media_fmt_v2;
1346 struct lsm_hw_params *in_param = &client->in_hw_params;
1347 struct param_hdr_v3 media_fmt_v2_hdr;
1348 int param_len = 0, rc = 0;
1349
1350 memset(&media_fmt_v2_hdr, 0, sizeof(media_fmt_v2_hdr));
1351
1352 param_len = sizeof(*media_fmt_v2) +
1353 (sizeof(uint8_t) * in_param->num_chs);
1354
1355 /* Add padding to make sure total length is 4-byte aligned */
1356 if (param_len % 4)
1357 param_len += (4 - (param_len % 4));
1358
1359 param_buf = kzalloc(param_len, GFP_KERNEL);
1360 if (!param_buf)
1361 return -ENOMEM;
1362 media_fmt_v2 = (struct lsm_param_media_fmt_v2 *) param_buf;
1363 media_fmt_v2->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1364 media_fmt_v2->sample_rate = in_param->sample_rate;
1365 media_fmt_v2->num_channels = in_param->num_chs;
1366 media_fmt_v2->bit_width = in_param->sample_size;
1367 rc = q6lsm_arrange_mch_map(media_fmt_v2->channel_mapping,
1368 in_param->num_chs);
1369 if (rc)
1370 goto err_mch_map;
1371
1372 media_fmt_v2_hdr.module_id = LSM_MODULE_ID_FRAMEWORK;
1373 media_fmt_v2_hdr.instance_id = INSTANCE_ID_0;
1374 media_fmt_v2_hdr.param_id = LSM_PARAM_ID_MEDIA_FMT_V2;
1375 media_fmt_v2_hdr.param_size = param_len;
1376
1377 pr_debug("%s: sample rate= %d, channels %d bit width %d\n", __func__,
1378 media_fmt_v2->sample_rate, media_fmt_v2->num_channels,
1379 media_fmt_v2->bit_width);
1380
1381 rc = q6lsm_pack_and_set_params(client, &media_fmt_v2_hdr,
1382 param_buf,
1383 LSM_SESSION_CMD_SET_PARAMS_V2);
1384 if (rc)
1385 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
1386
1387err_mch_map:
1388 kfree(param_buf);
1389 return rc;
1390}
1391EXPORT_SYMBOL(q6lsm_set_media_fmt_v2_params);
1392
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301393/**
1394 * q6lsm_set_data -
1395 * Command to set LSM data
1396 *
1397 * @client: LSM client handle
1398 * @mode: LSM detection mode value
1399 * @detectfailure: flag for detect failure
1400 *
1401 * Returns 0 on success or error on failure
1402 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301403int q6lsm_set_data(struct lsm_client *client,
1404 enum lsm_detection_mode mode,
1405 bool detectfailure)
1406{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001407 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301408 int rc = 0;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301409 struct lsm_params_info_v2 p_info = {0};
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001410
1411 memset(&param_hdr, 0, sizeof(param_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301412
1413 if (!client->confidence_levels) {
1414 /*
1415 * It is possible that confidence levels are
1416 * not provided. This is not a error condition.
1417 * Return gracefully without any error
1418 */
1419 pr_debug("%s: no conf levels to set\n",
1420 __func__);
1421 return rc;
1422 }
1423
1424 if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
1425 client->mode = 0x01;
1426 } else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
1427 client->mode = 0x03;
1428 } else {
1429 pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
1430 rc = -EINVAL;
1431 goto err_ret;
1432 }
1433 client->mode |= detectfailure << 2;
1434
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001435 param_hdr.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
1436 param_hdr.instance_id = INSTANCE_ID_0;
1437 param_hdr.param_id = LSM_PARAM_ID_OPERATION_MODE;
1438 rc = q6lsm_send_param_opmode(client, &param_hdr,
1439 LSM_SESSION_CMD_SET_PARAMS);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301440 if (rc) {
1441 pr_err("%s: Failed to set lsm config params %d\n",
1442 __func__, rc);
1443 goto err_ret;
1444 }
1445
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001446 param_hdr.param_id = LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
1447 rc = q6lsm_send_confidence_levels(client, &param_hdr,
1448 LSM_SESSION_CMD_SET_PARAMS);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301449 if (rc) {
1450 pr_err("%s: Failed to send conf_levels, err = %d\n",
1451 __func__, rc);
1452 goto err_ret;
1453 }
1454
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301455 p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
1456 rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, &p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301457 if (rc) {
1458 pr_err("%s: Failed to send calibration data %d\n",
1459 __func__, rc);
1460 goto err_ret;
1461 }
1462
1463err_ret:
1464 return rc;
1465}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301466EXPORT_SYMBOL(q6lsm_set_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301467
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301468/**
1469 * q6lsm_register_sound_model -
1470 * Register LSM snd model
1471 *
1472 * @client: LSM client handle
1473 *
1474 * Returns 0 on success or error on failure
1475 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301476int q6lsm_register_sound_model(struct lsm_client *client,
1477 enum lsm_detection_mode mode,
1478 bool detectfailure)
1479{
1480 int rc;
1481 struct lsm_cmd_reg_snd_model cmd;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301482 struct lsm_sound_model *sm;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301483
1484 memset(&cmd, 0, sizeof(cmd));
1485 rc = q6lsm_set_data(client, mode, detectfailure);
1486 if (rc) {
1487 pr_err("%s: Failed to set lsm data, err = %d\n",
1488 __func__, rc);
1489 return rc;
1490 }
1491
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301492 sm = &client->stage_cfg[LSM_STAGE_INDEX_FIRST].sound_model;
1493
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301494 q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
1495 cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301496 cmd.model_addr_lsw = lower_32_bits(sm->phys);
1497 cmd.model_addr_msw = msm_audio_populate_upper_32_bits(sm->phys);
1498 cmd.model_size = sm->size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301499 /* read updated mem_map_handle by q6lsm_mmapcallback */
1500 rmb();
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301501 cmd.mem_map_handle = sm->mem_map_handle;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301502
1503 pr_debug("%s: addr %pK, size %d, handle 0x%x\n", __func__,
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301504 &sm->phys, cmd.model_size, cmd.mem_map_handle);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301505 rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
1506 if (rc)
1507 pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
1508 cmd.hdr.opcode, rc);
1509 else
1510 pr_debug("%s: Register sound model succeeded\n", __func__);
1511
1512 return rc;
1513}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301514EXPORT_SYMBOL(q6lsm_register_sound_model);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301515
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301516/**
1517 * q6lsm_deregister_sound_model -
1518 * De-register LSM snd model
1519 *
1520 * @client: LSM client handle
1521 *
1522 * Returns 0 on success or error on failure
1523 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301524int q6lsm_deregister_sound_model(struct lsm_client *client)
1525{
1526 int rc;
1527 struct lsm_cmd_reg_snd_model cmd;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301528 /*
1529 * With multi-stage support sm buff allocation/free usage param info
1530 * to check stage index for which this sound model is being set, and
1531 * to check whether sm data is sent using set param command or not.
1532 * Hence, set param ids to '0' to indicate allocation is for legacy
1533 * reg_sm cmd, where buffer for param header need not be allocated,
1534 * also set stage index to LSM_STAGE_INDEX_FIRST.
1535 */
1536 struct lsm_params_info_v2 p_info = {0};
1537 p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301538
1539 if (!client) {
1540 pr_err("APR handle NULL\n");
1541 return -EINVAL;
1542 }
1543 if (!client->apr) {
1544 pr_err("APR client handle NULL\n");
1545 return -EINVAL;
1546 }
1547
1548 if (CHECK_SESSION(client->session)) {
1549 pr_err("%s: session[%d]", __func__, client->session);
1550 return -EINVAL;
1551 }
1552
1553 memset(&cmd, 0, sizeof(cmd));
1554 q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
1555 cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
1556
1557 rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
1558 if (rc) {
1559 pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
1560 cmd.hdr.opcode, rc);
1561 } else {
1562 pr_debug("%s: Deregister sound model succeeded\n", __func__);
1563 }
1564
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301565 q6lsm_snd_model_buf_free(client, &p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301566
1567 return rc;
1568}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301569EXPORT_SYMBOL(q6lsm_deregister_sound_model);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301570
1571static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
1572 u32 pkt_size, u32 cmd_flg, u32 token)
1573{
1574 pr_debug("%s: pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
1575 cmd_flg, client->session);
1576 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1577 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1578 hdr->src_port = 0x00;
1579 hdr->dest_port = client->session;
1580 if (cmd_flg)
1581 hdr->token = token;
1582 hdr->pkt_size = pkt_size;
1583}
1584
1585static int q6lsm_memory_map_regions(struct lsm_client *client,
1586 dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
1587 uint32_t *mmap_p)
1588{
1589 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
1590 struct avs_shared_map_region_payload *mregions = NULL;
1591 void *mmap_region_cmd = NULL;
1592 void *payload = NULL;
1593 int rc;
1594 int cmd_size = 0;
1595
1596 pr_debug("%s: dma_addr_p 0x%pK, dma_buf_sz %d, mmap_p 0x%pK, session %d\n",
1597 __func__, &dma_addr_p, dma_buf_sz, mmap_p,
1598 client->session);
1599 if (CHECK_SESSION(client->session)) {
1600 pr_err("%s: session[%d]", __func__, client->session);
1601 return -EINVAL;
1602 }
1603 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
1604 sizeof(struct avs_shared_map_region_payload);
1605
1606 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
1607 if (!mmap_region_cmd)
1608 return -ENOMEM;
1609
1610 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
1611 q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
1612 (client->session << 8));
1613
1614 mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
1615 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
1616 mmap_regions->num_regions = 1;
1617 mmap_regions->property_flag = 0x00;
1618 payload = ((u8 *)mmap_region_cmd +
1619 sizeof(struct avs_cmd_shared_mem_map_regions));
1620 mregions = (struct avs_shared_map_region_payload *)payload;
1621
1622 mregions->shm_addr_lsw = lower_32_bits(dma_addr_p);
1623 mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(dma_addr_p);
1624 mregions->mem_size_bytes = dma_buf_sz;
1625
1626 rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
1627 true, mmap_p);
1628 if (rc)
1629 pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
1630 __func__, mmap_regions->hdr.opcode, rc);
1631
1632 pr_debug("%s: leave %d\n", __func__, rc);
1633 kfree(mmap_region_cmd);
1634 return rc;
1635}
1636
1637static int q6lsm_memory_unmap_regions(struct lsm_client *client,
1638 uint32_t handle)
1639{
1640 struct avs_cmd_shared_mem_unmap_regions unmap;
1641 int rc = 0;
1642 int cmd_size = 0;
1643
1644 if (CHECK_SESSION(client->session)) {
1645 pr_err("%s: session[%d]", __func__, client->session);
1646 return -EINVAL;
1647 }
1648 cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
1649 q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
1650 true, (client->session << 8));
1651 unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
1652 unmap.mem_map_handle = handle;
1653
1654 pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
1655 rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
1656 NULL);
1657 if (rc)
1658 pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
1659 __func__, unmap.hdr.opcode, rc);
1660
1661 return rc;
1662}
1663
1664static int q6lsm_send_cal(struct lsm_client *client,
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301665 u32 set_params_opcode, struct lsm_params_info_v2 *p_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301666{
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301667 int rc = 0, stage_idx = p_info->stage_idx;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001668 struct mem_mapping_hdr mem_hdr;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301669 dma_addr_t lsm_cal_phy_addr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301670
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001671 memset(&mem_hdr, 0, sizeof(mem_hdr));
1672
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301673 pr_debug("%s: Session id %d\n", __func__, client->session);
1674 if (CHECK_SESSION(client->session)) {
1675 pr_err("%s: session[%d]", __func__, client->session);
1676 return -EINVAL;
1677 }
1678
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301679 lsm_cal_phy_addr = client->stage_cfg[stage_idx].cal_info.phys;
1680 if (lsm_cal_phy_addr != 0) {
1681 lsm_common.common_client[client->session].session = client->session;
1682 mem_hdr.data_payload_addr_lsw = lower_32_bits(lsm_cal_phy_addr);
1683 mem_hdr.data_payload_addr_msw =
1684 msm_audio_populate_upper_32_bits(lsm_cal_phy_addr);
1685 mem_hdr.mem_map_handle =
1686 client->stage_cfg[stage_idx].cal_info.mem_map_handle;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301687
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301688 rc = q6lsm_set_params(client, &mem_hdr, NULL,
1689 client->stage_cfg[stage_idx].cal_info.size, set_params_opcode);
1690 if (rc)
1691 pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
1692 }
1693
1694 return rc;
1695}
1696
1697static int q6lsm_snd_cal_free(struct lsm_client *client,
1698 struct lsm_params_info_v2 *p_info)
1699{
1700 int rc = 0, stage_idx = p_info->stage_idx;
1701 struct lsm_cal_data_info *cal = NULL;
1702
1703 if (!client->stage_cfg[stage_idx].cal_info.data)
1704 return 0;
1705
1706 mutex_lock(&client->cmd_lock);
1707 cal = &client->stage_cfg[stage_idx].cal_info;
1708 if (cal->mem_map_handle != 0) {
1709 rc = q6lsm_memory_unmap_regions(client, cal->mem_map_handle);
1710 if (rc)
1711 pr_err("%s: CMD Memory_unmap_regions failed %d\n",
1712 __func__, rc);
1713 cal->mem_map_handle = 0;
1714 }
1715 msm_audio_ion_free(cal->dma_buf);
1716 cal->dma_buf = NULL;
1717 cal->data = NULL;
1718 cal->phys = 0;
1719 mutex_unlock(&client->cmd_lock);
1720
1721 return rc;
1722}
1723
1724static int q6lsm_snd_cal_alloc(struct lsm_client *client,
1725 struct lsm_params_info_v2 *p_info)
1726{
1727 int rc = 0;
1728 size_t len = 0, total_mem = 0;
1729 struct lsm_cal_data_info *cal = NULL;
1730 struct cal_block_data *cal_block = NULL;
1731 struct audio_cal_info_lsm *lsm_cal_info = NULL;
1732 struct list_head *ptr = NULL;
1733 int app_type, stage_idx = p_info->stage_idx;
1734 bool cal_block_found = false;
1735
1736 app_type = client->stage_cfg[stage_idx].app_type;
1737 pr_debug("%s: app_type %d, stage_idx %d\n",
1738 __func__, app_type, stage_idx);
1739
1740 mutex_lock(&client->cmd_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301741 mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301742 list_for_each(ptr, &lsm_common.cal_data[LSM_CAL_IDX]->cal_blocks) {
1743 cal_block = list_entry(ptr, struct cal_block_data, list);
1744 lsm_cal_info = (struct audio_cal_info_lsm *)
1745 (cal_block) ? cal_block->cal_info : NULL;
1746 if ((cal_block && cal_block->cal_data.paddr) &&
1747 (lsm_cal_info != NULL) &&
1748 (app_type == 0 || app_type == lsm_cal_info->app_type)) {
1749 cal_block_found = true;
1750 len = cal_block->cal_data.size;
1751 break;
1752 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301753 }
1754
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301755 if (!cal_block_found) {
1756 pr_info("%s: cal not found for stage_idx %d\n", __func__, stage_idx);
1757 goto exit;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301758 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301759
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301760 if (!len) {
1761 pr_debug("%s: cal size is 0, for stage_idx %d\n", __func__, stage_idx);
1762 goto exit;
1763 }
1764
1765 cal = &client->stage_cfg[stage_idx].cal_info;
1766 if (cal->data) {
1767 pr_debug("%s: cal data for stage_idx(%d) is already set \n",
1768 __func__, stage_idx);
1769 goto exit;
1770 }
1771
1772 cal->size = len;
1773 total_mem = PAGE_ALIGN(len);
1774 pr_debug("%s: cal info data size %zd Total mem %zd, stage_idx %d\n",
1775 __func__, len, total_mem, stage_idx);
1776
1777 rc = msm_audio_ion_alloc(&cal->dma_buf, total_mem,
1778 &cal->phys, &len, &cal->data);
1779 if (rc) {
1780 pr_err("%s: Audio ION alloc is failed for stage_idx %d, rc = %d\n",
1781 __func__, stage_idx, rc);
1782 cal->dma_buf = NULL;
1783 cal->data = NULL;
1784 goto exit;
1785 }
1786
1787 memcpy(cal->data, (uint32_t *)cal_block->cal_data.kvaddr, cal->size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301788 mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301789 mutex_unlock(&client->cmd_lock);
1790 rc = q6lsm_memory_map_regions(client, cal->phys, len, &cal->mem_map_handle);
1791 if (rc) {
1792 pr_err("%s: CMD Memory_map_regions failed for stage_idx %d, rc = %d\n",
1793 __func__, stage_idx, rc);
1794 cal->mem_map_handle = 0;
1795 goto fail;
1796 }
1797
1798 return 0;
1799
1800exit:
1801 mutex_unlock(&client->cmd_lock);
1802 mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
1803fail:
1804 q6lsm_snd_cal_free(client, p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301805 return rc;
1806}
1807
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301808/**
1809 * q6lsm_snd_model_buf_free -
1810 * Free memory for LSM snd model
1811 *
1812 * @client: LSM client handle
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301813 * @p_info: sound model param info
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301814 *
1815 * Returns 0 on success or error on failure
1816 */
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301817int q6lsm_snd_model_buf_free(struct lsm_client *client,
1818 struct lsm_params_info_v2 *p_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301819{
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301820 int rc = 0, stage_idx = p_info->stage_idx;
1821 struct lsm_sound_model *sm = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301822
1823 pr_debug("%s: Session id %d\n", __func__, client->session);
1824 if (CHECK_SESSION(client->session)) {
1825 pr_err("%s: session[%d]", __func__, client->session);
1826 return -EINVAL;
1827 }
1828
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301829 if (!client->stage_cfg[stage_idx].sound_model.data)
1830 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301831
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301832 mutex_lock(&client->cmd_lock);
1833 sm = &client->stage_cfg[stage_idx].sound_model;
1834 if (sm->mem_map_handle != 0) {
1835 rc = q6lsm_memory_unmap_regions(client, sm->mem_map_handle);
1836 if (rc)
1837 pr_err("%s: CMD Memory_unmap_regions failed %d\n",
1838 __func__, rc);
1839 sm->mem_map_handle = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301840 }
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301841 msm_audio_ion_free(sm->dma_buf);
1842 sm->dma_buf = NULL;
1843 sm->data = NULL;
1844 sm->phys = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301845 mutex_unlock(&client->cmd_lock);
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301846
1847 rc = q6lsm_snd_cal_free(client, p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301848 return rc;
1849}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301850EXPORT_SYMBOL(q6lsm_snd_model_buf_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301851
1852static struct lsm_client *q6lsm_get_lsm_client(int session_id)
1853{
1854 unsigned long flags;
1855 struct lsm_client *client = NULL;
1856
1857 spin_lock_irqsave(&lsm_session_lock, flags);
1858 if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
1859 pr_err("%s: Invalid session %d\n", __func__, session_id);
1860 else if (!lsm_session[session_id])
1861 pr_err("%s: Not an active session %d\n", __func__, session_id);
1862 else
1863 client = lsm_session[session_id];
1864 spin_unlock_irqrestore(&lsm_session_lock, flags);
1865 return client;
1866}
1867
1868/*
1869 * q6lsm_mmapcallback : atomic context
1870 */
1871static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
1872{
1873 unsigned long flags;
1874 uint32_t command;
1875 uint32_t retcode;
1876 uint32_t sid;
1877 const uint32_t *payload = data->payload;
1878 struct lsm_client *client = NULL;
1879
1880 if (data->opcode == RESET_EVENTS) {
1881 sid = (data->token >> 8) & 0x0F;
1882 pr_debug("%s: SSR event received 0x%x, event 0x%x,\n"
1883 "proc 0x%x SID 0x%x\n", __func__, data->opcode,
1884 data->reset_event, data->reset_proc, sid);
Xiaoyu Yefb90eb62017-10-10 12:26:08 -07001885
Kunlei Zhang16e53592019-01-23 17:18:19 +08001886 if (sid < LSM_MIN_SESSION_ID || sid > LSM_MAX_SESSION_ID)
1887 pr_err("%s: Invalid session %d\n", __func__, sid);
Xiaoyu Yefb90eb62017-10-10 12:26:08 -07001888 apr_reset(lsm_common.apr);
1889 lsm_common.apr = NULL;
1890 atomic_set(&lsm_common.apr_users, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301891 cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
1892 lsm_common.cal_data);
1893 lsm_common.set_custom_topology = 1;
1894 return 0;
1895 }
1896
1897 command = payload[0];
1898 retcode = payload[1];
1899 sid = (data->token >> 8) & 0x0F;
1900 pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x SID 0x%x\n",
1901 __func__, data->opcode, command, retcode, sid);
1902 client = q6lsm_get_lsm_client(sid);
1903 if (!client) {
1904 pr_debug("%s: Session %d already freed\n", __func__, sid);
1905 return 0;
1906 }
1907
1908 switch (data->opcode) {
1909 case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
1910 if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
1911 spin_lock_irqsave(&mmap_lock, flags);
1912 *mmap_handle_p = command;
1913 /* spin_unlock_irqrestore implies barrier */
1914 spin_unlock_irqrestore(&mmap_lock, flags);
1915 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
1916 wake_up(&client->cmd_wait);
1917 }
1918 break;
1919 case APR_BASIC_RSP_RESULT:
1920 switch (command) {
1921 case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
1922 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
1923 wake_up(&client->cmd_wait);
1924 break;
1925 case LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS:
1926 if (retcode != 0) {
1927 /* error state, signal to stop waiting */
1928 if (atomic_read(&client->cmd_state) ==
1929 CMD_STATE_WAIT_RESP) {
1930 spin_lock_irqsave(&mmap_lock, flags);
1931 /* implies barrier */
1932 spin_unlock_irqrestore(&mmap_lock,
1933 flags);
1934 atomic_set(&client->cmd_state,
1935 CMD_STATE_CLEARED);
1936 wake_up(&client->cmd_wait);
1937 }
1938 }
1939 break;
1940 default:
1941 pr_warn("%s: Unexpected command 0x%x\n", __func__,
1942 command);
1943 }
1944 /* fallthrough */
1945 default:
1946 pr_debug("%s: command 0x%x return code 0x%x opcode 0x%x\n",
1947 __func__, command, retcode, data->opcode);
1948 break;
1949 }
1950 if (client->cb)
1951 client->cb(data->opcode, data->token,
Kunlei Zhang16e53592019-01-23 17:18:19 +08001952 data->payload, data->payload_size,
1953 client->priv);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301954 return 0;
1955}
1956
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301957/**
1958 * q6lsm_snd_model_buf_alloc -
1959 * Allocate memory for LSM snd model
1960 *
1961 * @client: LSM client handle
1962 * @len: size of sound model
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301963 * @p_info: sound model param info
1964 * p_info->param_id != 0 when using set param to register sound model
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301965 *
1966 * Returns 0 on success or error on failure
1967 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301968int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301969 struct lsm_params_info_v2 *p_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301970{
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301971 int rc = -EINVAL, stage_idx = p_info->stage_idx;
1972 size_t total_mem = 0;
1973 struct lsm_sound_model *sm = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301974
Xiaoyu Yeb58c0712019-11-20 11:08:43 -08001975 if (!client)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301976 return rc;
1977
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301978 pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
1979 __func__, len, stage_idx);
1980
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301981 mutex_lock(&client->cmd_lock);
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301982 sm = &client->stage_cfg[stage_idx].sound_model;
1983 if (!sm->data) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301984 /*
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301985 * If sound model is sent as set_param, i.e. param_id != 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301986 * Then memory needs to be allocated for
1987 * set_param payload as well.
1988 */
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301989 if (p_info->param_id != 0)
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08001990 len += sizeof(union param_hdrs);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301991
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301992 sm->size = len;
1993 total_mem = PAGE_ALIGN(len);
1994 pr_debug("%s: sm param size %zd Total mem %zd, stage_idx %d\n",
1995 __func__, len, total_mem, stage_idx);
1996 rc = msm_audio_ion_alloc(&sm->dma_buf, total_mem,
1997 &sm->phys, &len, &sm->data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301998 if (rc) {
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05301999 pr_err("%s: Audio ION alloc is failed, rc = %d, stage_idx = %d\n",
2000 __func__, rc, stage_idx);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302001 goto fail;
2002 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302003 } else {
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302004 pr_err("%s: sound model busy, stage_idx %d\n", __func__, stage_idx);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302005 rc = -EBUSY;
2006 goto fail;
2007 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302008
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302009 rc = q6lsm_memory_map_regions(client, sm->phys, len, &sm->mem_map_handle);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302010 if (rc) {
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302011 pr_err("%s: CMD Memory_map_regions failed %d, stage_idx %d\n",
2012 __func__, rc, stage_idx);
2013 sm->mem_map_handle = 0;
2014 goto fail;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302015 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302016 mutex_unlock(&client->cmd_lock);
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302017
2018 rc = q6lsm_snd_cal_alloc(client, p_info);
2019 if (rc) {
2020 pr_err("%s: cal alloc failed %d, stage_idx %d\n",
2021 __func__, rc, stage_idx);
2022 goto fail_1;
2023 }
2024 return rc;
2025
2026fail:
2027 mutex_unlock(&client->cmd_lock);
2028fail_1:
2029 q6lsm_snd_model_buf_free(client, p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302030 return rc;
2031}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302032EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302033
2034static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
2035{
2036 struct apr_hdr hdr;
2037 int rc;
2038
2039 pr_debug("%s: enter opcode %x wait %d\n", __func__, opcode, wait);
2040 q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
2041 switch (opcode) {
2042 case LSM_SESSION_CMD_START:
2043 case LSM_SESSION_CMD_STOP:
2044 case LSM_SESSION_CMD_CLOSE_TX:
2045 case LSM_SESSION_CMD_EOB:
2046 hdr.opcode = opcode;
2047 break;
2048 default:
2049 pr_err("%s: Invalid opcode 0x%x\n", __func__, opcode);
2050 return -EINVAL;
2051 }
2052 rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
2053 if (rc)
2054 pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
2055
2056 pr_debug("%s: leave %d\n", __func__, rc);
2057 return rc;
2058}
2059
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002060static int q6lsm_send_param_epd_thres(struct lsm_client *client, void *data,
2061 struct param_hdr_v3 *param_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302062{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002063 struct snd_lsm_ep_det_thres *ep_det_data = NULL;
2064 struct lsm_param_epd_thres epd_thres;
2065 int rc = 0;
2066
2067 memset(&epd_thres, 0, sizeof(epd_thres));
2068 param_info->param_size = sizeof(epd_thres);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302069
2070 ep_det_data = (struct snd_lsm_ep_det_thres *) data;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002071 epd_thres.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
2072 epd_thres.epd_begin = ep_det_data->epd_begin;
2073 epd_thres.epd_end = ep_det_data->epd_end;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302074
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002075 rc = q6lsm_pack_and_set_params(client, param_info,
2076 (uint8_t *) &epd_thres,
2077 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302078 if (unlikely(rc))
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002079 pr_err("%s: EPD_THRESHOLD failed, rc %d\n", __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302080 return rc;
2081}
2082
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002083static int q6lsm_send_param_gain(struct lsm_client *client, u16 gain,
2084 struct param_hdr_v3 *param_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302085{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002086 struct lsm_param_gain lsm_gain;
2087 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302088
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002089 memset(&lsm_gain, 0, sizeof(lsm_gain));
2090 param_info->param_size = sizeof(lsm_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302091
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002092 lsm_gain.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
2093 lsm_gain.gain = gain;
2094
2095 rc = q6lsm_pack_and_set_params(client, param_info,
2096 (uint8_t *) &lsm_gain,
2097 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302098 if (unlikely(rc))
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002099 pr_err("%s: LSM_GAIN CMD send failed, rc %d\n", __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302100 return rc;
2101}
2102
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302103/**
2104 * q6lsm_set_one_param -
2105 * command for LSM set params
2106 *
2107 * @client: LSM client handle
2108 * p_info: Params info
2109 * data: payload based on param type
2110 * param_type: LSM param type
2111 *
2112 * Returns 0 on success or error on failure
2113 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302114int q6lsm_set_one_param(struct lsm_client *client,
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302115 struct lsm_params_info_v2 *p_info, void *data,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302116 uint32_t param_type)
2117{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002118 struct param_hdr_v3 param_info;
2119 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302120
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002121 memset(&param_info, 0, sizeof(param_info));
2122
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302123 switch (param_type) {
2124 case LSM_ENDPOINT_DETECT_THRESHOLD: {
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002125 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302126 param_info.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002127 param_info.param_id = p_info->param_id;
2128 rc = q6lsm_send_param_epd_thres(client, data, &param_info);
2129 if (rc)
2130 pr_err("%s: LSM_ENDPOINT_DETECT_THRESHOLD failed, rc %d\n",
2131 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302132 break;
2133 }
2134
2135 case LSM_OPERATION_MODE: {
2136 struct snd_lsm_detect_mode *det_mode = data;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302137
2138 if (det_mode->mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
2139 client->mode = 0x01;
2140 } else if (det_mode->mode == LSM_MODE_USER_KEYWORD_DETECTION) {
2141 client->mode = 0x03;
2142 } else {
2143 pr_err("%s: Incorrect detection mode %d\n",
2144 __func__, det_mode->mode);
2145 return -EINVAL;
2146 }
2147
2148 client->mode |= det_mode->detect_failure << 2;
2149
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002150 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302151 param_info.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002152 param_info.param_id = p_info->param_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302153
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002154 rc = q6lsm_send_param_opmode(client, &param_info,
2155 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302156 if (rc)
2157 pr_err("%s: OPERATION_MODE failed, rc %d\n",
2158 __func__, rc);
2159 break;
2160 }
2161
2162 case LSM_GAIN: {
2163 struct snd_lsm_gain *lsm_gain = (struct snd_lsm_gain *) data;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002164 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302165 param_info.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002166 param_info.param_id = p_info->param_id;
2167 rc = q6lsm_send_param_gain(client, lsm_gain->gain, &param_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302168 if (rc)
2169 pr_err("%s: LSM_GAIN command failed, rc %d\n",
2170 __func__, rc);
2171 break;
2172 }
2173
2174 case LSM_MIN_CONFIDENCE_LEVELS:
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002175 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302176 param_info.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002177 param_info.param_id = p_info->param_id;
2178 rc = q6lsm_send_confidence_levels(
2179 client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302180 if (rc)
2181 pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
2182 __func__, rc);
2183 break;
2184 case LSM_POLLING_ENABLE: {
2185 struct snd_lsm_poll_enable *lsm_poll_enable =
2186 (struct snd_lsm_poll_enable *) data;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002187 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302188 param_info.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002189 param_info.param_id = p_info->param_id;
2190 rc = q6lsm_send_param_polling_enable(
2191 client, lsm_poll_enable->poll_en, &param_info,
2192 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302193 if (rc)
2194 pr_err("%s: POLLING ENABLE cmd failed, rc %d\n",
2195 __func__, rc);
2196 break;
2197 }
2198
2199 case LSM_REG_SND_MODEL: {
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002200 struct mem_mapping_hdr mem_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302201 u32 payload_size;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302202 struct lsm_sound_model *sm = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302203
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002204 memset(&mem_hdr, 0, sizeof(mem_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302205
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002206 if (q6common_is_instance_id_supported())
2207 payload_size = p_info->param_size +
2208 sizeof(struct param_hdr_v3);
2209 else
2210 payload_size = p_info->param_size +
2211 sizeof(struct param_hdr_v2);
2212
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302213 sm = &client->stage_cfg[p_info->stage_idx].sound_model;
2214
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002215 mem_hdr.data_payload_addr_lsw =
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302216 lower_32_bits(sm->phys);
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002217 mem_hdr.data_payload_addr_msw =
2218 msm_audio_populate_upper_32_bits(
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302219 sm->phys),
2220 mem_hdr.mem_map_handle = sm->mem_map_handle;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002221
2222 rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size,
2223 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302224 if (rc) {
2225 pr_err("%s: REG_SND_MODEL failed, rc %d\n",
2226 __func__, rc);
2227 return rc;
2228 }
2229
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302230 rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302231 if (rc)
2232 pr_err("%s: Failed to send lsm cal, err = %d\n",
2233 __func__, rc);
2234 break;
2235 }
2236
2237 case LSM_DEREG_SND_MODEL: {
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002238 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302239 param_info.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002240 param_info.param_id = p_info->param_id;
2241 param_info.param_size = 0;
2242 rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
2243 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302244 if (rc)
2245 pr_err("%s: DEREG_SND_MODEL failed, rc %d\n",
2246 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302247 break;
2248 }
2249
2250 case LSM_CUSTOM_PARAMS: {
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002251 u32 param_size = p_info->param_size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302252
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002253 /* Check minimum size, V2 structure is smaller than V3 */
2254 if (param_size < sizeof(struct param_hdr_v2)) {
2255 pr_err("%s: Invalid param_size %d\n", __func__,
2256 param_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302257 return -EINVAL;
2258 }
2259
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002260 rc = q6lsm_set_params(client, NULL, data, param_size,
2261 LSM_SESSION_CMD_SET_PARAMS_V2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302262 if (rc)
2263 pr_err("%s: CUSTOM_PARAMS failed, rc %d\n",
2264 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302265 break;
2266 }
Xiaoyu Yef0ec6862018-03-21 17:43:38 -07002267
2268 case LSM_DET_EVENT_TYPE: {
2269 struct lsm_param_det_event_type det_event_type;
2270 struct snd_lsm_det_event_type *det_event_data =
2271 (struct snd_lsm_det_event_type *)data;
2272
2273 param_info.module_id = p_info->module_id;
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302274 param_info.instance_id = p_info->instance_id;
Xiaoyu Yef0ec6862018-03-21 17:43:38 -07002275 param_info.param_id = p_info->param_id;
2276 param_info.param_size = sizeof(det_event_type);
2277
2278 memset(&det_event_type, 0, sizeof(det_event_type));
2279
2280 det_event_type.minor_version = QLSM_PARAM_ID_MINOR_VERSION;
2281 det_event_type.event_type = det_event_data->event_type;
2282 det_event_type.mode = det_event_data->mode;
2283
2284 rc = q6lsm_pack_and_set_params(client, &param_info,
2285 (uint8_t *)&det_event_type,
2286 LSM_SESSION_CMD_SET_PARAMS_V2);
2287 if (rc)
2288 pr_err("%s: DET_EVENT_TYPE cmd failed, rc %d\n",
2289 __func__, rc);
2290 break;
2291 }
2292
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302293 default:
2294 pr_err("%s: wrong param_type 0x%x\n",
2295 __func__, p_info->param_type);
2296 }
2297
2298 return rc;
2299}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302300EXPORT_SYMBOL(q6lsm_set_one_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302301
2302
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302303/**
2304 * q6lsm_start -
2305 * command for LSM start
2306 *
2307 * @client: LSM client handle
2308 *
2309 * Returns 0 on success or error on failure
2310 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302311int q6lsm_start(struct lsm_client *client, bool wait)
2312{
2313 return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
2314}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302315EXPORT_SYMBOL(q6lsm_start);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302316
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302317/**
2318 * q6lsm_stop -
2319 * command for LSM stop
2320 *
2321 * @client: LSM client handle
2322 *
2323 * Returns 0 on success or error on failure
2324 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302325int q6lsm_stop(struct lsm_client *client, bool wait)
2326{
2327 return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
2328}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302329EXPORT_SYMBOL(q6lsm_stop);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302330
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302331/**
2332 * q6lsm_close -
2333 * command for LSM close
2334 *
2335 * @client: LSM client handle
2336 *
2337 * Returns 0 on success or error on failure
2338 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302339int q6lsm_close(struct lsm_client *client)
2340{
2341 return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
2342}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302343EXPORT_SYMBOL(q6lsm_close);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302344
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302345/**
2346 * q6lsm_lab_control -
2347 * command to set LSM LAB control params
2348 *
2349 * @client: LSM client handle
2350 * @enable: bool flag to enable or disable LAB on DSP
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302351 * @p_info: param info to be used for sending lab control param
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302352 *
2353 * Returns 0 on success or error on failure
2354 */
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302355int q6lsm_lab_control(struct lsm_client *client, u32 enable,
2356 struct lsm_params_info_v2 *p_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302357{
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002358 struct lsm_param_lab_enable lab_enable;
2359 struct param_hdr_v3 lab_enable_hdr;
2360 struct lsm_param_lab_config lab_config;
2361 struct param_hdr_v3 lab_config_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302362 int rc = 0;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002363
2364 memset(&lab_enable, 0, sizeof(lab_enable));
2365 memset(&lab_enable_hdr, 0, sizeof(lab_enable_hdr));
2366 memset(&lab_config, 0, sizeof(lab_config));
2367 memset(&lab_config_hdr, 0, sizeof(lab_config_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302368
2369 if (!client) {
2370 pr_err("%s: invalid param client %pK\n", __func__, client);
2371 return -EINVAL;
2372 }
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002373
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302374 /* enable/disable lab on dsp */
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302375 lab_enable_hdr.module_id = p_info->module_id;
2376 lab_enable_hdr.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002377 lab_enable_hdr.param_id = LSM_PARAM_ID_LAB_ENABLE;
2378 lab_enable_hdr.param_size = sizeof(lab_enable);
2379 lab_enable.enable = (enable) ? 1 : 0;
2380 rc = q6lsm_pack_and_set_params(client, &lab_enable_hdr,
2381 (uint8_t *) &lab_enable,
2382 LSM_SESSION_CMD_SET_PARAMS);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302383 if (rc) {
2384 pr_err("%s: Lab enable failed rc %d\n", __func__, rc);
2385 return rc;
2386 }
2387 if (!enable)
2388 goto exit;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002389
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302390 /* lab session is being enabled set the config values */
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302391 lab_config_hdr.module_id = p_info->module_id;
2392 lab_config_hdr.instance_id = p_info->instance_id;
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002393 lab_config_hdr.param_id = LSM_PARAM_ID_LAB_CONFIG;
2394 lab_config_hdr.param_size = sizeof(lab_config);
2395 lab_config.minor_version = 1;
2396 lab_config.wake_up_latency_ms = 250;
2397 rc = q6lsm_pack_and_set_params(client, &lab_config_hdr,
2398 (uint8_t *) &lab_config,
2399 LSM_SESSION_CMD_SET_PARAMS);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302400 if (rc) {
2401 pr_err("%s: Lab config failed rc %d disable lab\n",
2402 __func__, rc);
2403 /* Lab config failed disable lab */
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002404 lab_enable.enable = 0;
2405 if (q6lsm_pack_and_set_params(client, &lab_enable_hdr,
2406 (uint8_t *) &lab_enable,
2407 LSM_SESSION_CMD_SET_PARAMS))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302408 pr_err("%s: Lab disable failed\n", __func__);
2409 }
2410exit:
2411 return rc;
2412}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302413EXPORT_SYMBOL(q6lsm_lab_control);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302414
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002415/*
2416 * q6lsm_lab_out_ch_cfg -
2417 * Command to set the channel configuration
2418 * for look-ahead buffer.
2419 *
2420 * @client: LSM client handle
2421 * @ch_map: Channel map indicating the order
2422 * of channels to be configured.
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302423 * @p_info: param info to be used for sending lab config param
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002424 *
2425 * Returns 0 on success or error on failure
2426 */
2427int q6lsm_lab_out_ch_cfg(struct lsm_client *client,
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302428 u8 *ch_map, struct lsm_params_info_v2 *p_info)
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002429{
2430 u8 *param_buf;
2431 struct lsm_param_lab_out_ch_cfg *lab_out_cfg;
2432 struct param_hdr_v3 lab_out_cfg_hdr;
2433 struct lsm_hw_params *out_params = &client->out_hw_params;
2434 int i, rc = 0, param_len = 0;
2435
2436 param_len = sizeof(*lab_out_cfg) +
2437 sizeof(u8) * out_params->num_chs;
2438
2439 if (param_len % 4)
2440 param_len += (4 - (param_len % 4));
2441
2442 param_buf = kzalloc(param_len, GFP_KERNEL);
2443 if (!param_buf)
2444 return -ENOMEM;
2445
2446 lab_out_cfg = (struct lsm_param_lab_out_ch_cfg *) param_buf;
2447 lab_out_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
2448 lab_out_cfg->num_channels = out_params->num_chs;
2449
2450 for (i = 0; i < out_params->num_chs; i++)
2451 lab_out_cfg->channel_indices[i] = ch_map[i];
2452
2453 memset(&lab_out_cfg_hdr, 0, sizeof(lab_out_cfg_hdr));
Dhananjay Kumarce6ec5f2018-06-19 06:07:29 +05302454 lab_out_cfg_hdr.module_id = p_info->module_id;
2455 lab_out_cfg_hdr.instance_id = p_info->instance_id;
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002456 lab_out_cfg_hdr.param_id = LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG;
2457 lab_out_cfg_hdr.param_size = param_len;
2458
2459 rc = q6lsm_pack_and_set_params(client, &lab_out_cfg_hdr,
2460 param_buf,
2461 LSM_SESSION_CMD_SET_PARAMS_V2);
2462 if (rc)
2463 pr_err("%s: Lab out channel config failed %d\n",
2464 __func__, rc);
2465
2466 kfree(param_buf);
2467
2468 return rc;
2469}
2470EXPORT_SYMBOL(q6lsm_lab_out_ch_cfg);
2471
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302472/**
2473 * q6lsm_stop_lab -
2474 * command to stop LSM LAB
2475 *
2476 * @client: LSM client handle
2477 *
2478 * Returns 0 on success or error on failure
2479 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302480int q6lsm_stop_lab(struct lsm_client *client)
2481{
2482 int rc = 0;
2483
2484 if (!client) {
2485 pr_err("%s: invalid param client %pK\n", __func__, client);
2486 return -EINVAL;
2487 }
2488 rc = q6lsm_cmd(client, LSM_SESSION_CMD_EOB, true);
2489 if (rc)
2490 pr_err("%s: Lab stop failed %d\n", __func__, rc);
2491 return rc;
2492}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302493EXPORT_SYMBOL(q6lsm_stop_lab);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302494
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302495/**
2496 * q6lsm_read -
2497 * command for LSM read
2498 *
2499 * @client: LSM client handle
2500 * @lsm_cmd_read: LSM read command
2501 *
2502 * Returns 0 on success or error on failure
2503 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302504int q6lsm_read(struct lsm_client *client, struct lsm_cmd_read *read)
2505{
2506 int rc = 0;
2507
2508 if (!client || !read) {
2509 pr_err("%s: Invalid params client %pK read %pK\n", __func__,
2510 client, read);
2511 return -EINVAL;
2512 }
2513 pr_debug("%s: read call memmap handle %x address %x%x size %d\n",
2514 __func__, read->mem_map_handle, read->buf_addr_msw,
2515 read->buf_addr_lsw, read->buf_size);
2516 q6lsm_add_hdr(client, &read->hdr, sizeof(struct lsm_cmd_read), true);
2517 read->hdr.opcode = LSM_SESSION_CMD_READ;
2518 rc = q6lsm_apr_send_pkt(client, client->apr, read, false, NULL);
2519 if (rc)
2520 pr_err("%s: read buffer call failed rc %d\n", __func__, rc);
2521 return rc;
2522}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302523EXPORT_SYMBOL(q6lsm_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302524
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302525/**
2526 * q6lsm_lab_buffer_alloc -
2527 * Lab buffer allocation or de-alloc
2528 *
2529 * @client: LSM client handle
2530 * @alloc: Allocate or free ion memory
2531 *
2532 * Returns 0 on success or error on failure
2533 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302534int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc)
2535{
2536 int ret = 0, i = 0;
2537 size_t allocate_size = 0, len = 0;
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002538 struct lsm_hw_params *out_params = &client->out_hw_params;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302539
2540 if (!client) {
2541 pr_err("%s: invalid client\n", __func__);
2542 return -EINVAL;
2543 }
2544 if (alloc) {
2545 if (client->lab_buffer) {
2546 pr_err("%s: buffers are allocated period count %d period size %d\n",
2547 __func__,
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002548 out_params->period_count,
2549 out_params->buf_sz);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302550 return -EINVAL;
2551 }
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002552 allocate_size = out_params->period_count *
2553 out_params->buf_sz;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302554 allocate_size = PAGE_ALIGN(allocate_size);
2555 client->lab_buffer =
2556 kzalloc(sizeof(struct lsm_lab_buffer) *
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002557 out_params->period_count, GFP_KERNEL);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302558 if (!client->lab_buffer) {
2559 pr_err("%s: memory allocation for lab buffer failed count %d\n"
2560 , __func__,
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002561 out_params->period_count);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302562 return -ENOMEM;
2563 }
Banajit Goswami08bb7362017-11-03 22:48:23 -07002564 ret = msm_audio_ion_alloc(&client->lab_buffer[0].dma_buf,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302565 allocate_size, &client->lab_buffer[0].phys,
2566 &len,
2567 &client->lab_buffer[0].data);
2568 if (ret)
2569 pr_err("%s: ion alloc failed ret %d size %zd\n",
2570 __func__, ret, allocate_size);
2571 else {
2572 ret = q6lsm_memory_map_regions(client,
2573 client->lab_buffer[0].phys, len,
2574 &client->lab_buffer[0].mem_map_handle);
2575 if (ret) {
2576 pr_err("%s: memory map filed ret %d size %zd\n",
2577 __func__, ret, len);
2578 msm_audio_ion_free(
Banajit Goswami08bb7362017-11-03 22:48:23 -07002579 client->lab_buffer[0].dma_buf);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302580 }
2581 }
2582 if (ret) {
2583 pr_err("%s: alloc lab buffer failed ret %d\n",
2584 __func__, ret);
2585 kfree(client->lab_buffer);
2586 client->lab_buffer = NULL;
2587 } else {
2588 pr_debug("%s: Memory map handle %x phys %pK size %d\n",
2589 __func__,
2590 client->lab_buffer[0].mem_map_handle,
2591 &client->lab_buffer[0].phys,
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002592 out_params->buf_sz);
2593
2594 for (i = 0; i < out_params->period_count; i++) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302595 client->lab_buffer[i].phys =
2596 client->lab_buffer[0].phys +
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002597 (i * out_params->buf_sz);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302598 client->lab_buffer[i].size =
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002599 out_params->buf_sz;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302600 client->lab_buffer[i].data =
2601 (u8 *)(client->lab_buffer[0].data) +
Bhalchandra Gajare6ee5b502018-05-12 20:43:40 -07002602 (i * out_params->buf_sz);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302603 client->lab_buffer[i].mem_map_handle =
2604 client->lab_buffer[0].mem_map_handle;
2605 }
2606 }
2607 } else {
2608 ret = q6lsm_memory_unmap_regions(client,
2609 client->lab_buffer[0].mem_map_handle);
2610 if (!ret)
Banajit Goswami08bb7362017-11-03 22:48:23 -07002611 msm_audio_ion_free(client->lab_buffer[0].dma_buf);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302612 else
2613 pr_err("%s: unmap failed not freeing memory\n",
2614 __func__);
2615 kfree(client->lab_buffer);
2616 client->lab_buffer = NULL;
2617 }
2618 return ret;
2619}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302620EXPORT_SYMBOL(q6lsm_lab_buffer_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302621
2622static int get_cal_type_index(int32_t cal_type)
2623{
2624 int ret = -EINVAL;
2625
2626 switch (cal_type) {
2627 case LSM_CUST_TOPOLOGY_CAL_TYPE:
2628 ret = LSM_CUSTOM_TOP_IDX;
2629 break;
2630 case LSM_TOPOLOGY_CAL_TYPE:
2631 ret = LSM_TOP_IDX;
2632 break;
2633 case LSM_CAL_TYPE:
2634 ret = LSM_CAL_IDX;
2635 break;
2636 default:
2637 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
2638 }
2639 return ret;
2640}
2641
2642static int q6lsm_alloc_cal(int32_t cal_type,
2643 size_t data_size, void *data)
2644{
2645 int ret = 0;
2646 int cal_index;
2647
2648 pr_debug("%s:\n", __func__);
2649
2650 cal_index = get_cal_type_index(cal_type);
2651 if (cal_index < 0) {
2652 pr_err("%s: could not get cal index %d!\n",
2653 __func__, cal_index);
2654 ret = -EINVAL;
2655 goto done;
2656 }
2657
2658 ret = cal_utils_alloc_cal(data_size, data,
2659 lsm_common.cal_data[cal_index], 0, NULL);
2660 if (ret < 0) {
2661 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
2662 __func__, ret, cal_type);
2663 ret = -EINVAL;
2664 goto done;
2665 }
2666done:
2667 return ret;
2668}
2669
2670static int q6lsm_dealloc_cal(int32_t cal_type,
2671 size_t data_size, void *data)
2672{
2673 int ret = 0;
2674 int cal_index;
2675
2676 pr_debug("%s:\n", __func__);
2677
2678 cal_index = get_cal_type_index(cal_type);
2679 if (cal_index < 0) {
2680 pr_err("%s: could not get cal index %d!\n",
2681 __func__, cal_index);
2682 ret = -EINVAL;
2683 goto done;
2684 }
2685
2686 ret = cal_utils_dealloc_cal(data_size, data,
2687 lsm_common.cal_data[cal_index]);
2688 if (ret < 0) {
2689 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
2690 __func__, ret, cal_type);
2691 ret = -EINVAL;
2692 goto done;
2693 }
2694done:
2695 return ret;
2696}
2697
2698static int q6lsm_set_cal(int32_t cal_type,
2699 size_t data_size, void *data)
2700{
2701 int ret = 0;
2702 int cal_index;
2703
2704 pr_debug("%s:\n", __func__);
2705
2706 cal_index = get_cal_type_index(cal_type);
2707 if (cal_index < 0) {
2708 pr_err("%s: could not get cal index %d!\n",
2709 __func__, cal_index);
2710 ret = -EINVAL;
2711 goto done;
2712 }
2713
2714 ret = cal_utils_set_cal(data_size, data,
2715 lsm_common.cal_data[cal_index], 0, NULL);
2716 if (ret < 0) {
2717 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
2718 __func__, ret, cal_type);
2719 ret = -EINVAL;
2720 goto done;
2721 }
2722
2723 if (cal_index == LSM_CUSTOM_TOP_IDX) {
2724 mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
2725 lsm_common.set_custom_topology = 1;
2726 mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
2727 }
2728
2729done:
2730 return ret;
2731}
2732
2733static void lsm_delete_cal_data(void)
2734{
2735 pr_debug("%s:\n", __func__);
2736
2737 cal_utils_destroy_cal_types(LSM_MAX_CAL_IDX, lsm_common.cal_data);
2738}
2739
2740static int q6lsm_init_cal_data(void)
2741{
2742 int ret = 0;
2743 struct cal_type_info cal_type_info[] = {
2744 {{LSM_CUST_TOPOLOGY_CAL_TYPE,
2745 {q6lsm_alloc_cal, q6lsm_dealloc_cal, NULL,
2746 q6lsm_set_cal, NULL, NULL} },
2747 {NULL, NULL, cal_utils_match_buf_num} },
2748
2749 {{LSM_TOPOLOGY_CAL_TYPE,
2750 {NULL, NULL, NULL,
2751 q6lsm_set_cal, NULL, NULL} },
2752 {NULL, NULL, cal_utils_match_buf_num} },
2753
2754 {{LSM_CAL_TYPE,
2755 {q6lsm_alloc_cal, q6lsm_dealloc_cal, NULL,
2756 q6lsm_set_cal, NULL, NULL} },
2757 {NULL, NULL, cal_utils_match_buf_num} }
2758 };
2759 pr_debug("%s:\n", __func__);
2760
2761 ret = cal_utils_create_cal_types(LSM_MAX_CAL_IDX,
2762 lsm_common.cal_data, cal_type_info);
2763 if (ret < 0) {
2764 pr_err("%s: could not create cal type!\n",
2765 __func__);
2766 ret = -EINVAL;
2767 goto err;
2768 }
2769
2770 return ret;
2771err:
2772 lsm_delete_cal_data();
2773 return ret;
2774}
2775
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302776int __init q6lsm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302777{
2778 int i = 0;
2779
2780 pr_debug("%s:\n", __func__);
Vignesh Kulothungana65e3012018-01-24 18:03:12 -08002781
2782 memset(&lsm_common, 0, sizeof(lsm_common));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302783 spin_lock_init(&lsm_session_lock);
2784 spin_lock_init(&mmap_lock);
2785 mutex_init(&lsm_common.apr_lock);
2786 for (; i <= LSM_MAX_SESSION_ID; i++) {
2787 lsm_common.common_client[i].session = LSM_CONTROL_SESSION;
2788 init_waitqueue_head(&lsm_common.common_client[i].cmd_wait);
2789 mutex_init(&lsm_common.common_client[i].cmd_lock);
2790 atomic_set(&lsm_common.common_client[i].cmd_state,
2791 CMD_STATE_CLEARED);
2792 }
2793
2794 if (q6lsm_init_cal_data())
2795 pr_err("%s: could not init cal data!\n", __func__);
2796
2797 return 0;
2798}
2799
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302800void q6lsm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302801{
2802 lsm_delete_cal_data();
2803}