blob: 8ebab78ac1e478c80d2c8f06e19fc4ede6fba2cf [file] [log] [blame]
Aditya Bavanari5106b562018-01-08 13:16:32 +05301/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/slab.h>
14#include <linux/wait.h>
15#include <linux/sched.h>
16#include <linux/jiffies.h>
17#include <linux/uaccess.h>
18#include <linux/atomic.h>
19#include <linux/wait.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053020#include <sound/asound.h>
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053021#include <dsp/msm-dts-srs-tm-config.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053022#include <dsp/apr_audio-v2.h>
23#include <dsp/q6adm-v2.h>
24#include <dsp/q6audio-v2.h>
25#include <dsp/q6afe-v2.h>
26#include <dsp/audio_cal_utils.h>
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -080027#include <dsp/q6common.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053028#include <ipc/apr.h>
29#include "adsp_err.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053030
31#define TIMEOUT_MS 1000
32
33#define RESET_COPP_ID 99
34#define INVALID_COPP_ID 0xFF
35/* Used for inband payload copy, max size is 4k */
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -080036/* 3 is to account for module, instance & param ID in payload */
37#define ADM_GET_PARAMETER_LENGTH (4096 - APR_HDR_SIZE - 3 * sizeof(uint32_t))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053038
39#define ULL_SUPPORTED_BITS_PER_SAMPLE 16
40#define ULL_SUPPORTED_SAMPLE_RATE 48000
41
42#ifndef CONFIG_DOLBY_DAP
43#undef DOLBY_ADM_COPP_TOPOLOGY_ID
44#define DOLBY_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFE
45#endif
46
47#ifndef CONFIG_DOLBY_DS2
48#undef DS2_ADM_COPP_TOPOLOGY_ID
49#define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF
50#endif
51
52/* ENUM for adm_status */
53enum adm_cal_status {
54 ADM_STATUS_CALIBRATION_REQUIRED = 0,
55 ADM_STATUS_MAX,
56};
57
58struct adm_copp {
59
60 atomic_t id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
61 atomic_t cnt[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
62 atomic_t topology[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
63 atomic_t mode[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
64 atomic_t stat[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
65 atomic_t rate[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
66 atomic_t bit_width[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
67 atomic_t channels[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
68 atomic_t app_type[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
69 atomic_t acdb_id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
70 wait_queue_head_t wait[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
71 wait_queue_head_t adm_delay_wait[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
72 atomic_t adm_delay_stat[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
73 uint32_t adm_delay[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
74 unsigned long adm_status[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
75};
76
77struct source_tracking_data {
Banajit Goswami08bb7362017-11-03 22:48:23 -070078 struct dma_buf *dma_buf;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053079 struct param_outband memmap;
80 int apr_cmd_status;
81};
82
83struct adm_ctl {
84 void *apr;
85
86 struct adm_copp copp;
87
88 atomic_t matrix_map_stat;
89 wait_queue_head_t matrix_map_wait;
90
91 atomic_t adm_stat;
92 wait_queue_head_t adm_wait;
93
94 struct cal_type_data *cal_data[ADM_MAX_CAL_TYPES];
95
96 atomic_t mem_map_handles[ADM_MEM_MAP_INDEX_MAX];
97 atomic_t mem_map_index;
98
99 struct param_outband outband_memmap;
100 struct source_tracking_data sourceTrackingData;
101
102 int set_custom_topology;
103 int ec_ref_rx;
104 int num_ec_ref_rx_chans;
105 int ec_ref_rx_bit_width;
106 int ec_ref_rx_sampling_rate;
107};
108
109static struct adm_ctl this_adm;
110
111struct adm_multi_ch_map {
112 bool set_channel_map;
113 char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
114};
115
116#define ADM_MCH_MAP_IDX_PLAYBACK 0
117#define ADM_MCH_MAP_IDX_REC 1
118static struct adm_multi_ch_map multi_ch_maps[2] = {
119 { false,
120 {0, 0, 0, 0, 0, 0, 0, 0}
121 },
122 { false,
123 {0, 0, 0, 0, 0, 0, 0, 0}
124 }
125};
126
127static int adm_get_parameters[MAX_COPPS_PER_PORT * ADM_GET_PARAMETER_LENGTH];
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800128static int adm_module_topo_list[MAX_COPPS_PER_PORT *
129 ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH];
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530130static struct mutex dts_srs_lock;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530131
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530132void msm_dts_srs_acquire_lock(void)
133{
134 mutex_lock(&dts_srs_lock);
135}
136
137void msm_dts_srs_release_lock(void)
138{
139 mutex_unlock(&dts_srs_lock);
140}
141
142/**
143 * adm_validate_and_get_port_index -
144 * validate given port id
145 *
146 * @port_id: Port ID number
147 *
148 * Returns valid index on success or error on failure
149 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530150int adm_validate_and_get_port_index(int port_id)
151{
152 int index;
153 int ret;
154
155 ret = q6audio_validate_port(port_id);
156 if (ret < 0) {
157 pr_err("%s: port validation failed id 0x%x ret %d\n",
158 __func__, port_id, ret);
159 return -EINVAL;
160 }
161
162 index = afe_get_port_index(port_id);
163 if (index < 0 || index >= AFE_MAX_PORTS) {
164 pr_err("%s: Invalid port idx %d port_id 0x%x\n",
165 __func__, index,
166 port_id);
167 return -EINVAL;
168 }
169 pr_debug("%s: port_idx- %d\n", __func__, index);
170 return index;
171}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530172EXPORT_SYMBOL(adm_validate_and_get_port_index);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530173
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530174/**
175 * adm_get_default_copp_idx -
176 * retrieve default copp_idx for given port
177 *
178 * @port_id: Port ID number
179 *
180 * Returns valid value on success or error on failure
181 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530182int adm_get_default_copp_idx(int port_id)
183{
184 int port_idx = adm_validate_and_get_port_index(port_id), idx;
185
186 if (port_idx < 0) {
187 pr_err("%s: Invalid port id: 0x%x", __func__, port_id);
188 return -EINVAL;
189 }
190 pr_debug("%s: port_idx:%d\n", __func__, port_idx);
191 for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
192 if (atomic_read(&this_adm.copp.id[port_idx][idx]) !=
193 RESET_COPP_ID)
194 return idx;
195 }
196 return -EINVAL;
197}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530198EXPORT_SYMBOL(adm_get_default_copp_idx);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530199
200int adm_get_topology_for_port_from_copp_id(int port_id, int copp_id)
201{
202 int port_idx = adm_validate_and_get_port_index(port_id), idx;
203
204 if (port_idx < 0) {
205 pr_err("%s: Invalid port id: 0x%x", __func__, port_id);
206 return 0;
207 }
208 for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
209 if (atomic_read(&this_adm.copp.id[port_idx][idx]) == copp_id)
210 return atomic_read(&this_adm.copp.topology[port_idx]
211 [idx]);
212 pr_err("%s: Invalid copp_id %d port_id 0x%x\n",
213 __func__, copp_id, port_id);
214 return 0;
215}
216
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530217/**
218 * adm_get_topology_for_port_copp_idx -
219 * retrieve topology of given port/copp_idx
220 *
221 * @port_id: Port ID number
222 * @copp_idx: copp index of ADM copp
223 *
224 * Returns valid value on success or 0 on failure
225 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530226int adm_get_topology_for_port_copp_idx(int port_id, int copp_idx)
227{
228 int port_idx = adm_validate_and_get_port_index(port_id);
229
230 if (port_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
231 pr_err("%s: Invalid port: 0x%x copp id: 0x%x",
232 __func__, port_id, copp_idx);
233 return 0;
234 }
235 return atomic_read(&this_adm.copp.topology[port_idx][copp_idx]);
236}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530237EXPORT_SYMBOL(adm_get_topology_for_port_copp_idx);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530238
239int adm_get_indexes_from_copp_id(int copp_id, int *copp_idx, int *port_idx)
240{
241 int p_idx, c_idx;
242
243 for (p_idx = 0; p_idx < AFE_MAX_PORTS; p_idx++) {
244 for (c_idx = 0; c_idx < MAX_COPPS_PER_PORT; c_idx++) {
245 if (atomic_read(&this_adm.copp.id[p_idx][c_idx])
246 == copp_id) {
247 if (copp_idx != NULL)
248 *copp_idx = c_idx;
249 if (port_idx != NULL)
250 *port_idx = p_idx;
251 return 0;
252 }
253 }
254 }
255 return -EINVAL;
256}
257
258static int adm_get_copp_id(int port_idx, int copp_idx)
259{
260 pr_debug("%s: port_idx:%d copp_idx:%d\n", __func__, port_idx, copp_idx);
261
262 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
263 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
264 return -EINVAL;
265 }
266 return atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
267}
268
269static int adm_get_idx_if_copp_exists(int port_idx, int topology, int mode,
270 int rate, int bit_width, int app_type)
271{
272 int idx;
273
274 pr_debug("%s: port_idx-%d, topology-0x%x, mode-%d, rate-%d, bit_width-%d\n",
275 __func__, port_idx, topology, mode, rate, bit_width);
276
277 for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++)
278 if ((topology ==
279 atomic_read(&this_adm.copp.topology[port_idx][idx])) &&
280 (mode == atomic_read(&this_adm.copp.mode[port_idx][idx])) &&
281 (rate == atomic_read(&this_adm.copp.rate[port_idx][idx])) &&
282 (bit_width ==
283 atomic_read(&this_adm.copp.bit_width[port_idx][idx])) &&
284 (app_type ==
285 atomic_read(&this_adm.copp.app_type[port_idx][idx])))
286 return idx;
287 return -EINVAL;
288}
289
290static int adm_get_next_available_copp(int port_idx)
291{
292 int idx;
293
294 pr_debug("%s:\n", __func__);
295 for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
296 pr_debug("%s: copp_id:0x%x port_idx:%d idx:%d\n", __func__,
297 atomic_read(&this_adm.copp.id[port_idx][idx]),
298 port_idx, idx);
299 if (atomic_read(&this_adm.copp.id[port_idx][idx]) ==
300 RESET_COPP_ID)
301 break;
302 }
303 return idx;
304}
305
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530306/**
307 * srs_trumedia_open -
308 * command to set SRS trumedia open
309 *
310 * @port_id: Port ID number
311 * @copp_idx: copp index of ADM copp
312 * @srs_tech_id: SRS tech index
313 * @srs_params: params pointer
314 *
315 * Returns 0 on success or error on failure
316 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530317int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
318 void *srs_params)
319{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800320 struct param_hdr_v3 param_hdr;
321 struct mem_mapping_hdr mem_hdr;
322 u32 total_param_size = 0;
323 bool outband = false;
324 int port_idx;
325 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530326
327 pr_debug("SRS - %s", __func__);
328
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800329 memset(&param_hdr, 0, sizeof(param_hdr));
330 memset(&mem_hdr, 0, sizeof(mem_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530331 port_id = afe_convert_virtual_to_portid(port_id);
332 port_idx = adm_validate_and_get_port_index(port_id);
333 if (port_idx < 0) {
334 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
335 return -EINVAL;
336 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800337
338 param_hdr.module_id = SRS_TRUMEDIA_MODULE_ID;
339 param_hdr.instance_id = INSTANCE_ID_0;
340
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530341 switch (srs_tech_id) {
342 case SRS_ID_GLOBAL: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800343 param_hdr.param_id = SRS_TRUMEDIA_PARAMS;
344 param_hdr.param_size =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530345 sizeof(struct srs_trumedia_params_GLOBAL);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530346 break;
347 }
348 case SRS_ID_WOWHD: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800349 param_hdr.param_id = SRS_TRUMEDIA_PARAMS_WOWHD;
350 param_hdr.param_size = sizeof(struct srs_trumedia_params_WOWHD);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530351 break;
352 }
353 case SRS_ID_CSHP: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800354 param_hdr.param_id = SRS_TRUMEDIA_PARAMS_CSHP;
355 param_hdr.param_size = sizeof(struct srs_trumedia_params_CSHP);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530356 break;
357 }
358 case SRS_ID_HPF: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800359 param_hdr.param_id = SRS_TRUMEDIA_PARAMS_HPF;
360 param_hdr.param_size = sizeof(struct srs_trumedia_params_HPF);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530361 break;
362 }
363 case SRS_ID_AEQ: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800364 u8 *update_params_ptr = (u8 *) this_adm.outband_memmap.kvaddr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530365
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800366 outband = true;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530367
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530368 if (update_params_ptr == NULL) {
369 pr_err("ADM_SRS_TRUMEDIA - %s: null memmap for AEQ params\n",
370 __func__);
371 ret = -EINVAL;
372 goto fail_cmd;
373 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530374
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800375 param_hdr.param_id = SRS_TRUMEDIA_PARAMS_AEQ;
376 param_hdr.param_size = sizeof(struct srs_trumedia_params_AEQ);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530377
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800378 ret = q6common_pack_pp_params(update_params_ptr, &param_hdr,
379 srs_params, &total_param_size);
380 if (ret) {
381 pr_err("%s: Failed to pack param header and data, error %d\n",
382 __func__, ret);
383 goto fail_cmd;
384 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530385 break;
386 }
387 case SRS_ID_HL: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800388 param_hdr.param_id = SRS_TRUMEDIA_PARAMS_HL;
389 param_hdr.param_size = sizeof(struct srs_trumedia_params_HL);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530390 break;
391 }
392 case SRS_ID_GEQ: {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800393 param_hdr.param_id = SRS_TRUMEDIA_PARAMS_GEQ;
394 param_hdr.param_size = sizeof(struct srs_trumedia_params_GEQ);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530395 break;
396 }
397 default:
398 goto fail_cmd;
399 }
400
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530401 if (outband && this_adm.outband_memmap.paddr) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800402 mem_hdr.data_payload_addr_lsw =
403 lower_32_bits(this_adm.outband_memmap.paddr);
404 mem_hdr.data_payload_addr_msw =
405 msm_audio_populate_upper_32_bits(
406 this_adm.outband_memmap.paddr);
407 mem_hdr.mem_map_handle = atomic_read(
408 &this_adm.mem_map_handles[ADM_SRS_TRUMEDIA]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530409
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800410 ret = adm_set_pp_params(port_id, copp_idx, &mem_hdr, NULL,
411 total_param_size);
412 } else {
413 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx,
414 param_hdr,
415 (u8 *) srs_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530416 }
417
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800418 if (ret < 0)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530419 pr_err("SRS - %s: ADM enable for port %d failed\n", __func__,
420 port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530421
422fail_cmd:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530423 return ret;
424}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530425EXPORT_SYMBOL(srs_trumedia_open);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530426
427static int adm_populate_channel_weight(u16 *ptr,
428 struct msm_pcm_channel_mixer *ch_mixer,
429 int channel_index)
430{
431 u16 i, j, start_index = 0;
432
433 if (channel_index > ch_mixer->output_channel) {
434 pr_err("%s: channel index %d is larger than output_channel %d\n",
435 __func__, channel_index, ch_mixer->output_channel);
436 return -EINVAL;
437 }
438
439 for (i = 0; i < ch_mixer->output_channel; i++) {
440 pr_debug("%s: weight for output %d:", __func__, i);
441 for (j = 0; j < ADM_MAX_CHANNELS; j++)
442 pr_debug(" %d",
443 ch_mixer->channel_weight[i][j]);
444 pr_debug("\n");
445 }
446
447 for (i = 0; i < channel_index; ++i)
448 start_index += ch_mixer->input_channels[i];
449
450 for (i = 0; i < ch_mixer->output_channel; ++i) {
451 for (j = start_index;
452 j < start_index +
453 ch_mixer->input_channels[channel_index]; j++) {
454 *ptr = ch_mixer->channel_weight[i][j];
455 pr_debug("%s: ptr[%d][%d] = %d\n",
456 __func__, i, j, *ptr);
457 ptr++;
458 }
459 }
460
461 return 0;
462}
463
464/*
465 * adm_programable_channel_mixer
466 *
467 * Receives port_id, copp_idx, session_id, session_type, ch_mixer
468 * and channel_index to send ADM command to mix COPP data.
469 *
470 * port_id - Passed value, port_id for which backend is wanted
471 * copp_idx - Passed value, copp_idx for which COPP is wanted
472 * session_id - Passed value, session_id for which session is needed
473 * session_type - Passed value, session_type for RX or TX
474 * ch_mixer - Passed value, ch_mixer for which channel mixer config is needed
475 * channel_index - Passed value, channel_index for which channel is needed
476 */
477int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
478 int session_type,
479 struct msm_pcm_channel_mixer *ch_mixer,
480 int channel_index)
481{
482 struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800483 struct param_hdr_v3 data_v5;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530484 int ret = 0, port_idx, sz = 0, param_size = 0;
485 u16 *adm_pspd_params;
486 u16 *ptr;
487 int index = 0;
488
489 pr_debug("%s: port_id = %d\n", __func__, port_id);
490 port_id = afe_convert_virtual_to_portid(port_id);
491 port_idx = adm_validate_and_get_port_index(port_id);
492 if (port_idx < 0) {
493 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
494 return -EINVAL;
495 }
496 /*
497 * First 8 bytes are 4 bytes as rule number, 2 bytes as output
498 * channel and 2 bytes as input channel.
499 * 2 * ch_mixer->output_channel means output channel mapping.
500 * 2 * ch_mixer->input_channels[channel_index]) means input
501 * channel mapping.
502 * 2 * ch_mixer->input_channels[channel_index] *
503 * ch_mixer->output_channel) means the channel mixer weighting
504 * coefficients.
505 * param_size needs to be a multiple of 4 bytes.
506 */
507
508 param_size = 2 * (4 + ch_mixer->output_channel +
509 ch_mixer->input_channels[channel_index] +
510 ch_mixer->input_channels[channel_index] *
511 ch_mixer->output_channel);
512 roundup(param_size, 4);
513
514 sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) +
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800515 sizeof(struct default_chmixer_param_id_coeff) +
516 sizeof(struct param_hdr_v3) + param_size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530517 pr_debug("%s: sz = %d\n", __func__, sz);
518 adm_params = kzalloc(sz, GFP_KERNEL);
519 if (!adm_params)
520 return -ENOMEM;
521
522 adm_params->payload_addr_lsw = 0;
523 adm_params->payload_addr_msw = 0;
524 adm_params->mem_map_handle = 0;
525 adm_params->direction = session_type;
526 adm_params->sessionid = session_id;
527 pr_debug("%s: copp_id = %d, session id %d\n", __func__,
528 atomic_read(&this_adm.copp.id[port_idx][copp_idx]),
529 session_id);
530 adm_params->deviceid = atomic_read(
531 &this_adm.copp.id[port_idx][copp_idx]);
532 adm_params->reserved = 0;
533
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800534 /*
535 * This module is internal to ADSP and cannot be configured with
536 * an instance id
537 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530538 data_v5.module_id = MTMX_MODULE_ID_DEFAULT_CHMIXER;
539 data_v5.param_id = DEFAULT_CHMIXER_PARAM_ID_COEFF;
540 data_v5.reserved = 0;
541 data_v5.param_size = param_size;
542 adm_params->payload_size =
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800543 sizeof(struct default_chmixer_param_id_coeff) +
544 sizeof(struct param_hdr_v3) + data_v5.param_size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530545 adm_pspd_params = (u16 *)((u8 *)adm_params +
546 sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5));
547 memcpy(adm_pspd_params, &data_v5, sizeof(data_v5));
548
549 adm_pspd_params = (u16 *)((u8 *)adm_params +
550 sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5)
551 + sizeof(data_v5));
552
553 adm_pspd_params[0] = ch_mixer->rule;
554 adm_pspd_params[2] = ch_mixer->output_channel;
555 adm_pspd_params[3] = ch_mixer->input_channels[channel_index];
556 index = 4;
557
558 if (ch_mixer->output_channel == 1) {
559 adm_pspd_params[index] = PCM_CHANNEL_FC;
560 } else if (ch_mixer->output_channel == 2) {
561 adm_pspd_params[index] = PCM_CHANNEL_FL;
562 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
563 } else if (ch_mixer->output_channel == 3) {
564 adm_pspd_params[index] = PCM_CHANNEL_FL;
565 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
566 adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
567 } else if (ch_mixer->output_channel == 4) {
568 adm_pspd_params[index] = PCM_CHANNEL_FL;
569 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
570 adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
571 adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
572 } else if (ch_mixer->output_channel == 5) {
573 adm_pspd_params[index] = PCM_CHANNEL_FL;
574 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
575 adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
576 adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
577 adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
578 } else if (ch_mixer->output_channel == 6) {
579 adm_pspd_params[index] = PCM_CHANNEL_FL;
580 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
581 adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
582 adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
583 adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
584 adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
585 } else if (ch_mixer->output_channel == 8) {
586 adm_pspd_params[index] = PCM_CHANNEL_FL;
587 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
588 adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
589 adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
590 adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
591 adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
592 adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
593 adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
594 }
595
596 index = index + ch_mixer->output_channel;
597 if (ch_mixer->input_channels[channel_index] == 1) {
598 adm_pspd_params[index] = PCM_CHANNEL_FC;
599 } else if (ch_mixer->input_channels[channel_index] == 2) {
600 adm_pspd_params[index] = PCM_CHANNEL_FL;
601 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
602 } else if (ch_mixer->input_channels[channel_index] == 3) {
603 adm_pspd_params[index] = PCM_CHANNEL_FL;
604 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
605 adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
606 } else if (ch_mixer->input_channels[channel_index] == 4) {
607 adm_pspd_params[index] = PCM_CHANNEL_FL;
608 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
609 adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
610 adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
611 } else if (ch_mixer->input_channels[channel_index] == 5) {
612 adm_pspd_params[index] = PCM_CHANNEL_FL;
613 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
614 adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
615 adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
616 adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
617 } else if (ch_mixer->input_channels[channel_index] == 6) {
618 adm_pspd_params[index] = PCM_CHANNEL_FL;
619 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
620 adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
621 adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
622 adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
623 adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
624 } else if (ch_mixer->input_channels[channel_index] == 8) {
625 adm_pspd_params[index] = PCM_CHANNEL_FL;
626 adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
627 adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
628 adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
629 adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
630 adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
631 adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
632 adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
633 }
634
635 index = index + ch_mixer->input_channels[channel_index];
636 ret = adm_populate_channel_weight(&adm_pspd_params[index],
637 ch_mixer, channel_index);
638 if (!ret) {
639 pr_err("%s: fail to get channel weight with error %d\n",
640 __func__, ret);
641 goto fail_cmd;
642 }
643
644 adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
645 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
646 adm_params->hdr.src_svc = APR_SVC_ADM;
647 adm_params->hdr.src_domain = APR_DOMAIN_APPS;
648 adm_params->hdr.src_port = port_id;
649 adm_params->hdr.dest_svc = APR_SVC_ADM;
650 adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
651 adm_params->hdr.dest_port =
652 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
653 adm_params->hdr.token = port_idx << 16 | copp_idx;
654 adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5;
655 adm_params->hdr.pkt_size = sz;
656 adm_params->payload_addr_lsw = 0;
657 adm_params->payload_addr_msw = 0;
658 adm_params->mem_map_handle = 0;
659 adm_params->reserved = 0;
660
661 ptr = (u16 *)adm_params;
662 for (index = 0; index < (sz / 2); index++)
663 pr_debug("%s: adm_params[%d] = 0x%x\n",
664 __func__, index, (unsigned int)ptr[index]);
665
666 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], 0);
667 ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
668 if (ret < 0) {
669 pr_err("%s: Set params failed port %d rc %d\n", __func__,
670 port_id, ret);
671 ret = -EINVAL;
672 goto fail_cmd;
673 }
674
675 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
676 atomic_read(
677 &this_adm.copp.stat[port_idx][copp_idx]) >= 0,
678 msecs_to_jiffies(TIMEOUT_MS));
679 if (!ret) {
680 pr_err("%s: set params timed out port = %d\n",
681 __func__, port_id);
682 ret = -ETIMEDOUT;
683 goto fail_cmd;
684 }
685 ret = 0;
686fail_cmd:
687 kfree(adm_params);
688
689 return ret;
690}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530691EXPORT_SYMBOL(adm_programable_channel_mixer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530692
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530693/**
694 * adm_set_stereo_to_custom_stereo -
695 * command to update custom stereo
696 *
697 * @port_id: Port ID number
698 * @copp_idx: copp index of ADM copp
699 * @session_id: session id to be updated
700 * @params: params pointer
701 * @param_length: length of params
702 *
703 * Returns 0 on success or error on failure
704 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530705int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx,
706 unsigned int session_id, char *params,
707 uint32_t params_length)
708{
709 struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL;
710 int sz, rc = 0, port_idx;
711
712 pr_debug("%s:\n", __func__);
713 port_id = afe_convert_virtual_to_portid(port_id);
714 port_idx = adm_validate_and_get_port_index(port_id);
715 if (port_idx < 0) {
716 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
717 return -EINVAL;
718 }
719
720 sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) +
721 params_length;
722 adm_params = kzalloc(sz, GFP_KERNEL);
723 if (!adm_params) {
724 pr_err("%s, adm params memory alloc failed\n", __func__);
725 return -ENOMEM;
726 }
727
728 memcpy(((u8 *)adm_params +
729 sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5)),
730 params, params_length);
731 adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
732 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
733 adm_params->hdr.pkt_size = sz;
734 adm_params->hdr.src_svc = APR_SVC_ADM;
735 adm_params->hdr.src_domain = APR_DOMAIN_APPS;
736 adm_params->hdr.src_port = port_id;
737 adm_params->hdr.dest_svc = APR_SVC_ADM;
738 adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
739 adm_params->hdr.dest_port = 0; /* Ignored */;
740 adm_params->hdr.token = port_idx << 16 | copp_idx;
741 adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5;
742 adm_params->payload_addr_lsw = 0;
743 adm_params->payload_addr_msw = 0;
744 adm_params->mem_map_handle = 0;
745 adm_params->payload_size = params_length;
746 /* direction RX as 0 */
747 adm_params->direction = ADM_MATRIX_ID_AUDIO_RX;
748 /* session id for this cmd to be applied on */
749 adm_params->sessionid = session_id;
750 adm_params->deviceid =
751 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
752 adm_params->reserved = 0;
753 pr_debug("%s: deviceid %d, session_id %d, src_port %d, dest_port %d\n",
754 __func__, adm_params->deviceid, adm_params->sessionid,
755 adm_params->hdr.src_port, adm_params->hdr.dest_port);
756 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
757 rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
758 if (rc < 0) {
759 pr_err("%s: Set params failed port = 0x%x rc %d\n",
760 __func__, port_id, rc);
761 rc = -EINVAL;
762 goto set_stereo_to_custom_stereo_return;
763 }
764 /* Wait for the callback */
765 rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
766 atomic_read(&this_adm.copp.stat
767 [port_idx][copp_idx]) >= 0,
768 msecs_to_jiffies(TIMEOUT_MS));
769 if (!rc) {
770 pr_err("%s: Set params timed out port = 0x%x\n", __func__,
771 port_id);
772 rc = -EINVAL;
773 goto set_stereo_to_custom_stereo_return;
774 } else if (atomic_read(&this_adm.copp.stat
775 [port_idx][copp_idx]) > 0) {
776 pr_err("%s: DSP returned error[%s]\n", __func__,
777 adsp_err_get_err_str(atomic_read(
778 &this_adm.copp.stat
779 [port_idx][copp_idx])));
780 rc = adsp_err_get_lnx_err_code(
781 atomic_read(&this_adm.copp.stat
782 [port_idx][copp_idx]));
783 goto set_stereo_to_custom_stereo_return;
784 }
785 rc = 0;
786set_stereo_to_custom_stereo_return:
787 kfree(adm_params);
788 return rc;
789}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530790EXPORT_SYMBOL(adm_set_stereo_to_custom_stereo);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530791
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530792/**
793 * adm_dolby_dap_send_params -
794 * command to send dolby dap params
795 *
796 * @port_id: Port ID number
797 * @copp_idx: copp index of ADM copp
798 * @params: params pointer
799 * @param_length: length of params
800 *
801 * Returns 0 on success or error on failure
802 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530803int adm_dolby_dap_send_params(int port_id, int copp_idx, char *params,
804 uint32_t params_length)
805{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800806 /* Use as wrapper for adm_set_pp_params until no longer used */
807 return adm_set_pp_params(port_id, copp_idx, NULL, params,
808 params_length);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530809}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530810EXPORT_SYMBOL(adm_dolby_dap_send_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530811
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800812/*
813 * With pre-packed data, only the opcode differes from V5 and V6.
814 * Use q6common_pack_pp_params to pack the data correctly.
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530815 */
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800816int adm_set_pp_params(int port_id, int copp_idx,
817 struct mem_mapping_hdr *mem_hdr, u8 *param_data,
818 u32 param_size)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530819{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800820 struct adm_cmd_set_pp_params *adm_set_params = NULL;
821 int size = 0;
822 int port_idx = 0;
823 atomic_t *copp_stat = NULL;
824 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530825
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530826 port_id = afe_convert_virtual_to_portid(port_id);
827 port_idx = adm_validate_and_get_port_index(port_id);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800828 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
829 pr_err("%s: Invalid port_idx 0x%x\n", __func__, port_idx);
830 return -EINVAL;
831 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
832 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530833 return -EINVAL;
834 }
835
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800836 /* Only add params_size in inband case */
837 size = sizeof(struct adm_cmd_set_pp_params);
838 if (param_data != NULL)
839 size += param_size;
840 adm_set_params = kzalloc(size, GFP_KERNEL);
841 if (!adm_set_params)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530842 return -ENOMEM;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800843
844 adm_set_params->apr_hdr.hdr_field =
845 APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
846 APR_PKT_VER);
847 adm_set_params->apr_hdr.pkt_size = size;
848 adm_set_params->apr_hdr.src_svc = APR_SVC_ADM;
849 adm_set_params->apr_hdr.src_domain = APR_DOMAIN_APPS;
850 adm_set_params->apr_hdr.src_port = port_id;
851 adm_set_params->apr_hdr.dest_svc = APR_SVC_ADM;
852 adm_set_params->apr_hdr.dest_domain = APR_DOMAIN_ADSP;
853 adm_set_params->apr_hdr.dest_port =
854 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
855 adm_set_params->apr_hdr.token = port_idx << 16 | copp_idx;
856
857 if (q6common_is_instance_id_supported())
858 adm_set_params->apr_hdr.opcode = ADM_CMD_SET_PP_PARAMS_V6;
859 else
860 adm_set_params->apr_hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
861
862 adm_set_params->payload_size = param_size;
863
864 if (mem_hdr != NULL) {
865 /* Out of Band Case */
866 adm_set_params->mem_hdr = *mem_hdr;
867 } else if (param_data != NULL) {
868 /*
869 * In band case. Parameter data must be pre-packed with its
870 * header before calling this function. Use
871 * q6common_pack_pp_params to pack parameter data and header
872 * correctly.
873 */
874 memcpy(&adm_set_params->param_data, param_data, param_size);
875 } else {
876 pr_err("%s: Received NULL pointers for both memory header and param data\n",
877 __func__);
878 ret = -EINVAL;
879 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530880 }
881
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800882 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
883 atomic_set(copp_stat, -1);
884 ret = apr_send_pkt(this_adm.apr, (uint32_t *) adm_set_params);
885 if (ret < 0) {
886 pr_err("%s: Set params APR send failed port = 0x%x ret %d\n",
887 __func__, port_id, ret);
888 goto done;
889 }
890 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
891 atomic_read(copp_stat) >= 0,
892 msecs_to_jiffies(TIMEOUT_MS));
893 if (!ret) {
894 pr_err("%s: Set params timed out port = 0x%x\n", __func__,
895 port_id);
896 ret = -ETIMEDOUT;
897 goto done;
898 }
899 if (atomic_read(copp_stat) > 0) {
900 pr_err("%s: DSP returned error[%s]\n", __func__,
901 adsp_err_get_err_str(atomic_read(copp_stat)));
902 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
903 goto done;
904 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530905
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800906 ret = 0;
907done:
908 kfree(adm_set_params);
909 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530910}
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800911EXPORT_SYMBOL(adm_set_pp_params);
912
913int adm_pack_and_set_one_pp_param(int port_id, int copp_idx,
914 struct param_hdr_v3 param_hdr, u8 *param_data)
915{
916 u8 *packed_data = NULL;
917 u32 total_size = 0;
918 int ret = 0;
919
920 total_size = sizeof(union param_hdrs) + param_hdr.param_size;
921 packed_data = kzalloc(total_size, GFP_KERNEL);
922 if (!packed_data)
923 return -ENOMEM;
924
925 ret = q6common_pack_pp_params(packed_data, &param_hdr, param_data,
926 &total_size);
927 if (ret) {
928 pr_err("%s: Failed to pack parameter data, error %d\n",
929 __func__, ret);
930 goto done;
931 }
932
933 ret = adm_set_pp_params(port_id, copp_idx, NULL, packed_data,
934 total_size);
935 if (ret)
936 pr_err("%s: Failed to set parameter data, error %d\n", __func__,
937 ret);
938done:
939 kfree(packed_data);
940 return ret;
941}
942EXPORT_SYMBOL(adm_pack_and_set_one_pp_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530943
944int adm_get_params_v2(int port_id, int copp_idx, uint32_t module_id,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800945 uint32_t param_id, uint32_t params_length, char *params,
946 uint32_t client_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530947{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800948 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530949
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800950 memset(&param_hdr, 0, sizeof(param_hdr));
951 param_hdr.module_id = module_id;
952 param_hdr.instance_id = INSTANCE_ID_0;
953 param_hdr.param_id = param_id;
954 param_hdr.param_size = params_length;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530955
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800956 return adm_get_pp_params(port_id, copp_idx, client_id, NULL, &param_hdr,
957 params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530958}
959
960int adm_get_params(int port_id, int copp_idx, uint32_t module_id,
961 uint32_t param_id, uint32_t params_length, char *params)
962{
963 return adm_get_params_v2(port_id, copp_idx, module_id, param_id,
964 params_length, params, 0);
965}
966
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800967/*
968 * Only one parameter can be requested at a time. Therefore, packing and sending
969 * the request can be handled locally.
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530970 */
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800971int adm_get_pp_params(int port_id, int copp_idx, uint32_t client_id,
972 struct mem_mapping_hdr *mem_hdr,
973 struct param_hdr_v3 *param_hdr, u8 *returned_param_data)
974{
975 struct adm_cmd_get_pp_params adm_get_params;
976 int total_size = 0;
977 int get_param_array_sz = ARRAY_SIZE(adm_get_parameters);
978 int returned_param_size = 0;
979 int returned_param_size_in_bytes = 0;
980 int port_idx = 0;
981 int idx = 0;
982 atomic_t *copp_stat = NULL;
983 int ret = 0;
984
985 if (param_hdr == NULL) {
986 pr_err("%s: Received NULL pointer for parameter header\n",
987 __func__);
988 return -EINVAL;
989 }
990
991 port_id = afe_convert_virtual_to_portid(port_id);
992 port_idx = adm_validate_and_get_port_index(port_id);
993 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
994 pr_err("%s: Invalid port_idx 0x%x\n", __func__, port_idx);
995 return -EINVAL;
996 }
997 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
998 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
999 return -EINVAL;
1000 }
1001
1002 memset(&adm_get_params, 0, sizeof(adm_get_params));
1003
1004 if (mem_hdr != NULL)
1005 adm_get_params.mem_hdr = *mem_hdr;
1006
1007 q6common_pack_pp_params((u8 *) &adm_get_params.param_hdr, param_hdr,
1008 NULL, &total_size);
1009
1010 /* Pack APR header after filling body so total_size has correct value */
1011 adm_get_params.apr_hdr.pkt_size = total_size;
1012 adm_get_params.apr_hdr.src_svc = APR_SVC_ADM;
1013 adm_get_params.apr_hdr.src_domain = APR_DOMAIN_APPS;
1014 adm_get_params.apr_hdr.src_port = port_id;
1015 adm_get_params.apr_hdr.dest_svc = APR_SVC_ADM;
1016 adm_get_params.apr_hdr.dest_domain = APR_DOMAIN_ADSP;
1017 adm_get_params.apr_hdr.dest_port =
1018 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
1019 adm_get_params.apr_hdr.token =
1020 port_idx << 16 | client_id << 8 | copp_idx;
1021
1022 if (q6common_is_instance_id_supported())
1023 adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V6;
1024 else
1025 adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
1026
1027 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
1028 atomic_set(copp_stat, -1);
1029 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_params);
1030 if (ret) {
1031 pr_err("%s: Get params APR send failed port = 0x%x ret %d\n",
1032 __func__, port_id, ret);
1033 ret = -EINVAL;
1034 goto done;
1035 }
1036 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
1037 atomic_read(copp_stat) >= 0,
1038 msecs_to_jiffies(TIMEOUT_MS));
1039 if (!ret) {
1040 pr_err("%s: Get params timed out port = 0x%x\n", __func__,
1041 port_id);
1042 ret = -ETIMEDOUT;
1043 goto done;
1044 }
1045 if (atomic_read(copp_stat) > 0) {
1046 pr_err("%s: DSP returned error[%s]\n", __func__,
1047 adsp_err_get_err_str(atomic_read(copp_stat)));
1048 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
1049 goto done;
1050 }
1051
1052 ret = 0;
1053
1054 /* Copy data to caller if sent in band */
1055 if (!returned_param_data) {
1056 pr_debug("%s: Received NULL pointer for param destination, not copying payload\n",
1057 __func__);
1058 return 0;
1059 }
1060
1061 idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
1062 returned_param_size = adm_get_parameters[idx];
1063 if (returned_param_size < 0 ||
1064 returned_param_size + idx + 1 > get_param_array_sz) {
1065 pr_err("%s: Invalid parameter size %d\n", __func__,
1066 returned_param_size);
1067 return -EINVAL;
1068 }
1069
1070 returned_param_size_in_bytes = returned_param_size * sizeof(uint32_t);
1071 if (param_hdr->param_size < returned_param_size_in_bytes) {
1072 pr_err("%s: Provided buffer is not big enough, provided buffer size(%d) size needed(%d)\n",
1073 __func__, param_hdr->param_size,
1074 returned_param_size_in_bytes);
1075 return -EINVAL;
1076 }
1077
1078 memcpy(returned_param_data, &adm_get_parameters[idx + 1],
1079 returned_param_size_in_bytes);
1080done:
1081 return ret;
1082}
1083EXPORT_SYMBOL(adm_get_pp_params);
1084
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301085int adm_get_pp_topo_module_list(int port_id, int copp_idx, int32_t param_length,
1086 char *params)
1087{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001088 return adm_get_pp_topo_module_list_v2(port_id, copp_idx, param_length,
1089 (int32_t *) params);
1090}
1091EXPORT_SYMBOL(adm_get_pp_topo_module_list);
1092
1093int adm_get_pp_topo_module_list_v2(int port_id, int copp_idx,
1094 int32_t param_length,
1095 int32_t *returned_params)
1096{
1097 struct adm_cmd_get_pp_topo_module_list adm_get_module_list;
1098 bool iid_supported = q6common_is_instance_id_supported();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301099 int *topo_list;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001100 int num_modules = 0;
1101 int list_size = 0;
1102 int port_idx, idx;
1103 int i = 0;
1104 atomic_t *copp_stat = NULL;
1105 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301106
1107 pr_debug("%s : port_id %x", __func__, port_id);
1108 port_id = afe_convert_virtual_to_portid(port_id);
1109 port_idx = adm_validate_and_get_port_index(port_id);
1110 if (port_idx < 0) {
1111 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
1112 return -EINVAL;
1113 }
1114
1115 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1116 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
1117 return -EINVAL;
1118 }
1119
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001120 memset(&adm_get_module_list, 0, sizeof(adm_get_module_list));
1121
1122 adm_get_module_list.apr_hdr.pkt_size = sizeof(adm_get_module_list);
1123 adm_get_module_list.apr_hdr.src_svc = APR_SVC_ADM;
1124 adm_get_module_list.apr_hdr.src_domain = APR_DOMAIN_APPS;
1125 adm_get_module_list.apr_hdr.src_port = port_id;
1126 adm_get_module_list.apr_hdr.dest_svc = APR_SVC_ADM;
1127 adm_get_module_list.apr_hdr.dest_domain = APR_DOMAIN_ADSP;
1128 adm_get_module_list.apr_hdr.dest_port =
1129 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
1130 adm_get_module_list.apr_hdr.token = port_idx << 16 | copp_idx;
1131 /*
1132 * Out of band functionality is not currently utilized.
1133 * Assume in band.
1134 */
1135 if (iid_supported) {
1136 adm_get_module_list.apr_hdr.opcode =
1137 ADM_CMD_GET_PP_TOPO_MODULE_LIST_V2;
1138 adm_get_module_list.param_max_size = param_length;
1139 } else {
1140 adm_get_module_list.apr_hdr.opcode =
1141 ADM_CMD_GET_PP_TOPO_MODULE_LIST;
1142
1143 if (param_length > U16_MAX) {
1144 pr_err("%s: Invalid param length for V1 %d\n", __func__,
1145 param_length);
1146 return -EINVAL;
1147 }
1148 adm_get_module_list.param_max_size = param_length << 16;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301149 }
1150
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001151 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
1152 atomic_set(copp_stat, -1);
1153 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_module_list);
1154 if (ret) {
1155 pr_err("%s: APR send pkt failed for port_id: 0x%x failed ret %d\n",
1156 __func__, port_id, ret);
1157 ret = -EINVAL;
1158 goto done;
1159 }
1160 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
1161 atomic_read(copp_stat) >= 0,
1162 msecs_to_jiffies(TIMEOUT_MS));
1163 if (!ret) {
1164 pr_err("%s: Timeout for port_id: 0x%x\n", __func__, port_id);
1165 ret = -ETIMEDOUT;
1166 goto done;
1167 }
1168 if (atomic_read(copp_stat) > 0) {
1169 pr_err("%s: DSP returned error[%s]\n", __func__,
1170 adsp_err_get_err_str(atomic_read(copp_stat)));
1171 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
1172 goto done;
1173 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301174
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001175 ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301176
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001177 if (returned_params) {
1178 /*
1179 * When processing ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST IID is
1180 * added since it is not present. Therefore, there is no need to
1181 * do anything different if IID is not supported here as it is
1182 * already taken care of.
1183 */
1184 idx = ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH * copp_idx;
1185 num_modules = adm_module_topo_list[idx];
1186 if (num_modules < 0 || num_modules > MAX_MODULES_IN_TOPO) {
1187 pr_err("%s: Invalid number of modules returned %d\n",
1188 __func__, num_modules);
1189 return -EINVAL;
1190 }
1191
1192 list_size = num_modules * sizeof(struct module_instance_info);
1193 if (param_length < list_size) {
1194 pr_err("%s: Provided buffer not big enough to hold module-instance list, provided size %d, needed size %d\n",
1195 __func__, param_length, list_size);
1196 return -EINVAL;
1197 }
1198
1199 topo_list = (int32_t *) (&adm_module_topo_list[idx]);
1200 memcpy(returned_params, topo_list, list_size);
1201 for (i = 1; i <= num_modules; i += 2) {
1202 pr_debug("module = 0x%x instance = 0x%x\n",
1203 returned_params[i], returned_params[i + 1]);
1204 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301205 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001206done:
1207 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301208}
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001209EXPORT_SYMBOL(adm_get_pp_topo_module_list_v2);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301210
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301211static void adm_callback_debug_print(struct apr_client_data *data)
1212{
1213 uint32_t *payload;
1214
1215 payload = data->payload;
1216
1217 if (data->payload_size >= 8)
1218 pr_debug("%s: code = 0x%x PL#0[0x%x], PL#1[0x%x], size = %d\n",
1219 __func__, data->opcode, payload[0], payload[1],
1220 data->payload_size);
1221 else if (data->payload_size >= 4)
1222 pr_debug("%s: code = 0x%x PL#0[0x%x], size = %d\n",
1223 __func__, data->opcode, payload[0],
1224 data->payload_size);
1225 else
1226 pr_debug("%s: code = 0x%x, size = %d\n",
1227 __func__, data->opcode, data->payload_size);
1228}
1229
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301230/**
1231 * adm_set_multi_ch_map -
1232 * Update multi channel map info
1233 *
1234 * @channel_map: pointer with channel map info
1235 * @path: direction or ADM path type
1236 *
1237 * Returns 0 on success or error on failure
1238 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301239int adm_set_multi_ch_map(char *channel_map, int path)
1240{
1241 int idx;
1242
1243 if (path == ADM_PATH_PLAYBACK) {
1244 idx = ADM_MCH_MAP_IDX_PLAYBACK;
1245 } else if (path == ADM_PATH_LIVE_REC) {
1246 idx = ADM_MCH_MAP_IDX_REC;
1247 } else {
1248 pr_err("%s: invalid attempt to set path %d\n", __func__, path);
1249 return -EINVAL;
1250 }
1251
1252 memcpy(multi_ch_maps[idx].channel_mapping, channel_map,
1253 PCM_FORMAT_MAX_NUM_CHANNEL);
1254 multi_ch_maps[idx].set_channel_map = true;
1255
1256 return 0;
1257}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301258EXPORT_SYMBOL(adm_set_multi_ch_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301259
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301260/**
1261 * adm_get_multi_ch_map -
1262 * Retrieves multi channel map info
1263 *
1264 * @channel_map: pointer to be updated with channel map
1265 * @path: direction or ADM path type
1266 *
1267 * Returns 0 on success or error on failure
1268 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301269int adm_get_multi_ch_map(char *channel_map, int path)
1270{
1271 int idx;
1272
1273 if (path == ADM_PATH_PLAYBACK) {
1274 idx = ADM_MCH_MAP_IDX_PLAYBACK;
1275 } else if (path == ADM_PATH_LIVE_REC) {
1276 idx = ADM_MCH_MAP_IDX_REC;
1277 } else {
1278 pr_err("%s: invalid attempt to get path %d\n", __func__, path);
1279 return -EINVAL;
1280 }
1281
1282 if (multi_ch_maps[idx].set_channel_map) {
1283 memcpy(channel_map, multi_ch_maps[idx].channel_mapping,
1284 PCM_FORMAT_MAX_NUM_CHANNEL);
1285 }
1286
1287 return 0;
1288}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301289EXPORT_SYMBOL(adm_get_multi_ch_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301290
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001291static int adm_process_get_param_response(u32 opcode, u32 idx, u32 *payload,
1292 u32 payload_size)
1293{
1294 struct adm_cmd_rsp_get_pp_params_v5 *v5_rsp = NULL;
1295 struct adm_cmd_rsp_get_pp_params_v6 *v6_rsp = NULL;
1296 u32 *param_data = NULL;
1297 int data_size = 0;
1298 int struct_size = 0;
1299
1300 if (payload == NULL) {
1301 pr_err("%s: Payload is NULL\n", __func__);
1302 return -EINVAL;
1303 }
1304
1305 switch (opcode) {
1306 case ADM_CMDRSP_GET_PP_PARAMS_V5:
1307 struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v5);
1308 v5_rsp = (struct adm_cmd_rsp_get_pp_params_v5 *) payload;
1309 data_size = v5_rsp->param_hdr.param_size;
1310 param_data = v5_rsp->param_data;
1311 break;
1312 case ADM_CMDRSP_GET_PP_PARAMS_V6:
1313 struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v6);
1314 v6_rsp = (struct adm_cmd_rsp_get_pp_params_v6 *) payload;
1315 data_size = v6_rsp->param_hdr.param_size;
1316 param_data = v6_rsp->param_data;
1317 break;
1318 default:
1319 pr_err("%s: Invalid opcode %d\n", __func__, opcode);
1320 return -EINVAL;
1321 }
1322
1323 /*
1324 * Just store the returned parameter data, not the header. The calling
1325 * function is expected to know what it asked for. Therefore, there is
1326 * no difference between V5 and V6.
1327 */
1328 if ((payload_size >= struct_size + data_size) &&
1329 (ARRAY_SIZE(adm_get_parameters) > idx) &&
1330 (ARRAY_SIZE(adm_get_parameters) >= idx + 1 + data_size)) {
1331 /*
1332 * data_size is expressed in number of bytes, store in number of
1333 * ints
1334 */
1335 adm_get_parameters[idx] =
1336 data_size / sizeof(*adm_get_parameters);
1337 pr_debug("%s: GET_PP PARAM: received parameter length: 0x%x\n",
1338 __func__, adm_get_parameters[idx]);
1339 /* store params after param_size */
1340 memcpy(&adm_get_parameters[idx + 1], param_data, data_size);
1341 return 0;
1342 }
1343
1344 pr_err("%s: Invalid parameter combination, payload_size %d, idx %d\n",
1345 __func__, payload_size, idx);
1346 return -EINVAL;
1347}
1348
1349static int adm_process_get_topo_list_response(u32 opcode, int copp_idx,
1350 u32 num_modules, u32 *payload,
1351 u32 payload_size)
1352{
1353 u32 *fill_list = NULL;
1354 int idx = 0;
1355 int i = 0;
1356 int j = 0;
1357
1358 if (payload == NULL) {
1359 pr_err("%s: Payload is NULL\n", __func__);
1360 return -EINVAL;
1361 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1362 pr_err("%s: Invalid COPP index %d\n", __func__, copp_idx);
1363 return -EINVAL;
1364 }
1365
1366 idx = ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH * copp_idx;
1367 fill_list = adm_module_topo_list + idx;
1368 *fill_list++ = num_modules;
1369 for (i = 0; i < num_modules; i++) {
1370 if (j > payload_size / sizeof(u32)) {
1371 pr_err("%s: Invalid number of modules specified %d\n",
1372 __func__, num_modules);
1373 return -EINVAL;
1374 }
1375
1376 /* store module ID */
1377 *fill_list++ = payload[j];
1378 j++;
1379
1380 switch (opcode) {
1381 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
1382 /* store instance ID */
1383 *fill_list++ = payload[j];
1384 j++;
1385 break;
1386 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
1387 /* Insert IID 0 when repacking */
1388 *fill_list++ = INSTANCE_ID_0;
1389 break;
1390 default:
1391 pr_err("%s: Invalid opcode %d\n", __func__, opcode);
1392 return -EINVAL;
1393 }
1394 }
1395
1396 return 0;
1397}
1398
Laxminath Kasam30ad7512017-11-28 12:40:22 +05301399static void adm_reset_data(void)
1400{
1401 int i, j;
1402
1403 apr_reset(this_adm.apr);
1404 for (i = 0; i < AFE_MAX_PORTS; i++) {
1405 for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
1406 atomic_set(&this_adm.copp.id[i][j],
1407 RESET_COPP_ID);
1408 atomic_set(&this_adm.copp.cnt[i][j], 0);
1409 atomic_set(
1410 &this_adm.copp.topology[i][j], 0);
1411 atomic_set(&this_adm.copp.mode[i][j],
1412 0);
1413 atomic_set(&this_adm.copp.stat[i][j],
1414 0);
1415 atomic_set(&this_adm.copp.rate[i][j],
1416 0);
1417 atomic_set(
1418 &this_adm.copp.channels[i][j],
1419 0);
1420 atomic_set(
1421 &this_adm.copp.bit_width[i][j], 0);
1422 atomic_set(
1423 &this_adm.copp.app_type[i][j], 0);
1424 atomic_set(
1425 &this_adm.copp.acdb_id[i][j], 0);
1426 this_adm.copp.adm_status[i][j] =
1427 ADM_STATUS_CALIBRATION_REQUIRED;
1428 }
1429 }
1430 this_adm.apr = NULL;
1431 cal_utils_clear_cal_block_q6maps(ADM_MAX_CAL_TYPES,
1432 this_adm.cal_data);
1433 mutex_lock(&this_adm.cal_data
1434 [ADM_CUSTOM_TOP_CAL]->lock);
1435 this_adm.set_custom_topology = 1;
1436 mutex_unlock(&this_adm.cal_data[
1437 ADM_CUSTOM_TOP_CAL]->lock);
1438 rtac_clear_mapping(ADM_RTAC_CAL);
1439 /*
1440 * Free the ION memory and clear the map handles
1441 * for Source Tracking
1442 */
1443 if (this_adm.sourceTrackingData.memmap.paddr != 0) {
1444 msm_audio_ion_free(
1445 this_adm.sourceTrackingData.dma_buf);
1446 this_adm.sourceTrackingData.dma_buf = NULL;
1447 this_adm.sourceTrackingData.memmap.size = 0;
1448 this_adm.sourceTrackingData.memmap.kvaddr =
1449 NULL;
1450 this_adm.sourceTrackingData.memmap.paddr = 0;
1451 this_adm.sourceTrackingData.apr_cmd_status = -1;
1452 atomic_set(&this_adm.mem_map_handles[
1453 ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
1454 }
1455}
1456
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301457static int32_t adm_callback(struct apr_client_data *data, void *priv)
1458{
1459 uint32_t *payload;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001460 int port_idx, copp_idx, idx, client_id;
1461 int num_modules;
1462 int ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301463
1464 if (data == NULL) {
1465 pr_err("%s: data parameter is null\n", __func__);
1466 return -EINVAL;
1467 }
1468
1469 payload = data->payload;
1470
1471 if (data->opcode == RESET_EVENTS) {
1472 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1473 __func__,
1474 data->reset_event, data->reset_proc, this_adm.apr);
Laxminath Kasam30ad7512017-11-28 12:40:22 +05301475 if (this_adm.apr)
1476 adm_reset_data();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301477 return 0;
1478 }
1479
1480 adm_callback_debug_print(data);
1481 if (data->payload_size) {
1482 copp_idx = (data->token) & 0XFF;
1483 port_idx = ((data->token) >> 16) & 0xFF;
1484 client_id = ((data->token) >> 8) & 0xFF;
1485 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
1486 pr_err("%s: Invalid port idx %d token %d\n",
1487 __func__, port_idx, data->token);
1488 return 0;
1489 }
1490 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1491 pr_err("%s: Invalid copp idx %d token %d\n",
1492 __func__, copp_idx, data->token);
1493 return 0;
1494 }
1495 if (client_id < 0 || client_id >= ADM_CLIENT_ID_MAX) {
1496 pr_err("%s: Invalid client id %d\n", __func__,
1497 client_id);
1498 return 0;
1499 }
1500 if (data->opcode == APR_BASIC_RSP_RESULT) {
1501 pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n",
1502 __func__, payload[0]);
1503 if (payload[1] != 0) {
1504 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
1505 __func__, payload[0], payload[1]);
1506 }
1507 switch (payload[0]) {
1508 case ADM_CMD_SET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001509 case ADM_CMD_SET_PP_PARAMS_V6:
1510 pr_debug("%s: ADM_CMD_SET_PP_PARAMS\n",
1511 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301512 if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
1513 this_adm.sourceTrackingData.
1514 apr_cmd_status = payload[1];
1515 else if (rtac_make_adm_callback(payload,
1516 data->payload_size))
1517 break;
1518 /*
1519 * if soft volume is called and already
1520 * interrupted break out of the sequence here
1521 */
1522 case ADM_CMD_DEVICE_OPEN_V5:
1523 case ADM_CMD_DEVICE_CLOSE_V5:
1524 case ADM_CMD_DEVICE_OPEN_V6:
1525 pr_debug("%s: Basic callback received, wake up.\n",
1526 __func__);
1527 atomic_set(&this_adm.copp.stat[port_idx]
1528 [copp_idx], payload[1]);
1529 wake_up(
1530 &this_adm.copp.wait[port_idx][copp_idx]);
1531 break;
1532 case ADM_CMD_ADD_TOPOLOGIES:
1533 pr_debug("%s: callback received, ADM_CMD_ADD_TOPOLOGIES.\n",
1534 __func__);
1535 atomic_set(&this_adm.adm_stat, payload[1]);
1536 wake_up(&this_adm.adm_wait);
1537 break;
1538 case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
1539 case ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5:
1540 pr_debug("%s: Basic callback received, wake up.\n",
1541 __func__);
1542 atomic_set(&this_adm.matrix_map_stat,
1543 payload[1]);
1544 wake_up(&this_adm.matrix_map_wait);
1545 break;
1546 case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
1547 pr_debug("%s: ADM_CMD_SHARED_MEM_UNMAP_REGIONS\n",
1548 __func__);
1549 atomic_set(&this_adm.adm_stat, payload[1]);
1550 wake_up(&this_adm.adm_wait);
1551 break;
1552 case ADM_CMD_SHARED_MEM_MAP_REGIONS:
1553 pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
1554 __func__);
1555 /* Should only come here if there is an APR */
1556 /* error or malformed APR packet. Otherwise */
1557 /* response will be returned as */
1558 if (payload[1] != 0) {
1559 pr_err("%s: ADM map error, resuming\n",
1560 __func__);
1561 atomic_set(&this_adm.adm_stat,
1562 payload[1]);
1563 wake_up(&this_adm.adm_wait);
1564 }
1565 break;
1566 case ADM_CMD_GET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001567 case ADM_CMD_GET_PP_PARAMS_V6:
1568 pr_debug("%s: ADM_CMD_GET_PP_PARAMS\n",
1569 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301570 /* Should only come here if there is an APR */
1571 /* error or malformed APR packet. Otherwise */
1572 /* response will be returned as */
1573 /* ADM_CMDRSP_GET_PP_PARAMS_V5 */
1574 if (client_id ==
1575 ADM_CLIENT_ID_SOURCE_TRACKING) {
1576 this_adm.sourceTrackingData.
1577 apr_cmd_status = payload[1];
1578 if (payload[1] != 0)
1579 pr_err("%s: ADM get param error = %d\n",
1580 __func__, payload[1]);
1581
1582 atomic_set(&this_adm.copp.stat
1583 [port_idx][copp_idx],
1584 payload[1]);
1585 wake_up(&this_adm.copp.wait
1586 [port_idx][copp_idx]);
1587 } else {
1588 if (payload[1] != 0) {
1589 pr_err("%s: ADM get param error = %d, resuming\n",
1590 __func__, payload[1]);
1591
1592 rtac_make_adm_callback(payload,
1593 data->payload_size);
1594 }
1595 }
1596 break;
1597 case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5:
1598 pr_debug("%s: ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5\n",
1599 __func__);
1600 atomic_set(&this_adm.copp.stat[port_idx]
1601 [copp_idx], payload[1]);
1602 wake_up(
1603 &this_adm.copp.wait[port_idx][copp_idx]);
1604 break;
1605 case ADM_CMD_GET_PP_TOPO_MODULE_LIST:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001606 case ADM_CMD_GET_PP_TOPO_MODULE_LIST_V2:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301607 pr_debug("%s:ADM_CMD_GET_PP_TOPO_MODULE_LIST\n",
1608 __func__);
1609 if (payload[1] != 0)
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001610 pr_err("%s: ADM get topo list error = %d\n",
1611 __func__, payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301612 break;
1613 default:
1614 pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
1615 payload[0]);
1616 break;
1617 }
1618 return 0;
1619 }
1620
1621 switch (data->opcode) {
1622 case ADM_CMDRSP_DEVICE_OPEN_V5:
1623 case ADM_CMDRSP_DEVICE_OPEN_V6: {
1624 struct adm_cmd_rsp_device_open_v5 *open =
1625 (struct adm_cmd_rsp_device_open_v5 *)data->payload;
1626
1627 if (open->copp_id == INVALID_COPP_ID) {
1628 pr_err("%s: invalid coppid rxed %d\n",
1629 __func__, open->copp_id);
1630 atomic_set(&this_adm.copp.stat[port_idx]
1631 [copp_idx], ADSP_EBADPARAM);
1632 wake_up(
1633 &this_adm.copp.wait[port_idx][copp_idx]);
1634 break;
1635 }
1636 atomic_set(&this_adm.copp.stat
1637 [port_idx][copp_idx], payload[0]);
1638 atomic_set(&this_adm.copp.id[port_idx][copp_idx],
1639 open->copp_id);
1640 pr_debug("%s: coppid rxed=%d\n", __func__,
1641 open->copp_id);
1642 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1643 }
1644 break;
1645 case ADM_CMDRSP_GET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001646 case ADM_CMDRSP_GET_PP_PARAMS_V6:
1647 pr_debug("%s: ADM_CMDRSP_GET_PP_PARAMS\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301648 if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
1649 this_adm.sourceTrackingData.apr_cmd_status =
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001650 payload[0];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301651 else if (rtac_make_adm_callback(payload,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001652 data->payload_size))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301653 break;
1654
1655 idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001656 if (payload[0] == 0 && data->payload_size > 0) {
1657 pr_debug("%s: Received parameter data in band\n",
1658 __func__);
1659 ret = adm_process_get_param_response(
1660 data->opcode, idx, payload,
1661 data->payload_size);
1662 if (ret)
1663 pr_err("%s: Failed to process get param response, error %d\n",
1664 __func__, ret);
1665 } else if (payload[0] == 0 && data->payload_size == 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301666 adm_get_parameters[idx] = -1;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001667 pr_debug("%s: Out of band case, setting size to %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301668 __func__, adm_get_parameters[idx]);
1669 } else {
1670 adm_get_parameters[idx] = -1;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001671 pr_err("%s: ADM_CMDRSP_GET_PP_PARAMS returned error 0x%x\n",
1672 __func__, payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301673 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001674 atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
1675 payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301676 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1677 break;
1678 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001679 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301680 pr_debug("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST\n",
1681 __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001682 num_modules = payload[1];
1683 pr_debug("%s: Num modules %d\n", __func__, num_modules);
1684 if (payload[0]) {
1685 pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST, error = %d\n",
1686 __func__, payload[0]);
1687 } else if (num_modules > MAX_MODULES_IN_TOPO) {
1688 pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST invalid num modules received, num modules = %d\n",
1689 __func__, num_modules);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301690 } else {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001691 ret = adm_process_get_topo_list_response(
1692 data->opcode, copp_idx, num_modules,
1693 payload, data->payload_size);
1694 if (ret)
1695 pr_err("%s: Failed to process get topo modules list response, error %d\n",
1696 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301697 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001698 atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
1699 payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301700 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1701 break;
1702 case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
1703 pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
1704 __func__);
1705 atomic_set(&this_adm.mem_map_handles[
1706 atomic_read(&this_adm.mem_map_index)],
1707 *payload);
1708 atomic_set(&this_adm.adm_stat, 0);
1709 wake_up(&this_adm.adm_wait);
1710 break;
1711 default:
1712 pr_err("%s: Unknown cmd:0x%x\n", __func__,
1713 data->opcode);
1714 break;
1715 }
1716 }
1717 return 0;
1718}
1719
1720static int adm_memory_map_regions(phys_addr_t *buf_add, uint32_t mempool_id,
1721 uint32_t *bufsz, uint32_t bufcnt)
1722{
1723 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
1724 struct avs_shared_map_region_payload *mregions = NULL;
1725 void *mmap_region_cmd = NULL;
1726 void *payload = NULL;
1727 int ret = 0;
1728 int i = 0;
1729 int cmd_size = 0;
1730
1731 pr_debug("%s:\n", __func__);
1732 if (this_adm.apr == NULL) {
1733 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
1734 0xFFFFFFFF, &this_adm);
1735 if (this_adm.apr == NULL) {
1736 pr_err("%s: Unable to register ADM\n", __func__);
1737 ret = -ENODEV;
1738 return ret;
1739 }
1740 rtac_set_adm_handle(this_adm.apr);
1741 }
1742
1743 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
1744 + sizeof(struct avs_shared_map_region_payload)
1745 * bufcnt;
1746
1747 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
1748 if (!mmap_region_cmd)
1749 return -ENOMEM;
1750
1751 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
1752 mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1753 APR_HDR_LEN(APR_HDR_SIZE),
1754 APR_PKT_VER);
1755 mmap_regions->hdr.pkt_size = cmd_size;
1756 mmap_regions->hdr.src_port = 0;
1757
1758 mmap_regions->hdr.dest_port = 0;
1759 mmap_regions->hdr.token = 0;
1760 mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
1761 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
1762 mmap_regions->num_regions = bufcnt & 0x00ff;
1763 mmap_regions->property_flag = 0x00;
1764
1765 pr_debug("%s: map_regions->num_regions = %d\n", __func__,
1766 mmap_regions->num_regions);
1767 payload = ((u8 *) mmap_region_cmd +
1768 sizeof(struct avs_cmd_shared_mem_map_regions));
1769 mregions = (struct avs_shared_map_region_payload *)payload;
1770
1771 for (i = 0; i < bufcnt; i++) {
1772 mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
1773 mregions->shm_addr_msw =
1774 msm_audio_populate_upper_32_bits(buf_add[i]);
1775 mregions->mem_size_bytes = bufsz[i];
1776 ++mregions;
1777 }
1778
1779 atomic_set(&this_adm.adm_stat, -1);
1780 ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
1781 if (ret < 0) {
1782 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
1783 mmap_regions->hdr.opcode, ret);
1784 ret = -EINVAL;
1785 goto fail_cmd;
1786 }
1787
1788 ret = wait_event_timeout(this_adm.adm_wait,
1789 atomic_read(&this_adm.adm_stat) >= 0,
1790 5 * HZ);
1791 if (!ret) {
1792 pr_err("%s: timeout. waited for memory_map\n", __func__);
1793 ret = -EINVAL;
1794 goto fail_cmd;
1795 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1796 pr_err("%s: DSP returned error[%s]\n",
1797 __func__, adsp_err_get_err_str(
1798 atomic_read(&this_adm.adm_stat)));
1799 ret = adsp_err_get_lnx_err_code(
1800 atomic_read(&this_adm.adm_stat));
1801 goto fail_cmd;
1802 }
1803fail_cmd:
1804 kfree(mmap_region_cmd);
1805 return ret;
1806}
1807
1808static int adm_memory_unmap_regions(void)
1809{
1810 struct avs_cmd_shared_mem_unmap_regions unmap_regions;
1811 int ret = 0;
1812
1813 pr_debug("%s:\n", __func__);
1814 if (this_adm.apr == NULL) {
1815 pr_err("%s: APR handle NULL\n", __func__);
1816 return -EINVAL;
1817 }
1818
1819 unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1820 APR_HDR_LEN(APR_HDR_SIZE),
1821 APR_PKT_VER);
1822 unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
1823 unmap_regions.hdr.src_port = 0;
1824 unmap_regions.hdr.dest_port = 0;
1825 unmap_regions.hdr.token = 0;
1826 unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
1827 unmap_regions.mem_map_handle = atomic_read(&this_adm.
1828 mem_map_handles[atomic_read(&this_adm.mem_map_index)]);
1829 atomic_set(&this_adm.adm_stat, -1);
1830 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
1831 if (ret < 0) {
1832 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
1833 unmap_regions.hdr.opcode, ret);
1834 ret = -EINVAL;
1835 goto fail_cmd;
1836 }
1837
1838 ret = wait_event_timeout(this_adm.adm_wait,
1839 atomic_read(&this_adm.adm_stat) >= 0,
1840 5 * HZ);
1841 if (!ret) {
1842 pr_err("%s: timeout. waited for memory_unmap\n",
1843 __func__);
1844 ret = -EINVAL;
1845 goto fail_cmd;
1846 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1847 pr_err("%s: DSP returned error[%s]\n",
1848 __func__, adsp_err_get_err_str(
1849 atomic_read(&this_adm.adm_stat)));
1850 ret = adsp_err_get_lnx_err_code(
1851 atomic_read(&this_adm.adm_stat));
1852 goto fail_cmd;
1853 } else {
1854 pr_debug("%s: Unmap handle 0x%x succeeded\n", __func__,
1855 unmap_regions.mem_map_handle);
1856 }
1857fail_cmd:
1858 return ret;
1859}
1860
1861static int remap_cal_data(struct cal_block_data *cal_block, int cal_index)
1862{
1863 int ret = 0;
1864
Banajit Goswami08bb7362017-11-03 22:48:23 -07001865 if (cal_block->map_data.dma_buf == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301866 pr_err("%s: No ION allocation for cal index %d!\n",
1867 __func__, cal_index);
1868 ret = -EINVAL;
1869 goto done;
1870 }
1871
1872 if ((cal_block->map_data.map_size > 0) &&
1873 (cal_block->map_data.q6map_handle == 0)) {
1874 atomic_set(&this_adm.mem_map_index, cal_index);
1875 ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
1876 (uint32_t *)&cal_block->map_data.map_size, 1);
1877 if (ret < 0) {
1878 pr_err("%s: ADM mmap did not work! size = %zd ret %d\n",
1879 __func__,
1880 cal_block->map_data.map_size, ret);
1881 pr_debug("%s: ADM mmap did not work! addr = 0x%pK, size = %zd ret %d\n",
1882 __func__,
1883 &cal_block->cal_data.paddr,
1884 cal_block->map_data.map_size, ret);
1885 goto done;
1886 }
1887 cal_block->map_data.q6map_handle = atomic_read(&this_adm.
1888 mem_map_handles[cal_index]);
1889 }
1890done:
1891 return ret;
1892}
1893
1894static void send_adm_custom_topology(void)
1895{
1896 struct cal_block_data *cal_block = NULL;
1897 struct cmd_set_topologies adm_top;
1898 int cal_index = ADM_CUSTOM_TOP_CAL;
1899 int result;
1900
1901 if (this_adm.cal_data[cal_index] == NULL)
1902 goto done;
1903
1904 mutex_lock(&this_adm.cal_data[cal_index]->lock);
1905 if (!this_adm.set_custom_topology)
1906 goto unlock;
1907 this_adm.set_custom_topology = 0;
1908
1909 cal_block = cal_utils_get_only_cal_block(this_adm.cal_data[cal_index]);
1910 if (cal_block == NULL)
1911 goto unlock;
1912
1913 pr_debug("%s: Sending cal_index %d\n", __func__, cal_index);
1914
1915 result = remap_cal_data(cal_block, cal_index);
1916 if (result) {
1917 pr_err("%s: Remap_cal_data failed for cal %d!\n",
1918 __func__, cal_index);
1919 goto unlock;
1920 }
1921 atomic_set(&this_adm.mem_map_index, cal_index);
1922 atomic_set(&this_adm.mem_map_handles[cal_index],
1923 cal_block->map_data.q6map_handle);
1924
1925 if (cal_block->cal_data.size == 0) {
1926 pr_debug("%s: No ADM cal to send\n", __func__);
1927 goto unlock;
1928 }
1929
1930 adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1931 APR_HDR_LEN(20), APR_PKT_VER);
1932 adm_top.hdr.pkt_size = sizeof(adm_top);
1933 adm_top.hdr.src_svc = APR_SVC_ADM;
1934 adm_top.hdr.src_domain = APR_DOMAIN_APPS;
1935 adm_top.hdr.src_port = 0;
1936 adm_top.hdr.dest_svc = APR_SVC_ADM;
1937 adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
1938 adm_top.hdr.dest_port = 0;
1939 adm_top.hdr.token = 0;
1940 adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
1941 adm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
1942 adm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
1943 cal_block->cal_data.paddr);
1944 adm_top.mem_map_handle = cal_block->map_data.q6map_handle;
1945 adm_top.payload_size = cal_block->cal_data.size;
1946
1947 atomic_set(&this_adm.adm_stat, -1);
1948 pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%pK, size = %d\n",
1949 __func__, &cal_block->cal_data.paddr,
1950 adm_top.payload_size);
1951 result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
1952 if (result < 0) {
1953 pr_err("%s: Set topologies failed payload size = %zd result %d\n",
1954 __func__, cal_block->cal_data.size, result);
1955 goto unlock;
1956 }
1957 /* Wait for the callback */
1958 result = wait_event_timeout(this_adm.adm_wait,
1959 atomic_read(&this_adm.adm_stat) >= 0,
1960 msecs_to_jiffies(TIMEOUT_MS));
1961 if (!result) {
1962 pr_err("%s: Set topologies timed out payload size = %zd\n",
1963 __func__, cal_block->cal_data.size);
1964 goto unlock;
1965 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1966 pr_err("%s: DSP returned error[%s]\n",
1967 __func__, adsp_err_get_err_str(
1968 atomic_read(&this_adm.adm_stat)));
1969 result = adsp_err_get_lnx_err_code(
1970 atomic_read(&this_adm.adm_stat));
1971 goto unlock;
1972 }
1973unlock:
1974 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
1975done:
1976 return;
1977}
1978
1979static int send_adm_cal_block(int port_id, int copp_idx,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001980 struct cal_block_data *cal_block, int perf_mode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301981{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001982 struct mem_mapping_hdr mem_hdr;
1983 int payload_size = 0;
1984 int port_idx = 0;
1985 int topology = 0;
1986 int result = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301987
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001988 pr_debug("%s: Port id 0x%x,\n", __func__, port_id);
1989
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301990 if (!cal_block) {
1991 pr_debug("%s: No ADM cal to send for port_id = 0x%x!\n",
1992 __func__, port_id);
1993 result = -EINVAL;
1994 goto done;
1995 }
1996 if (cal_block->cal_data.size <= 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001997 pr_debug("%s: No ADM cal sent for port_id = 0x%x!\n", __func__,
1998 port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301999 result = -EINVAL;
2000 goto done;
2001 }
2002
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002003 memset(&mem_hdr, 0, sizeof(mem_hdr));
2004 port_id = afe_convert_virtual_to_portid(port_id);
2005 port_idx = adm_validate_and_get_port_index(port_id);
2006 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
2007 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2008 return -EINVAL;
2009 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
2010 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
2011 return -EINVAL;
2012 }
2013
2014 topology = atomic_read(&this_adm.copp.topology[port_idx][copp_idx]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302015 if (perf_mode == LEGACY_PCM_MODE &&
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002016 topology == DS2_ADM_COPP_TOPOLOGY_ID) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302017 pr_err("%s: perf_mode %d, topology 0x%x\n", __func__, perf_mode,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002018 topology);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302019 goto done;
2020 }
2021
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002022 mem_hdr.data_payload_addr_lsw =
2023 lower_32_bits(cal_block->cal_data.paddr);
2024 mem_hdr.data_payload_addr_msw =
2025 msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
2026 mem_hdr.mem_map_handle = cal_block->map_data.q6map_handle;
2027 payload_size = cal_block->cal_data.size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302028
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002029 adm_set_pp_params(port_id, copp_idx, &mem_hdr, NULL, payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302030
2031done:
2032 return result;
2033}
2034
2035static struct cal_block_data *adm_find_cal_by_path(int cal_index, int path)
2036{
2037 struct list_head *ptr, *next;
2038 struct cal_block_data *cal_block = NULL;
2039 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2040 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2041
2042 pr_debug("%s:\n", __func__);
2043
2044 list_for_each_safe(ptr, next,
2045 &this_adm.cal_data[cal_index]->cal_blocks) {
2046
2047 cal_block = list_entry(ptr,
2048 struct cal_block_data, list);
2049
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302050 if (cal_index == ADM_AUDPROC_CAL ||
2051 cal_index == ADM_LSM_AUDPROC_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302052 audproc_cal_info = cal_block->cal_info;
2053 if ((audproc_cal_info->path == path) &&
2054 (cal_block->cal_data.size > 0))
2055 return cal_block;
2056 } else if (cal_index == ADM_AUDVOL_CAL) {
2057 audvol_cal_info = cal_block->cal_info;
2058 if ((audvol_cal_info->path == path) &&
2059 (cal_block->cal_data.size > 0))
2060 return cal_block;
2061 }
2062 }
2063 pr_debug("%s: Can't find ADM cal for cal_index %d, path %d\n",
2064 __func__, cal_index, path);
2065 return NULL;
2066}
2067
2068static struct cal_block_data *adm_find_cal_by_app_type(int cal_index, int path,
2069 int app_type)
2070{
2071 struct list_head *ptr, *next;
2072 struct cal_block_data *cal_block = NULL;
2073 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2074 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2075
2076 pr_debug("%s\n", __func__);
2077
2078 list_for_each_safe(ptr, next,
2079 &this_adm.cal_data[cal_index]->cal_blocks) {
2080
2081 cal_block = list_entry(ptr,
2082 struct cal_block_data, list);
2083
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302084 if (cal_index == ADM_AUDPROC_CAL ||
2085 cal_index == ADM_LSM_AUDPROC_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302086 audproc_cal_info = cal_block->cal_info;
2087 if ((audproc_cal_info->path == path) &&
2088 (audproc_cal_info->app_type == app_type) &&
2089 (cal_block->cal_data.size > 0))
2090 return cal_block;
2091 } else if (cal_index == ADM_AUDVOL_CAL) {
2092 audvol_cal_info = cal_block->cal_info;
2093 if ((audvol_cal_info->path == path) &&
2094 (audvol_cal_info->app_type == app_type) &&
2095 (cal_block->cal_data.size > 0))
2096 return cal_block;
2097 }
2098 }
2099 pr_debug("%s: Can't find ADM cali for cal_index %d, path %d, app %d, defaulting to search by path\n",
2100 __func__, cal_index, path, app_type);
2101 return adm_find_cal_by_path(cal_index, path);
2102}
2103
2104
2105static struct cal_block_data *adm_find_cal(int cal_index, int path,
2106 int app_type, int acdb_id,
2107 int sample_rate)
2108{
2109 struct list_head *ptr, *next;
2110 struct cal_block_data *cal_block = NULL;
2111 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2112 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2113
2114 pr_debug("%s:\n", __func__);
2115
2116 list_for_each_safe(ptr, next,
2117 &this_adm.cal_data[cal_index]->cal_blocks) {
2118
2119 cal_block = list_entry(ptr,
2120 struct cal_block_data, list);
2121
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302122 if (cal_index == ADM_AUDPROC_CAL ||
2123 cal_index == ADM_LSM_AUDPROC_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302124 audproc_cal_info = cal_block->cal_info;
2125 if ((audproc_cal_info->path == path) &&
2126 (audproc_cal_info->app_type == app_type) &&
2127 (audproc_cal_info->acdb_id == acdb_id) &&
2128 (audproc_cal_info->sample_rate == sample_rate) &&
2129 (cal_block->cal_data.size > 0))
2130 return cal_block;
2131 } else if (cal_index == ADM_AUDVOL_CAL) {
2132 audvol_cal_info = cal_block->cal_info;
2133 if ((audvol_cal_info->path == path) &&
2134 (audvol_cal_info->app_type == app_type) &&
2135 (audvol_cal_info->acdb_id == acdb_id) &&
2136 (cal_block->cal_data.size > 0))
2137 return cal_block;
2138 }
2139 }
2140 pr_debug("%s: Can't find ADM cal for cal_index %d, path %d, app %d, acdb_id %d sample_rate %d defaulting to search by app type\n",
2141 __func__, cal_index, path, app_type, acdb_id, sample_rate);
2142 return adm_find_cal_by_app_type(cal_index, path, app_type);
2143}
2144
2145static int adm_remap_and_send_cal_block(int cal_index, int port_id,
2146 int copp_idx, struct cal_block_data *cal_block, int perf_mode,
2147 int app_type, int acdb_id, int sample_rate)
2148{
2149 int ret = 0;
2150
2151 pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
2152 ret = remap_cal_data(cal_block, cal_index);
2153 if (ret) {
2154 pr_err("%s: Remap_cal_data failed for cal %d!\n",
2155 __func__, cal_index);
2156 goto done;
2157 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002158 ret = send_adm_cal_block(port_id, copp_idx, cal_block, perf_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302159 if (ret < 0)
2160 pr_debug("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d sample_rate %d\n",
2161 __func__, cal_index, port_id, ret, sample_rate);
2162done:
2163 return ret;
2164}
2165
2166static void send_adm_cal_type(int cal_index, int path, int port_id,
2167 int copp_idx, int perf_mode, int app_type,
2168 int acdb_id, int sample_rate)
2169{
2170 struct cal_block_data *cal_block = NULL;
2171 int ret;
2172
2173 pr_debug("%s: cal index %d\n", __func__, cal_index);
2174
2175 if (this_adm.cal_data[cal_index] == NULL) {
2176 pr_debug("%s: cal_index %d not allocated!\n",
2177 __func__, cal_index);
2178 goto done;
2179 }
2180
2181 mutex_lock(&this_adm.cal_data[cal_index]->lock);
2182 cal_block = adm_find_cal(cal_index, path, app_type, acdb_id,
2183 sample_rate);
2184 if (cal_block == NULL)
2185 goto unlock;
2186
2187 ret = adm_remap_and_send_cal_block(cal_index, port_id, copp_idx,
2188 cal_block, perf_mode, app_type, acdb_id, sample_rate);
2189unlock:
2190 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
2191done:
2192 return;
2193}
2194
2195static int get_cal_path(int path)
2196{
2197 if (path == 0x1)
2198 return RX_DEVICE;
2199 else
2200 return TX_DEVICE;
2201}
2202
2203static void send_adm_cal(int port_id, int copp_idx, int path, int perf_mode,
Aditya Bavanari5106b562018-01-08 13:16:32 +05302204 int app_type, int acdb_id, int sample_rate,
2205 int passthr_mode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302206{
2207 pr_debug("%s: port id 0x%x copp_idx %d\n", __func__, port_id, copp_idx);
2208
Aditya Bavanari5106b562018-01-08 13:16:32 +05302209 if (passthr_mode != LISTEN)
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302210 send_adm_cal_type(ADM_AUDPROC_CAL, path, port_id, copp_idx,
2211 perf_mode, app_type, acdb_id, sample_rate);
2212 else
2213 send_adm_cal_type(ADM_LSM_AUDPROC_CAL, path, port_id, copp_idx,
2214 perf_mode, app_type, acdb_id, sample_rate);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302215 send_adm_cal_type(ADM_AUDVOL_CAL, path, port_id, copp_idx, perf_mode,
2216 app_type, acdb_id, sample_rate);
2217}
2218
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302219/**
2220 * adm_connect_afe_port -
2221 * command to send ADM connect AFE port
2222 *
2223 * @mode: value of mode for ADM connect AFE
2224 * @session_id: session active to connect
2225 * @port_id: Port ID number
2226 *
2227 * Returns 0 on success or error on failure
2228 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302229int adm_connect_afe_port(int mode, int session_id, int port_id)
2230{
2231 struct adm_cmd_connect_afe_port_v5 cmd;
2232 int ret = 0;
2233 int port_idx, copp_idx = 0;
2234
2235 pr_debug("%s: port_id: 0x%x session id:%d mode:%d\n", __func__,
2236 port_id, session_id, mode);
2237
2238 port_id = afe_convert_virtual_to_portid(port_id);
2239 port_idx = adm_validate_and_get_port_index(port_id);
2240 if (port_idx < 0) {
2241 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2242 return -EINVAL;
2243 }
2244
2245 if (this_adm.apr == NULL) {
2246 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
2247 0xFFFFFFFF, &this_adm);
2248 if (this_adm.apr == NULL) {
2249 pr_err("%s: Unable to register ADM\n", __func__);
2250 ret = -ENODEV;
2251 return ret;
2252 }
2253 rtac_set_adm_handle(this_adm.apr);
2254 }
2255 pr_debug("%s: Port ID 0x%x, index %d\n", __func__, port_id, port_idx);
2256
2257 cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2258 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2259 cmd.hdr.pkt_size = sizeof(cmd);
2260 cmd.hdr.src_svc = APR_SVC_ADM;
2261 cmd.hdr.src_domain = APR_DOMAIN_APPS;
2262 cmd.hdr.src_port = port_id;
2263 cmd.hdr.dest_svc = APR_SVC_ADM;
2264 cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
2265 cmd.hdr.dest_port = 0; /* Ignored */
2266 cmd.hdr.token = port_idx << 16 | copp_idx;
2267 cmd.hdr.opcode = ADM_CMD_CONNECT_AFE_PORT_V5;
2268
2269 cmd.mode = mode;
2270 cmd.session_id = session_id;
2271 cmd.afe_port_id = port_id;
2272
2273 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2274 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
2275 if (ret < 0) {
2276 pr_err("%s: ADM enable for port_id: 0x%x failed ret %d\n",
2277 __func__, port_id, ret);
2278 ret = -EINVAL;
2279 goto fail_cmd;
2280 }
2281 /* Wait for the callback with copp id */
2282 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
2283 atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
2284 msecs_to_jiffies(TIMEOUT_MS));
2285 if (!ret) {
2286 pr_err("%s: ADM connect timedout for port_id: 0x%x\n",
2287 __func__, port_id);
2288 ret = -EINVAL;
2289 goto fail_cmd;
2290 } else if (atomic_read(&this_adm.copp.stat
2291 [port_idx][copp_idx]) > 0) {
2292 pr_err("%s: DSP returned error[%s]\n",
2293 __func__, adsp_err_get_err_str(
2294 atomic_read(&this_adm.copp.stat
2295 [port_idx][copp_idx])));
2296 ret = adsp_err_get_lnx_err_code(
2297 atomic_read(&this_adm.copp.stat
2298 [port_idx][copp_idx]));
2299 goto fail_cmd;
2300 }
2301 atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
2302 return 0;
2303
2304fail_cmd:
2305
2306 return ret;
2307}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302308EXPORT_SYMBOL(adm_connect_afe_port);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302309
2310int adm_arrange_mch_map(struct adm_cmd_device_open_v5 *open, int path,
2311 int channel_mode)
2312{
2313 int rc = 0, idx;
2314
2315 memset(open->dev_channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
2316 switch (path) {
2317 case ADM_PATH_PLAYBACK:
2318 idx = ADM_MCH_MAP_IDX_PLAYBACK;
2319 break;
2320 case ADM_PATH_LIVE_REC:
2321 case ADM_PATH_NONLIVE_REC:
2322 idx = ADM_MCH_MAP_IDX_REC;
2323 break;
2324 default:
2325 goto non_mch_path;
2326 };
2327 if ((open->dev_num_channel > 2) && multi_ch_maps[idx].set_channel_map) {
2328 memcpy(open->dev_channel_mapping,
2329 multi_ch_maps[idx].channel_mapping,
2330 PCM_FORMAT_MAX_NUM_CHANNEL);
2331 } else {
2332 if (channel_mode == 1) {
2333 open->dev_channel_mapping[0] = PCM_CHANNEL_FC;
2334 } else if (channel_mode == 2) {
2335 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2336 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2337 } else if (channel_mode == 3) {
2338 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2339 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2340 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2341 } else if (channel_mode == 4) {
2342 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2343 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2344 open->dev_channel_mapping[2] = PCM_CHANNEL_LS;
2345 open->dev_channel_mapping[3] = PCM_CHANNEL_RS;
2346 } else if (channel_mode == 5) {
2347 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2348 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2349 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2350 open->dev_channel_mapping[3] = PCM_CHANNEL_LS;
2351 open->dev_channel_mapping[4] = PCM_CHANNEL_RS;
2352 } else if (channel_mode == 6) {
2353 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2354 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2355 open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
2356 open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
2357 open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
2358 open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
2359 } else if (channel_mode == 7) {
2360 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2361 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2362 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2363 open->dev_channel_mapping[3] = PCM_CHANNEL_LFE;
2364 open->dev_channel_mapping[4] = PCM_CHANNEL_LB;
2365 open->dev_channel_mapping[5] = PCM_CHANNEL_RB;
2366 open->dev_channel_mapping[6] = PCM_CHANNEL_CS;
2367 } else if (channel_mode == 8) {
2368 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2369 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2370 open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
2371 open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
2372 open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
2373 open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
2374 open->dev_channel_mapping[6] = PCM_CHANNEL_LB;
2375 open->dev_channel_mapping[7] = PCM_CHANNEL_RB;
2376 } else {
2377 pr_err("%s: invalid num_chan %d\n", __func__,
2378 channel_mode);
2379 rc = -EINVAL;
2380 goto inval_ch_mod;
2381 }
2382 }
2383
2384non_mch_path:
2385inval_ch_mod:
2386 return rc;
2387}
2388
2389int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
2390 int channel_mode)
2391{
2392 int rc = 0;
2393
2394 memset(open_v6->dev_channel_mapping_eid2, 0,
2395 PCM_FORMAT_MAX_NUM_CHANNEL);
2396
2397 if (channel_mode == 1) {
2398 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FC;
2399 } else if (channel_mode == 2) {
2400 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2401 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2402 } else if (channel_mode == 3) {
2403 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2404 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2405 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
2406 } else if (channel_mode == 4) {
2407 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2408 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2409 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LS;
2410 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_RS;
2411 } else if (channel_mode == 5) {
2412 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2413 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2414 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
2415 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_LS;
2416 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_RS;
2417 } else if (channel_mode == 6) {
2418 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2419 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2420 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
2421 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
2422 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
2423 open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
2424 } else if (channel_mode == 8) {
2425 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2426 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2427 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
2428 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
2429 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
2430 open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
2431 open_v6->dev_channel_mapping_eid2[6] = PCM_CHANNEL_LB;
2432 open_v6->dev_channel_mapping_eid2[7] = PCM_CHANNEL_RB;
2433 } else {
2434 pr_err("%s: invalid num_chan %d\n", __func__,
2435 channel_mode);
2436 rc = -EINVAL;
2437 }
2438
2439 return rc;
2440}
2441
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302442/**
2443 * adm_open -
2444 * command to send ADM open
2445 *
2446 * @port_id: port id number
2447 * @path: direction or ADM path type
2448 * @rate: sample rate of session
2449 * @channel_mode: number of channels set
2450 * @topology: topology active for this session
2451 * @perf_mode: performance mode like LL/ULL/..
2452 * @bit_width: bit width to set for copp
2453 * @app_type: App type used for this session
2454 * @acdb_id: ACDB ID of this device
2455 *
2456 * Returns 0 on success or error on failure
2457 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302458int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
2459 int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
2460{
2461 struct adm_cmd_device_open_v5 open;
2462 struct adm_cmd_device_open_v6 open_v6;
2463 int ret = 0;
Asish Bhattacharya34504582017-08-08 12:55:01 +05302464 int port_idx, flags;
2465 int copp_idx = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302466 int tmp_port = q6audio_get_port_id(port_id);
2467
2468 pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n",
2469 __func__, port_id, path, rate, channel_mode, perf_mode,
2470 topology);
2471
2472 port_id = q6audio_convert_virtual_to_portid(port_id);
2473 port_idx = adm_validate_and_get_port_index(port_id);
2474 if (port_idx < 0) {
2475 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2476 return -EINVAL;
2477 }
2478
2479 if (this_adm.apr == NULL) {
2480 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
2481 0xFFFFFFFF, &this_adm);
2482 if (this_adm.apr == NULL) {
2483 pr_err("%s: Unable to register ADM\n", __func__);
2484 return -ENODEV;
2485 }
2486 rtac_set_adm_handle(this_adm.apr);
2487 }
2488
2489 if (perf_mode == ULL_POST_PROCESSING_PCM_MODE) {
2490 flags = ADM_ULL_POST_PROCESSING_DEVICE_SESSION;
2491 if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
2492 (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
2493 (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
2494 topology = DEFAULT_COPP_TOPOLOGY;
2495 } else if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
2496 flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
2497 topology = NULL_COPP_TOPOLOGY;
2498 rate = ULL_SUPPORTED_SAMPLE_RATE;
2499 bit_width = ULL_SUPPORTED_BITS_PER_SAMPLE;
2500 } else if (perf_mode == LOW_LATENCY_PCM_MODE) {
2501 flags = ADM_LOW_LATENCY_DEVICE_SESSION;
2502 if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
2503 (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
2504 (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
2505 topology = DEFAULT_COPP_TOPOLOGY;
2506 } else {
2507 if ((path == ADM_PATH_COMPRESSED_RX) ||
2508 (path == ADM_PATH_COMPRESSED_TX))
2509 flags = 0;
2510 else
2511 flags = ADM_LEGACY_DEVICE_SESSION;
2512 }
2513
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +05302514 if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302515 (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
2516 (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
2517 rate = 16000;
2518
Asish Bhattacharya34504582017-08-08 12:55:01 +05302519 /*
2520 * Routing driver reuses the same adm for streams with the same
2521 * app_type, sample_rate etc.
2522 * This isn't allowed for ULL streams as per the DSP interface
2523 */
2524 if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE)
2525 copp_idx = adm_get_idx_if_copp_exists(port_idx, topology,
2526 perf_mode,
2527 rate, bit_width,
2528 app_type);
2529
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302530 if (copp_idx < 0) {
2531 copp_idx = adm_get_next_available_copp(port_idx);
2532 if (copp_idx >= MAX_COPPS_PER_PORT) {
2533 pr_err("%s: exceeded copp id %d\n",
2534 __func__, copp_idx);
2535 return -EINVAL;
2536 }
2537 atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
2538 atomic_set(&this_adm.copp.topology[port_idx][copp_idx],
2539 topology);
2540 atomic_set(&this_adm.copp.mode[port_idx][copp_idx],
2541 perf_mode);
2542 atomic_set(&this_adm.copp.rate[port_idx][copp_idx],
2543 rate);
2544 atomic_set(&this_adm.copp.channels[port_idx][copp_idx],
2545 channel_mode);
2546 atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx],
2547 bit_width);
2548 atomic_set(&this_adm.copp.app_type[port_idx][copp_idx],
2549 app_type);
2550 atomic_set(&this_adm.copp.acdb_id[port_idx][copp_idx],
2551 acdb_id);
2552 set_bit(ADM_STATUS_CALIBRATION_REQUIRED,
2553 (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
2554 if ((path != ADM_PATH_COMPRESSED_RX) &&
2555 (path != ADM_PATH_COMPRESSED_TX))
2556 send_adm_custom_topology();
2557 }
2558
2559 if (this_adm.copp.adm_delay[port_idx][copp_idx] &&
2560 perf_mode == LEGACY_PCM_MODE) {
2561 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
2562 1);
2563 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
2564 wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
2565 }
2566
2567 /* Create a COPP if port id are not enabled */
2568 if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) {
2569 pr_debug("%s: open ADM: port_idx: %d, copp_idx: %d\n", __func__,
2570 port_idx, copp_idx);
2571 if ((topology == SRS_TRUMEDIA_TOPOLOGY_ID) &&
2572 perf_mode == LEGACY_PCM_MODE) {
2573 int res;
2574
2575 atomic_set(&this_adm.mem_map_index, ADM_SRS_TRUMEDIA);
2576 msm_dts_srs_tm_ion_memmap(&this_adm.outband_memmap);
2577 res = adm_memory_map_regions(&this_adm.outband_memmap.paddr, 0,
2578 (uint32_t *)&this_adm.outband_memmap.size, 1);
2579 if (res < 0) {
2580 pr_err("%s: SRS adm_memory_map_regions failed ! addr = 0x%pK, size = %d\n",
2581 __func__, (void *)this_adm.outband_memmap.paddr,
2582 (uint32_t)this_adm.outband_memmap.size);
2583 }
2584 }
2585 open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2586 APR_HDR_LEN(APR_HDR_SIZE),
2587 APR_PKT_VER);
2588 open.hdr.pkt_size = sizeof(open);
2589 open.hdr.src_svc = APR_SVC_ADM;
2590 open.hdr.src_domain = APR_DOMAIN_APPS;
2591 open.hdr.src_port = tmp_port;
2592 open.hdr.dest_svc = APR_SVC_ADM;
2593 open.hdr.dest_domain = APR_DOMAIN_ADSP;
2594 open.hdr.dest_port = tmp_port;
2595 open.hdr.token = port_idx << 16 | copp_idx;
2596 open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
2597 open.flags = flags;
2598 open.mode_of_operation = path;
2599 open.endpoint_id_1 = tmp_port;
2600 open.endpoint_id_2 = 0xFFFF;
2601
2602 if (this_adm.ec_ref_rx && (path != 1)) {
2603 open.endpoint_id_2 = this_adm.ec_ref_rx;
2604 this_adm.ec_ref_rx = -1;
2605 }
2606
2607 open.topology_id = topology;
2608
2609 open.dev_num_channel = channel_mode & 0x00FF;
2610 open.bit_width = bit_width;
2611 WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
2612 (rate != ULL_SUPPORTED_SAMPLE_RATE));
2613 open.sample_rate = rate;
2614
2615 ret = adm_arrange_mch_map(&open, path, channel_mode);
2616
2617 if (ret)
2618 return ret;
2619
2620 pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
2621 __func__, open.endpoint_id_1, open.sample_rate,
2622 open.topology_id);
2623
2624 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2625
2626 if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
2627 (open.endpoint_id_2 != 0xFFFF)) {
2628 memset(&open_v6, 0,
2629 sizeof(struct adm_cmd_device_open_v6));
2630 memcpy(&open_v6, &open,
2631 sizeof(struct adm_cmd_device_open_v5));
2632 open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
2633 open_v6.hdr.pkt_size = sizeof(open_v6);
2634 open_v6.dev_num_channel_eid2 =
2635 this_adm.num_ec_ref_rx_chans;
2636 this_adm.num_ec_ref_rx_chans = 0;
2637
2638 if (this_adm.ec_ref_rx_bit_width != 0) {
2639 open_v6.bit_width_eid2 =
2640 this_adm.ec_ref_rx_bit_width;
2641 this_adm.ec_ref_rx_bit_width = 0;
2642 } else {
2643 open_v6.bit_width_eid2 = bit_width;
2644 }
2645
2646 if (this_adm.ec_ref_rx_sampling_rate != 0) {
2647 open_v6.sample_rate_eid2 =
2648 this_adm.ec_ref_rx_sampling_rate;
2649 this_adm.ec_ref_rx_sampling_rate = 0;
2650 } else {
2651 open_v6.sample_rate_eid2 = rate;
2652 }
2653
2654 pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
2655 __func__, open_v6.dev_num_channel_eid2,
2656 open_v6.bit_width_eid2,
2657 open_v6.sample_rate_eid2);
2658
2659 ret = adm_arrange_mch_ep2_map(&open_v6,
2660 open_v6.dev_num_channel_eid2);
2661
2662 if (ret)
2663 return ret;
2664
2665 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
2666 } else {
2667 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
2668 }
2669 if (ret < 0) {
2670 pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
2671 __func__, tmp_port, port_id, ret);
2672 return -EINVAL;
2673 }
2674 /* Wait for the callback with copp id */
2675 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
2676 atomic_read(&this_adm.copp.stat
2677 [port_idx][copp_idx]) >= 0,
2678 msecs_to_jiffies(TIMEOUT_MS));
2679 if (!ret) {
2680 pr_err("%s: ADM open timedout for port_id: 0x%x for [0x%x]\n",
2681 __func__, tmp_port, port_id);
2682 return -EINVAL;
2683 } else if (atomic_read(&this_adm.copp.stat
2684 [port_idx][copp_idx]) > 0) {
2685 pr_err("%s: DSP returned error[%s]\n",
2686 __func__, adsp_err_get_err_str(
2687 atomic_read(&this_adm.copp.stat
2688 [port_idx][copp_idx])));
2689 return adsp_err_get_lnx_err_code(
2690 atomic_read(&this_adm.copp.stat
2691 [port_idx][copp_idx]));
2692 }
2693 }
2694 atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
2695 return copp_idx;
2696}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302697EXPORT_SYMBOL(adm_open);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302698
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302699/**
2700 * adm_copp_mfc_cfg -
2701 * command to send ADM MFC config
2702 *
2703 * @port_id: Port ID number
2704 * @copp_idx: copp index assigned
2705 * @dst_sample_rate: sink sample rate
2706 *
2707 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302708void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate)
2709{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002710 struct audproc_mfc_param_media_fmt mfc_cfg;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302711 struct adm_cmd_device_open_v5 open;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002712 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302713 int port_idx;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302714 int rc = 0;
2715 int i = 0;
2716
2717 port_id = q6audio_convert_virtual_to_portid(port_id);
2718 port_idx = adm_validate_and_get_port_index(port_id);
2719
2720 if (port_idx < 0) {
2721 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
2722 goto fail_cmd;
2723 }
2724
2725 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
2726 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
2727 goto fail_cmd;
2728 }
2729
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002730 memset(&mfc_cfg, 0, sizeof(mfc_cfg));
2731 memset(&open, 0, sizeof(open));
2732 memset(&param_hdr, 0, sizeof(param_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302733
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002734 param_hdr.module_id = AUDPROC_MODULE_ID_MFC;
2735 param_hdr.instance_id = INSTANCE_ID_0;
2736 param_hdr.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
2737 param_hdr.param_size = sizeof(mfc_cfg);
2738
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302739 mfc_cfg.sampling_rate = dst_sample_rate;
2740 mfc_cfg.bits_per_sample =
2741 atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
2742 open.dev_num_channel = mfc_cfg.num_channels =
2743 atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
2744
2745 rc = adm_arrange_mch_map(&open, ADM_PATH_PLAYBACK,
2746 mfc_cfg.num_channels);
2747 if (rc < 0) {
2748 pr_err("%s: unable to get channal map\n", __func__);
2749 goto fail_cmd;
2750 }
2751
2752 for (i = 0; i < mfc_cfg.num_channels; i++)
2753 mfc_cfg.channel_type[i] =
2754 (uint16_t) open.dev_channel_mapping[i];
2755
2756 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2757
2758 pr_debug("%s: mfc config: port_idx %d copp_idx %d copp SR %d copp BW %d copp chan %d o/p SR %d\n",
2759 __func__, port_idx, copp_idx,
2760 atomic_read(&this_adm.copp.rate[port_idx][copp_idx]),
2761 mfc_cfg.bits_per_sample, mfc_cfg.num_channels,
2762 mfc_cfg.sampling_rate);
2763
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002764 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
2765 (uint8_t *) &mfc_cfg);
2766 if (rc)
2767 pr_err("%s: Failed to set media format configuration data, err %d\n",
2768 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302769
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302770fail_cmd:
2771 return;
2772}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302773EXPORT_SYMBOL(adm_copp_mfc_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302774
2775static void route_set_opcode_matrix_id(
2776 struct adm_cmd_matrix_map_routings_v5 **route_addr,
2777 int path, uint32_t passthr_mode)
2778{
2779 struct adm_cmd_matrix_map_routings_v5 *route = *route_addr;
2780
2781 switch (path) {
2782 case ADM_PATH_PLAYBACK:
2783 route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
2784 route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
2785 break;
2786 case ADM_PATH_LIVE_REC:
2787 if (passthr_mode == LISTEN) {
2788 route->hdr.opcode =
2789 ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2790 route->matrix_id = ADM_MATRIX_ID_LISTEN_TX;
2791 break;
2792 }
2793 /* fall through to set matrix id for non-listen case */
2794 case ADM_PATH_NONLIVE_REC:
2795 route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
2796 route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
2797 break;
2798 case ADM_PATH_COMPRESSED_RX:
2799 route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2800 route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
2801 break;
2802 case ADM_PATH_COMPRESSED_TX:
2803 route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2804 route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_TX;
2805 break;
2806 default:
2807 pr_err("%s: Wrong path set[%d]\n", __func__, path);
2808 break;
2809 }
2810 pr_debug("%s: opcode 0x%x, matrix id %d\n",
2811 __func__, route->hdr.opcode, route->matrix_id);
2812}
2813
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302814/**
2815 * adm_matrix_map -
2816 * command to send ADM matrix map for ADM copp list
2817 *
2818 * @path: direction or ADM path type
2819 * @payload_map: have info of session id and associated copp_idx/num_copps
2820 * @perf_mode: performance mode like LL/ULL/..
2821 * @passthr_mode: flag to indicate passthrough mode
2822 *
2823 * Returns 0 on success or error on failure
2824 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302825int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
2826 uint32_t passthr_mode)
2827{
2828 struct adm_cmd_matrix_map_routings_v5 *route;
2829 struct adm_session_map_node_v5 *node;
2830 uint16_t *copps_list;
2831 int cmd_size = 0;
2832 int ret = 0, i = 0;
2833 void *payload = NULL;
2834 void *matrix_map = NULL;
2835 int port_idx, copp_idx;
2836
2837 /* Assumes port_ids have already been validated during adm_open */
2838 cmd_size = (sizeof(struct adm_cmd_matrix_map_routings_v5) +
2839 sizeof(struct adm_session_map_node_v5) +
2840 (sizeof(uint32_t) * payload_map.num_copps));
2841 matrix_map = kzalloc(cmd_size, GFP_KERNEL);
2842 if (matrix_map == NULL) {
2843 pr_err("%s: Mem alloc failed\n", __func__);
2844 ret = -EINVAL;
2845 return ret;
2846 }
2847 route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
2848
2849 route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2850 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2851 route->hdr.pkt_size = cmd_size;
2852 route->hdr.src_svc = 0;
2853 route->hdr.src_domain = APR_DOMAIN_APPS;
2854 route->hdr.src_port = 0; /* Ignored */;
2855 route->hdr.dest_svc = APR_SVC_ADM;
2856 route->hdr.dest_domain = APR_DOMAIN_ADSP;
2857 route->hdr.dest_port = 0; /* Ignored */;
2858 route->hdr.token = 0;
2859 route->num_sessions = 1;
2860 route_set_opcode_matrix_id(&route, path, passthr_mode);
2861
2862 payload = ((u8 *)matrix_map +
2863 sizeof(struct adm_cmd_matrix_map_routings_v5));
2864 node = (struct adm_session_map_node_v5 *)payload;
2865
2866 node->session_id = payload_map.session_id;
2867 node->num_copps = payload_map.num_copps;
2868 payload = (u8 *)node + sizeof(struct adm_session_map_node_v5);
2869 copps_list = (uint16_t *)payload;
2870 for (i = 0; i < payload_map.num_copps; i++) {
2871 port_idx =
2872 adm_validate_and_get_port_index(payload_map.port_id[i]);
2873 if (port_idx < 0) {
2874 pr_err("%s: Invalid port_id 0x%x\n", __func__,
2875 payload_map.port_id[i]);
2876 ret = -EINVAL;
2877 goto fail_cmd;
2878 }
2879 copp_idx = payload_map.copp_idx[i];
2880 copps_list[i] = atomic_read(&this_adm.copp.id[port_idx]
2881 [copp_idx]);
2882 }
2883 atomic_set(&this_adm.matrix_map_stat, -1);
2884
2885 ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
2886 if (ret < 0) {
2887 pr_err("%s: routing for syream %d failed ret %d\n",
2888 __func__, payload_map.session_id, ret);
2889 ret = -EINVAL;
2890 goto fail_cmd;
2891 }
2892 ret = wait_event_timeout(this_adm.matrix_map_wait,
2893 atomic_read(&this_adm.matrix_map_stat) >= 0,
2894 msecs_to_jiffies(TIMEOUT_MS));
2895 if (!ret) {
2896 pr_err("%s: routing for syream %d failed\n", __func__,
2897 payload_map.session_id);
2898 ret = -EINVAL;
2899 goto fail_cmd;
2900 } else if (atomic_read(&this_adm.matrix_map_stat) > 0) {
2901 pr_err("%s: DSP returned error[%s]\n", __func__,
2902 adsp_err_get_err_str(atomic_read(
2903 &this_adm.matrix_map_stat)));
2904 ret = adsp_err_get_lnx_err_code(
2905 atomic_read(&this_adm.matrix_map_stat));
2906 goto fail_cmd;
2907 }
2908
2909 if ((perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) &&
2910 (path != ADM_PATH_COMPRESSED_RX)) {
2911 for (i = 0; i < payload_map.num_copps; i++) {
2912 port_idx = afe_get_port_index(payload_map.port_id[i]);
2913 copp_idx = payload_map.copp_idx[i];
2914 if (port_idx < 0 || copp_idx < 0 ||
2915 (copp_idx > MAX_COPPS_PER_PORT - 1)) {
2916 pr_err("%s: Invalid idx port_idx %d copp_idx %d\n",
2917 __func__, port_idx, copp_idx);
2918 continue;
2919 }
2920 rtac_add_adm_device(payload_map.port_id[i],
2921 atomic_read(&this_adm.copp.id
2922 [port_idx][copp_idx]),
2923 get_cal_path(path),
2924 payload_map.session_id,
2925 payload_map.app_type[i],
2926 payload_map.acdb_dev_id[i]);
2927
2928 if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
2929 (void *)&this_adm.copp.adm_status[port_idx]
2930 [copp_idx])) {
2931 pr_debug("%s: adm copp[0x%x][%d] already sent",
2932 __func__, port_idx, copp_idx);
2933 continue;
2934 }
2935 send_adm_cal(payload_map.port_id[i], copp_idx,
2936 get_cal_path(path), perf_mode,
2937 payload_map.app_type[i],
2938 payload_map.acdb_dev_id[i],
Aditya Bavanari5106b562018-01-08 13:16:32 +05302939 payload_map.sample_rate[i],
2940 passthr_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302941 /* ADM COPP calibration is already sent */
2942 clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
2943 (void *)&this_adm.copp.
2944 adm_status[port_idx][copp_idx]);
2945 pr_debug("%s: copp_id: %d\n", __func__,
2946 atomic_read(&this_adm.copp.id[port_idx]
2947 [copp_idx]));
2948 }
2949 }
2950
2951fail_cmd:
2952 kfree(matrix_map);
2953 return ret;
2954}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302955EXPORT_SYMBOL(adm_matrix_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302956
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302957/**
2958 * adm_ec_ref_rx_id -
2959 * Update EC ref port ID
2960 *
2961 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302962void adm_ec_ref_rx_id(int port_id)
2963{
2964 this_adm.ec_ref_rx = port_id;
2965 pr_debug("%s: ec_ref_rx:%d\n", __func__, this_adm.ec_ref_rx);
2966}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302967EXPORT_SYMBOL(adm_ec_ref_rx_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302968
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302969/**
2970 * adm_num_ec_ref_rx_chans -
2971 * Update EC ref number of channels
2972 *
2973 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302974void adm_num_ec_ref_rx_chans(int num_chans)
2975{
2976 this_adm.num_ec_ref_rx_chans = num_chans;
2977 pr_debug("%s: num_ec_ref_rx_chans:%d\n",
2978 __func__, this_adm.num_ec_ref_rx_chans);
2979}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302980EXPORT_SYMBOL(adm_num_ec_ref_rx_chans);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302981
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302982/**
2983 * adm_ec_ref_rx_bit_width -
2984 * Update EC ref bit_width
2985 *
2986 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302987void adm_ec_ref_rx_bit_width(int bit_width)
2988{
2989 this_adm.ec_ref_rx_bit_width = bit_width;
2990 pr_debug("%s: ec_ref_rx_bit_width:%d\n",
2991 __func__, this_adm.ec_ref_rx_bit_width);
2992}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302993EXPORT_SYMBOL(adm_ec_ref_rx_bit_width);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302994
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302995/**
2996 * adm_ec_ref_rx_sampling_rate -
2997 * Update EC ref sample rate
2998 *
2999 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303000void adm_ec_ref_rx_sampling_rate(int sampling_rate)
3001{
3002 this_adm.ec_ref_rx_sampling_rate = sampling_rate;
3003 pr_debug("%s: ec_ref_rx_sampling_rate:%d\n",
3004 __func__, this_adm.ec_ref_rx_sampling_rate);
3005}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303006EXPORT_SYMBOL(adm_ec_ref_rx_sampling_rate);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303007
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303008/**
3009 * adm_close -
3010 * command to close ADM copp
3011 *
3012 * @port_id: Port ID number
3013 * @perf_mode: performance mode like LL/ULL/..
3014 * @copp_idx: copp index assigned
3015 *
3016 * Returns 0 on success or error on failure
3017 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303018int adm_close(int port_id, int perf_mode, int copp_idx)
3019{
3020 struct apr_hdr close;
3021
3022 int ret = 0, port_idx;
3023 int copp_id = RESET_COPP_ID;
3024
3025 pr_debug("%s: port_id=0x%x perf_mode: %d copp_idx: %d\n", __func__,
3026 port_id, perf_mode, copp_idx);
3027
3028 port_id = q6audio_convert_virtual_to_portid(port_id);
3029 port_idx = adm_validate_and_get_port_index(port_id);
3030 if (port_idx < 0) {
3031 pr_err("%s: Invalid port_id 0x%x\n",
3032 __func__, port_id);
3033 return -EINVAL;
3034 }
3035
3036 if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
3037 pr_err("%s: Invalid copp idx: %d\n", __func__, copp_idx);
3038 return -EINVAL;
3039 }
3040
3041 if (this_adm.copp.adm_delay[port_idx][copp_idx] && perf_mode
3042 == LEGACY_PCM_MODE) {
3043 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
3044 1);
3045 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
3046 wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
3047 }
3048
3049 atomic_dec(&this_adm.copp.cnt[port_idx][copp_idx]);
3050 if (!(atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]))) {
3051 copp_id = adm_get_copp_id(port_idx, copp_idx);
3052 pr_debug("%s: Closing ADM port_idx:%d copp_idx:%d copp_id:0x%x\n",
3053 __func__, port_idx, copp_idx, copp_id);
3054 if ((!perf_mode) && (this_adm.outband_memmap.paddr != 0) &&
3055 (atomic_read(&this_adm.copp.topology[port_idx][copp_idx]) ==
3056 SRS_TRUMEDIA_TOPOLOGY_ID)) {
3057 atomic_set(&this_adm.mem_map_index,
3058 ADM_SRS_TRUMEDIA);
3059 ret = adm_memory_unmap_regions();
3060 if (ret < 0) {
3061 pr_err("%s: adm mem unmmap err %d",
3062 __func__, ret);
3063 } else {
3064 atomic_set(&this_adm.mem_map_handles
3065 [ADM_SRS_TRUMEDIA], 0);
3066 }
3067 }
3068
3069
3070 if ((afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) &&
3071 this_adm.sourceTrackingData.memmap.paddr) {
3072 atomic_set(&this_adm.mem_map_index,
3073 ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
3074 ret = adm_memory_unmap_regions();
3075 if (ret < 0) {
3076 pr_err("%s: adm mem unmmap err %d",
3077 __func__, ret);
3078 }
3079 msm_audio_ion_free(
Banajit Goswami08bb7362017-11-03 22:48:23 -07003080 this_adm.sourceTrackingData.dma_buf);
3081 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303082 this_adm.sourceTrackingData.memmap.size = 0;
3083 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
3084 this_adm.sourceTrackingData.memmap.paddr = 0;
3085 this_adm.sourceTrackingData.apr_cmd_status = -1;
3086 atomic_set(&this_adm.mem_map_handles[
3087 ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
3088 }
3089
3090 close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
3091 APR_HDR_LEN(APR_HDR_SIZE),
3092 APR_PKT_VER);
3093 close.pkt_size = sizeof(close);
3094 close.src_svc = APR_SVC_ADM;
3095 close.src_domain = APR_DOMAIN_APPS;
3096 close.src_port = port_id;
3097 close.dest_svc = APR_SVC_ADM;
3098 close.dest_domain = APR_DOMAIN_ADSP;
3099 close.dest_port = copp_id;
3100 close.token = port_idx << 16 | copp_idx;
3101 close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
3102
3103 atomic_set(&this_adm.copp.id[port_idx][copp_idx],
3104 RESET_COPP_ID);
3105 atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
3106 atomic_set(&this_adm.copp.topology[port_idx][copp_idx], 0);
3107 atomic_set(&this_adm.copp.mode[port_idx][copp_idx], 0);
3108 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
3109 atomic_set(&this_adm.copp.rate[port_idx][copp_idx], 0);
3110 atomic_set(&this_adm.copp.channels[port_idx][copp_idx], 0);
3111 atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx], 0);
3112 atomic_set(&this_adm.copp.app_type[port_idx][copp_idx], 0);
3113
3114 clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3115 (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
3116
3117 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
3118 if (ret < 0) {
3119 pr_err("%s: ADM close failed %d\n", __func__, ret);
3120 return -EINVAL;
3121 }
3122
3123 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
3124 atomic_read(&this_adm.copp.stat
3125 [port_idx][copp_idx]) >= 0,
3126 msecs_to_jiffies(TIMEOUT_MS));
3127 if (!ret) {
3128 pr_err("%s: ADM cmd Route timedout for port 0x%x\n",
3129 __func__, port_id);
3130 return -EINVAL;
3131 } else if (atomic_read(&this_adm.copp.stat
3132 [port_idx][copp_idx]) > 0) {
3133 pr_err("%s: DSP returned error[%s]\n",
3134 __func__, adsp_err_get_err_str(
3135 atomic_read(&this_adm.copp.stat
3136 [port_idx][copp_idx])));
3137 return adsp_err_get_lnx_err_code(
3138 atomic_read(&this_adm.copp.stat
3139 [port_idx][copp_idx]));
3140 }
3141 }
3142
3143 if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
3144 pr_debug("%s: remove adm device from rtac\n", __func__);
3145 rtac_remove_adm_device(port_id, copp_id);
3146 }
3147 return 0;
3148}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303149EXPORT_SYMBOL(adm_close);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303150
3151int send_rtac_audvol_cal(void)
3152{
3153 int ret = 0;
3154 int ret2 = 0;
3155 int i = 0;
3156 int copp_idx, port_idx, acdb_id, app_id, path;
3157 struct cal_block_data *cal_block = NULL;
3158 struct audio_cal_info_audvol *audvol_cal_info = NULL;
3159 struct rtac_adm rtac_adm_data;
3160
3161 mutex_lock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
3162
3163 cal_block = cal_utils_get_only_cal_block(
3164 this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]);
3165 if (cal_block == NULL) {
3166 pr_err("%s: can't find cal block!\n", __func__);
3167 goto unlock;
3168 }
3169
3170 audvol_cal_info = cal_block->cal_info;
3171 if (audvol_cal_info == NULL) {
3172 pr_err("%s: audvol_cal_info is NULL!\n", __func__);
3173 goto unlock;
3174 }
3175
3176 get_rtac_adm_data(&rtac_adm_data);
3177 for (; i < rtac_adm_data.num_of_dev; i++) {
3178
3179 acdb_id = rtac_adm_data.device[i].acdb_dev_id;
3180 if (acdb_id == 0)
3181 acdb_id = audvol_cal_info->acdb_id;
3182
3183 app_id = rtac_adm_data.device[i].app_type;
3184 if (app_id == 0)
3185 app_id = audvol_cal_info->app_type;
3186
3187 path = afe_get_port_type(rtac_adm_data.device[i].afe_port);
3188 if ((acdb_id == audvol_cal_info->acdb_id) &&
3189 (app_id == audvol_cal_info->app_type) &&
3190 (path == audvol_cal_info->path)) {
3191
3192 if (adm_get_indexes_from_copp_id(rtac_adm_data.
3193 device[i].copp, &copp_idx, &port_idx) != 0) {
3194 pr_debug("%s: Copp Id %d is not active\n",
3195 __func__,
3196 rtac_adm_data.device[i].copp);
3197 continue;
3198 }
3199
3200 ret2 = adm_remap_and_send_cal_block(ADM_RTAC_AUDVOL_CAL,
3201 rtac_adm_data.device[i].afe_port,
3202 copp_idx, cal_block,
3203 atomic_read(&this_adm.copp.
3204 mode[port_idx][copp_idx]),
3205 audvol_cal_info->app_type,
3206 audvol_cal_info->acdb_id,
3207 atomic_read(&this_adm.copp.
3208 rate[port_idx][copp_idx]));
3209 if (ret2 < 0) {
3210 pr_debug("%s: remap and send failed for copp Id %d, acdb id %d, app type %d, path %d\n",
3211 __func__, rtac_adm_data.device[i].copp,
3212 audvol_cal_info->acdb_id,
3213 audvol_cal_info->app_type,
3214 audvol_cal_info->path);
3215 ret = ret2;
3216 }
3217 }
3218 }
3219unlock:
3220 mutex_unlock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
3221 return ret;
3222}
3223
3224int adm_map_rtac_block(struct rtac_cal_block_data *cal_block)
3225{
3226 int result = 0;
3227
3228 pr_debug("%s:\n", __func__);
3229
3230 if (cal_block == NULL) {
3231 pr_err("%s: cal_block is NULL!\n",
3232 __func__);
3233 result = -EINVAL;
3234 goto done;
3235 }
3236
3237 if (cal_block->cal_data.paddr == 0) {
3238 pr_debug("%s: No address to map!\n",
3239 __func__);
3240 result = -EINVAL;
3241 goto done;
3242 }
3243
3244 if (cal_block->map_data.map_size == 0) {
3245 pr_debug("%s: map size is 0!\n",
3246 __func__);
3247 result = -EINVAL;
3248 goto done;
3249 }
3250
3251 /* valid port ID needed for callback use primary I2S */
3252 atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
3253 result = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
3254 &cal_block->map_data.map_size, 1);
3255 if (result < 0) {
3256 pr_err("%s: RTAC mmap did not work! size = %d result %d\n",
3257 __func__,
3258 cal_block->map_data.map_size, result);
3259 pr_debug("%s: RTAC mmap did not work! addr = 0x%pK, size = %d\n",
3260 __func__,
3261 &cal_block->cal_data.paddr,
3262 cal_block->map_data.map_size);
3263 goto done;
3264 }
3265
3266 cal_block->map_data.map_handle = atomic_read(
3267 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]);
3268done:
3269 return result;
3270}
3271
3272int adm_unmap_rtac_block(uint32_t *mem_map_handle)
3273{
3274 int result = 0;
3275
3276 pr_debug("%s:\n", __func__);
3277
3278 if (mem_map_handle == NULL) {
3279 pr_debug("%s: Map handle is NULL, nothing to unmap\n",
3280 __func__);
3281 goto done;
3282 }
3283
3284 if (*mem_map_handle == 0) {
3285 pr_debug("%s: Map handle is 0, nothing to unmap\n",
3286 __func__);
3287 goto done;
3288 }
3289
3290 if (*mem_map_handle != atomic_read(
3291 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL])) {
3292 pr_err("%s: Map handles do not match! Unmapping RTAC, RTAC map 0x%x, ADM map 0x%x\n",
3293 __func__, *mem_map_handle, atomic_read(
3294 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]));
3295
3296 /* if mismatch use handle passed in to unmap */
3297 atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL],
3298 *mem_map_handle);
3299 }
3300
3301 /* valid port ID needed for callback use primary I2S */
3302 atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
3303 result = adm_memory_unmap_regions();
3304 if (result < 0) {
3305 pr_debug("%s: adm_memory_unmap_regions failed, error %d\n",
3306 __func__, result);
3307 } else {
3308 atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL], 0);
3309 *mem_map_handle = 0;
3310 }
3311done:
3312 return result;
3313}
3314
3315static int get_cal_type_index(int32_t cal_type)
3316{
3317 int ret = -EINVAL;
3318
3319 switch (cal_type) {
3320 case ADM_AUDPROC_CAL_TYPE:
3321 ret = ADM_AUDPROC_CAL;
3322 break;
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05303323 case ADM_LSM_AUDPROC_CAL_TYPE:
3324 ret = ADM_LSM_AUDPROC_CAL;
3325 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303326 case ADM_AUDVOL_CAL_TYPE:
3327 ret = ADM_AUDVOL_CAL;
3328 break;
3329 case ADM_CUST_TOPOLOGY_CAL_TYPE:
3330 ret = ADM_CUSTOM_TOP_CAL;
3331 break;
3332 case ADM_RTAC_INFO_CAL_TYPE:
3333 ret = ADM_RTAC_INFO_CAL;
3334 break;
3335 case ADM_RTAC_APR_CAL_TYPE:
3336 ret = ADM_RTAC_APR_CAL;
3337 break;
3338 case ADM_RTAC_AUDVOL_CAL_TYPE:
3339 ret = ADM_RTAC_AUDVOL_CAL;
3340 break;
3341 default:
3342 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
3343 }
3344 return ret;
3345}
3346
3347static int adm_alloc_cal(int32_t cal_type, size_t data_size, void *data)
3348{
3349 int ret = 0;
3350 int cal_index;
3351
3352 pr_debug("%s:\n", __func__);
3353
3354 cal_index = get_cal_type_index(cal_type);
3355 if (cal_index < 0) {
3356 pr_err("%s: could not get cal index %d!\n",
3357 __func__, cal_index);
3358 ret = -EINVAL;
3359 goto done;
3360 }
3361
3362 ret = cal_utils_alloc_cal(data_size, data,
3363 this_adm.cal_data[cal_index], 0, NULL);
3364 if (ret < 0) {
3365 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
3366 __func__, ret, cal_type);
3367 ret = -EINVAL;
3368 goto done;
3369 }
3370done:
3371 return ret;
3372}
3373
3374static int adm_dealloc_cal(int32_t cal_type, size_t data_size, void *data)
3375{
3376 int ret = 0;
3377 int cal_index;
3378
3379 pr_debug("%s:\n", __func__);
3380
3381 cal_index = get_cal_type_index(cal_type);
3382 if (cal_index < 0) {
3383 pr_err("%s: could not get cal index %d!\n",
3384 __func__, cal_index);
3385 ret = -EINVAL;
3386 goto done;
3387 }
3388
3389 ret = cal_utils_dealloc_cal(data_size, data,
3390 this_adm.cal_data[cal_index]);
3391 if (ret < 0) {
3392 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
3393 __func__, ret, cal_type);
3394 ret = -EINVAL;
3395 goto done;
3396 }
3397done:
3398 return ret;
3399}
3400
3401static int adm_set_cal(int32_t cal_type, size_t data_size, void *data)
3402{
3403 int ret = 0;
3404 int cal_index;
3405
3406 pr_debug("%s:\n", __func__);
3407
3408 cal_index = get_cal_type_index(cal_type);
3409 if (cal_index < 0) {
3410 pr_err("%s: could not get cal index %d!\n",
3411 __func__, cal_index);
3412 ret = -EINVAL;
3413 goto done;
3414 }
3415
3416 ret = cal_utils_set_cal(data_size, data,
3417 this_adm.cal_data[cal_index], 0, NULL);
3418 if (ret < 0) {
3419 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
3420 __func__, ret, cal_type);
3421 ret = -EINVAL;
3422 goto done;
3423 }
3424
3425 if (cal_index == ADM_CUSTOM_TOP_CAL) {
3426 mutex_lock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
3427 this_adm.set_custom_topology = 1;
3428 mutex_unlock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
3429 } else if (cal_index == ADM_RTAC_AUDVOL_CAL) {
3430 send_rtac_audvol_cal();
3431 }
3432done:
3433 return ret;
3434}
3435
3436static int adm_map_cal_data(int32_t cal_type,
3437 struct cal_block_data *cal_block)
3438{
3439 int ret = 0;
3440 int cal_index;
3441
3442 pr_debug("%s:\n", __func__);
3443
3444 cal_index = get_cal_type_index(cal_type);
3445 if (cal_index < 0) {
3446 pr_err("%s: could not get cal index %d!\n",
3447 __func__, cal_index);
3448 ret = -EINVAL;
3449 goto done;
3450 }
3451
3452 atomic_set(&this_adm.mem_map_index, cal_index);
3453 ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
3454 (uint32_t *)&cal_block->map_data.map_size, 1);
3455 if (ret < 0) {
3456 pr_err("%s: map did not work! cal_type %i ret %d\n",
3457 __func__, cal_index, ret);
3458 ret = -ENODEV;
3459 goto done;
3460 }
3461 cal_block->map_data.q6map_handle = atomic_read(&this_adm.
3462 mem_map_handles[cal_index]);
3463done:
3464 return ret;
3465}
3466
3467static int adm_unmap_cal_data(int32_t cal_type,
3468 struct cal_block_data *cal_block)
3469{
3470 int ret = 0;
3471 int cal_index;
3472
3473 pr_debug("%s:\n", __func__);
3474
3475 cal_index = get_cal_type_index(cal_type);
3476 if (cal_index < 0) {
3477 pr_err("%s: could not get cal index %d!\n",
3478 __func__, cal_index);
3479 ret = -EINVAL;
3480 goto done;
3481 }
3482
3483 if (cal_block == NULL) {
3484 pr_err("%s: Cal block is NULL!\n",
3485 __func__);
3486 goto done;
3487 }
3488
3489 if (cal_block->map_data.q6map_handle == 0) {
3490 pr_err("%s: Map handle is NULL, nothing to unmap\n",
3491 __func__);
3492 goto done;
3493 }
3494
3495 atomic_set(&this_adm.mem_map_handles[cal_index],
3496 cal_block->map_data.q6map_handle);
3497 atomic_set(&this_adm.mem_map_index, cal_index);
3498 ret = adm_memory_unmap_regions();
3499 if (ret < 0) {
3500 pr_err("%s: unmap did not work! cal_type %i ret %d\n",
3501 __func__, cal_index, ret);
3502 ret = -ENODEV;
3503 goto done;
3504 }
3505 cal_block->map_data.q6map_handle = 0;
3506done:
3507 return ret;
3508}
3509
3510static void adm_delete_cal_data(void)
3511{
3512 pr_debug("%s:\n", __func__);
3513
3514 cal_utils_destroy_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data);
3515}
3516
3517static int adm_init_cal_data(void)
3518{
3519 int ret = 0;
3520 struct cal_type_info cal_type_info[] = {
3521 {{ADM_CUST_TOPOLOGY_CAL_TYPE,
3522 {adm_alloc_cal, adm_dealloc_cal, NULL,
3523 adm_set_cal, NULL, NULL} },
3524 {adm_map_cal_data, adm_unmap_cal_data,
3525 cal_utils_match_buf_num} },
3526
3527 {{ADM_AUDPROC_CAL_TYPE,
3528 {adm_alloc_cal, adm_dealloc_cal, NULL,
3529 adm_set_cal, NULL, NULL} },
3530 {adm_map_cal_data, adm_unmap_cal_data,
3531 cal_utils_match_buf_num} },
3532
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05303533 {{ADM_LSM_AUDPROC_CAL_TYPE,
3534 {adm_alloc_cal, adm_dealloc_cal, NULL,
3535 adm_set_cal, NULL, NULL} },
3536 {adm_map_cal_data, adm_unmap_cal_data,
3537 cal_utils_match_buf_num} },
3538
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303539 {{ADM_AUDVOL_CAL_TYPE,
3540 {adm_alloc_cal, adm_dealloc_cal, NULL,
3541 adm_set_cal, NULL, NULL} },
3542 {adm_map_cal_data, adm_unmap_cal_data,
3543 cal_utils_match_buf_num} },
3544
3545 {{ADM_RTAC_INFO_CAL_TYPE,
3546 {NULL, NULL, NULL, NULL, NULL, NULL} },
3547 {NULL, NULL, cal_utils_match_buf_num} },
3548
3549 {{ADM_RTAC_APR_CAL_TYPE,
3550 {NULL, NULL, NULL, NULL, NULL, NULL} },
3551 {NULL, NULL, cal_utils_match_buf_num} },
3552
3553 {{SRS_TRUMEDIA_CAL_TYPE,
3554 {NULL, NULL, NULL, NULL, NULL, NULL} },
3555 {NULL, NULL, cal_utils_match_buf_num} },
3556
3557 {{ADM_RTAC_AUDVOL_CAL_TYPE,
3558 {adm_alloc_cal, adm_dealloc_cal, NULL,
3559 adm_set_cal, NULL, NULL} },
3560 {adm_map_cal_data, adm_unmap_cal_data,
3561 cal_utils_match_buf_num} },
3562 };
3563 pr_debug("%s:\n", __func__);
3564
3565 ret = cal_utils_create_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data,
3566 cal_type_info);
3567 if (ret < 0) {
3568 pr_err("%s: could not create cal type! ret %d\n",
3569 __func__, ret);
3570 ret = -EINVAL;
3571 goto err;
3572 }
3573
3574 return ret;
3575err:
3576 adm_delete_cal_data();
3577 return ret;
3578}
3579
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303580/**
3581 * adm_set_volume -
3582 * command to set volume on ADM copp
3583 *
3584 * @port_id: Port ID number
3585 * @copp_idx: copp index assigned
3586 * @volume: gain value to set
3587 *
3588 * Returns 0 on success or error on failure
3589 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303590int adm_set_volume(int port_id, int copp_idx, int volume)
3591{
3592 struct audproc_volume_ctrl_master_gain audproc_vol;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003593 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303594 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303595
3596 pr_debug("%s: port_id %d, volume %d\n", __func__, port_id, volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303597
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003598 memset(&audproc_vol, 0, sizeof(audproc_vol));
3599 memset(&param_hdr, 0, sizeof(param_hdr));
3600 param_hdr.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
3601 param_hdr.instance_id = INSTANCE_ID_0;
3602 param_hdr.param_id = AUDPROC_PARAM_ID_VOL_CTRL_MASTER_GAIN;
3603 param_hdr.param_size = sizeof(audproc_vol);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303604
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303605 audproc_vol.master_gain = volume;
3606
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003607 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3608 (uint8_t *) &audproc_vol);
3609 if (rc)
3610 pr_err("%s: Failed to set volume, err %d\n", __func__, rc);
3611
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303612 return rc;
3613}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303614EXPORT_SYMBOL(adm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303615
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303616/**
3617 * adm_set_softvolume -
3618 * command to set softvolume
3619 *
3620 * @port_id: Port ID number
3621 * @copp_idx: copp index assigned
3622 * @softvol_param: Params to set for softvolume
3623 *
3624 * Returns 0 on success or error on failure
3625 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303626int adm_set_softvolume(int port_id, int copp_idx,
3627 struct audproc_softvolume_params *softvol_param)
3628{
3629 struct audproc_soft_step_volume_params audproc_softvol;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003630 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303631 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303632
3633 pr_debug("%s: period %d step %d curve %d\n", __func__,
3634 softvol_param->period, softvol_param->step,
3635 softvol_param->rampingcurve);
3636
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003637 memset(&audproc_softvol, 0, sizeof(audproc_softvol));
3638 memset(&param_hdr, 0, sizeof(param_hdr));
3639 param_hdr.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
3640 param_hdr.instance_id = INSTANCE_ID_0;
3641 param_hdr.param_id = AUDPROC_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
3642 param_hdr.param_size = sizeof(audproc_softvol);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303643
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303644 audproc_softvol.period = softvol_param->period;
3645 audproc_softvol.step = softvol_param->step;
3646 audproc_softvol.ramping_curve = softvol_param->rampingcurve;
3647
3648 pr_debug("%s: period %d, step %d, curve %d\n", __func__,
3649 audproc_softvol.period, audproc_softvol.step,
3650 audproc_softvol.ramping_curve);
3651
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003652 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3653 (uint8_t *) &audproc_softvol);
3654 if (rc)
3655 pr_err("%s: Failed to set soft volume, err %d\n", __func__, rc);
3656
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303657 return rc;
3658}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303659EXPORT_SYMBOL(adm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303660
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303661/**
3662 * adm_set_mic_gain -
3663 * command to set MIC gain
3664 *
3665 * @port_id: Port ID number
3666 * @copp_idx: copp index assigned
3667 * @volume: gain value to set
3668 *
3669 * Returns 0 on success or error on failure
3670 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303671int adm_set_mic_gain(int port_id, int copp_idx, int volume)
3672{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003673 struct admx_mic_gain mic_gain_params;
3674 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303675 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303676
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003677 pr_debug("%s: Setting mic gain to %d at port_id 0x%x\n", __func__,
3678 volume, port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303679
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003680 memset(&mic_gain_params, 0, sizeof(mic_gain_params));
3681 memset(&param_hdr, 0, sizeof(param_hdr));
3682 param_hdr.module_id = ADM_MODULE_IDX_MIC_GAIN_CTRL;
3683 param_hdr.instance_id = INSTANCE_ID_0;
3684 param_hdr.param_id = ADM_PARAM_IDX_MIC_GAIN;
3685 param_hdr.param_size = sizeof(mic_gain_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303686
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003687 mic_gain_params.tx_mic_gain = volume;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303688
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003689 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3690 (uint8_t *) &mic_gain_params);
3691 if (rc)
3692 pr_err("%s: Failed to set mic gain, err %d\n", __func__, rc);
3693
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303694 return rc;
3695}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303696EXPORT_SYMBOL(adm_set_mic_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303697
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303698/**
3699 * adm_send_set_multichannel_ec_primary_mic_ch -
3700 * command to set multi-ch EC primary mic
3701 *
3702 * @port_id: Port ID number
3703 * @copp_idx: copp index assigned
3704 * @primary_mic_ch: channel number of primary mic
3705 *
3706 * Returns 0 on success or error on failure
3707 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303708int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
3709 int primary_mic_ch)
3710{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003711 struct admx_sec_primary_mic_ch sec_primary_ch_params;
3712 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303713 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303714
3715 pr_debug("%s port_id 0x%x, copp_idx 0x%x, primary_mic_ch %d\n",
3716 __func__, port_id, copp_idx, primary_mic_ch);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303717
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003718 memset(&sec_primary_ch_params, 0, sizeof(sec_primary_ch_params));
3719 memset(&param_hdr, 0, sizeof(param_hdr));
3720 param_hdr.module_id = AUDPROC_MODULE_ID_VOICE_TX_SECNS;
3721 param_hdr.instance_id = INSTANCE_ID_0;
3722 param_hdr.param_id = AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH;
3723 param_hdr.param_size = sizeof(sec_primary_ch_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303724
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003725 sec_primary_ch_params.version = 0;
3726 sec_primary_ch_params.sec_primary_mic_ch = primary_mic_ch;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303727
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003728 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3729 (uint8_t *) &sec_primary_ch_params);
3730 if (rc)
3731 pr_err("%s: Failed to set primary mic chanel, err %d\n",
3732 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303733
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303734 return rc;
3735}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303736EXPORT_SYMBOL(adm_send_set_multichannel_ec_primary_mic_ch);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303737
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303738/**
3739 * adm_param_enable -
3740 * command to send params to ADM for given module
3741 *
3742 * @port_id: Port ID number
3743 * @copp_idx: copp index assigned
3744 * @module_id: ADM module
3745 * @enable: flag to enable or disable module
3746 *
3747 * Returns 0 on success or error on failure
3748 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303749int adm_param_enable(int port_id, int copp_idx, int module_id, int enable)
3750{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003751 struct module_instance_info mod_inst_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303752
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003753 memset(&mod_inst_info, 0, sizeof(mod_inst_info));
3754 mod_inst_info.module_id = module_id;
3755 mod_inst_info.instance_id = INSTANCE_ID_0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303756
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003757 return adm_param_enable_v2(port_id, copp_idx, mod_inst_info, enable);
3758}
3759
3760/**
3761 * adm_param_enable_v2 -
3762 * command to send params to ADM for given module
3763 *
3764 * @port_id: Port ID number
3765 * @copp_idx: copp index assigned
3766 * @mod_inst_info: module and instance ID info
3767 * @enable: flag to enable or disable module
3768 *
3769 * Returns 0 on success or error on failure
3770 */
3771int adm_param_enable_v2(int port_id, int copp_idx,
3772 struct module_instance_info mod_inst_info, int enable)
3773{
3774 uint32_t enable_param;
3775 struct param_hdr_v3 param_hdr;
3776 int rc = 0;
3777
3778 if (enable < 0 || enable > 1) {
3779 pr_err("%s: Invalid value for enable %d\n", __func__, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303780 return -EINVAL;
3781 }
3782
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003783 pr_debug("%s port_id %d, module_id 0x%x, instance_id 0x%x, enable %d\n",
3784 __func__, port_id, mod_inst_info.module_id,
3785 mod_inst_info.instance_id, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303786
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003787 memset(&param_hdr, 0, sizeof(param_hdr));
3788 param_hdr.module_id = mod_inst_info.module_id;
3789 param_hdr.instance_id = mod_inst_info.instance_id;
3790 param_hdr.param_id = AUDPROC_PARAM_ID_ENABLE;
3791 param_hdr.param_size = sizeof(enable_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303792
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003793 enable_param = enable;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303794
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003795 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3796 (uint8_t *) &enable_param);
3797 if (rc)
3798 pr_err("%s: Failed to set enable of module(%d) instance(%d) to %d, err %d\n",
3799 __func__, mod_inst_info.module_id,
3800 mod_inst_info.instance_id, enable, rc);
3801
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303802 return rc;
3803
3804}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303805EXPORT_SYMBOL(adm_param_enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303806
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303807/**
3808 * adm_send_calibration -
3809 * send ADM calibration to DSP
3810 *
3811 * @port_id: Port ID number
3812 * @copp_idx: copp index assigned
3813 * @path: direction or ADM path type
3814 * @perf_mode: performance mode like LL/ULL/..
3815 * @cal_type: calibration type to use
3816 * @params: pointer with cal data
3817 * @size: cal size
3818 *
3819 * Returns 0 on success or error on failure
3820 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303821int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode,
3822 int cal_type, char *params, int size)
3823{
3824
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003825 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303826
3827 pr_debug("%s:port_id %d, path %d, perf_mode %d, cal_type %d, size %d\n",
3828 __func__, port_id, path, perf_mode, cal_type, size);
3829
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303830 /* Maps audio_dev_ctrl path definition to ACDB definition */
3831 if (get_cal_path(path) != RX_DEVICE) {
3832 pr_err("%s: acdb_path %d\n", __func__, path);
3833 rc = -EINVAL;
3834 goto end;
3835 }
3836
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003837 rc = adm_set_pp_params(port_id, copp_idx, NULL, (u8 *) params, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303838
3839end:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303840 return rc;
3841}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303842EXPORT_SYMBOL(adm_send_calibration);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303843
3844/*
3845 * adm_update_wait_parameters must be called with routing driver locks.
3846 * adm_reset_wait_parameters must be called with routing driver locks.
3847 * set and reset parmeters are separated to make sure it is always called
3848 * under routing driver lock.
3849 * adm_wait_timeout is to block until timeout or interrupted. Timeout is
3850 * not a an error.
3851 */
3852int adm_set_wait_parameters(int port_id, int copp_idx)
3853{
3854
3855 int ret = 0, port_idx;
3856
3857 pr_debug("%s: port_id 0x%x, copp_idx %d\n", __func__, port_id,
3858 copp_idx);
3859 port_id = afe_convert_virtual_to_portid(port_id);
3860 port_idx = adm_validate_and_get_port_index(port_id);
3861 if (port_idx < 0) {
3862 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3863 ret = -EINVAL;
3864 goto end;
3865 }
3866
3867 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3868 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3869 return -EINVAL;
3870 }
3871
3872 this_adm.copp.adm_delay[port_idx][copp_idx] = 1;
3873 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 0);
3874
3875end:
3876 return ret;
3877
3878}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303879EXPORT_SYMBOL(adm_set_wait_parameters);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303880
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303881/**
3882 * adm_reset_wait_parameters -
3883 * reset wait parameters or ADM delay value
3884 *
3885 * @port_id: Port ID number
3886 * @copp_idx: copp index assigned
3887 *
3888 * Returns 0 on success or error on failure
3889 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303890int adm_reset_wait_parameters(int port_id, int copp_idx)
3891{
3892 int ret = 0, port_idx;
3893
3894 pr_debug("%s: port_id 0x%x copp_idx %d\n", __func__, port_id,
3895 copp_idx);
3896 port_id = afe_convert_virtual_to_portid(port_id);
3897 port_idx = adm_validate_and_get_port_index(port_id);
3898 if (port_idx < 0) {
3899 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3900 ret = -EINVAL;
3901 goto end;
3902 }
3903
3904 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3905 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3906 return -EINVAL;
3907 }
3908
3909 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 1);
3910 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
3911
3912end:
3913 return ret;
3914}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303915EXPORT_SYMBOL(adm_reset_wait_parameters);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303916
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303917/**
3918 * adm_wait_timeout -
3919 * ADM wait command after command send to DSP
3920 *
3921 * @port_id: Port ID number
3922 * @copp_idx: copp index assigned
3923 * @wait_time: value in ms for command timeout
3924 *
3925 * Returns 0 on success or error on failure
3926 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303927int adm_wait_timeout(int port_id, int copp_idx, int wait_time)
3928{
3929 int ret = 0, port_idx;
3930
3931 pr_debug("%s: port_id 0x%x, copp_idx %d, wait_time %d\n", __func__,
3932 port_id, copp_idx, wait_time);
3933 port_id = afe_convert_virtual_to_portid(port_id);
3934 port_idx = adm_validate_and_get_port_index(port_id);
3935 if (port_idx < 0) {
3936 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3937 ret = -EINVAL;
3938 goto end;
3939 }
3940
3941 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3942 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3943 return -EINVAL;
3944 }
3945
3946 ret = wait_event_timeout(
3947 this_adm.copp.adm_delay_wait[port_idx][copp_idx],
3948 atomic_read(&this_adm.copp.adm_delay_stat[port_idx][copp_idx]),
3949 msecs_to_jiffies(wait_time));
3950 pr_debug("%s: return %d\n", __func__, ret);
3951 if (ret != 0)
3952 ret = -EINTR;
3953end:
3954 pr_debug("%s: return %d--\n", __func__, ret);
3955 return ret;
3956}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303957EXPORT_SYMBOL(adm_wait_timeout);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303958
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303959/**
3960 * adm_store_cal_data -
3961 * Retrieve calibration data for ADM copp device
3962 *
3963 * @port_id: Port ID number
3964 * @copp_idx: copp index assigned
3965 * @path: direction or copp type
3966 * @perf_mode: performance mode like LL/ULL/..
3967 * @cal_index: calibration index to use
3968 * @params: pointer to store cal data
3969 * @size: pointer to fill with cal size
3970 *
3971 * Returns 0 on success or error on failure
3972 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303973int adm_store_cal_data(int port_id, int copp_idx, int path, int perf_mode,
3974 int cal_index, char *params, int *size)
3975{
3976 int rc = 0;
3977 struct cal_block_data *cal_block = NULL;
3978 int app_type, acdb_id, port_idx, sample_rate;
3979
3980 if (this_adm.cal_data[cal_index] == NULL) {
3981 pr_debug("%s: cal_index %d not allocated!\n",
3982 __func__, cal_index);
3983 goto end;
3984 }
3985
3986 if (get_cal_path(path) != RX_DEVICE) {
3987 pr_debug("%s: Invalid path to store calibration %d\n",
3988 __func__, path);
3989 rc = -EINVAL;
3990 goto end;
3991 }
3992
3993 port_id = afe_convert_virtual_to_portid(port_id);
3994 port_idx = adm_validate_and_get_port_index(port_id);
3995 if (port_idx < 0) {
3996 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
3997 rc = -EINVAL;
3998 goto end;
3999 }
4000
4001 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4002 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
4003 return -EINVAL;
4004 }
4005
4006 acdb_id = atomic_read(&this_adm.copp.acdb_id[port_idx][copp_idx]);
4007 app_type = atomic_read(&this_adm.copp.app_type[port_idx][copp_idx]);
4008 sample_rate = atomic_read(&this_adm.copp.rate[port_idx][copp_idx]);
4009
4010 mutex_lock(&this_adm.cal_data[cal_index]->lock);
4011 cal_block = adm_find_cal(cal_index, get_cal_path(path), app_type,
4012 acdb_id, sample_rate);
4013 if (cal_block == NULL)
4014 goto unlock;
4015
4016 if (cal_block->cal_data.size <= 0) {
4017 pr_debug("%s: No ADM cal send for port_id = 0x%x!\n",
4018 __func__, port_id);
4019 rc = -EINVAL;
4020 goto unlock;
4021 }
4022
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05304023 if (cal_index == ADM_AUDPROC_CAL || cal_index == ADM_LSM_AUDPROC_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304024 if (cal_block->cal_data.size > AUD_PROC_BLOCK_SIZE) {
4025 pr_err("%s:audproc:invalid size exp/actual[%zd, %d]\n",
4026 __func__, cal_block->cal_data.size, *size);
4027 rc = -ENOMEM;
4028 goto unlock;
4029 }
4030 } else if (cal_index == ADM_AUDVOL_CAL) {
4031 if (cal_block->cal_data.size > AUD_VOL_BLOCK_SIZE) {
4032 pr_err("%s:aud_vol:invalid size exp/actual[%zd, %d]\n",
4033 __func__, cal_block->cal_data.size, *size);
4034 rc = -ENOMEM;
4035 goto unlock;
4036 }
4037 } else {
4038 pr_debug("%s: Not valid calibration for dolby topolgy\n",
4039 __func__);
4040 rc = -EINVAL;
4041 goto unlock;
4042 }
4043 memcpy(params, cal_block->cal_data.kvaddr, cal_block->cal_data.size);
4044 *size = cal_block->cal_data.size;
4045
4046 pr_debug("%s:port_id %d, copp_idx %d, path %d",
4047 __func__, port_id, copp_idx, path);
4048 pr_debug("perf_mode %d, cal_type %d, size %d\n",
4049 perf_mode, cal_index, *size);
4050
4051unlock:
4052 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
4053end:
4054 return rc;
4055}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304056EXPORT_SYMBOL(adm_store_cal_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304057
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304058/**
4059 * adm_send_compressed_device_mute -
4060 * command to send mute for compressed device
4061 *
4062 * @port_id: Port ID number
4063 * @copp_idx: copp index assigned
4064 * @mute_on: flag to indicate mute or unmute
4065 *
4066 * Returns 0 on success or error on failure
4067 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304068int adm_send_compressed_device_mute(int port_id, int copp_idx, bool mute_on)
4069{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004070 u32 mute_param = mute_on ? 1 : 0;
4071 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304072 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304073
4074 pr_debug("%s port_id: 0x%x, copp_idx %d, mute_on: %d\n",
4075 __func__, port_id, copp_idx, mute_on);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304076
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004077 memset(&param_hdr, 0, sizeof(param_hdr));
4078 param_hdr.module_id = AUDPROC_MODULE_ID_COMPRESSED_MUTE;
4079 param_hdr.instance_id = INSTANCE_ID_0;
4080 param_hdr.param_id = AUDPROC_PARAM_ID_COMPRESSED_MUTE;
4081 param_hdr.param_size = sizeof(mute_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304082
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004083 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4084 (uint8_t *) &mute_param);
4085 if (ret)
4086 pr_err("%s: Failed to set mute, err %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304087
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304088 return ret;
4089}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304090EXPORT_SYMBOL(adm_send_compressed_device_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304091
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304092/**
4093 * adm_send_compressed_device_latency -
4094 * command to send latency for compressed device
4095 *
4096 * @port_id: Port ID number
4097 * @copp_idx: copp index assigned
4098 * @latency: latency value to pass
4099 *
4100 * Returns 0 on success or error on failure
4101 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304102int adm_send_compressed_device_latency(int port_id, int copp_idx, int latency)
4103{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004104 u32 latency_param;
4105 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304106 int ret = 0;
4107
4108 pr_debug("%s port_id: 0x%x, copp_idx %d latency: %d\n", __func__,
4109 port_id, copp_idx, latency);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004110
4111 if (latency < 0) {
4112 pr_err("%s: Invalid value for latency %d", __func__, latency);
4113 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304114 }
4115
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004116 memset(&param_hdr, 0, sizeof(param_hdr));
4117 param_hdr.module_id = AUDPROC_MODULE_ID_COMPRESSED_LATENCY;
4118 param_hdr.instance_id = INSTANCE_ID_0;
4119 param_hdr.param_id = AUDPROC_PARAM_ID_COMPRESSED_LATENCY;
4120 param_hdr.param_size = sizeof(latency_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304121
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004122 latency_param = latency;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304123
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004124 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4125 (uint8_t *) &latency_param);
4126 if (ret)
4127 pr_err("%s: Failed to set latency, err %d\n", __func__, ret);
4128
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304129 return ret;
4130}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304131EXPORT_SYMBOL(adm_send_compressed_device_latency);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304132
4133/**
4134 * adm_swap_speaker_channels
4135 *
4136 * Receives port_id, copp_idx, sample rate, spk_swap and
4137 * send MFC command to swap speaker channel.
4138 * Return zero on success. On failure returns nonzero.
4139 *
4140 * port_id - Passed value, port_id for which channels swap is wanted
4141 * copp_idx - Passed value, copp_idx for which channels swap is wanted
4142 * sample_rate - Passed value, sample rate used by app type config
4143 * spk_swap - Passed value, spk_swap for check if swap flag is set
4144 */
4145int adm_swap_speaker_channels(int port_id, int copp_idx,
4146 int sample_rate, bool spk_swap)
4147{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004148 struct audproc_mfc_param_media_fmt mfc_cfg;
4149 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304150 uint16_t num_channels;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004151 int port_idx = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304152 int ret = 0;
4153
4154 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4155 __func__, port_id, copp_idx);
4156 port_id = q6audio_convert_virtual_to_portid(port_id);
4157 port_idx = adm_validate_and_get_port_index(port_id);
4158 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
4159 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004160 return -EINVAL;
4161 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4162 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
4163 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304164 }
4165
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004166 num_channels = atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304167 if (num_channels != 2) {
4168 pr_debug("%s: Invalid number of channels: %d\n",
4169 __func__, num_channels);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004170 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304171 }
4172
4173 memset(&mfc_cfg, 0, sizeof(mfc_cfg));
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004174 memset(&param_hdr, 0, sizeof(param_hdr));
4175
4176 param_hdr.module_id = AUDPROC_MODULE_ID_MFC;
4177 param_hdr.instance_id = INSTANCE_ID_0;
4178 param_hdr.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
4179 param_hdr.param_size = sizeof(mfc_cfg);
4180
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304181 mfc_cfg.sampling_rate = sample_rate;
4182 mfc_cfg.bits_per_sample =
4183 atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
4184 mfc_cfg.num_channels = num_channels;
4185
4186 /* Currently applying speaker swap for only 2 channel use case */
4187 if (spk_swap) {
4188 mfc_cfg.channel_type[0] =
4189 (uint16_t) PCM_CHANNEL_FR;
4190 mfc_cfg.channel_type[1] =
4191 (uint16_t) PCM_CHANNEL_FL;
4192 } else {
4193 mfc_cfg.channel_type[0] =
4194 (uint16_t) PCM_CHANNEL_FL;
4195 mfc_cfg.channel_type[1] =
4196 (uint16_t) PCM_CHANNEL_FR;
4197 }
4198
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004199 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4200 (u8 *) &mfc_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304201 if (ret < 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004202 pr_err("%s: Failed to set swap speaker channels on port[0x%x] failed %d\n",
4203 __func__, port_id, ret);
4204 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304205 }
4206
4207 pr_debug("%s: mfc_cfg Set params returned success", __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004208 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304209}
4210EXPORT_SYMBOL(adm_swap_speaker_channels);
4211
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304212/**
4213 * adm_set_sound_focus -
4214 * Update sound focus info
4215 *
4216 * @port_id: Port ID number
4217 * @copp_idx: copp index assigned
4218 * @soundFocusData: sound focus data to pass
4219 *
4220 * Returns 0 on success or error on failure
4221 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304222int adm_set_sound_focus(int port_id, int copp_idx,
4223 struct sound_focus_param soundFocusData)
4224{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004225 struct adm_param_fluence_soundfocus_t soundfocus_params;
4226 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304227 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304228 int i;
4229
4230 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4231 __func__, port_id, copp_idx);
4232
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004233 memset(&param_hdr, 0, sizeof(param_hdr));
4234 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4235 param_hdr.instance_id = INSTANCE_ID_0;
4236 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
4237 param_hdr.param_size = sizeof(soundfocus_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304238
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004239 memset(&(soundfocus_params), 0xFF, sizeof(soundfocus_params));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304240 for (i = 0; i < MAX_SECTORS; i++) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004241 soundfocus_params.start_angles[i] =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304242 soundFocusData.start_angle[i];
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004243 soundfocus_params.enables[i] = soundFocusData.enable[i];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304244 pr_debug("%s: start_angle[%d] = %d\n",
4245 __func__, i, soundFocusData.start_angle[i]);
4246 pr_debug("%s: enable[%d] = %d\n",
4247 __func__, i, soundFocusData.enable[i]);
4248 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004249 soundfocus_params.gain_step = soundFocusData.gain_step;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304250 pr_debug("%s: gain_step = %d\n", __func__, soundFocusData.gain_step);
4251
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004252 soundfocus_params.reserved = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304253
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004254 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4255 (uint8_t *) &soundfocus_params);
4256 if (ret)
4257 pr_err("%s: Failed to set sound focus params, err %d\n",
4258 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304259
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304260 pr_debug("%s: Exit, ret=%d\n", __func__, ret);
4261
4262 return ret;
4263}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304264EXPORT_SYMBOL(adm_set_sound_focus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304265
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304266/**
4267 * adm_get_sound_focus -
4268 * Retrieve sound focus info
4269 *
4270 * @port_id: Port ID number
4271 * @copp_idx: copp index assigned
4272 * @soundFocusData: pointer for sound focus data to be updated with
4273 *
4274 * Returns 0 on success or error on failure
4275 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304276int adm_get_sound_focus(int port_id, int copp_idx,
4277 struct sound_focus_param *soundFocusData)
4278{
4279 int ret = 0, i;
4280 char *params_value;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004281 uint32_t max_param_size = 0;
4282 struct adm_param_fluence_soundfocus_t *soundfocus_params = NULL;
4283 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304284
4285 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4286 __func__, port_id, copp_idx);
4287
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004288 max_param_size = sizeof(struct adm_param_fluence_soundfocus_t) +
4289 sizeof(union param_hdrs);
4290 params_value = kzalloc(max_param_size, GFP_KERNEL);
4291 if (!params_value)
4292 return -ENOMEM;
4293
4294 memset(&param_hdr, 0, sizeof(param_hdr));
4295 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4296 param_hdr.instance_id = INSTANCE_ID_0;
4297 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
4298 param_hdr.param_size = max_param_size;
4299 ret = adm_get_pp_params(port_id, copp_idx,
4300 ADM_CLIENT_ID_SOURCE_TRACKING, NULL, &param_hdr,
4301 params_value);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304302 if (ret) {
4303 pr_err("%s: get parameters failed ret:%d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304304 ret = -EINVAL;
4305 goto done;
4306 }
4307
4308 if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
4309 pr_err("%s - get params returned error [%s]\n",
4310 __func__, adsp_err_get_err_str(
4311 this_adm.sourceTrackingData.apr_cmd_status));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304312 ret = adsp_err_get_lnx_err_code(
4313 this_adm.sourceTrackingData.apr_cmd_status);
4314 goto done;
4315 }
4316
4317 soundfocus_params = (struct adm_param_fluence_soundfocus_t *)
4318 params_value;
4319 for (i = 0; i < MAX_SECTORS; i++) {
4320 soundFocusData->start_angle[i] =
4321 soundfocus_params->start_angles[i];
4322 soundFocusData->enable[i] = soundfocus_params->enables[i];
4323 pr_debug("%s: start_angle[%d] = %d\n",
4324 __func__, i, soundFocusData->start_angle[i]);
4325 pr_debug("%s: enable[%d] = %d\n",
4326 __func__, i, soundFocusData->enable[i]);
4327 }
4328 soundFocusData->gain_step = soundfocus_params->gain_step;
4329 pr_debug("%s: gain_step = %d\n", __func__, soundFocusData->gain_step);
4330
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304331done:
4332 pr_debug("%s: Exit, ret = %d\n", __func__, ret);
4333
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004334 kfree(params_value);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304335 return ret;
4336}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304337EXPORT_SYMBOL(adm_get_sound_focus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304338
4339static int adm_source_tracking_alloc_map_memory(void)
4340{
4341 int ret;
4342
4343 pr_debug("%s: Enter\n", __func__);
4344
Banajit Goswami08bb7362017-11-03 22:48:23 -07004345 ret = msm_audio_ion_alloc(&this_adm.sourceTrackingData.dma_buf,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304346 AUD_PROC_BLOCK_SIZE,
4347 &this_adm.sourceTrackingData.memmap.paddr,
4348 &this_adm.sourceTrackingData.memmap.size,
4349 &this_adm.sourceTrackingData.memmap.kvaddr);
4350 if (ret) {
4351 pr_err("%s: failed to allocate memory\n", __func__);
4352
4353 ret = -EINVAL;
4354 goto done;
4355 }
4356
4357 atomic_set(&this_adm.mem_map_index, ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
4358 ret = adm_memory_map_regions(&this_adm.sourceTrackingData.memmap.paddr,
4359 0,
4360 (uint32_t *)&this_adm.sourceTrackingData.memmap.size,
4361 1);
4362 if (ret < 0) {
4363 pr_err("%s: failed to map memory, paddr = 0x%pK, size = %d\n",
4364 __func__,
4365 (void *)this_adm.sourceTrackingData.memmap.paddr,
4366 (uint32_t)this_adm.sourceTrackingData.memmap.size);
4367
Banajit Goswami08bb7362017-11-03 22:48:23 -07004368 msm_audio_ion_free(this_adm.sourceTrackingData.dma_buf);
4369 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304370 this_adm.sourceTrackingData.memmap.size = 0;
4371 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
4372 this_adm.sourceTrackingData.memmap.paddr = 0;
4373 this_adm.sourceTrackingData.apr_cmd_status = -1;
4374 atomic_set(&this_adm.mem_map_handles
4375 [ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
4376
4377 ret = -EINVAL;
4378 goto done;
4379 }
4380 ret = 0;
4381 pr_debug("%s: paddr = 0x%pK, size = %d, mem_map_handle = 0x%x\n",
4382 __func__, (void *)this_adm.sourceTrackingData.memmap.paddr,
4383 (uint32_t)this_adm.sourceTrackingData.memmap.size,
4384 atomic_read(&this_adm.mem_map_handles
4385 [ADM_MEM_MAP_INDEX_SOURCE_TRACKING]));
4386
4387done:
4388 pr_debug("%s: Exit, ret = %d\n", __func__, ret);
4389
4390 return ret;
4391}
4392
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304393/**
4394 * adm_get_source_tracking -
4395 * Retrieve source tracking info
4396 *
4397 * @port_id: Port ID number
4398 * @copp_idx: copp index assigned
4399 * @sourceTrackingData: pointer for source track data to be updated with
4400 *
4401 * Returns 0 on success or error on failure
4402 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304403int adm_get_source_tracking(int port_id, int copp_idx,
4404 struct source_tracking_param *sourceTrackingData)
4405{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004406 struct adm_param_fluence_sourcetracking_t *source_tracking_params =
4407 NULL;
4408 struct mem_mapping_hdr mem_hdr;
4409 struct param_hdr_v3 param_hdr;
4410 int i = 0;
4411 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304412
4413 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4414 __func__, port_id, copp_idx);
4415
4416 if (!this_adm.sourceTrackingData.memmap.paddr) {
4417 /* Allocate and map shared memory for out of band usage */
4418 ret = adm_source_tracking_alloc_map_memory();
4419 if (ret != 0) {
4420 ret = -EINVAL;
4421 goto done;
4422 }
4423 }
4424
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004425 memset(&mem_hdr, 0, sizeof(mem_hdr));
4426 memset(&param_hdr, 0, sizeof(param_hdr));
4427 mem_hdr.data_payload_addr_lsw =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304428 lower_32_bits(this_adm.sourceTrackingData.memmap.paddr);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004429 mem_hdr.data_payload_addr_msw = msm_audio_populate_upper_32_bits(
4430 this_adm.sourceTrackingData.memmap.paddr);
4431 mem_hdr.mem_map_handle = atomic_read(
4432 &this_adm.mem_map_handles[ADM_MEM_MAP_INDEX_SOURCE_TRACKING]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304433
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004434 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4435 param_hdr.instance_id = INSTANCE_ID_0;
4436 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOURCETRACKING;
4437 /*
4438 * This size should be the max size of the calibration data + header.
4439 * Use the union size to ensure max size is used.
4440 */
4441 param_hdr.param_size =
4442 sizeof(struct adm_param_fluence_sourcetracking_t) +
4443 sizeof(union param_hdrs);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304444
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004445 /*
4446 * Retrieving parameters out of band, so no need to provide a buffer for
4447 * the returned parameter data as it will be at the memory location
4448 * provided.
4449 */
4450 ret = adm_get_pp_params(port_id, copp_idx,
4451 ADM_CLIENT_ID_SOURCE_TRACKING, &mem_hdr,
4452 &param_hdr, NULL);
4453 if (ret) {
4454 pr_err("%s: Failed to get params, error %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304455 goto done;
4456 }
4457
4458 if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
4459 pr_err("%s - get params returned error [%s]\n",
4460 __func__, adsp_err_get_err_str(
4461 this_adm.sourceTrackingData.apr_cmd_status));
4462
4463 ret = adsp_err_get_lnx_err_code(
4464 this_adm.sourceTrackingData.apr_cmd_status);
4465 goto done;
4466 }
4467
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004468 /* How do we know what the param data was retrieved with for hdr size */
4469 source_tracking_params =
4470 (struct adm_param_fluence_sourcetracking_t
4471 *) (this_adm.sourceTrackingData.memmap.kvaddr +
4472 sizeof(struct param_hdr_v1));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304473 for (i = 0; i < MAX_SECTORS; i++) {
4474 sourceTrackingData->vad[i] = source_tracking_params->vad[i];
4475 pr_debug("%s: vad[%d] = %d\n",
4476 __func__, i, sourceTrackingData->vad[i]);
4477 }
4478 sourceTrackingData->doa_speech = source_tracking_params->doa_speech;
4479 pr_debug("%s: doa_speech = %d\n",
4480 __func__, sourceTrackingData->doa_speech);
4481
4482 for (i = 0; i < MAX_NOISE_SOURCE_INDICATORS; i++) {
4483 sourceTrackingData->doa_noise[i] =
4484 source_tracking_params->doa_noise[i];
4485 pr_debug("%s: doa_noise[%d] = %d\n",
4486 __func__, i, sourceTrackingData->doa_noise[i]);
4487 }
4488 for (i = 0; i < MAX_POLAR_ACTIVITY_INDICATORS; i++) {
4489 sourceTrackingData->polar_activity[i] =
4490 source_tracking_params->polar_activity[i];
4491 pr_debug("%s: polar_activity[%d] = %d\n",
4492 __func__, i, sourceTrackingData->polar_activity[i]);
4493 }
4494
4495 ret = 0;
4496
4497done:
4498 pr_debug("%s: Exit, ret=%d\n", __func__, ret);
4499
4500 return ret;
4501}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304502EXPORT_SYMBOL(adm_get_source_tracking);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304503
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304504int __init adm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304505{
4506 int i = 0, j;
4507
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304508 this_adm.ec_ref_rx = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304509 init_waitqueue_head(&this_adm.matrix_map_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304510 init_waitqueue_head(&this_adm.adm_wait);
4511
4512 for (i = 0; i < AFE_MAX_PORTS; i++) {
4513 for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
4514 atomic_set(&this_adm.copp.id[i][j], RESET_COPP_ID);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304515 init_waitqueue_head(&this_adm.copp.wait[i][j]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304516 init_waitqueue_head(
4517 &this_adm.copp.adm_delay_wait[i][j]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304518 }
4519 }
4520
4521 if (adm_init_cal_data())
4522 pr_err("%s: could not init cal data!\n", __func__);
4523
Banajit Goswami08bb7362017-11-03 22:48:23 -07004524 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304525 this_adm.sourceTrackingData.memmap.size = 0;
4526 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
4527 this_adm.sourceTrackingData.memmap.paddr = 0;
4528 this_adm.sourceTrackingData.apr_cmd_status = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304529
4530 return 0;
4531}
4532
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05304533void adm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304534{
Laxminath Kasam30ad7512017-11-28 12:40:22 +05304535 if (this_adm.apr)
4536 adm_reset_data();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304537 adm_delete_cal_data();
4538}