blob: b9893c45803052a129f823b851eecb9cb7904421 [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 Kulothungan2c6dccd2018-03-22 14:18:43 -0700483 struct param_hdr_v1 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) +
Vignesh Kulothungan2c6dccd2018-03-22 14:18:43 -0700516 sizeof(struct param_hdr_v1) + 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) +
Vignesh Kulothungan2c6dccd2018-03-22 14:18:43 -0700544 sizeof(struct param_hdr_v1) + 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
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800792/*
Bhalchandra Gajareeed46bd2018-05-15 16:48:07 -0700793 * adm_set_custom_chmix_cfg:
794 * Set the custom channel mixer configuration for ADM
795 *
796 * @port_id: Backend port id
797 * @copp_idx: ADM copp index
798 * @session_id: ID of the requesting session
799 * @params: Expected packaged params for channel mixer
800 * @params_length: Length of the params to be set
801 * @direction: RX or TX direction
802 * @stream_type: Audio or Listen stream type
803 */
804int adm_set_custom_chmix_cfg(int port_id, int copp_idx,
805 unsigned int session_id, char *params,
806 uint32_t params_length, int direction,
807 int stream_type)
808{
809 struct adm_cmd_set_pspd_mtmx_strtr_params_v6 *adm_params = NULL;
810 int sz, rc = 0, port_idx;
811
812 port_id = afe_convert_virtual_to_portid(port_id);
813 port_idx = adm_validate_and_get_port_index(port_id);
814 if (port_idx < 0) {
815 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
816 return -EINVAL;
817 }
818
819 sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v6) +
820 params_length;
821 adm_params = kzalloc(sz, GFP_KERNEL);
822 if (!adm_params) {
823 pr_err("%s, adm params memory alloc failed\n", __func__);
824 return -ENOMEM;
825 }
826
827 memcpy(((u8 *)adm_params +
828 sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v6)),
829 params, params_length);
830 adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
831 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
832 adm_params->hdr.pkt_size = sz;
833 adm_params->hdr.src_svc = APR_SVC_ADM;
834 adm_params->hdr.src_domain = APR_DOMAIN_APPS;
835 adm_params->hdr.src_port = port_id;
836 adm_params->hdr.dest_svc = APR_SVC_ADM;
837 adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
838 adm_params->hdr.dest_port = 0; /* Ignored */;
839 adm_params->hdr.token = port_idx << 16 | copp_idx;
840 adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V6;
841 adm_params->payload_addr_lsw = 0;
842 adm_params->payload_addr_msw = 0;
843 adm_params->mem_map_handle = 0;
844 adm_params->payload_size = params_length;
845 adm_params->direction = direction;
846 /* session id for this cmd to be applied on */
847 adm_params->sessionid = session_id;
848 adm_params->deviceid =
849 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
850 /* connecting stream type i.e. lsm or asm */
851 adm_params->stream_type = stream_type;
852 pr_debug("%s: deviceid %d, session_id %d, src_port %d, dest_port %d\n",
853 __func__, adm_params->deviceid, adm_params->sessionid,
854 adm_params->hdr.src_port, adm_params->hdr.dest_port);
855 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
856 rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
857 if (rc < 0) {
858 pr_err("%s: Set params failed port = 0x%x rc %d\n",
859 __func__, port_id, rc);
860 rc = -EINVAL;
861 goto exit;
862 }
863 /* Wait for the callback */
864 rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
865 atomic_read(&this_adm.copp.stat
866 [port_idx][copp_idx]),
867 msecs_to_jiffies(TIMEOUT_MS));
868 if (!rc) {
869 pr_err("%s: Set params timed out port = 0x%x\n", __func__,
870 port_id);
871 rc = -EINVAL;
872 goto exit;
873 } else if (atomic_read(&this_adm.copp.stat
874 [port_idx][copp_idx]) > 0) {
875 pr_err("%s: DSP returned error[%s]\n", __func__,
876 adsp_err_get_err_str(atomic_read(
877 &this_adm.copp.stat
878 [port_idx][copp_idx])));
879 rc = adsp_err_get_lnx_err_code(
880 atomic_read(&this_adm.copp.stat
881 [port_idx][copp_idx]));
882 goto exit;
883 }
884
885 rc = 0;
886exit:
887 kfree(adm_params);
888 return rc;
889}
890EXPORT_SYMBOL(adm_set_custom_chmix_cfg);
891
892/*
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800893 * With pre-packed data, only the opcode differes from V5 and V6.
894 * Use q6common_pack_pp_params to pack the data correctly.
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530895 */
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800896int adm_set_pp_params(int port_id, int copp_idx,
897 struct mem_mapping_hdr *mem_hdr, u8 *param_data,
898 u32 param_size)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530899{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800900 struct adm_cmd_set_pp_params *adm_set_params = NULL;
901 int size = 0;
902 int port_idx = 0;
903 atomic_t *copp_stat = NULL;
904 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530905
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530906 port_id = afe_convert_virtual_to_portid(port_id);
907 port_idx = adm_validate_and_get_port_index(port_id);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800908 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
909 pr_err("%s: Invalid port_idx 0x%x\n", __func__, port_idx);
910 return -EINVAL;
911 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
912 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530913 return -EINVAL;
914 }
915
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800916 /* Only add params_size in inband case */
917 size = sizeof(struct adm_cmd_set_pp_params);
918 if (param_data != NULL)
919 size += param_size;
920 adm_set_params = kzalloc(size, GFP_KERNEL);
921 if (!adm_set_params)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530922 return -ENOMEM;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800923
924 adm_set_params->apr_hdr.hdr_field =
925 APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
926 APR_PKT_VER);
927 adm_set_params->apr_hdr.pkt_size = size;
928 adm_set_params->apr_hdr.src_svc = APR_SVC_ADM;
929 adm_set_params->apr_hdr.src_domain = APR_DOMAIN_APPS;
930 adm_set_params->apr_hdr.src_port = port_id;
931 adm_set_params->apr_hdr.dest_svc = APR_SVC_ADM;
932 adm_set_params->apr_hdr.dest_domain = APR_DOMAIN_ADSP;
933 adm_set_params->apr_hdr.dest_port =
934 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
935 adm_set_params->apr_hdr.token = port_idx << 16 | copp_idx;
936
937 if (q6common_is_instance_id_supported())
938 adm_set_params->apr_hdr.opcode = ADM_CMD_SET_PP_PARAMS_V6;
939 else
940 adm_set_params->apr_hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
941
942 adm_set_params->payload_size = param_size;
943
944 if (mem_hdr != NULL) {
945 /* Out of Band Case */
946 adm_set_params->mem_hdr = *mem_hdr;
947 } else if (param_data != NULL) {
948 /*
949 * In band case. Parameter data must be pre-packed with its
950 * header before calling this function. Use
951 * q6common_pack_pp_params to pack parameter data and header
952 * correctly.
953 */
954 memcpy(&adm_set_params->param_data, param_data, param_size);
955 } else {
956 pr_err("%s: Received NULL pointers for both memory header and param data\n",
957 __func__);
958 ret = -EINVAL;
959 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530960 }
961
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800962 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
963 atomic_set(copp_stat, -1);
964 ret = apr_send_pkt(this_adm.apr, (uint32_t *) adm_set_params);
965 if (ret < 0) {
966 pr_err("%s: Set params APR send failed port = 0x%x ret %d\n",
967 __func__, port_id, ret);
968 goto done;
969 }
970 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
971 atomic_read(copp_stat) >= 0,
972 msecs_to_jiffies(TIMEOUT_MS));
973 if (!ret) {
974 pr_err("%s: Set params timed out port = 0x%x\n", __func__,
975 port_id);
976 ret = -ETIMEDOUT;
977 goto done;
978 }
979 if (atomic_read(copp_stat) > 0) {
980 pr_err("%s: DSP returned error[%s]\n", __func__,
981 adsp_err_get_err_str(atomic_read(copp_stat)));
982 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
983 goto done;
984 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530985
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800986 ret = 0;
987done:
988 kfree(adm_set_params);
989 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530990}
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -0800991EXPORT_SYMBOL(adm_set_pp_params);
992
993int adm_pack_and_set_one_pp_param(int port_id, int copp_idx,
994 struct param_hdr_v3 param_hdr, u8 *param_data)
995{
996 u8 *packed_data = NULL;
997 u32 total_size = 0;
998 int ret = 0;
999
1000 total_size = sizeof(union param_hdrs) + param_hdr.param_size;
1001 packed_data = kzalloc(total_size, GFP_KERNEL);
1002 if (!packed_data)
1003 return -ENOMEM;
1004
1005 ret = q6common_pack_pp_params(packed_data, &param_hdr, param_data,
1006 &total_size);
1007 if (ret) {
1008 pr_err("%s: Failed to pack parameter data, error %d\n",
1009 __func__, ret);
1010 goto done;
1011 }
1012
1013 ret = adm_set_pp_params(port_id, copp_idx, NULL, packed_data,
1014 total_size);
1015 if (ret)
1016 pr_err("%s: Failed to set parameter data, error %d\n", __func__,
1017 ret);
1018done:
1019 kfree(packed_data);
1020 return ret;
1021}
1022EXPORT_SYMBOL(adm_pack_and_set_one_pp_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301023
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001024/*
1025 * Only one parameter can be requested at a time. Therefore, packing and sending
1026 * the request can be handled locally.
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301027 */
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001028int adm_get_pp_params(int port_id, int copp_idx, uint32_t client_id,
1029 struct mem_mapping_hdr *mem_hdr,
1030 struct param_hdr_v3 *param_hdr, u8 *returned_param_data)
1031{
1032 struct adm_cmd_get_pp_params adm_get_params;
1033 int total_size = 0;
1034 int get_param_array_sz = ARRAY_SIZE(adm_get_parameters);
1035 int returned_param_size = 0;
1036 int returned_param_size_in_bytes = 0;
1037 int port_idx = 0;
1038 int idx = 0;
1039 atomic_t *copp_stat = NULL;
1040 int ret = 0;
1041
1042 if (param_hdr == NULL) {
1043 pr_err("%s: Received NULL pointer for parameter header\n",
1044 __func__);
1045 return -EINVAL;
1046 }
1047
1048 port_id = afe_convert_virtual_to_portid(port_id);
1049 port_idx = adm_validate_and_get_port_index(port_id);
1050 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
1051 pr_err("%s: Invalid port_idx 0x%x\n", __func__, port_idx);
1052 return -EINVAL;
1053 }
1054 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1055 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
1056 return -EINVAL;
1057 }
1058
1059 memset(&adm_get_params, 0, sizeof(adm_get_params));
1060
1061 if (mem_hdr != NULL)
1062 adm_get_params.mem_hdr = *mem_hdr;
1063
1064 q6common_pack_pp_params((u8 *) &adm_get_params.param_hdr, param_hdr,
1065 NULL, &total_size);
1066
1067 /* Pack APR header after filling body so total_size has correct value */
1068 adm_get_params.apr_hdr.pkt_size = total_size;
1069 adm_get_params.apr_hdr.src_svc = APR_SVC_ADM;
1070 adm_get_params.apr_hdr.src_domain = APR_DOMAIN_APPS;
1071 adm_get_params.apr_hdr.src_port = port_id;
1072 adm_get_params.apr_hdr.dest_svc = APR_SVC_ADM;
1073 adm_get_params.apr_hdr.dest_domain = APR_DOMAIN_ADSP;
1074 adm_get_params.apr_hdr.dest_port =
1075 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
1076 adm_get_params.apr_hdr.token =
1077 port_idx << 16 | client_id << 8 | copp_idx;
1078
1079 if (q6common_is_instance_id_supported())
1080 adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V6;
1081 else
1082 adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
1083
1084 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
1085 atomic_set(copp_stat, -1);
1086 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_params);
1087 if (ret) {
1088 pr_err("%s: Get params APR send failed port = 0x%x ret %d\n",
1089 __func__, port_id, ret);
1090 ret = -EINVAL;
1091 goto done;
1092 }
1093 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
1094 atomic_read(copp_stat) >= 0,
1095 msecs_to_jiffies(TIMEOUT_MS));
1096 if (!ret) {
1097 pr_err("%s: Get params timed out port = 0x%x\n", __func__,
1098 port_id);
1099 ret = -ETIMEDOUT;
1100 goto done;
1101 }
1102 if (atomic_read(copp_stat) > 0) {
1103 pr_err("%s: DSP returned error[%s]\n", __func__,
1104 adsp_err_get_err_str(atomic_read(copp_stat)));
1105 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
1106 goto done;
1107 }
1108
1109 ret = 0;
1110
1111 /* Copy data to caller if sent in band */
1112 if (!returned_param_data) {
1113 pr_debug("%s: Received NULL pointer for param destination, not copying payload\n",
1114 __func__);
1115 return 0;
1116 }
1117
1118 idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
1119 returned_param_size = adm_get_parameters[idx];
1120 if (returned_param_size < 0 ||
1121 returned_param_size + idx + 1 > get_param_array_sz) {
1122 pr_err("%s: Invalid parameter size %d\n", __func__,
1123 returned_param_size);
1124 return -EINVAL;
1125 }
1126
1127 returned_param_size_in_bytes = returned_param_size * sizeof(uint32_t);
1128 if (param_hdr->param_size < returned_param_size_in_bytes) {
1129 pr_err("%s: Provided buffer is not big enough, provided buffer size(%d) size needed(%d)\n",
1130 __func__, param_hdr->param_size,
1131 returned_param_size_in_bytes);
1132 return -EINVAL;
1133 }
1134
1135 memcpy(returned_param_data, &adm_get_parameters[idx + 1],
1136 returned_param_size_in_bytes);
1137done:
1138 return ret;
1139}
1140EXPORT_SYMBOL(adm_get_pp_params);
1141
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001142int adm_get_pp_topo_module_list_v2(int port_id, int copp_idx,
1143 int32_t param_length,
1144 int32_t *returned_params)
1145{
1146 struct adm_cmd_get_pp_topo_module_list adm_get_module_list;
1147 bool iid_supported = q6common_is_instance_id_supported();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301148 int *topo_list;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001149 int num_modules = 0;
1150 int list_size = 0;
1151 int port_idx, idx;
1152 int i = 0;
1153 atomic_t *copp_stat = NULL;
1154 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301155
1156 pr_debug("%s : port_id %x", __func__, port_id);
1157 port_id = afe_convert_virtual_to_portid(port_id);
1158 port_idx = adm_validate_and_get_port_index(port_id);
1159 if (port_idx < 0) {
1160 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
1161 return -EINVAL;
1162 }
1163
1164 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1165 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
1166 return -EINVAL;
1167 }
1168
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001169 memset(&adm_get_module_list, 0, sizeof(adm_get_module_list));
1170
1171 adm_get_module_list.apr_hdr.pkt_size = sizeof(adm_get_module_list);
1172 adm_get_module_list.apr_hdr.src_svc = APR_SVC_ADM;
1173 adm_get_module_list.apr_hdr.src_domain = APR_DOMAIN_APPS;
1174 adm_get_module_list.apr_hdr.src_port = port_id;
1175 adm_get_module_list.apr_hdr.dest_svc = APR_SVC_ADM;
1176 adm_get_module_list.apr_hdr.dest_domain = APR_DOMAIN_ADSP;
1177 adm_get_module_list.apr_hdr.dest_port =
1178 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
1179 adm_get_module_list.apr_hdr.token = port_idx << 16 | copp_idx;
1180 /*
1181 * Out of band functionality is not currently utilized.
1182 * Assume in band.
1183 */
1184 if (iid_supported) {
1185 adm_get_module_list.apr_hdr.opcode =
1186 ADM_CMD_GET_PP_TOPO_MODULE_LIST_V2;
1187 adm_get_module_list.param_max_size = param_length;
1188 } else {
1189 adm_get_module_list.apr_hdr.opcode =
1190 ADM_CMD_GET_PP_TOPO_MODULE_LIST;
1191
1192 if (param_length > U16_MAX) {
1193 pr_err("%s: Invalid param length for V1 %d\n", __func__,
1194 param_length);
1195 return -EINVAL;
1196 }
1197 adm_get_module_list.param_max_size = param_length << 16;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301198 }
1199
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001200 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
1201 atomic_set(copp_stat, -1);
1202 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_module_list);
1203 if (ret) {
1204 pr_err("%s: APR send pkt failed for port_id: 0x%x failed ret %d\n",
1205 __func__, port_id, ret);
1206 ret = -EINVAL;
1207 goto done;
1208 }
1209 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
1210 atomic_read(copp_stat) >= 0,
1211 msecs_to_jiffies(TIMEOUT_MS));
1212 if (!ret) {
1213 pr_err("%s: Timeout for port_id: 0x%x\n", __func__, port_id);
1214 ret = -ETIMEDOUT;
1215 goto done;
1216 }
1217 if (atomic_read(copp_stat) > 0) {
1218 pr_err("%s: DSP returned error[%s]\n", __func__,
1219 adsp_err_get_err_str(atomic_read(copp_stat)));
1220 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
1221 goto done;
1222 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301223
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001224 ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301225
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001226 if (returned_params) {
1227 /*
1228 * When processing ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST IID is
1229 * added since it is not present. Therefore, there is no need to
1230 * do anything different if IID is not supported here as it is
1231 * already taken care of.
1232 */
1233 idx = ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH * copp_idx;
1234 num_modules = adm_module_topo_list[idx];
1235 if (num_modules < 0 || num_modules > MAX_MODULES_IN_TOPO) {
1236 pr_err("%s: Invalid number of modules returned %d\n",
1237 __func__, num_modules);
1238 return -EINVAL;
1239 }
1240
1241 list_size = num_modules * sizeof(struct module_instance_info);
1242 if (param_length < list_size) {
1243 pr_err("%s: Provided buffer not big enough to hold module-instance list, provided size %d, needed size %d\n",
1244 __func__, param_length, list_size);
1245 return -EINVAL;
1246 }
1247
1248 topo_list = (int32_t *) (&adm_module_topo_list[idx]);
1249 memcpy(returned_params, topo_list, list_size);
1250 for (i = 1; i <= num_modules; i += 2) {
1251 pr_debug("module = 0x%x instance = 0x%x\n",
1252 returned_params[i], returned_params[i + 1]);
1253 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301254 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001255done:
1256 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301257}
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001258EXPORT_SYMBOL(adm_get_pp_topo_module_list_v2);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301259
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301260static void adm_callback_debug_print(struct apr_client_data *data)
1261{
1262 uint32_t *payload;
1263
1264 payload = data->payload;
1265
1266 if (data->payload_size >= 8)
1267 pr_debug("%s: code = 0x%x PL#0[0x%x], PL#1[0x%x], size = %d\n",
1268 __func__, data->opcode, payload[0], payload[1],
1269 data->payload_size);
1270 else if (data->payload_size >= 4)
1271 pr_debug("%s: code = 0x%x PL#0[0x%x], size = %d\n",
1272 __func__, data->opcode, payload[0],
1273 data->payload_size);
1274 else
1275 pr_debug("%s: code = 0x%x, size = %d\n",
1276 __func__, data->opcode, data->payload_size);
1277}
1278
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301279/**
1280 * adm_set_multi_ch_map -
1281 * Update multi channel map info
1282 *
1283 * @channel_map: pointer with channel map info
1284 * @path: direction or ADM path type
1285 *
1286 * Returns 0 on success or error on failure
1287 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301288int adm_set_multi_ch_map(char *channel_map, int path)
1289{
1290 int idx;
1291
1292 if (path == ADM_PATH_PLAYBACK) {
1293 idx = ADM_MCH_MAP_IDX_PLAYBACK;
1294 } else if (path == ADM_PATH_LIVE_REC) {
1295 idx = ADM_MCH_MAP_IDX_REC;
1296 } else {
1297 pr_err("%s: invalid attempt to set path %d\n", __func__, path);
1298 return -EINVAL;
1299 }
1300
1301 memcpy(multi_ch_maps[idx].channel_mapping, channel_map,
1302 PCM_FORMAT_MAX_NUM_CHANNEL);
1303 multi_ch_maps[idx].set_channel_map = true;
1304
1305 return 0;
1306}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301307EXPORT_SYMBOL(adm_set_multi_ch_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301308
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301309/**
1310 * adm_get_multi_ch_map -
1311 * Retrieves multi channel map info
1312 *
1313 * @channel_map: pointer to be updated with channel map
1314 * @path: direction or ADM path type
1315 *
1316 * Returns 0 on success or error on failure
1317 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301318int adm_get_multi_ch_map(char *channel_map, int path)
1319{
1320 int idx;
1321
1322 if (path == ADM_PATH_PLAYBACK) {
1323 idx = ADM_MCH_MAP_IDX_PLAYBACK;
1324 } else if (path == ADM_PATH_LIVE_REC) {
1325 idx = ADM_MCH_MAP_IDX_REC;
1326 } else {
1327 pr_err("%s: invalid attempt to get path %d\n", __func__, path);
1328 return -EINVAL;
1329 }
1330
1331 if (multi_ch_maps[idx].set_channel_map) {
1332 memcpy(channel_map, multi_ch_maps[idx].channel_mapping,
1333 PCM_FORMAT_MAX_NUM_CHANNEL);
1334 }
1335
1336 return 0;
1337}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301338EXPORT_SYMBOL(adm_get_multi_ch_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301339
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001340static int adm_process_get_param_response(u32 opcode, u32 idx, u32 *payload,
1341 u32 payload_size)
1342{
1343 struct adm_cmd_rsp_get_pp_params_v5 *v5_rsp = NULL;
1344 struct adm_cmd_rsp_get_pp_params_v6 *v6_rsp = NULL;
1345 u32 *param_data = NULL;
1346 int data_size = 0;
1347 int struct_size = 0;
1348
1349 if (payload == NULL) {
1350 pr_err("%s: Payload is NULL\n", __func__);
1351 return -EINVAL;
1352 }
1353
1354 switch (opcode) {
1355 case ADM_CMDRSP_GET_PP_PARAMS_V5:
1356 struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v5);
1357 v5_rsp = (struct adm_cmd_rsp_get_pp_params_v5 *) payload;
1358 data_size = v5_rsp->param_hdr.param_size;
1359 param_data = v5_rsp->param_data;
1360 break;
1361 case ADM_CMDRSP_GET_PP_PARAMS_V6:
1362 struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v6);
1363 v6_rsp = (struct adm_cmd_rsp_get_pp_params_v6 *) payload;
1364 data_size = v6_rsp->param_hdr.param_size;
1365 param_data = v6_rsp->param_data;
1366 break;
1367 default:
1368 pr_err("%s: Invalid opcode %d\n", __func__, opcode);
1369 return -EINVAL;
1370 }
1371
1372 /*
1373 * Just store the returned parameter data, not the header. The calling
1374 * function is expected to know what it asked for. Therefore, there is
1375 * no difference between V5 and V6.
1376 */
1377 if ((payload_size >= struct_size + data_size) &&
1378 (ARRAY_SIZE(adm_get_parameters) > idx) &&
1379 (ARRAY_SIZE(adm_get_parameters) >= idx + 1 + data_size)) {
1380 /*
1381 * data_size is expressed in number of bytes, store in number of
1382 * ints
1383 */
1384 adm_get_parameters[idx] =
1385 data_size / sizeof(*adm_get_parameters);
1386 pr_debug("%s: GET_PP PARAM: received parameter length: 0x%x\n",
1387 __func__, adm_get_parameters[idx]);
1388 /* store params after param_size */
1389 memcpy(&adm_get_parameters[idx + 1], param_data, data_size);
1390 return 0;
1391 }
1392
1393 pr_err("%s: Invalid parameter combination, payload_size %d, idx %d\n",
1394 __func__, payload_size, idx);
1395 return -EINVAL;
1396}
1397
1398static int adm_process_get_topo_list_response(u32 opcode, int copp_idx,
1399 u32 num_modules, u32 *payload,
1400 u32 payload_size)
1401{
1402 u32 *fill_list = NULL;
1403 int idx = 0;
1404 int i = 0;
1405 int j = 0;
1406
1407 if (payload == NULL) {
1408 pr_err("%s: Payload is NULL\n", __func__);
1409 return -EINVAL;
1410 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1411 pr_err("%s: Invalid COPP index %d\n", __func__, copp_idx);
1412 return -EINVAL;
1413 }
1414
1415 idx = ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH * copp_idx;
1416 fill_list = adm_module_topo_list + idx;
1417 *fill_list++ = num_modules;
1418 for (i = 0; i < num_modules; i++) {
1419 if (j > payload_size / sizeof(u32)) {
1420 pr_err("%s: Invalid number of modules specified %d\n",
1421 __func__, num_modules);
1422 return -EINVAL;
1423 }
1424
1425 /* store module ID */
1426 *fill_list++ = payload[j];
1427 j++;
1428
1429 switch (opcode) {
1430 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
1431 /* store instance ID */
1432 *fill_list++ = payload[j];
1433 j++;
1434 break;
1435 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
1436 /* Insert IID 0 when repacking */
1437 *fill_list++ = INSTANCE_ID_0;
1438 break;
1439 default:
1440 pr_err("%s: Invalid opcode %d\n", __func__, opcode);
1441 return -EINVAL;
1442 }
1443 }
1444
1445 return 0;
1446}
1447
Laxminath Kasam30ad7512017-11-28 12:40:22 +05301448static void adm_reset_data(void)
1449{
1450 int i, j;
1451
1452 apr_reset(this_adm.apr);
1453 for (i = 0; i < AFE_MAX_PORTS; i++) {
1454 for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
1455 atomic_set(&this_adm.copp.id[i][j],
1456 RESET_COPP_ID);
1457 atomic_set(&this_adm.copp.cnt[i][j], 0);
1458 atomic_set(
1459 &this_adm.copp.topology[i][j], 0);
1460 atomic_set(&this_adm.copp.mode[i][j],
1461 0);
1462 atomic_set(&this_adm.copp.stat[i][j],
1463 0);
1464 atomic_set(&this_adm.copp.rate[i][j],
1465 0);
1466 atomic_set(
1467 &this_adm.copp.channels[i][j],
1468 0);
1469 atomic_set(
1470 &this_adm.copp.bit_width[i][j], 0);
1471 atomic_set(
1472 &this_adm.copp.app_type[i][j], 0);
1473 atomic_set(
1474 &this_adm.copp.acdb_id[i][j], 0);
1475 this_adm.copp.adm_status[i][j] =
1476 ADM_STATUS_CALIBRATION_REQUIRED;
1477 }
1478 }
1479 this_adm.apr = NULL;
1480 cal_utils_clear_cal_block_q6maps(ADM_MAX_CAL_TYPES,
1481 this_adm.cal_data);
1482 mutex_lock(&this_adm.cal_data
1483 [ADM_CUSTOM_TOP_CAL]->lock);
1484 this_adm.set_custom_topology = 1;
1485 mutex_unlock(&this_adm.cal_data[
1486 ADM_CUSTOM_TOP_CAL]->lock);
1487 rtac_clear_mapping(ADM_RTAC_CAL);
1488 /*
1489 * Free the ION memory and clear the map handles
1490 * for Source Tracking
1491 */
1492 if (this_adm.sourceTrackingData.memmap.paddr != 0) {
1493 msm_audio_ion_free(
1494 this_adm.sourceTrackingData.dma_buf);
1495 this_adm.sourceTrackingData.dma_buf = NULL;
1496 this_adm.sourceTrackingData.memmap.size = 0;
1497 this_adm.sourceTrackingData.memmap.kvaddr =
1498 NULL;
1499 this_adm.sourceTrackingData.memmap.paddr = 0;
1500 this_adm.sourceTrackingData.apr_cmd_status = -1;
1501 atomic_set(&this_adm.mem_map_handles[
1502 ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
1503 }
1504}
1505
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301506static int32_t adm_callback(struct apr_client_data *data, void *priv)
1507{
1508 uint32_t *payload;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001509 int port_idx, copp_idx, idx, client_id;
1510 int num_modules;
1511 int ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301512
1513 if (data == NULL) {
1514 pr_err("%s: data parameter is null\n", __func__);
1515 return -EINVAL;
1516 }
1517
1518 payload = data->payload;
1519
1520 if (data->opcode == RESET_EVENTS) {
1521 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1522 __func__,
1523 data->reset_event, data->reset_proc, this_adm.apr);
Laxminath Kasam30ad7512017-11-28 12:40:22 +05301524 if (this_adm.apr)
1525 adm_reset_data();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301526 return 0;
1527 }
1528
1529 adm_callback_debug_print(data);
1530 if (data->payload_size) {
1531 copp_idx = (data->token) & 0XFF;
1532 port_idx = ((data->token) >> 16) & 0xFF;
1533 client_id = ((data->token) >> 8) & 0xFF;
1534 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
1535 pr_err("%s: Invalid port idx %d token %d\n",
1536 __func__, port_idx, data->token);
1537 return 0;
1538 }
1539 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1540 pr_err("%s: Invalid copp idx %d token %d\n",
1541 __func__, copp_idx, data->token);
1542 return 0;
1543 }
1544 if (client_id < 0 || client_id >= ADM_CLIENT_ID_MAX) {
1545 pr_err("%s: Invalid client id %d\n", __func__,
1546 client_id);
1547 return 0;
1548 }
1549 if (data->opcode == APR_BASIC_RSP_RESULT) {
1550 pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n",
1551 __func__, payload[0]);
1552 if (payload[1] != 0) {
1553 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
1554 __func__, payload[0], payload[1]);
1555 }
1556 switch (payload[0]) {
1557 case ADM_CMD_SET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001558 case ADM_CMD_SET_PP_PARAMS_V6:
1559 pr_debug("%s: ADM_CMD_SET_PP_PARAMS\n",
1560 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301561 if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
1562 this_adm.sourceTrackingData.
1563 apr_cmd_status = payload[1];
1564 else if (rtac_make_adm_callback(payload,
1565 data->payload_size))
1566 break;
1567 /*
1568 * if soft volume is called and already
1569 * interrupted break out of the sequence here
1570 */
1571 case ADM_CMD_DEVICE_OPEN_V5:
1572 case ADM_CMD_DEVICE_CLOSE_V5:
1573 case ADM_CMD_DEVICE_OPEN_V6:
1574 pr_debug("%s: Basic callback received, wake up.\n",
1575 __func__);
1576 atomic_set(&this_adm.copp.stat[port_idx]
1577 [copp_idx], payload[1]);
1578 wake_up(
1579 &this_adm.copp.wait[port_idx][copp_idx]);
1580 break;
1581 case ADM_CMD_ADD_TOPOLOGIES:
1582 pr_debug("%s: callback received, ADM_CMD_ADD_TOPOLOGIES.\n",
1583 __func__);
1584 atomic_set(&this_adm.adm_stat, payload[1]);
1585 wake_up(&this_adm.adm_wait);
1586 break;
1587 case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
1588 case ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5:
1589 pr_debug("%s: Basic callback received, wake up.\n",
1590 __func__);
1591 atomic_set(&this_adm.matrix_map_stat,
1592 payload[1]);
1593 wake_up(&this_adm.matrix_map_wait);
1594 break;
1595 case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
1596 pr_debug("%s: ADM_CMD_SHARED_MEM_UNMAP_REGIONS\n",
1597 __func__);
1598 atomic_set(&this_adm.adm_stat, payload[1]);
1599 wake_up(&this_adm.adm_wait);
1600 break;
1601 case ADM_CMD_SHARED_MEM_MAP_REGIONS:
1602 pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
1603 __func__);
1604 /* Should only come here if there is an APR */
1605 /* error or malformed APR packet. Otherwise */
1606 /* response will be returned as */
1607 if (payload[1] != 0) {
1608 pr_err("%s: ADM map error, resuming\n",
1609 __func__);
1610 atomic_set(&this_adm.adm_stat,
1611 payload[1]);
1612 wake_up(&this_adm.adm_wait);
1613 }
1614 break;
1615 case ADM_CMD_GET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001616 case ADM_CMD_GET_PP_PARAMS_V6:
1617 pr_debug("%s: ADM_CMD_GET_PP_PARAMS\n",
1618 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301619 /* Should only come here if there is an APR */
1620 /* error or malformed APR packet. Otherwise */
1621 /* response will be returned as */
1622 /* ADM_CMDRSP_GET_PP_PARAMS_V5 */
1623 if (client_id ==
1624 ADM_CLIENT_ID_SOURCE_TRACKING) {
1625 this_adm.sourceTrackingData.
1626 apr_cmd_status = payload[1];
1627 if (payload[1] != 0)
1628 pr_err("%s: ADM get param error = %d\n",
1629 __func__, payload[1]);
1630
1631 atomic_set(&this_adm.copp.stat
1632 [port_idx][copp_idx],
1633 payload[1]);
1634 wake_up(&this_adm.copp.wait
1635 [port_idx][copp_idx]);
1636 } else {
1637 if (payload[1] != 0) {
1638 pr_err("%s: ADM get param error = %d, resuming\n",
1639 __func__, payload[1]);
1640
1641 rtac_make_adm_callback(payload,
1642 data->payload_size);
1643 }
1644 }
1645 break;
1646 case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5:
Bhalchandra Gajareeed46bd2018-05-15 16:48:07 -07001647 case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V6:
1648 pr_debug("%s:callback received PSPD MTMX, wake up\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301649 __func__);
1650 atomic_set(&this_adm.copp.stat[port_idx]
1651 [copp_idx], payload[1]);
1652 wake_up(
1653 &this_adm.copp.wait[port_idx][copp_idx]);
1654 break;
1655 case ADM_CMD_GET_PP_TOPO_MODULE_LIST:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001656 case ADM_CMD_GET_PP_TOPO_MODULE_LIST_V2:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301657 pr_debug("%s:ADM_CMD_GET_PP_TOPO_MODULE_LIST\n",
1658 __func__);
1659 if (payload[1] != 0)
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001660 pr_err("%s: ADM get topo list error = %d\n",
1661 __func__, payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301662 break;
1663 default:
1664 pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
1665 payload[0]);
1666 break;
1667 }
1668 return 0;
1669 }
1670
1671 switch (data->opcode) {
1672 case ADM_CMDRSP_DEVICE_OPEN_V5:
1673 case ADM_CMDRSP_DEVICE_OPEN_V6: {
1674 struct adm_cmd_rsp_device_open_v5 *open =
1675 (struct adm_cmd_rsp_device_open_v5 *)data->payload;
1676
1677 if (open->copp_id == INVALID_COPP_ID) {
1678 pr_err("%s: invalid coppid rxed %d\n",
1679 __func__, open->copp_id);
1680 atomic_set(&this_adm.copp.stat[port_idx]
1681 [copp_idx], ADSP_EBADPARAM);
1682 wake_up(
1683 &this_adm.copp.wait[port_idx][copp_idx]);
1684 break;
1685 }
1686 atomic_set(&this_adm.copp.stat
1687 [port_idx][copp_idx], payload[0]);
1688 atomic_set(&this_adm.copp.id[port_idx][copp_idx],
1689 open->copp_id);
1690 pr_debug("%s: coppid rxed=%d\n", __func__,
1691 open->copp_id);
1692 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1693 }
1694 break;
1695 case ADM_CMDRSP_GET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001696 case ADM_CMDRSP_GET_PP_PARAMS_V6:
1697 pr_debug("%s: ADM_CMDRSP_GET_PP_PARAMS\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301698 if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
1699 this_adm.sourceTrackingData.apr_cmd_status =
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001700 payload[0];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301701 else if (rtac_make_adm_callback(payload,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001702 data->payload_size))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301703 break;
1704
1705 idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001706 if (payload[0] == 0 && data->payload_size > 0) {
1707 pr_debug("%s: Received parameter data in band\n",
1708 __func__);
1709 ret = adm_process_get_param_response(
1710 data->opcode, idx, payload,
1711 data->payload_size);
1712 if (ret)
1713 pr_err("%s: Failed to process get param response, error %d\n",
1714 __func__, ret);
1715 } else if (payload[0] == 0 && data->payload_size == 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301716 adm_get_parameters[idx] = -1;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001717 pr_debug("%s: Out of band case, setting size to %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301718 __func__, adm_get_parameters[idx]);
1719 } else {
1720 adm_get_parameters[idx] = -1;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001721 pr_err("%s: ADM_CMDRSP_GET_PP_PARAMS returned error 0x%x\n",
1722 __func__, payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301723 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001724 atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
1725 payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301726 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1727 break;
1728 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001729 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301730 pr_debug("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST\n",
1731 __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001732 num_modules = payload[1];
1733 pr_debug("%s: Num modules %d\n", __func__, num_modules);
1734 if (payload[0]) {
1735 pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST, error = %d\n",
1736 __func__, payload[0]);
1737 } else if (num_modules > MAX_MODULES_IN_TOPO) {
1738 pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST invalid num modules received, num modules = %d\n",
1739 __func__, num_modules);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301740 } else {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001741 ret = adm_process_get_topo_list_response(
1742 data->opcode, copp_idx, num_modules,
1743 payload, data->payload_size);
1744 if (ret)
1745 pr_err("%s: Failed to process get topo modules list response, error %d\n",
1746 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301747 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001748 atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
1749 payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301750 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1751 break;
1752 case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
1753 pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
1754 __func__);
1755 atomic_set(&this_adm.mem_map_handles[
1756 atomic_read(&this_adm.mem_map_index)],
1757 *payload);
1758 atomic_set(&this_adm.adm_stat, 0);
1759 wake_up(&this_adm.adm_wait);
1760 break;
1761 default:
1762 pr_err("%s: Unknown cmd:0x%x\n", __func__,
1763 data->opcode);
1764 break;
1765 }
1766 }
1767 return 0;
1768}
1769
1770static int adm_memory_map_regions(phys_addr_t *buf_add, uint32_t mempool_id,
1771 uint32_t *bufsz, uint32_t bufcnt)
1772{
1773 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
1774 struct avs_shared_map_region_payload *mregions = NULL;
1775 void *mmap_region_cmd = NULL;
1776 void *payload = NULL;
1777 int ret = 0;
1778 int i = 0;
1779 int cmd_size = 0;
1780
1781 pr_debug("%s:\n", __func__);
1782 if (this_adm.apr == NULL) {
1783 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
1784 0xFFFFFFFF, &this_adm);
1785 if (this_adm.apr == NULL) {
1786 pr_err("%s: Unable to register ADM\n", __func__);
1787 ret = -ENODEV;
1788 return ret;
1789 }
1790 rtac_set_adm_handle(this_adm.apr);
1791 }
1792
1793 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
1794 + sizeof(struct avs_shared_map_region_payload)
1795 * bufcnt;
1796
1797 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
1798 if (!mmap_region_cmd)
1799 return -ENOMEM;
1800
1801 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
1802 mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1803 APR_HDR_LEN(APR_HDR_SIZE),
1804 APR_PKT_VER);
1805 mmap_regions->hdr.pkt_size = cmd_size;
1806 mmap_regions->hdr.src_port = 0;
1807
1808 mmap_regions->hdr.dest_port = 0;
1809 mmap_regions->hdr.token = 0;
1810 mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
1811 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
1812 mmap_regions->num_regions = bufcnt & 0x00ff;
1813 mmap_regions->property_flag = 0x00;
1814
1815 pr_debug("%s: map_regions->num_regions = %d\n", __func__,
1816 mmap_regions->num_regions);
1817 payload = ((u8 *) mmap_region_cmd +
1818 sizeof(struct avs_cmd_shared_mem_map_regions));
1819 mregions = (struct avs_shared_map_region_payload *)payload;
1820
1821 for (i = 0; i < bufcnt; i++) {
1822 mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
1823 mregions->shm_addr_msw =
1824 msm_audio_populate_upper_32_bits(buf_add[i]);
1825 mregions->mem_size_bytes = bufsz[i];
1826 ++mregions;
1827 }
1828
1829 atomic_set(&this_adm.adm_stat, -1);
1830 ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
1831 if (ret < 0) {
1832 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
1833 mmap_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_map\n", __func__);
1843 ret = -EINVAL;
1844 goto fail_cmd;
1845 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1846 pr_err("%s: DSP returned error[%s]\n",
1847 __func__, adsp_err_get_err_str(
1848 atomic_read(&this_adm.adm_stat)));
1849 ret = adsp_err_get_lnx_err_code(
1850 atomic_read(&this_adm.adm_stat));
1851 goto fail_cmd;
1852 }
1853fail_cmd:
1854 kfree(mmap_region_cmd);
1855 return ret;
1856}
1857
1858static int adm_memory_unmap_regions(void)
1859{
1860 struct avs_cmd_shared_mem_unmap_regions unmap_regions;
1861 int ret = 0;
1862
1863 pr_debug("%s:\n", __func__);
1864 if (this_adm.apr == NULL) {
1865 pr_err("%s: APR handle NULL\n", __func__);
1866 return -EINVAL;
1867 }
1868
1869 unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1870 APR_HDR_LEN(APR_HDR_SIZE),
1871 APR_PKT_VER);
1872 unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
1873 unmap_regions.hdr.src_port = 0;
1874 unmap_regions.hdr.dest_port = 0;
1875 unmap_regions.hdr.token = 0;
1876 unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
1877 unmap_regions.mem_map_handle = atomic_read(&this_adm.
1878 mem_map_handles[atomic_read(&this_adm.mem_map_index)]);
1879 atomic_set(&this_adm.adm_stat, -1);
1880 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
1881 if (ret < 0) {
1882 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
1883 unmap_regions.hdr.opcode, ret);
1884 ret = -EINVAL;
1885 goto fail_cmd;
1886 }
1887
1888 ret = wait_event_timeout(this_adm.adm_wait,
1889 atomic_read(&this_adm.adm_stat) >= 0,
1890 5 * HZ);
1891 if (!ret) {
1892 pr_err("%s: timeout. waited for memory_unmap\n",
1893 __func__);
1894 ret = -EINVAL;
1895 goto fail_cmd;
1896 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1897 pr_err("%s: DSP returned error[%s]\n",
1898 __func__, adsp_err_get_err_str(
1899 atomic_read(&this_adm.adm_stat)));
1900 ret = adsp_err_get_lnx_err_code(
1901 atomic_read(&this_adm.adm_stat));
1902 goto fail_cmd;
1903 } else {
1904 pr_debug("%s: Unmap handle 0x%x succeeded\n", __func__,
1905 unmap_regions.mem_map_handle);
1906 }
1907fail_cmd:
1908 return ret;
1909}
1910
1911static int remap_cal_data(struct cal_block_data *cal_block, int cal_index)
1912{
1913 int ret = 0;
1914
Banajit Goswami08bb7362017-11-03 22:48:23 -07001915 if (cal_block->map_data.dma_buf == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301916 pr_err("%s: No ION allocation for cal index %d!\n",
1917 __func__, cal_index);
1918 ret = -EINVAL;
1919 goto done;
1920 }
1921
1922 if ((cal_block->map_data.map_size > 0) &&
1923 (cal_block->map_data.q6map_handle == 0)) {
1924 atomic_set(&this_adm.mem_map_index, cal_index);
1925 ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
1926 (uint32_t *)&cal_block->map_data.map_size, 1);
1927 if (ret < 0) {
1928 pr_err("%s: ADM mmap did not work! size = %zd ret %d\n",
1929 __func__,
1930 cal_block->map_data.map_size, ret);
1931 pr_debug("%s: ADM mmap did not work! addr = 0x%pK, size = %zd ret %d\n",
1932 __func__,
1933 &cal_block->cal_data.paddr,
1934 cal_block->map_data.map_size, ret);
1935 goto done;
1936 }
1937 cal_block->map_data.q6map_handle = atomic_read(&this_adm.
1938 mem_map_handles[cal_index]);
1939 }
1940done:
1941 return ret;
1942}
1943
1944static void send_adm_custom_topology(void)
1945{
1946 struct cal_block_data *cal_block = NULL;
1947 struct cmd_set_topologies adm_top;
1948 int cal_index = ADM_CUSTOM_TOP_CAL;
1949 int result;
1950
1951 if (this_adm.cal_data[cal_index] == NULL)
1952 goto done;
1953
1954 mutex_lock(&this_adm.cal_data[cal_index]->lock);
1955 if (!this_adm.set_custom_topology)
1956 goto unlock;
1957 this_adm.set_custom_topology = 0;
1958
1959 cal_block = cal_utils_get_only_cal_block(this_adm.cal_data[cal_index]);
Vikram Panduranga770b8382017-09-27 12:17:36 -07001960 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301961 goto unlock;
1962
1963 pr_debug("%s: Sending cal_index %d\n", __func__, cal_index);
1964
1965 result = remap_cal_data(cal_block, cal_index);
1966 if (result) {
1967 pr_err("%s: Remap_cal_data failed for cal %d!\n",
1968 __func__, cal_index);
1969 goto unlock;
1970 }
1971 atomic_set(&this_adm.mem_map_index, cal_index);
1972 atomic_set(&this_adm.mem_map_handles[cal_index],
1973 cal_block->map_data.q6map_handle);
1974
1975 if (cal_block->cal_data.size == 0) {
1976 pr_debug("%s: No ADM cal to send\n", __func__);
1977 goto unlock;
1978 }
1979
1980 adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1981 APR_HDR_LEN(20), APR_PKT_VER);
1982 adm_top.hdr.pkt_size = sizeof(adm_top);
1983 adm_top.hdr.src_svc = APR_SVC_ADM;
1984 adm_top.hdr.src_domain = APR_DOMAIN_APPS;
1985 adm_top.hdr.src_port = 0;
1986 adm_top.hdr.dest_svc = APR_SVC_ADM;
1987 adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
1988 adm_top.hdr.dest_port = 0;
1989 adm_top.hdr.token = 0;
1990 adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
1991 adm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
1992 adm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
1993 cal_block->cal_data.paddr);
1994 adm_top.mem_map_handle = cal_block->map_data.q6map_handle;
1995 adm_top.payload_size = cal_block->cal_data.size;
1996
1997 atomic_set(&this_adm.adm_stat, -1);
1998 pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%pK, size = %d\n",
1999 __func__, &cal_block->cal_data.paddr,
2000 adm_top.payload_size);
2001 result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
2002 if (result < 0) {
2003 pr_err("%s: Set topologies failed payload size = %zd result %d\n",
2004 __func__, cal_block->cal_data.size, result);
2005 goto unlock;
2006 }
2007 /* Wait for the callback */
2008 result = wait_event_timeout(this_adm.adm_wait,
2009 atomic_read(&this_adm.adm_stat) >= 0,
2010 msecs_to_jiffies(TIMEOUT_MS));
2011 if (!result) {
2012 pr_err("%s: Set topologies timed out payload size = %zd\n",
2013 __func__, cal_block->cal_data.size);
2014 goto unlock;
2015 } else if (atomic_read(&this_adm.adm_stat) > 0) {
2016 pr_err("%s: DSP returned error[%s]\n",
2017 __func__, adsp_err_get_err_str(
2018 atomic_read(&this_adm.adm_stat)));
2019 result = adsp_err_get_lnx_err_code(
2020 atomic_read(&this_adm.adm_stat));
2021 goto unlock;
2022 }
2023unlock:
2024 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
2025done:
2026 return;
2027}
2028
2029static int send_adm_cal_block(int port_id, int copp_idx,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002030 struct cal_block_data *cal_block, int perf_mode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302031{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002032 struct mem_mapping_hdr mem_hdr;
2033 int payload_size = 0;
2034 int port_idx = 0;
2035 int topology = 0;
2036 int result = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302037
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002038 pr_debug("%s: Port id 0x%x,\n", __func__, port_id);
2039
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302040 if (!cal_block) {
2041 pr_debug("%s: No ADM cal to send for port_id = 0x%x!\n",
2042 __func__, port_id);
2043 result = -EINVAL;
2044 goto done;
2045 }
2046 if (cal_block->cal_data.size <= 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002047 pr_debug("%s: No ADM cal sent for port_id = 0x%x!\n", __func__,
2048 port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302049 result = -EINVAL;
2050 goto done;
2051 }
2052
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002053 memset(&mem_hdr, 0, sizeof(mem_hdr));
2054 port_id = afe_convert_virtual_to_portid(port_id);
2055 port_idx = adm_validate_and_get_port_index(port_id);
2056 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
2057 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2058 return -EINVAL;
2059 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
2060 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
2061 return -EINVAL;
2062 }
2063
2064 topology = atomic_read(&this_adm.copp.topology[port_idx][copp_idx]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302065 if (perf_mode == LEGACY_PCM_MODE &&
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002066 topology == DS2_ADM_COPP_TOPOLOGY_ID) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302067 pr_err("%s: perf_mode %d, topology 0x%x\n", __func__, perf_mode,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002068 topology);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302069 goto done;
2070 }
2071
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002072 mem_hdr.data_payload_addr_lsw =
2073 lower_32_bits(cal_block->cal_data.paddr);
2074 mem_hdr.data_payload_addr_msw =
2075 msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
2076 mem_hdr.mem_map_handle = cal_block->map_data.q6map_handle;
2077 payload_size = cal_block->cal_data.size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302078
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002079 adm_set_pp_params(port_id, copp_idx, &mem_hdr, NULL, payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302080
2081done:
2082 return result;
2083}
2084
2085static struct cal_block_data *adm_find_cal_by_path(int cal_index, int path)
2086{
2087 struct list_head *ptr, *next;
2088 struct cal_block_data *cal_block = NULL;
2089 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2090 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2091
2092 pr_debug("%s:\n", __func__);
2093
2094 list_for_each_safe(ptr, next,
2095 &this_adm.cal_data[cal_index]->cal_blocks) {
2096
2097 cal_block = list_entry(ptr,
2098 struct cal_block_data, list);
2099
Vikram Panduranga770b8382017-09-27 12:17:36 -07002100 if (cal_utils_is_cal_stale(cal_block))
2101 continue;
2102
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302103 if (cal_index == ADM_AUDPROC_CAL ||
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002104 cal_index == ADM_LSM_AUDPROC_CAL ||
2105 cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302106 audproc_cal_info = cal_block->cal_info;
2107 if ((audproc_cal_info->path == path) &&
2108 (cal_block->cal_data.size > 0))
2109 return cal_block;
2110 } else if (cal_index == ADM_AUDVOL_CAL) {
2111 audvol_cal_info = cal_block->cal_info;
2112 if ((audvol_cal_info->path == path) &&
2113 (cal_block->cal_data.size > 0))
2114 return cal_block;
2115 }
2116 }
2117 pr_debug("%s: Can't find ADM cal for cal_index %d, path %d\n",
2118 __func__, cal_index, path);
2119 return NULL;
2120}
2121
2122static struct cal_block_data *adm_find_cal_by_app_type(int cal_index, int path,
2123 int app_type)
2124{
2125 struct list_head *ptr, *next;
2126 struct cal_block_data *cal_block = NULL;
2127 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2128 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2129
2130 pr_debug("%s\n", __func__);
2131
2132 list_for_each_safe(ptr, next,
2133 &this_adm.cal_data[cal_index]->cal_blocks) {
2134
2135 cal_block = list_entry(ptr,
2136 struct cal_block_data, list);
2137
Vikram Panduranga770b8382017-09-27 12:17:36 -07002138 if (cal_utils_is_cal_stale(cal_block))
2139 continue;
2140
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302141 if (cal_index == ADM_AUDPROC_CAL ||
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002142 cal_index == ADM_LSM_AUDPROC_CAL ||
2143 cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302144 audproc_cal_info = cal_block->cal_info;
2145 if ((audproc_cal_info->path == path) &&
2146 (audproc_cal_info->app_type == app_type) &&
2147 (cal_block->cal_data.size > 0))
2148 return cal_block;
2149 } else if (cal_index == ADM_AUDVOL_CAL) {
2150 audvol_cal_info = cal_block->cal_info;
2151 if ((audvol_cal_info->path == path) &&
2152 (audvol_cal_info->app_type == app_type) &&
2153 (cal_block->cal_data.size > 0))
2154 return cal_block;
2155 }
2156 }
2157 pr_debug("%s: Can't find ADM cali for cal_index %d, path %d, app %d, defaulting to search by path\n",
2158 __func__, cal_index, path, app_type);
2159 return adm_find_cal_by_path(cal_index, path);
2160}
2161
2162
2163static struct cal_block_data *adm_find_cal(int cal_index, int path,
2164 int app_type, int acdb_id,
2165 int sample_rate)
2166{
2167 struct list_head *ptr, *next;
2168 struct cal_block_data *cal_block = NULL;
2169 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2170 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2171
2172 pr_debug("%s:\n", __func__);
2173
2174 list_for_each_safe(ptr, next,
2175 &this_adm.cal_data[cal_index]->cal_blocks) {
2176
2177 cal_block = list_entry(ptr,
2178 struct cal_block_data, list);
Vikram Panduranga770b8382017-09-27 12:17:36 -07002179 if (cal_utils_is_cal_stale(cal_block))
2180 continue;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302181
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302182 if (cal_index == ADM_AUDPROC_CAL ||
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002183 cal_index == ADM_LSM_AUDPROC_CAL ||
2184 cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302185 audproc_cal_info = cal_block->cal_info;
2186 if ((audproc_cal_info->path == path) &&
2187 (audproc_cal_info->app_type == app_type) &&
2188 (audproc_cal_info->acdb_id == acdb_id) &&
2189 (audproc_cal_info->sample_rate == sample_rate) &&
2190 (cal_block->cal_data.size > 0))
2191 return cal_block;
2192 } else if (cal_index == ADM_AUDVOL_CAL) {
2193 audvol_cal_info = cal_block->cal_info;
2194 if ((audvol_cal_info->path == path) &&
2195 (audvol_cal_info->app_type == app_type) &&
2196 (audvol_cal_info->acdb_id == acdb_id) &&
2197 (cal_block->cal_data.size > 0))
2198 return cal_block;
2199 }
2200 }
2201 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",
2202 __func__, cal_index, path, app_type, acdb_id, sample_rate);
2203 return adm_find_cal_by_app_type(cal_index, path, app_type);
2204}
2205
2206static int adm_remap_and_send_cal_block(int cal_index, int port_id,
2207 int copp_idx, struct cal_block_data *cal_block, int perf_mode,
2208 int app_type, int acdb_id, int sample_rate)
2209{
2210 int ret = 0;
2211
2212 pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
2213 ret = remap_cal_data(cal_block, cal_index);
2214 if (ret) {
2215 pr_err("%s: Remap_cal_data failed for cal %d!\n",
2216 __func__, cal_index);
2217 goto done;
2218 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002219 ret = send_adm_cal_block(port_id, copp_idx, cal_block, perf_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302220 if (ret < 0)
2221 pr_debug("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d sample_rate %d\n",
2222 __func__, cal_index, port_id, ret, sample_rate);
2223done:
2224 return ret;
2225}
2226
2227static void send_adm_cal_type(int cal_index, int path, int port_id,
2228 int copp_idx, int perf_mode, int app_type,
2229 int acdb_id, int sample_rate)
2230{
2231 struct cal_block_data *cal_block = NULL;
2232 int ret;
2233
2234 pr_debug("%s: cal index %d\n", __func__, cal_index);
2235
2236 if (this_adm.cal_data[cal_index] == NULL) {
2237 pr_debug("%s: cal_index %d not allocated!\n",
2238 __func__, cal_index);
2239 goto done;
2240 }
2241
2242 mutex_lock(&this_adm.cal_data[cal_index]->lock);
2243 cal_block = adm_find_cal(cal_index, path, app_type, acdb_id,
2244 sample_rate);
2245 if (cal_block == NULL)
2246 goto unlock;
2247
2248 ret = adm_remap_and_send_cal_block(cal_index, port_id, copp_idx,
2249 cal_block, perf_mode, app_type, acdb_id, sample_rate);
Vikram Panduranga770b8382017-09-27 12:17:36 -07002250
2251 cal_utils_mark_cal_used(cal_block);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302252unlock:
2253 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
2254done:
2255 return;
2256}
2257
2258static int get_cal_path(int path)
2259{
2260 if (path == 0x1)
2261 return RX_DEVICE;
2262 else
2263 return TX_DEVICE;
2264}
2265
2266static void send_adm_cal(int port_id, int copp_idx, int path, int perf_mode,
Aditya Bavanari5106b562018-01-08 13:16:32 +05302267 int app_type, int acdb_id, int sample_rate,
2268 int passthr_mode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302269{
2270 pr_debug("%s: port id 0x%x copp_idx %d\n", __func__, port_id, copp_idx);
2271
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002272 if (passthr_mode != LISTEN) {
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302273 send_adm_cal_type(ADM_AUDPROC_CAL, path, port_id, copp_idx,
2274 perf_mode, app_type, acdb_id, sample_rate);
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002275 } else {
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302276 send_adm_cal_type(ADM_LSM_AUDPROC_CAL, path, port_id, copp_idx,
2277 perf_mode, app_type, acdb_id, sample_rate);
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002278
2279 send_adm_cal_type(ADM_LSM_AUDPROC_PERSISTENT_CAL, path,
2280 port_id, copp_idx, perf_mode, app_type,
2281 acdb_id, sample_rate);
2282 }
2283
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302284 send_adm_cal_type(ADM_AUDVOL_CAL, path, port_id, copp_idx, perf_mode,
2285 app_type, acdb_id, sample_rate);
2286}
2287
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302288/**
2289 * adm_connect_afe_port -
2290 * command to send ADM connect AFE port
2291 *
2292 * @mode: value of mode for ADM connect AFE
2293 * @session_id: session active to connect
2294 * @port_id: Port ID number
2295 *
2296 * Returns 0 on success or error on failure
2297 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302298int adm_connect_afe_port(int mode, int session_id, int port_id)
2299{
2300 struct adm_cmd_connect_afe_port_v5 cmd;
2301 int ret = 0;
2302 int port_idx, copp_idx = 0;
2303
2304 pr_debug("%s: port_id: 0x%x session id:%d mode:%d\n", __func__,
2305 port_id, session_id, mode);
2306
2307 port_id = afe_convert_virtual_to_portid(port_id);
2308 port_idx = adm_validate_and_get_port_index(port_id);
2309 if (port_idx < 0) {
2310 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2311 return -EINVAL;
2312 }
2313
2314 if (this_adm.apr == NULL) {
2315 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
2316 0xFFFFFFFF, &this_adm);
2317 if (this_adm.apr == NULL) {
2318 pr_err("%s: Unable to register ADM\n", __func__);
2319 ret = -ENODEV;
2320 return ret;
2321 }
2322 rtac_set_adm_handle(this_adm.apr);
2323 }
2324 pr_debug("%s: Port ID 0x%x, index %d\n", __func__, port_id, port_idx);
2325
2326 cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2327 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2328 cmd.hdr.pkt_size = sizeof(cmd);
2329 cmd.hdr.src_svc = APR_SVC_ADM;
2330 cmd.hdr.src_domain = APR_DOMAIN_APPS;
2331 cmd.hdr.src_port = port_id;
2332 cmd.hdr.dest_svc = APR_SVC_ADM;
2333 cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
2334 cmd.hdr.dest_port = 0; /* Ignored */
2335 cmd.hdr.token = port_idx << 16 | copp_idx;
2336 cmd.hdr.opcode = ADM_CMD_CONNECT_AFE_PORT_V5;
2337
2338 cmd.mode = mode;
2339 cmd.session_id = session_id;
2340 cmd.afe_port_id = port_id;
2341
2342 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2343 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
2344 if (ret < 0) {
2345 pr_err("%s: ADM enable for port_id: 0x%x failed ret %d\n",
2346 __func__, port_id, ret);
2347 ret = -EINVAL;
2348 goto fail_cmd;
2349 }
2350 /* Wait for the callback with copp id */
2351 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
2352 atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
2353 msecs_to_jiffies(TIMEOUT_MS));
2354 if (!ret) {
2355 pr_err("%s: ADM connect timedout for port_id: 0x%x\n",
2356 __func__, port_id);
2357 ret = -EINVAL;
2358 goto fail_cmd;
2359 } else if (atomic_read(&this_adm.copp.stat
2360 [port_idx][copp_idx]) > 0) {
2361 pr_err("%s: DSP returned error[%s]\n",
2362 __func__, adsp_err_get_err_str(
2363 atomic_read(&this_adm.copp.stat
2364 [port_idx][copp_idx])));
2365 ret = adsp_err_get_lnx_err_code(
2366 atomic_read(&this_adm.copp.stat
2367 [port_idx][copp_idx]));
2368 goto fail_cmd;
2369 }
2370 atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
2371 return 0;
2372
2373fail_cmd:
2374
2375 return ret;
2376}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302377EXPORT_SYMBOL(adm_connect_afe_port);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302378
2379int adm_arrange_mch_map(struct adm_cmd_device_open_v5 *open, int path,
2380 int channel_mode)
2381{
2382 int rc = 0, idx;
2383
Bhalchandra Gajareeed46bd2018-05-15 16:48:07 -07002384 pr_debug("%s: channel mode %d", __func__, channel_mode);
2385
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302386 memset(open->dev_channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
2387 switch (path) {
2388 case ADM_PATH_PLAYBACK:
2389 idx = ADM_MCH_MAP_IDX_PLAYBACK;
2390 break;
2391 case ADM_PATH_LIVE_REC:
2392 case ADM_PATH_NONLIVE_REC:
2393 idx = ADM_MCH_MAP_IDX_REC;
2394 break;
2395 default:
2396 goto non_mch_path;
2397 };
2398 if ((open->dev_num_channel > 2) && multi_ch_maps[idx].set_channel_map) {
2399 memcpy(open->dev_channel_mapping,
2400 multi_ch_maps[idx].channel_mapping,
2401 PCM_FORMAT_MAX_NUM_CHANNEL);
2402 } else {
2403 if (channel_mode == 1) {
2404 open->dev_channel_mapping[0] = PCM_CHANNEL_FC;
2405 } else if (channel_mode == 2) {
2406 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2407 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2408 } else if (channel_mode == 3) {
2409 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2410 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2411 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2412 } else if (channel_mode == 4) {
2413 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2414 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2415 open->dev_channel_mapping[2] = PCM_CHANNEL_LS;
2416 open->dev_channel_mapping[3] = PCM_CHANNEL_RS;
2417 } else if (channel_mode == 5) {
2418 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2419 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2420 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2421 open->dev_channel_mapping[3] = PCM_CHANNEL_LS;
2422 open->dev_channel_mapping[4] = PCM_CHANNEL_RS;
2423 } else if (channel_mode == 6) {
2424 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2425 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2426 open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
2427 open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
2428 open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
2429 open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
2430 } else if (channel_mode == 7) {
2431 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2432 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2433 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2434 open->dev_channel_mapping[3] = PCM_CHANNEL_LFE;
2435 open->dev_channel_mapping[4] = PCM_CHANNEL_LB;
2436 open->dev_channel_mapping[5] = PCM_CHANNEL_RB;
2437 open->dev_channel_mapping[6] = PCM_CHANNEL_CS;
2438 } else if (channel_mode == 8) {
2439 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2440 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2441 open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
2442 open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
2443 open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
2444 open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
2445 open->dev_channel_mapping[6] = PCM_CHANNEL_LB;
2446 open->dev_channel_mapping[7] = PCM_CHANNEL_RB;
2447 } else {
2448 pr_err("%s: invalid num_chan %d\n", __func__,
2449 channel_mode);
2450 rc = -EINVAL;
2451 goto inval_ch_mod;
2452 }
2453 }
2454
2455non_mch_path:
2456inval_ch_mod:
2457 return rc;
2458}
2459
2460int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
2461 int channel_mode)
2462{
2463 int rc = 0;
2464
2465 memset(open_v6->dev_channel_mapping_eid2, 0,
2466 PCM_FORMAT_MAX_NUM_CHANNEL);
2467
2468 if (channel_mode == 1) {
2469 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FC;
2470 } else if (channel_mode == 2) {
2471 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2472 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2473 } else if (channel_mode == 3) {
2474 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2475 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2476 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
2477 } else if (channel_mode == 4) {
2478 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2479 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2480 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LS;
2481 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_RS;
2482 } else if (channel_mode == 5) {
2483 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2484 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2485 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
2486 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_LS;
2487 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_RS;
2488 } else if (channel_mode == 6) {
2489 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2490 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2491 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
2492 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
2493 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
2494 open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
2495 } else if (channel_mode == 8) {
2496 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2497 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2498 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
2499 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
2500 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
2501 open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
2502 open_v6->dev_channel_mapping_eid2[6] = PCM_CHANNEL_LB;
2503 open_v6->dev_channel_mapping_eid2[7] = PCM_CHANNEL_RB;
2504 } else {
2505 pr_err("%s: invalid num_chan %d\n", __func__,
2506 channel_mode);
2507 rc = -EINVAL;
2508 }
2509
2510 return rc;
2511}
2512
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302513/**
2514 * adm_open -
2515 * command to send ADM open
2516 *
2517 * @port_id: port id number
2518 * @path: direction or ADM path type
2519 * @rate: sample rate of session
2520 * @channel_mode: number of channels set
2521 * @topology: topology active for this session
2522 * @perf_mode: performance mode like LL/ULL/..
2523 * @bit_width: bit width to set for copp
2524 * @app_type: App type used for this session
2525 * @acdb_id: ACDB ID of this device
2526 *
2527 * Returns 0 on success or error on failure
2528 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302529int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
2530 int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
2531{
2532 struct adm_cmd_device_open_v5 open;
2533 struct adm_cmd_device_open_v6 open_v6;
2534 int ret = 0;
Asish Bhattacharya34504582017-08-08 12:55:01 +05302535 int port_idx, flags;
2536 int copp_idx = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302537 int tmp_port = q6audio_get_port_id(port_id);
2538
2539 pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n",
2540 __func__, port_id, path, rate, channel_mode, perf_mode,
2541 topology);
2542
2543 port_id = q6audio_convert_virtual_to_portid(port_id);
2544 port_idx = adm_validate_and_get_port_index(port_id);
2545 if (port_idx < 0) {
2546 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2547 return -EINVAL;
2548 }
2549
2550 if (this_adm.apr == NULL) {
2551 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
2552 0xFFFFFFFF, &this_adm);
2553 if (this_adm.apr == NULL) {
2554 pr_err("%s: Unable to register ADM\n", __func__);
2555 return -ENODEV;
2556 }
2557 rtac_set_adm_handle(this_adm.apr);
2558 }
2559
2560 if (perf_mode == ULL_POST_PROCESSING_PCM_MODE) {
2561 flags = ADM_ULL_POST_PROCESSING_DEVICE_SESSION;
2562 if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
2563 (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
2564 (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
2565 topology = DEFAULT_COPP_TOPOLOGY;
2566 } else if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
2567 flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
2568 topology = NULL_COPP_TOPOLOGY;
2569 rate = ULL_SUPPORTED_SAMPLE_RATE;
2570 bit_width = ULL_SUPPORTED_BITS_PER_SAMPLE;
2571 } else if (perf_mode == LOW_LATENCY_PCM_MODE) {
2572 flags = ADM_LOW_LATENCY_DEVICE_SESSION;
2573 if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
2574 (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
2575 (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
2576 topology = DEFAULT_COPP_TOPOLOGY;
2577 } else {
2578 if ((path == ADM_PATH_COMPRESSED_RX) ||
2579 (path == ADM_PATH_COMPRESSED_TX))
2580 flags = 0;
2581 else
2582 flags = ADM_LEGACY_DEVICE_SESSION;
2583 }
2584
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +05302585 if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302586 (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
2587 (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
2588 rate = 16000;
2589
Asish Bhattacharya34504582017-08-08 12:55:01 +05302590 /*
2591 * Routing driver reuses the same adm for streams with the same
2592 * app_type, sample_rate etc.
2593 * This isn't allowed for ULL streams as per the DSP interface
2594 */
2595 if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE)
2596 copp_idx = adm_get_idx_if_copp_exists(port_idx, topology,
2597 perf_mode,
2598 rate, bit_width,
2599 app_type);
2600
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302601 if (copp_idx < 0) {
2602 copp_idx = adm_get_next_available_copp(port_idx);
2603 if (copp_idx >= MAX_COPPS_PER_PORT) {
2604 pr_err("%s: exceeded copp id %d\n",
2605 __func__, copp_idx);
2606 return -EINVAL;
2607 }
2608 atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
2609 atomic_set(&this_adm.copp.topology[port_idx][copp_idx],
2610 topology);
2611 atomic_set(&this_adm.copp.mode[port_idx][copp_idx],
2612 perf_mode);
2613 atomic_set(&this_adm.copp.rate[port_idx][copp_idx],
2614 rate);
2615 atomic_set(&this_adm.copp.channels[port_idx][copp_idx],
2616 channel_mode);
2617 atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx],
2618 bit_width);
2619 atomic_set(&this_adm.copp.app_type[port_idx][copp_idx],
2620 app_type);
2621 atomic_set(&this_adm.copp.acdb_id[port_idx][copp_idx],
2622 acdb_id);
2623 set_bit(ADM_STATUS_CALIBRATION_REQUIRED,
2624 (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
2625 if ((path != ADM_PATH_COMPRESSED_RX) &&
2626 (path != ADM_PATH_COMPRESSED_TX))
2627 send_adm_custom_topology();
2628 }
2629
2630 if (this_adm.copp.adm_delay[port_idx][copp_idx] &&
2631 perf_mode == LEGACY_PCM_MODE) {
2632 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
2633 1);
2634 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
2635 wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
2636 }
2637
2638 /* Create a COPP if port id are not enabled */
2639 if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) {
2640 pr_debug("%s: open ADM: port_idx: %d, copp_idx: %d\n", __func__,
2641 port_idx, copp_idx);
2642 if ((topology == SRS_TRUMEDIA_TOPOLOGY_ID) &&
2643 perf_mode == LEGACY_PCM_MODE) {
2644 int res;
2645
2646 atomic_set(&this_adm.mem_map_index, ADM_SRS_TRUMEDIA);
2647 msm_dts_srs_tm_ion_memmap(&this_adm.outband_memmap);
2648 res = adm_memory_map_regions(&this_adm.outband_memmap.paddr, 0,
2649 (uint32_t *)&this_adm.outband_memmap.size, 1);
2650 if (res < 0) {
2651 pr_err("%s: SRS adm_memory_map_regions failed ! addr = 0x%pK, size = %d\n",
2652 __func__, (void *)this_adm.outband_memmap.paddr,
2653 (uint32_t)this_adm.outband_memmap.size);
2654 }
2655 }
2656 open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2657 APR_HDR_LEN(APR_HDR_SIZE),
2658 APR_PKT_VER);
2659 open.hdr.pkt_size = sizeof(open);
2660 open.hdr.src_svc = APR_SVC_ADM;
2661 open.hdr.src_domain = APR_DOMAIN_APPS;
2662 open.hdr.src_port = tmp_port;
2663 open.hdr.dest_svc = APR_SVC_ADM;
2664 open.hdr.dest_domain = APR_DOMAIN_ADSP;
2665 open.hdr.dest_port = tmp_port;
2666 open.hdr.token = port_idx << 16 | copp_idx;
2667 open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
2668 open.flags = flags;
2669 open.mode_of_operation = path;
2670 open.endpoint_id_1 = tmp_port;
2671 open.endpoint_id_2 = 0xFFFF;
2672
2673 if (this_adm.ec_ref_rx && (path != 1)) {
2674 open.endpoint_id_2 = this_adm.ec_ref_rx;
2675 this_adm.ec_ref_rx = -1;
2676 }
2677
2678 open.topology_id = topology;
2679
2680 open.dev_num_channel = channel_mode & 0x00FF;
2681 open.bit_width = bit_width;
2682 WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
2683 (rate != ULL_SUPPORTED_SAMPLE_RATE));
2684 open.sample_rate = rate;
2685
2686 ret = adm_arrange_mch_map(&open, path, channel_mode);
2687
2688 if (ret)
2689 return ret;
2690
2691 pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
2692 __func__, open.endpoint_id_1, open.sample_rate,
2693 open.topology_id);
2694
2695 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2696
2697 if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
2698 (open.endpoint_id_2 != 0xFFFF)) {
2699 memset(&open_v6, 0,
2700 sizeof(struct adm_cmd_device_open_v6));
2701 memcpy(&open_v6, &open,
2702 sizeof(struct adm_cmd_device_open_v5));
2703 open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
2704 open_v6.hdr.pkt_size = sizeof(open_v6);
2705 open_v6.dev_num_channel_eid2 =
2706 this_adm.num_ec_ref_rx_chans;
2707 this_adm.num_ec_ref_rx_chans = 0;
2708
2709 if (this_adm.ec_ref_rx_bit_width != 0) {
2710 open_v6.bit_width_eid2 =
2711 this_adm.ec_ref_rx_bit_width;
2712 this_adm.ec_ref_rx_bit_width = 0;
2713 } else {
2714 open_v6.bit_width_eid2 = bit_width;
2715 }
2716
2717 if (this_adm.ec_ref_rx_sampling_rate != 0) {
2718 open_v6.sample_rate_eid2 =
2719 this_adm.ec_ref_rx_sampling_rate;
2720 this_adm.ec_ref_rx_sampling_rate = 0;
2721 } else {
2722 open_v6.sample_rate_eid2 = rate;
2723 }
2724
2725 pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
2726 __func__, open_v6.dev_num_channel_eid2,
2727 open_v6.bit_width_eid2,
2728 open_v6.sample_rate_eid2);
2729
2730 ret = adm_arrange_mch_ep2_map(&open_v6,
2731 open_v6.dev_num_channel_eid2);
2732
2733 if (ret)
2734 return ret;
2735
2736 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
2737 } else {
2738 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
2739 }
2740 if (ret < 0) {
2741 pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
2742 __func__, tmp_port, port_id, ret);
2743 return -EINVAL;
2744 }
2745 /* Wait for the callback with copp id */
2746 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
2747 atomic_read(&this_adm.copp.stat
2748 [port_idx][copp_idx]) >= 0,
2749 msecs_to_jiffies(TIMEOUT_MS));
2750 if (!ret) {
2751 pr_err("%s: ADM open timedout for port_id: 0x%x for [0x%x]\n",
2752 __func__, tmp_port, port_id);
2753 return -EINVAL;
2754 } else if (atomic_read(&this_adm.copp.stat
2755 [port_idx][copp_idx]) > 0) {
2756 pr_err("%s: DSP returned error[%s]\n",
2757 __func__, adsp_err_get_err_str(
2758 atomic_read(&this_adm.copp.stat
2759 [port_idx][copp_idx])));
2760 return adsp_err_get_lnx_err_code(
2761 atomic_read(&this_adm.copp.stat
2762 [port_idx][copp_idx]));
2763 }
2764 }
2765 atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
2766 return copp_idx;
2767}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302768EXPORT_SYMBOL(adm_open);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302769
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302770/**
2771 * adm_copp_mfc_cfg -
2772 * command to send ADM MFC config
2773 *
2774 * @port_id: Port ID number
2775 * @copp_idx: copp index assigned
2776 * @dst_sample_rate: sink sample rate
2777 *
2778 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302779void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate)
2780{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002781 struct audproc_mfc_param_media_fmt mfc_cfg;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302782 struct adm_cmd_device_open_v5 open;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002783 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302784 int port_idx;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302785 int rc = 0;
2786 int i = 0;
2787
2788 port_id = q6audio_convert_virtual_to_portid(port_id);
2789 port_idx = adm_validate_and_get_port_index(port_id);
2790
2791 if (port_idx < 0) {
2792 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
2793 goto fail_cmd;
2794 }
2795
2796 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
2797 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
2798 goto fail_cmd;
2799 }
2800
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002801 memset(&mfc_cfg, 0, sizeof(mfc_cfg));
2802 memset(&open, 0, sizeof(open));
2803 memset(&param_hdr, 0, sizeof(param_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302804
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002805 param_hdr.module_id = AUDPROC_MODULE_ID_MFC;
2806 param_hdr.instance_id = INSTANCE_ID_0;
2807 param_hdr.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
2808 param_hdr.param_size = sizeof(mfc_cfg);
2809
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302810 mfc_cfg.sampling_rate = dst_sample_rate;
2811 mfc_cfg.bits_per_sample =
2812 atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
2813 open.dev_num_channel = mfc_cfg.num_channels =
2814 atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
2815
2816 rc = adm_arrange_mch_map(&open, ADM_PATH_PLAYBACK,
2817 mfc_cfg.num_channels);
2818 if (rc < 0) {
2819 pr_err("%s: unable to get channal map\n", __func__);
2820 goto fail_cmd;
2821 }
2822
2823 for (i = 0; i < mfc_cfg.num_channels; i++)
2824 mfc_cfg.channel_type[i] =
2825 (uint16_t) open.dev_channel_mapping[i];
2826
2827 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2828
2829 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",
2830 __func__, port_idx, copp_idx,
2831 atomic_read(&this_adm.copp.rate[port_idx][copp_idx]),
2832 mfc_cfg.bits_per_sample, mfc_cfg.num_channels,
2833 mfc_cfg.sampling_rate);
2834
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002835 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
2836 (uint8_t *) &mfc_cfg);
2837 if (rc)
2838 pr_err("%s: Failed to set media format configuration data, err %d\n",
2839 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302840
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302841fail_cmd:
2842 return;
2843}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302844EXPORT_SYMBOL(adm_copp_mfc_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302845
2846static void route_set_opcode_matrix_id(
2847 struct adm_cmd_matrix_map_routings_v5 **route_addr,
2848 int path, uint32_t passthr_mode)
2849{
2850 struct adm_cmd_matrix_map_routings_v5 *route = *route_addr;
2851
2852 switch (path) {
2853 case ADM_PATH_PLAYBACK:
2854 route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
2855 route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
2856 break;
2857 case ADM_PATH_LIVE_REC:
2858 if (passthr_mode == LISTEN) {
2859 route->hdr.opcode =
2860 ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2861 route->matrix_id = ADM_MATRIX_ID_LISTEN_TX;
2862 break;
2863 }
2864 /* fall through to set matrix id for non-listen case */
2865 case ADM_PATH_NONLIVE_REC:
2866 route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
2867 route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
2868 break;
2869 case ADM_PATH_COMPRESSED_RX:
2870 route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2871 route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
2872 break;
2873 case ADM_PATH_COMPRESSED_TX:
2874 route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2875 route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_TX;
2876 break;
2877 default:
2878 pr_err("%s: Wrong path set[%d]\n", __func__, path);
2879 break;
2880 }
2881 pr_debug("%s: opcode 0x%x, matrix id %d\n",
2882 __func__, route->hdr.opcode, route->matrix_id);
2883}
2884
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302885/**
2886 * adm_matrix_map -
2887 * command to send ADM matrix map for ADM copp list
2888 *
2889 * @path: direction or ADM path type
2890 * @payload_map: have info of session id and associated copp_idx/num_copps
2891 * @perf_mode: performance mode like LL/ULL/..
2892 * @passthr_mode: flag to indicate passthrough mode
2893 *
2894 * Returns 0 on success or error on failure
2895 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302896int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
2897 uint32_t passthr_mode)
2898{
2899 struct adm_cmd_matrix_map_routings_v5 *route;
2900 struct adm_session_map_node_v5 *node;
2901 uint16_t *copps_list;
2902 int cmd_size = 0;
2903 int ret = 0, i = 0;
2904 void *payload = NULL;
2905 void *matrix_map = NULL;
2906 int port_idx, copp_idx;
2907
2908 /* Assumes port_ids have already been validated during adm_open */
2909 cmd_size = (sizeof(struct adm_cmd_matrix_map_routings_v5) +
2910 sizeof(struct adm_session_map_node_v5) +
2911 (sizeof(uint32_t) * payload_map.num_copps));
2912 matrix_map = kzalloc(cmd_size, GFP_KERNEL);
2913 if (matrix_map == NULL) {
2914 pr_err("%s: Mem alloc failed\n", __func__);
2915 ret = -EINVAL;
2916 return ret;
2917 }
2918 route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
2919
2920 route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2921 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2922 route->hdr.pkt_size = cmd_size;
2923 route->hdr.src_svc = 0;
2924 route->hdr.src_domain = APR_DOMAIN_APPS;
2925 route->hdr.src_port = 0; /* Ignored */;
2926 route->hdr.dest_svc = APR_SVC_ADM;
2927 route->hdr.dest_domain = APR_DOMAIN_ADSP;
2928 route->hdr.dest_port = 0; /* Ignored */;
2929 route->hdr.token = 0;
2930 route->num_sessions = 1;
2931 route_set_opcode_matrix_id(&route, path, passthr_mode);
2932
2933 payload = ((u8 *)matrix_map +
2934 sizeof(struct adm_cmd_matrix_map_routings_v5));
2935 node = (struct adm_session_map_node_v5 *)payload;
2936
2937 node->session_id = payload_map.session_id;
2938 node->num_copps = payload_map.num_copps;
2939 payload = (u8 *)node + sizeof(struct adm_session_map_node_v5);
2940 copps_list = (uint16_t *)payload;
2941 for (i = 0; i < payload_map.num_copps; i++) {
2942 port_idx =
2943 adm_validate_and_get_port_index(payload_map.port_id[i]);
2944 if (port_idx < 0) {
2945 pr_err("%s: Invalid port_id 0x%x\n", __func__,
2946 payload_map.port_id[i]);
2947 ret = -EINVAL;
2948 goto fail_cmd;
2949 }
2950 copp_idx = payload_map.copp_idx[i];
2951 copps_list[i] = atomic_read(&this_adm.copp.id[port_idx]
2952 [copp_idx]);
2953 }
2954 atomic_set(&this_adm.matrix_map_stat, -1);
2955
2956 ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
2957 if (ret < 0) {
2958 pr_err("%s: routing for syream %d failed ret %d\n",
2959 __func__, payload_map.session_id, ret);
2960 ret = -EINVAL;
2961 goto fail_cmd;
2962 }
2963 ret = wait_event_timeout(this_adm.matrix_map_wait,
2964 atomic_read(&this_adm.matrix_map_stat) >= 0,
2965 msecs_to_jiffies(TIMEOUT_MS));
2966 if (!ret) {
2967 pr_err("%s: routing for syream %d failed\n", __func__,
2968 payload_map.session_id);
2969 ret = -EINVAL;
2970 goto fail_cmd;
2971 } else if (atomic_read(&this_adm.matrix_map_stat) > 0) {
2972 pr_err("%s: DSP returned error[%s]\n", __func__,
2973 adsp_err_get_err_str(atomic_read(
2974 &this_adm.matrix_map_stat)));
2975 ret = adsp_err_get_lnx_err_code(
2976 atomic_read(&this_adm.matrix_map_stat));
2977 goto fail_cmd;
2978 }
2979
2980 if ((perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) &&
2981 (path != ADM_PATH_COMPRESSED_RX)) {
2982 for (i = 0; i < payload_map.num_copps; i++) {
2983 port_idx = afe_get_port_index(payload_map.port_id[i]);
2984 copp_idx = payload_map.copp_idx[i];
2985 if (port_idx < 0 || copp_idx < 0 ||
2986 (copp_idx > MAX_COPPS_PER_PORT - 1)) {
2987 pr_err("%s: Invalid idx port_idx %d copp_idx %d\n",
2988 __func__, port_idx, copp_idx);
2989 continue;
2990 }
2991 rtac_add_adm_device(payload_map.port_id[i],
2992 atomic_read(&this_adm.copp.id
2993 [port_idx][copp_idx]),
2994 get_cal_path(path),
2995 payload_map.session_id,
2996 payload_map.app_type[i],
2997 payload_map.acdb_dev_id[i]);
2998
2999 if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3000 (void *)&this_adm.copp.adm_status[port_idx]
3001 [copp_idx])) {
3002 pr_debug("%s: adm copp[0x%x][%d] already sent",
3003 __func__, port_idx, copp_idx);
3004 continue;
3005 }
3006 send_adm_cal(payload_map.port_id[i], copp_idx,
3007 get_cal_path(path), perf_mode,
3008 payload_map.app_type[i],
3009 payload_map.acdb_dev_id[i],
Aditya Bavanari5106b562018-01-08 13:16:32 +05303010 payload_map.sample_rate[i],
3011 passthr_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303012 /* ADM COPP calibration is already sent */
3013 clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3014 (void *)&this_adm.copp.
3015 adm_status[port_idx][copp_idx]);
3016 pr_debug("%s: copp_id: %d\n", __func__,
3017 atomic_read(&this_adm.copp.id[port_idx]
3018 [copp_idx]));
3019 }
3020 }
3021
3022fail_cmd:
3023 kfree(matrix_map);
3024 return ret;
3025}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303026EXPORT_SYMBOL(adm_matrix_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303027
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303028/**
3029 * adm_ec_ref_rx_id -
3030 * Update EC ref port ID
3031 *
3032 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303033void adm_ec_ref_rx_id(int port_id)
3034{
3035 this_adm.ec_ref_rx = port_id;
3036 pr_debug("%s: ec_ref_rx:%d\n", __func__, this_adm.ec_ref_rx);
3037}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303038EXPORT_SYMBOL(adm_ec_ref_rx_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303039
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303040/**
3041 * adm_num_ec_ref_rx_chans -
3042 * Update EC ref number of channels
3043 *
3044 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303045void adm_num_ec_ref_rx_chans(int num_chans)
3046{
3047 this_adm.num_ec_ref_rx_chans = num_chans;
3048 pr_debug("%s: num_ec_ref_rx_chans:%d\n",
3049 __func__, this_adm.num_ec_ref_rx_chans);
3050}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303051EXPORT_SYMBOL(adm_num_ec_ref_rx_chans);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303052
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303053/**
3054 * adm_ec_ref_rx_bit_width -
3055 * Update EC ref bit_width
3056 *
3057 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303058void adm_ec_ref_rx_bit_width(int bit_width)
3059{
3060 this_adm.ec_ref_rx_bit_width = bit_width;
3061 pr_debug("%s: ec_ref_rx_bit_width:%d\n",
3062 __func__, this_adm.ec_ref_rx_bit_width);
3063}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303064EXPORT_SYMBOL(adm_ec_ref_rx_bit_width);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303065
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303066/**
3067 * adm_ec_ref_rx_sampling_rate -
3068 * Update EC ref sample rate
3069 *
3070 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303071void adm_ec_ref_rx_sampling_rate(int sampling_rate)
3072{
3073 this_adm.ec_ref_rx_sampling_rate = sampling_rate;
3074 pr_debug("%s: ec_ref_rx_sampling_rate:%d\n",
3075 __func__, this_adm.ec_ref_rx_sampling_rate);
3076}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303077EXPORT_SYMBOL(adm_ec_ref_rx_sampling_rate);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303078
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303079/**
3080 * adm_close -
3081 * command to close ADM copp
3082 *
3083 * @port_id: Port ID number
3084 * @perf_mode: performance mode like LL/ULL/..
3085 * @copp_idx: copp index assigned
3086 *
3087 * Returns 0 on success or error on failure
3088 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303089int adm_close(int port_id, int perf_mode, int copp_idx)
3090{
3091 struct apr_hdr close;
3092
3093 int ret = 0, port_idx;
3094 int copp_id = RESET_COPP_ID;
3095
3096 pr_debug("%s: port_id=0x%x perf_mode: %d copp_idx: %d\n", __func__,
3097 port_id, perf_mode, copp_idx);
3098
3099 port_id = q6audio_convert_virtual_to_portid(port_id);
3100 port_idx = adm_validate_and_get_port_index(port_id);
3101 if (port_idx < 0) {
3102 pr_err("%s: Invalid port_id 0x%x\n",
3103 __func__, port_id);
3104 return -EINVAL;
3105 }
3106
3107 if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
3108 pr_err("%s: Invalid copp idx: %d\n", __func__, copp_idx);
3109 return -EINVAL;
3110 }
3111
3112 if (this_adm.copp.adm_delay[port_idx][copp_idx] && perf_mode
3113 == LEGACY_PCM_MODE) {
3114 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
3115 1);
3116 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
3117 wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
3118 }
3119
3120 atomic_dec(&this_adm.copp.cnt[port_idx][copp_idx]);
3121 if (!(atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]))) {
3122 copp_id = adm_get_copp_id(port_idx, copp_idx);
3123 pr_debug("%s: Closing ADM port_idx:%d copp_idx:%d copp_id:0x%x\n",
3124 __func__, port_idx, copp_idx, copp_id);
3125 if ((!perf_mode) && (this_adm.outband_memmap.paddr != 0) &&
3126 (atomic_read(&this_adm.copp.topology[port_idx][copp_idx]) ==
3127 SRS_TRUMEDIA_TOPOLOGY_ID)) {
3128 atomic_set(&this_adm.mem_map_index,
3129 ADM_SRS_TRUMEDIA);
3130 ret = adm_memory_unmap_regions();
3131 if (ret < 0) {
3132 pr_err("%s: adm mem unmmap err %d",
3133 __func__, ret);
3134 } else {
3135 atomic_set(&this_adm.mem_map_handles
3136 [ADM_SRS_TRUMEDIA], 0);
3137 }
3138 }
3139
3140
3141 if ((afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) &&
3142 this_adm.sourceTrackingData.memmap.paddr) {
3143 atomic_set(&this_adm.mem_map_index,
3144 ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
3145 ret = adm_memory_unmap_regions();
3146 if (ret < 0) {
3147 pr_err("%s: adm mem unmmap err %d",
3148 __func__, ret);
3149 }
3150 msm_audio_ion_free(
Banajit Goswami08bb7362017-11-03 22:48:23 -07003151 this_adm.sourceTrackingData.dma_buf);
3152 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303153 this_adm.sourceTrackingData.memmap.size = 0;
3154 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
3155 this_adm.sourceTrackingData.memmap.paddr = 0;
3156 this_adm.sourceTrackingData.apr_cmd_status = -1;
3157 atomic_set(&this_adm.mem_map_handles[
3158 ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
3159 }
3160
3161 close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
3162 APR_HDR_LEN(APR_HDR_SIZE),
3163 APR_PKT_VER);
3164 close.pkt_size = sizeof(close);
3165 close.src_svc = APR_SVC_ADM;
3166 close.src_domain = APR_DOMAIN_APPS;
3167 close.src_port = port_id;
3168 close.dest_svc = APR_SVC_ADM;
3169 close.dest_domain = APR_DOMAIN_ADSP;
3170 close.dest_port = copp_id;
3171 close.token = port_idx << 16 | copp_idx;
3172 close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
3173
3174 atomic_set(&this_adm.copp.id[port_idx][copp_idx],
3175 RESET_COPP_ID);
3176 atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
3177 atomic_set(&this_adm.copp.topology[port_idx][copp_idx], 0);
3178 atomic_set(&this_adm.copp.mode[port_idx][copp_idx], 0);
3179 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
3180 atomic_set(&this_adm.copp.rate[port_idx][copp_idx], 0);
3181 atomic_set(&this_adm.copp.channels[port_idx][copp_idx], 0);
3182 atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx], 0);
3183 atomic_set(&this_adm.copp.app_type[port_idx][copp_idx], 0);
3184
3185 clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3186 (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
3187
3188 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
3189 if (ret < 0) {
3190 pr_err("%s: ADM close failed %d\n", __func__, ret);
3191 return -EINVAL;
3192 }
3193
3194 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
3195 atomic_read(&this_adm.copp.stat
3196 [port_idx][copp_idx]) >= 0,
3197 msecs_to_jiffies(TIMEOUT_MS));
3198 if (!ret) {
3199 pr_err("%s: ADM cmd Route timedout for port 0x%x\n",
3200 __func__, port_id);
3201 return -EINVAL;
3202 } else if (atomic_read(&this_adm.copp.stat
3203 [port_idx][copp_idx]) > 0) {
3204 pr_err("%s: DSP returned error[%s]\n",
3205 __func__, adsp_err_get_err_str(
3206 atomic_read(&this_adm.copp.stat
3207 [port_idx][copp_idx])));
3208 return adsp_err_get_lnx_err_code(
3209 atomic_read(&this_adm.copp.stat
3210 [port_idx][copp_idx]));
3211 }
3212 }
3213
3214 if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
3215 pr_debug("%s: remove adm device from rtac\n", __func__);
3216 rtac_remove_adm_device(port_id, copp_id);
3217 }
3218 return 0;
3219}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303220EXPORT_SYMBOL(adm_close);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303221
3222int send_rtac_audvol_cal(void)
3223{
3224 int ret = 0;
3225 int ret2 = 0;
3226 int i = 0;
3227 int copp_idx, port_idx, acdb_id, app_id, path;
3228 struct cal_block_data *cal_block = NULL;
3229 struct audio_cal_info_audvol *audvol_cal_info = NULL;
3230 struct rtac_adm rtac_adm_data;
3231
3232 mutex_lock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
3233
3234 cal_block = cal_utils_get_only_cal_block(
3235 this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]);
Vikram Panduranga770b8382017-09-27 12:17:36 -07003236 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303237 pr_err("%s: can't find cal block!\n", __func__);
3238 goto unlock;
3239 }
3240
3241 audvol_cal_info = cal_block->cal_info;
3242 if (audvol_cal_info == NULL) {
3243 pr_err("%s: audvol_cal_info is NULL!\n", __func__);
3244 goto unlock;
3245 }
3246
3247 get_rtac_adm_data(&rtac_adm_data);
3248 for (; i < rtac_adm_data.num_of_dev; i++) {
3249
3250 acdb_id = rtac_adm_data.device[i].acdb_dev_id;
3251 if (acdb_id == 0)
3252 acdb_id = audvol_cal_info->acdb_id;
3253
3254 app_id = rtac_adm_data.device[i].app_type;
3255 if (app_id == 0)
3256 app_id = audvol_cal_info->app_type;
3257
3258 path = afe_get_port_type(rtac_adm_data.device[i].afe_port);
3259 if ((acdb_id == audvol_cal_info->acdb_id) &&
3260 (app_id == audvol_cal_info->app_type) &&
3261 (path == audvol_cal_info->path)) {
3262
3263 if (adm_get_indexes_from_copp_id(rtac_adm_data.
3264 device[i].copp, &copp_idx, &port_idx) != 0) {
3265 pr_debug("%s: Copp Id %d is not active\n",
3266 __func__,
3267 rtac_adm_data.device[i].copp);
3268 continue;
3269 }
3270
3271 ret2 = adm_remap_and_send_cal_block(ADM_RTAC_AUDVOL_CAL,
3272 rtac_adm_data.device[i].afe_port,
3273 copp_idx, cal_block,
3274 atomic_read(&this_adm.copp.
3275 mode[port_idx][copp_idx]),
3276 audvol_cal_info->app_type,
3277 audvol_cal_info->acdb_id,
3278 atomic_read(&this_adm.copp.
3279 rate[port_idx][copp_idx]));
3280 if (ret2 < 0) {
3281 pr_debug("%s: remap and send failed for copp Id %d, acdb id %d, app type %d, path %d\n",
3282 __func__, rtac_adm_data.device[i].copp,
3283 audvol_cal_info->acdb_id,
3284 audvol_cal_info->app_type,
3285 audvol_cal_info->path);
3286 ret = ret2;
3287 }
3288 }
3289 }
3290unlock:
3291 mutex_unlock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
3292 return ret;
3293}
3294
3295int adm_map_rtac_block(struct rtac_cal_block_data *cal_block)
3296{
3297 int result = 0;
3298
3299 pr_debug("%s:\n", __func__);
3300
3301 if (cal_block == NULL) {
3302 pr_err("%s: cal_block is NULL!\n",
3303 __func__);
3304 result = -EINVAL;
3305 goto done;
3306 }
3307
3308 if (cal_block->cal_data.paddr == 0) {
3309 pr_debug("%s: No address to map!\n",
3310 __func__);
3311 result = -EINVAL;
3312 goto done;
3313 }
3314
3315 if (cal_block->map_data.map_size == 0) {
3316 pr_debug("%s: map size is 0!\n",
3317 __func__);
3318 result = -EINVAL;
3319 goto done;
3320 }
3321
3322 /* valid port ID needed for callback use primary I2S */
3323 atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
3324 result = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
3325 &cal_block->map_data.map_size, 1);
3326 if (result < 0) {
3327 pr_err("%s: RTAC mmap did not work! size = %d result %d\n",
3328 __func__,
3329 cal_block->map_data.map_size, result);
3330 pr_debug("%s: RTAC mmap did not work! addr = 0x%pK, size = %d\n",
3331 __func__,
3332 &cal_block->cal_data.paddr,
3333 cal_block->map_data.map_size);
3334 goto done;
3335 }
3336
3337 cal_block->map_data.map_handle = atomic_read(
3338 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]);
3339done:
3340 return result;
3341}
3342
3343int adm_unmap_rtac_block(uint32_t *mem_map_handle)
3344{
3345 int result = 0;
3346
3347 pr_debug("%s:\n", __func__);
3348
3349 if (mem_map_handle == NULL) {
3350 pr_debug("%s: Map handle is NULL, nothing to unmap\n",
3351 __func__);
3352 goto done;
3353 }
3354
3355 if (*mem_map_handle == 0) {
3356 pr_debug("%s: Map handle is 0, nothing to unmap\n",
3357 __func__);
3358 goto done;
3359 }
3360
3361 if (*mem_map_handle != atomic_read(
3362 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL])) {
3363 pr_err("%s: Map handles do not match! Unmapping RTAC, RTAC map 0x%x, ADM map 0x%x\n",
3364 __func__, *mem_map_handle, atomic_read(
3365 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]));
3366
3367 /* if mismatch use handle passed in to unmap */
3368 atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL],
3369 *mem_map_handle);
3370 }
3371
3372 /* valid port ID needed for callback use primary I2S */
3373 atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
3374 result = adm_memory_unmap_regions();
3375 if (result < 0) {
3376 pr_debug("%s: adm_memory_unmap_regions failed, error %d\n",
3377 __func__, result);
3378 } else {
3379 atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL], 0);
3380 *mem_map_handle = 0;
3381 }
3382done:
3383 return result;
3384}
3385
3386static int get_cal_type_index(int32_t cal_type)
3387{
3388 int ret = -EINVAL;
3389
3390 switch (cal_type) {
3391 case ADM_AUDPROC_CAL_TYPE:
3392 ret = ADM_AUDPROC_CAL;
3393 break;
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05303394 case ADM_LSM_AUDPROC_CAL_TYPE:
3395 ret = ADM_LSM_AUDPROC_CAL;
3396 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303397 case ADM_AUDVOL_CAL_TYPE:
3398 ret = ADM_AUDVOL_CAL;
3399 break;
3400 case ADM_CUST_TOPOLOGY_CAL_TYPE:
3401 ret = ADM_CUSTOM_TOP_CAL;
3402 break;
3403 case ADM_RTAC_INFO_CAL_TYPE:
3404 ret = ADM_RTAC_INFO_CAL;
3405 break;
3406 case ADM_RTAC_APR_CAL_TYPE:
3407 ret = ADM_RTAC_APR_CAL;
3408 break;
3409 case ADM_RTAC_AUDVOL_CAL_TYPE:
3410 ret = ADM_RTAC_AUDVOL_CAL;
3411 break;
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07003412 case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE:
3413 ret = ADM_LSM_AUDPROC_PERSISTENT_CAL;
3414 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303415 default:
3416 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
3417 }
3418 return ret;
3419}
3420
3421static int adm_alloc_cal(int32_t cal_type, size_t data_size, void *data)
3422{
3423 int ret = 0;
3424 int cal_index;
3425
3426 pr_debug("%s:\n", __func__);
3427
3428 cal_index = get_cal_type_index(cal_type);
3429 if (cal_index < 0) {
3430 pr_err("%s: could not get cal index %d!\n",
3431 __func__, cal_index);
3432 ret = -EINVAL;
3433 goto done;
3434 }
3435
3436 ret = cal_utils_alloc_cal(data_size, data,
3437 this_adm.cal_data[cal_index], 0, NULL);
3438 if (ret < 0) {
3439 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
3440 __func__, ret, cal_type);
3441 ret = -EINVAL;
3442 goto done;
3443 }
3444done:
3445 return ret;
3446}
3447
3448static int adm_dealloc_cal(int32_t cal_type, size_t data_size, void *data)
3449{
3450 int ret = 0;
3451 int cal_index;
3452
3453 pr_debug("%s:\n", __func__);
3454
3455 cal_index = get_cal_type_index(cal_type);
3456 if (cal_index < 0) {
3457 pr_err("%s: could not get cal index %d!\n",
3458 __func__, cal_index);
3459 ret = -EINVAL;
3460 goto done;
3461 }
3462
3463 ret = cal_utils_dealloc_cal(data_size, data,
3464 this_adm.cal_data[cal_index]);
3465 if (ret < 0) {
3466 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
3467 __func__, ret, cal_type);
3468 ret = -EINVAL;
3469 goto done;
3470 }
3471done:
3472 return ret;
3473}
3474
3475static int adm_set_cal(int32_t cal_type, size_t data_size, void *data)
3476{
3477 int ret = 0;
3478 int cal_index;
3479
3480 pr_debug("%s:\n", __func__);
3481
3482 cal_index = get_cal_type_index(cal_type);
3483 if (cal_index < 0) {
3484 pr_err("%s: could not get cal index %d!\n",
3485 __func__, cal_index);
3486 ret = -EINVAL;
3487 goto done;
3488 }
3489
3490 ret = cal_utils_set_cal(data_size, data,
3491 this_adm.cal_data[cal_index], 0, NULL);
3492 if (ret < 0) {
3493 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
3494 __func__, ret, cal_type);
3495 ret = -EINVAL;
3496 goto done;
3497 }
3498
3499 if (cal_index == ADM_CUSTOM_TOP_CAL) {
3500 mutex_lock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
3501 this_adm.set_custom_topology = 1;
3502 mutex_unlock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
3503 } else if (cal_index == ADM_RTAC_AUDVOL_CAL) {
3504 send_rtac_audvol_cal();
3505 }
3506done:
3507 return ret;
3508}
3509
3510static int adm_map_cal_data(int32_t cal_type,
3511 struct cal_block_data *cal_block)
3512{
3513 int ret = 0;
3514 int cal_index;
3515
3516 pr_debug("%s:\n", __func__);
3517
3518 cal_index = get_cal_type_index(cal_type);
3519 if (cal_index < 0) {
3520 pr_err("%s: could not get cal index %d!\n",
3521 __func__, cal_index);
3522 ret = -EINVAL;
3523 goto done;
3524 }
3525
3526 atomic_set(&this_adm.mem_map_index, cal_index);
3527 ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
3528 (uint32_t *)&cal_block->map_data.map_size, 1);
3529 if (ret < 0) {
3530 pr_err("%s: map did not work! cal_type %i ret %d\n",
3531 __func__, cal_index, ret);
3532 ret = -ENODEV;
3533 goto done;
3534 }
3535 cal_block->map_data.q6map_handle = atomic_read(&this_adm.
3536 mem_map_handles[cal_index]);
3537done:
3538 return ret;
3539}
3540
3541static int adm_unmap_cal_data(int32_t cal_type,
3542 struct cal_block_data *cal_block)
3543{
3544 int ret = 0;
3545 int cal_index;
3546
3547 pr_debug("%s:\n", __func__);
3548
3549 cal_index = get_cal_type_index(cal_type);
3550 if (cal_index < 0) {
3551 pr_err("%s: could not get cal index %d!\n",
3552 __func__, cal_index);
3553 ret = -EINVAL;
3554 goto done;
3555 }
3556
3557 if (cal_block == NULL) {
3558 pr_err("%s: Cal block is NULL!\n",
3559 __func__);
3560 goto done;
3561 }
3562
3563 if (cal_block->map_data.q6map_handle == 0) {
3564 pr_err("%s: Map handle is NULL, nothing to unmap\n",
3565 __func__);
3566 goto done;
3567 }
3568
3569 atomic_set(&this_adm.mem_map_handles[cal_index],
3570 cal_block->map_data.q6map_handle);
3571 atomic_set(&this_adm.mem_map_index, cal_index);
3572 ret = adm_memory_unmap_regions();
3573 if (ret < 0) {
3574 pr_err("%s: unmap did not work! cal_type %i ret %d\n",
3575 __func__, cal_index, ret);
3576 ret = -ENODEV;
3577 goto done;
3578 }
3579 cal_block->map_data.q6map_handle = 0;
3580done:
3581 return ret;
3582}
3583
3584static void adm_delete_cal_data(void)
3585{
3586 pr_debug("%s:\n", __func__);
3587
3588 cal_utils_destroy_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data);
3589}
3590
3591static int adm_init_cal_data(void)
3592{
3593 int ret = 0;
3594 struct cal_type_info cal_type_info[] = {
3595 {{ADM_CUST_TOPOLOGY_CAL_TYPE,
3596 {adm_alloc_cal, adm_dealloc_cal, NULL,
3597 adm_set_cal, NULL, NULL} },
3598 {adm_map_cal_data, adm_unmap_cal_data,
3599 cal_utils_match_buf_num} },
3600
3601 {{ADM_AUDPROC_CAL_TYPE,
3602 {adm_alloc_cal, adm_dealloc_cal, NULL,
3603 adm_set_cal, NULL, NULL} },
3604 {adm_map_cal_data, adm_unmap_cal_data,
3605 cal_utils_match_buf_num} },
3606
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05303607 {{ADM_LSM_AUDPROC_CAL_TYPE,
3608 {adm_alloc_cal, adm_dealloc_cal, NULL,
3609 adm_set_cal, NULL, NULL} },
3610 {adm_map_cal_data, adm_unmap_cal_data,
3611 cal_utils_match_buf_num} },
3612
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303613 {{ADM_AUDVOL_CAL_TYPE,
3614 {adm_alloc_cal, adm_dealloc_cal, NULL,
3615 adm_set_cal, NULL, NULL} },
3616 {adm_map_cal_data, adm_unmap_cal_data,
3617 cal_utils_match_buf_num} },
3618
3619 {{ADM_RTAC_INFO_CAL_TYPE,
3620 {NULL, NULL, NULL, NULL, NULL, NULL} },
3621 {NULL, NULL, cal_utils_match_buf_num} },
3622
3623 {{ADM_RTAC_APR_CAL_TYPE,
3624 {NULL, NULL, NULL, NULL, NULL, NULL} },
3625 {NULL, NULL, cal_utils_match_buf_num} },
3626
3627 {{SRS_TRUMEDIA_CAL_TYPE,
3628 {NULL, NULL, NULL, NULL, NULL, NULL} },
3629 {NULL, NULL, cal_utils_match_buf_num} },
3630
3631 {{ADM_RTAC_AUDVOL_CAL_TYPE,
3632 {adm_alloc_cal, adm_dealloc_cal, NULL,
3633 adm_set_cal, NULL, NULL} },
3634 {adm_map_cal_data, adm_unmap_cal_data,
3635 cal_utils_match_buf_num} },
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07003636
3637 {{ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE,
3638 {adm_alloc_cal, adm_dealloc_cal, NULL,
3639 adm_set_cal, NULL, NULL} },
3640 {adm_map_cal_data, adm_unmap_cal_data,
3641 cal_utils_match_buf_num} },
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303642 };
3643 pr_debug("%s:\n", __func__);
3644
3645 ret = cal_utils_create_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data,
3646 cal_type_info);
3647 if (ret < 0) {
3648 pr_err("%s: could not create cal type! ret %d\n",
3649 __func__, ret);
3650 ret = -EINVAL;
3651 goto err;
3652 }
3653
3654 return ret;
3655err:
3656 adm_delete_cal_data();
3657 return ret;
3658}
3659
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303660/**
3661 * adm_set_volume -
3662 * command to set volume on ADM copp
3663 *
3664 * @port_id: Port ID number
3665 * @copp_idx: copp index assigned
3666 * @volume: gain value to set
3667 *
3668 * Returns 0 on success or error on failure
3669 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303670int adm_set_volume(int port_id, int copp_idx, int volume)
3671{
3672 struct audproc_volume_ctrl_master_gain audproc_vol;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003673 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303674 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303675
3676 pr_debug("%s: port_id %d, volume %d\n", __func__, port_id, volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303677
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003678 memset(&audproc_vol, 0, sizeof(audproc_vol));
3679 memset(&param_hdr, 0, sizeof(param_hdr));
3680 param_hdr.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
3681 param_hdr.instance_id = INSTANCE_ID_0;
3682 param_hdr.param_id = AUDPROC_PARAM_ID_VOL_CTRL_MASTER_GAIN;
3683 param_hdr.param_size = sizeof(audproc_vol);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303684
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303685 audproc_vol.master_gain = volume;
3686
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003687 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3688 (uint8_t *) &audproc_vol);
3689 if (rc)
3690 pr_err("%s: Failed to set volume, err %d\n", __func__, rc);
3691
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303692 return rc;
3693}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303694EXPORT_SYMBOL(adm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303695
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303696/**
3697 * adm_set_softvolume -
3698 * command to set softvolume
3699 *
3700 * @port_id: Port ID number
3701 * @copp_idx: copp index assigned
3702 * @softvol_param: Params to set for softvolume
3703 *
3704 * Returns 0 on success or error on failure
3705 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303706int adm_set_softvolume(int port_id, int copp_idx,
3707 struct audproc_softvolume_params *softvol_param)
3708{
3709 struct audproc_soft_step_volume_params audproc_softvol;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003710 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303711 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303712
3713 pr_debug("%s: period %d step %d curve %d\n", __func__,
3714 softvol_param->period, softvol_param->step,
3715 softvol_param->rampingcurve);
3716
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003717 memset(&audproc_softvol, 0, sizeof(audproc_softvol));
3718 memset(&param_hdr, 0, sizeof(param_hdr));
3719 param_hdr.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
3720 param_hdr.instance_id = INSTANCE_ID_0;
3721 param_hdr.param_id = AUDPROC_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
3722 param_hdr.param_size = sizeof(audproc_softvol);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303723
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303724 audproc_softvol.period = softvol_param->period;
3725 audproc_softvol.step = softvol_param->step;
3726 audproc_softvol.ramping_curve = softvol_param->rampingcurve;
3727
3728 pr_debug("%s: period %d, step %d, curve %d\n", __func__,
3729 audproc_softvol.period, audproc_softvol.step,
3730 audproc_softvol.ramping_curve);
3731
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003732 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3733 (uint8_t *) &audproc_softvol);
3734 if (rc)
3735 pr_err("%s: Failed to set soft volume, err %d\n", __func__, rc);
3736
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303737 return rc;
3738}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303739EXPORT_SYMBOL(adm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303740
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303741/**
3742 * adm_set_mic_gain -
3743 * command to set MIC gain
3744 *
3745 * @port_id: Port ID number
3746 * @copp_idx: copp index assigned
3747 * @volume: gain value to set
3748 *
3749 * Returns 0 on success or error on failure
3750 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303751int adm_set_mic_gain(int port_id, int copp_idx, int volume)
3752{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003753 struct admx_mic_gain mic_gain_params;
3754 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303755 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303756
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003757 pr_debug("%s: Setting mic gain to %d at port_id 0x%x\n", __func__,
3758 volume, port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303759
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003760 memset(&mic_gain_params, 0, sizeof(mic_gain_params));
3761 memset(&param_hdr, 0, sizeof(param_hdr));
3762 param_hdr.module_id = ADM_MODULE_IDX_MIC_GAIN_CTRL;
3763 param_hdr.instance_id = INSTANCE_ID_0;
3764 param_hdr.param_id = ADM_PARAM_IDX_MIC_GAIN;
3765 param_hdr.param_size = sizeof(mic_gain_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303766
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003767 mic_gain_params.tx_mic_gain = volume;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303768
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003769 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3770 (uint8_t *) &mic_gain_params);
3771 if (rc)
3772 pr_err("%s: Failed to set mic gain, err %d\n", __func__, rc);
3773
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303774 return rc;
3775}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303776EXPORT_SYMBOL(adm_set_mic_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303777
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303778/**
3779 * adm_send_set_multichannel_ec_primary_mic_ch -
3780 * command to set multi-ch EC primary mic
3781 *
3782 * @port_id: Port ID number
3783 * @copp_idx: copp index assigned
3784 * @primary_mic_ch: channel number of primary mic
3785 *
3786 * Returns 0 on success or error on failure
3787 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303788int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
3789 int primary_mic_ch)
3790{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003791 struct admx_sec_primary_mic_ch sec_primary_ch_params;
3792 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303793 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303794
3795 pr_debug("%s port_id 0x%x, copp_idx 0x%x, primary_mic_ch %d\n",
3796 __func__, port_id, copp_idx, primary_mic_ch);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303797
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003798 memset(&sec_primary_ch_params, 0, sizeof(sec_primary_ch_params));
3799 memset(&param_hdr, 0, sizeof(param_hdr));
3800 param_hdr.module_id = AUDPROC_MODULE_ID_VOICE_TX_SECNS;
3801 param_hdr.instance_id = INSTANCE_ID_0;
3802 param_hdr.param_id = AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH;
3803 param_hdr.param_size = sizeof(sec_primary_ch_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303804
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003805 sec_primary_ch_params.version = 0;
3806 sec_primary_ch_params.sec_primary_mic_ch = primary_mic_ch;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303807
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003808 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3809 (uint8_t *) &sec_primary_ch_params);
3810 if (rc)
3811 pr_err("%s: Failed to set primary mic chanel, err %d\n",
3812 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303813
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303814 return rc;
3815}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303816EXPORT_SYMBOL(adm_send_set_multichannel_ec_primary_mic_ch);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303817
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303818/**
3819 * adm_param_enable -
3820 * command to send params to ADM for given module
3821 *
3822 * @port_id: Port ID number
3823 * @copp_idx: copp index assigned
3824 * @module_id: ADM module
3825 * @enable: flag to enable or disable module
3826 *
3827 * Returns 0 on success or error on failure
3828 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303829int adm_param_enable(int port_id, int copp_idx, int module_id, int enable)
3830{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003831 struct module_instance_info mod_inst_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303832
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003833 memset(&mod_inst_info, 0, sizeof(mod_inst_info));
3834 mod_inst_info.module_id = module_id;
3835 mod_inst_info.instance_id = INSTANCE_ID_0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303836
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003837 return adm_param_enable_v2(port_id, copp_idx, mod_inst_info, enable);
3838}
Vidyakumar Athota98464a22018-03-15 20:39:37 -07003839EXPORT_SYMBOL(adm_param_enable);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003840
3841/**
3842 * adm_param_enable_v2 -
3843 * command to send params to ADM for given module
3844 *
3845 * @port_id: Port ID number
3846 * @copp_idx: copp index assigned
3847 * @mod_inst_info: module and instance ID info
3848 * @enable: flag to enable or disable module
3849 *
3850 * Returns 0 on success or error on failure
3851 */
3852int adm_param_enable_v2(int port_id, int copp_idx,
3853 struct module_instance_info mod_inst_info, int enable)
3854{
3855 uint32_t enable_param;
3856 struct param_hdr_v3 param_hdr;
3857 int rc = 0;
3858
3859 if (enable < 0 || enable > 1) {
3860 pr_err("%s: Invalid value for enable %d\n", __func__, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303861 return -EINVAL;
3862 }
3863
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003864 pr_debug("%s port_id %d, module_id 0x%x, instance_id 0x%x, enable %d\n",
3865 __func__, port_id, mod_inst_info.module_id,
3866 mod_inst_info.instance_id, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303867
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003868 memset(&param_hdr, 0, sizeof(param_hdr));
3869 param_hdr.module_id = mod_inst_info.module_id;
3870 param_hdr.instance_id = mod_inst_info.instance_id;
3871 param_hdr.param_id = AUDPROC_PARAM_ID_ENABLE;
3872 param_hdr.param_size = sizeof(enable_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303873
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003874 enable_param = enable;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303875
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003876 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3877 (uint8_t *) &enable_param);
3878 if (rc)
3879 pr_err("%s: Failed to set enable of module(%d) instance(%d) to %d, err %d\n",
3880 __func__, mod_inst_info.module_id,
3881 mod_inst_info.instance_id, enable, rc);
3882
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303883 return rc;
3884
3885}
Vidyakumar Athota98464a22018-03-15 20:39:37 -07003886EXPORT_SYMBOL(adm_param_enable_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303887
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303888/**
3889 * adm_send_calibration -
3890 * send ADM calibration to DSP
3891 *
3892 * @port_id: Port ID number
3893 * @copp_idx: copp index assigned
3894 * @path: direction or ADM path type
3895 * @perf_mode: performance mode like LL/ULL/..
3896 * @cal_type: calibration type to use
3897 * @params: pointer with cal data
3898 * @size: cal size
3899 *
3900 * Returns 0 on success or error on failure
3901 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303902int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode,
3903 int cal_type, char *params, int size)
3904{
3905
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003906 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303907
3908 pr_debug("%s:port_id %d, path %d, perf_mode %d, cal_type %d, size %d\n",
3909 __func__, port_id, path, perf_mode, cal_type, size);
3910
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303911 /* Maps audio_dev_ctrl path definition to ACDB definition */
3912 if (get_cal_path(path) != RX_DEVICE) {
3913 pr_err("%s: acdb_path %d\n", __func__, path);
3914 rc = -EINVAL;
3915 goto end;
3916 }
3917
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003918 rc = adm_set_pp_params(port_id, copp_idx, NULL, (u8 *) params, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303919
3920end:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303921 return rc;
3922}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303923EXPORT_SYMBOL(adm_send_calibration);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303924
3925/*
3926 * adm_update_wait_parameters must be called with routing driver locks.
3927 * adm_reset_wait_parameters must be called with routing driver locks.
3928 * set and reset parmeters are separated to make sure it is always called
3929 * under routing driver lock.
3930 * adm_wait_timeout is to block until timeout or interrupted. Timeout is
3931 * not a an error.
3932 */
3933int adm_set_wait_parameters(int port_id, int copp_idx)
3934{
3935
3936 int ret = 0, port_idx;
3937
3938 pr_debug("%s: port_id 0x%x, copp_idx %d\n", __func__, port_id,
3939 copp_idx);
3940 port_id = afe_convert_virtual_to_portid(port_id);
3941 port_idx = adm_validate_and_get_port_index(port_id);
3942 if (port_idx < 0) {
3943 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3944 ret = -EINVAL;
3945 goto end;
3946 }
3947
3948 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3949 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3950 return -EINVAL;
3951 }
3952
3953 this_adm.copp.adm_delay[port_idx][copp_idx] = 1;
3954 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 0);
3955
3956end:
3957 return ret;
3958
3959}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303960EXPORT_SYMBOL(adm_set_wait_parameters);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303961
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303962/**
3963 * adm_reset_wait_parameters -
3964 * reset wait parameters or ADM delay value
3965 *
3966 * @port_id: Port ID number
3967 * @copp_idx: copp index assigned
3968 *
3969 * Returns 0 on success or error on failure
3970 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303971int adm_reset_wait_parameters(int port_id, int copp_idx)
3972{
3973 int ret = 0, port_idx;
3974
3975 pr_debug("%s: port_id 0x%x copp_idx %d\n", __func__, port_id,
3976 copp_idx);
3977 port_id = afe_convert_virtual_to_portid(port_id);
3978 port_idx = adm_validate_and_get_port_index(port_id);
3979 if (port_idx < 0) {
3980 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3981 ret = -EINVAL;
3982 goto end;
3983 }
3984
3985 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3986 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3987 return -EINVAL;
3988 }
3989
3990 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 1);
3991 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
3992
3993end:
3994 return ret;
3995}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303996EXPORT_SYMBOL(adm_reset_wait_parameters);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303997
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303998/**
3999 * adm_wait_timeout -
4000 * ADM wait command after command send to DSP
4001 *
4002 * @port_id: Port ID number
4003 * @copp_idx: copp index assigned
4004 * @wait_time: value in ms for command timeout
4005 *
4006 * Returns 0 on success or error on failure
4007 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304008int adm_wait_timeout(int port_id, int copp_idx, int wait_time)
4009{
4010 int ret = 0, port_idx;
4011
4012 pr_debug("%s: port_id 0x%x, copp_idx %d, wait_time %d\n", __func__,
4013 port_id, copp_idx, wait_time);
4014 port_id = afe_convert_virtual_to_portid(port_id);
4015 port_idx = adm_validate_and_get_port_index(port_id);
4016 if (port_idx < 0) {
4017 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
4018 ret = -EINVAL;
4019 goto end;
4020 }
4021
4022 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4023 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
4024 return -EINVAL;
4025 }
4026
4027 ret = wait_event_timeout(
4028 this_adm.copp.adm_delay_wait[port_idx][copp_idx],
4029 atomic_read(&this_adm.copp.adm_delay_stat[port_idx][copp_idx]),
4030 msecs_to_jiffies(wait_time));
4031 pr_debug("%s: return %d\n", __func__, ret);
4032 if (ret != 0)
4033 ret = -EINTR;
4034end:
4035 pr_debug("%s: return %d--\n", __func__, ret);
4036 return ret;
4037}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304038EXPORT_SYMBOL(adm_wait_timeout);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304039
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304040/**
4041 * adm_store_cal_data -
4042 * Retrieve calibration data for ADM copp device
4043 *
4044 * @port_id: Port ID number
4045 * @copp_idx: copp index assigned
4046 * @path: direction or copp type
4047 * @perf_mode: performance mode like LL/ULL/..
4048 * @cal_index: calibration index to use
4049 * @params: pointer to store cal data
4050 * @size: pointer to fill with cal size
4051 *
4052 * Returns 0 on success or error on failure
4053 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304054int adm_store_cal_data(int port_id, int copp_idx, int path, int perf_mode,
4055 int cal_index, char *params, int *size)
4056{
4057 int rc = 0;
4058 struct cal_block_data *cal_block = NULL;
4059 int app_type, acdb_id, port_idx, sample_rate;
4060
4061 if (this_adm.cal_data[cal_index] == NULL) {
4062 pr_debug("%s: cal_index %d not allocated!\n",
4063 __func__, cal_index);
4064 goto end;
4065 }
4066
4067 if (get_cal_path(path) != RX_DEVICE) {
4068 pr_debug("%s: Invalid path to store calibration %d\n",
4069 __func__, path);
4070 rc = -EINVAL;
4071 goto end;
4072 }
4073
4074 port_id = afe_convert_virtual_to_portid(port_id);
4075 port_idx = adm_validate_and_get_port_index(port_id);
4076 if (port_idx < 0) {
4077 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
4078 rc = -EINVAL;
4079 goto end;
4080 }
4081
4082 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4083 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
4084 return -EINVAL;
4085 }
4086
4087 acdb_id = atomic_read(&this_adm.copp.acdb_id[port_idx][copp_idx]);
4088 app_type = atomic_read(&this_adm.copp.app_type[port_idx][copp_idx]);
4089 sample_rate = atomic_read(&this_adm.copp.rate[port_idx][copp_idx]);
4090
4091 mutex_lock(&this_adm.cal_data[cal_index]->lock);
4092 cal_block = adm_find_cal(cal_index, get_cal_path(path), app_type,
4093 acdb_id, sample_rate);
4094 if (cal_block == NULL)
4095 goto unlock;
4096
4097 if (cal_block->cal_data.size <= 0) {
4098 pr_debug("%s: No ADM cal send for port_id = 0x%x!\n",
4099 __func__, port_id);
4100 rc = -EINVAL;
4101 goto unlock;
4102 }
4103
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05304104 if (cal_index == ADM_AUDPROC_CAL || cal_index == ADM_LSM_AUDPROC_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304105 if (cal_block->cal_data.size > AUD_PROC_BLOCK_SIZE) {
4106 pr_err("%s:audproc:invalid size exp/actual[%zd, %d]\n",
4107 __func__, cal_block->cal_data.size, *size);
4108 rc = -ENOMEM;
4109 goto unlock;
4110 }
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07004111 } else if (cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
4112 if (cal_block->cal_data.size > AUD_PROC_PERSIST_BLOCK_SIZE) {
4113 pr_err("%s:persist invalid size exp/actual[%zd, %d]\n",
4114 __func__, cal_block->cal_data.size, *size);
4115 rc = -ENOMEM;
4116 goto unlock;
4117 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304118 } else if (cal_index == ADM_AUDVOL_CAL) {
4119 if (cal_block->cal_data.size > AUD_VOL_BLOCK_SIZE) {
4120 pr_err("%s:aud_vol:invalid size exp/actual[%zd, %d]\n",
4121 __func__, cal_block->cal_data.size, *size);
4122 rc = -ENOMEM;
4123 goto unlock;
4124 }
4125 } else {
4126 pr_debug("%s: Not valid calibration for dolby topolgy\n",
4127 __func__);
4128 rc = -EINVAL;
4129 goto unlock;
4130 }
4131 memcpy(params, cal_block->cal_data.kvaddr, cal_block->cal_data.size);
4132 *size = cal_block->cal_data.size;
4133
4134 pr_debug("%s:port_id %d, copp_idx %d, path %d",
4135 __func__, port_id, copp_idx, path);
4136 pr_debug("perf_mode %d, cal_type %d, size %d\n",
4137 perf_mode, cal_index, *size);
4138
4139unlock:
4140 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
4141end:
4142 return rc;
4143}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304144EXPORT_SYMBOL(adm_store_cal_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304145
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304146/**
4147 * adm_send_compressed_device_mute -
4148 * command to send mute for compressed device
4149 *
4150 * @port_id: Port ID number
4151 * @copp_idx: copp index assigned
4152 * @mute_on: flag to indicate mute or unmute
4153 *
4154 * Returns 0 on success or error on failure
4155 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304156int adm_send_compressed_device_mute(int port_id, int copp_idx, bool mute_on)
4157{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004158 u32 mute_param = mute_on ? 1 : 0;
4159 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304160 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304161
4162 pr_debug("%s port_id: 0x%x, copp_idx %d, mute_on: %d\n",
4163 __func__, port_id, copp_idx, mute_on);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304164
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004165 memset(&param_hdr, 0, sizeof(param_hdr));
4166 param_hdr.module_id = AUDPROC_MODULE_ID_COMPRESSED_MUTE;
4167 param_hdr.instance_id = INSTANCE_ID_0;
4168 param_hdr.param_id = AUDPROC_PARAM_ID_COMPRESSED_MUTE;
4169 param_hdr.param_size = sizeof(mute_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304170
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004171 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4172 (uint8_t *) &mute_param);
4173 if (ret)
4174 pr_err("%s: Failed to set mute, err %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304175
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304176 return ret;
4177}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304178EXPORT_SYMBOL(adm_send_compressed_device_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304179
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304180/**
4181 * adm_send_compressed_device_latency -
4182 * command to send latency for compressed device
4183 *
4184 * @port_id: Port ID number
4185 * @copp_idx: copp index assigned
4186 * @latency: latency value to pass
4187 *
4188 * Returns 0 on success or error on failure
4189 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304190int adm_send_compressed_device_latency(int port_id, int copp_idx, int latency)
4191{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004192 u32 latency_param;
4193 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304194 int ret = 0;
4195
4196 pr_debug("%s port_id: 0x%x, copp_idx %d latency: %d\n", __func__,
4197 port_id, copp_idx, latency);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004198
4199 if (latency < 0) {
4200 pr_err("%s: Invalid value for latency %d", __func__, latency);
4201 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304202 }
4203
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004204 memset(&param_hdr, 0, sizeof(param_hdr));
4205 param_hdr.module_id = AUDPROC_MODULE_ID_COMPRESSED_LATENCY;
4206 param_hdr.instance_id = INSTANCE_ID_0;
4207 param_hdr.param_id = AUDPROC_PARAM_ID_COMPRESSED_LATENCY;
4208 param_hdr.param_size = sizeof(latency_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304209
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004210 latency_param = latency;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304211
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004212 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4213 (uint8_t *) &latency_param);
4214 if (ret)
4215 pr_err("%s: Failed to set latency, err %d\n", __func__, ret);
4216
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304217 return ret;
4218}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304219EXPORT_SYMBOL(adm_send_compressed_device_latency);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304220
4221/**
4222 * adm_swap_speaker_channels
4223 *
4224 * Receives port_id, copp_idx, sample rate, spk_swap and
4225 * send MFC command to swap speaker channel.
4226 * Return zero on success. On failure returns nonzero.
4227 *
4228 * port_id - Passed value, port_id for which channels swap is wanted
4229 * copp_idx - Passed value, copp_idx for which channels swap is wanted
4230 * sample_rate - Passed value, sample rate used by app type config
4231 * spk_swap - Passed value, spk_swap for check if swap flag is set
4232 */
4233int adm_swap_speaker_channels(int port_id, int copp_idx,
4234 int sample_rate, bool spk_swap)
4235{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004236 struct audproc_mfc_param_media_fmt mfc_cfg;
4237 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304238 uint16_t num_channels;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004239 int port_idx = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304240 int ret = 0;
4241
4242 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4243 __func__, port_id, copp_idx);
4244 port_id = q6audio_convert_virtual_to_portid(port_id);
4245 port_idx = adm_validate_and_get_port_index(port_id);
4246 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
4247 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004248 return -EINVAL;
4249 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4250 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
4251 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304252 }
4253
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004254 num_channels = atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304255 if (num_channels != 2) {
4256 pr_debug("%s: Invalid number of channels: %d\n",
4257 __func__, num_channels);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004258 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304259 }
4260
4261 memset(&mfc_cfg, 0, sizeof(mfc_cfg));
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004262 memset(&param_hdr, 0, sizeof(param_hdr));
4263
4264 param_hdr.module_id = AUDPROC_MODULE_ID_MFC;
4265 param_hdr.instance_id = INSTANCE_ID_0;
4266 param_hdr.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
4267 param_hdr.param_size = sizeof(mfc_cfg);
4268
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304269 mfc_cfg.sampling_rate = sample_rate;
4270 mfc_cfg.bits_per_sample =
4271 atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
4272 mfc_cfg.num_channels = num_channels;
4273
4274 /* Currently applying speaker swap for only 2 channel use case */
4275 if (spk_swap) {
4276 mfc_cfg.channel_type[0] =
4277 (uint16_t) PCM_CHANNEL_FR;
4278 mfc_cfg.channel_type[1] =
4279 (uint16_t) PCM_CHANNEL_FL;
4280 } else {
4281 mfc_cfg.channel_type[0] =
4282 (uint16_t) PCM_CHANNEL_FL;
4283 mfc_cfg.channel_type[1] =
4284 (uint16_t) PCM_CHANNEL_FR;
4285 }
4286
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004287 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4288 (u8 *) &mfc_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304289 if (ret < 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004290 pr_err("%s: Failed to set swap speaker channels on port[0x%x] failed %d\n",
4291 __func__, port_id, ret);
4292 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304293 }
4294
4295 pr_debug("%s: mfc_cfg Set params returned success", __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004296 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304297}
4298EXPORT_SYMBOL(adm_swap_speaker_channels);
4299
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304300/**
4301 * adm_set_sound_focus -
4302 * Update sound focus info
4303 *
4304 * @port_id: Port ID number
4305 * @copp_idx: copp index assigned
4306 * @soundFocusData: sound focus data to pass
4307 *
4308 * Returns 0 on success or error on failure
4309 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304310int adm_set_sound_focus(int port_id, int copp_idx,
4311 struct sound_focus_param soundFocusData)
4312{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004313 struct adm_param_fluence_soundfocus_t soundfocus_params;
4314 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304315 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304316 int i;
4317
4318 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4319 __func__, port_id, copp_idx);
4320
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004321 memset(&param_hdr, 0, sizeof(param_hdr));
4322 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4323 param_hdr.instance_id = INSTANCE_ID_0;
4324 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
4325 param_hdr.param_size = sizeof(soundfocus_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304326
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004327 memset(&(soundfocus_params), 0xFF, sizeof(soundfocus_params));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304328 for (i = 0; i < MAX_SECTORS; i++) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004329 soundfocus_params.start_angles[i] =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304330 soundFocusData.start_angle[i];
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004331 soundfocus_params.enables[i] = soundFocusData.enable[i];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304332 pr_debug("%s: start_angle[%d] = %d\n",
4333 __func__, i, soundFocusData.start_angle[i]);
4334 pr_debug("%s: enable[%d] = %d\n",
4335 __func__, i, soundFocusData.enable[i]);
4336 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004337 soundfocus_params.gain_step = soundFocusData.gain_step;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304338 pr_debug("%s: gain_step = %d\n", __func__, soundFocusData.gain_step);
4339
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004340 soundfocus_params.reserved = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304341
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004342 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4343 (uint8_t *) &soundfocus_params);
4344 if (ret)
4345 pr_err("%s: Failed to set sound focus params, err %d\n",
4346 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304347
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304348 pr_debug("%s: Exit, ret=%d\n", __func__, ret);
4349
4350 return ret;
4351}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304352EXPORT_SYMBOL(adm_set_sound_focus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304353
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304354/**
4355 * adm_get_sound_focus -
4356 * Retrieve sound focus info
4357 *
4358 * @port_id: Port ID number
4359 * @copp_idx: copp index assigned
4360 * @soundFocusData: pointer for sound focus data to be updated with
4361 *
4362 * Returns 0 on success or error on failure
4363 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304364int adm_get_sound_focus(int port_id, int copp_idx,
4365 struct sound_focus_param *soundFocusData)
4366{
4367 int ret = 0, i;
4368 char *params_value;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004369 uint32_t max_param_size = 0;
4370 struct adm_param_fluence_soundfocus_t *soundfocus_params = NULL;
4371 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304372
4373 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4374 __func__, port_id, copp_idx);
4375
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004376 max_param_size = sizeof(struct adm_param_fluence_soundfocus_t) +
4377 sizeof(union param_hdrs);
4378 params_value = kzalloc(max_param_size, GFP_KERNEL);
4379 if (!params_value)
4380 return -ENOMEM;
4381
4382 memset(&param_hdr, 0, sizeof(param_hdr));
4383 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4384 param_hdr.instance_id = INSTANCE_ID_0;
4385 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
4386 param_hdr.param_size = max_param_size;
4387 ret = adm_get_pp_params(port_id, copp_idx,
4388 ADM_CLIENT_ID_SOURCE_TRACKING, NULL, &param_hdr,
4389 params_value);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304390 if (ret) {
4391 pr_err("%s: get parameters failed ret:%d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304392 ret = -EINVAL;
4393 goto done;
4394 }
4395
4396 if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
4397 pr_err("%s - get params returned error [%s]\n",
4398 __func__, adsp_err_get_err_str(
4399 this_adm.sourceTrackingData.apr_cmd_status));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304400 ret = adsp_err_get_lnx_err_code(
4401 this_adm.sourceTrackingData.apr_cmd_status);
4402 goto done;
4403 }
4404
4405 soundfocus_params = (struct adm_param_fluence_soundfocus_t *)
4406 params_value;
4407 for (i = 0; i < MAX_SECTORS; i++) {
4408 soundFocusData->start_angle[i] =
4409 soundfocus_params->start_angles[i];
4410 soundFocusData->enable[i] = soundfocus_params->enables[i];
4411 pr_debug("%s: start_angle[%d] = %d\n",
4412 __func__, i, soundFocusData->start_angle[i]);
4413 pr_debug("%s: enable[%d] = %d\n",
4414 __func__, i, soundFocusData->enable[i]);
4415 }
4416 soundFocusData->gain_step = soundfocus_params->gain_step;
4417 pr_debug("%s: gain_step = %d\n", __func__, soundFocusData->gain_step);
4418
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304419done:
4420 pr_debug("%s: Exit, ret = %d\n", __func__, ret);
4421
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004422 kfree(params_value);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304423 return ret;
4424}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304425EXPORT_SYMBOL(adm_get_sound_focus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304426
4427static int adm_source_tracking_alloc_map_memory(void)
4428{
4429 int ret;
4430
4431 pr_debug("%s: Enter\n", __func__);
4432
Banajit Goswami08bb7362017-11-03 22:48:23 -07004433 ret = msm_audio_ion_alloc(&this_adm.sourceTrackingData.dma_buf,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304434 AUD_PROC_BLOCK_SIZE,
4435 &this_adm.sourceTrackingData.memmap.paddr,
4436 &this_adm.sourceTrackingData.memmap.size,
4437 &this_adm.sourceTrackingData.memmap.kvaddr);
4438 if (ret) {
4439 pr_err("%s: failed to allocate memory\n", __func__);
4440
4441 ret = -EINVAL;
4442 goto done;
4443 }
4444
4445 atomic_set(&this_adm.mem_map_index, ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
4446 ret = adm_memory_map_regions(&this_adm.sourceTrackingData.memmap.paddr,
4447 0,
4448 (uint32_t *)&this_adm.sourceTrackingData.memmap.size,
4449 1);
4450 if (ret < 0) {
4451 pr_err("%s: failed to map memory, paddr = 0x%pK, size = %d\n",
4452 __func__,
4453 (void *)this_adm.sourceTrackingData.memmap.paddr,
4454 (uint32_t)this_adm.sourceTrackingData.memmap.size);
4455
Banajit Goswami08bb7362017-11-03 22:48:23 -07004456 msm_audio_ion_free(this_adm.sourceTrackingData.dma_buf);
4457 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304458 this_adm.sourceTrackingData.memmap.size = 0;
4459 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
4460 this_adm.sourceTrackingData.memmap.paddr = 0;
4461 this_adm.sourceTrackingData.apr_cmd_status = -1;
4462 atomic_set(&this_adm.mem_map_handles
4463 [ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
4464
4465 ret = -EINVAL;
4466 goto done;
4467 }
4468 ret = 0;
4469 pr_debug("%s: paddr = 0x%pK, size = %d, mem_map_handle = 0x%x\n",
4470 __func__, (void *)this_adm.sourceTrackingData.memmap.paddr,
4471 (uint32_t)this_adm.sourceTrackingData.memmap.size,
4472 atomic_read(&this_adm.mem_map_handles
4473 [ADM_MEM_MAP_INDEX_SOURCE_TRACKING]));
4474
4475done:
4476 pr_debug("%s: Exit, ret = %d\n", __func__, ret);
4477
4478 return ret;
4479}
4480
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304481/**
4482 * adm_get_source_tracking -
4483 * Retrieve source tracking info
4484 *
4485 * @port_id: Port ID number
4486 * @copp_idx: copp index assigned
4487 * @sourceTrackingData: pointer for source track data to be updated with
4488 *
4489 * Returns 0 on success or error on failure
4490 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304491int adm_get_source_tracking(int port_id, int copp_idx,
4492 struct source_tracking_param *sourceTrackingData)
4493{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004494 struct adm_param_fluence_sourcetracking_t *source_tracking_params =
4495 NULL;
4496 struct mem_mapping_hdr mem_hdr;
4497 struct param_hdr_v3 param_hdr;
4498 int i = 0;
4499 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304500
4501 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4502 __func__, port_id, copp_idx);
4503
4504 if (!this_adm.sourceTrackingData.memmap.paddr) {
4505 /* Allocate and map shared memory for out of band usage */
4506 ret = adm_source_tracking_alloc_map_memory();
4507 if (ret != 0) {
4508 ret = -EINVAL;
4509 goto done;
4510 }
4511 }
4512
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004513 memset(&mem_hdr, 0, sizeof(mem_hdr));
4514 memset(&param_hdr, 0, sizeof(param_hdr));
4515 mem_hdr.data_payload_addr_lsw =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304516 lower_32_bits(this_adm.sourceTrackingData.memmap.paddr);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004517 mem_hdr.data_payload_addr_msw = msm_audio_populate_upper_32_bits(
4518 this_adm.sourceTrackingData.memmap.paddr);
4519 mem_hdr.mem_map_handle = atomic_read(
4520 &this_adm.mem_map_handles[ADM_MEM_MAP_INDEX_SOURCE_TRACKING]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304521
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004522 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4523 param_hdr.instance_id = INSTANCE_ID_0;
4524 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOURCETRACKING;
4525 /*
4526 * This size should be the max size of the calibration data + header.
4527 * Use the union size to ensure max size is used.
4528 */
4529 param_hdr.param_size =
4530 sizeof(struct adm_param_fluence_sourcetracking_t) +
4531 sizeof(union param_hdrs);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304532
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004533 /*
4534 * Retrieving parameters out of band, so no need to provide a buffer for
4535 * the returned parameter data as it will be at the memory location
4536 * provided.
4537 */
4538 ret = adm_get_pp_params(port_id, copp_idx,
4539 ADM_CLIENT_ID_SOURCE_TRACKING, &mem_hdr,
4540 &param_hdr, NULL);
4541 if (ret) {
4542 pr_err("%s: Failed to get params, error %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304543 goto done;
4544 }
4545
4546 if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
4547 pr_err("%s - get params returned error [%s]\n",
4548 __func__, adsp_err_get_err_str(
4549 this_adm.sourceTrackingData.apr_cmd_status));
4550
4551 ret = adsp_err_get_lnx_err_code(
4552 this_adm.sourceTrackingData.apr_cmd_status);
4553 goto done;
4554 }
4555
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004556 /* How do we know what the param data was retrieved with for hdr size */
4557 source_tracking_params =
4558 (struct adm_param_fluence_sourcetracking_t
4559 *) (this_adm.sourceTrackingData.memmap.kvaddr +
4560 sizeof(struct param_hdr_v1));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304561 for (i = 0; i < MAX_SECTORS; i++) {
4562 sourceTrackingData->vad[i] = source_tracking_params->vad[i];
4563 pr_debug("%s: vad[%d] = %d\n",
4564 __func__, i, sourceTrackingData->vad[i]);
4565 }
4566 sourceTrackingData->doa_speech = source_tracking_params->doa_speech;
4567 pr_debug("%s: doa_speech = %d\n",
4568 __func__, sourceTrackingData->doa_speech);
4569
4570 for (i = 0; i < MAX_NOISE_SOURCE_INDICATORS; i++) {
4571 sourceTrackingData->doa_noise[i] =
4572 source_tracking_params->doa_noise[i];
4573 pr_debug("%s: doa_noise[%d] = %d\n",
4574 __func__, i, sourceTrackingData->doa_noise[i]);
4575 }
4576 for (i = 0; i < MAX_POLAR_ACTIVITY_INDICATORS; i++) {
4577 sourceTrackingData->polar_activity[i] =
4578 source_tracking_params->polar_activity[i];
4579 pr_debug("%s: polar_activity[%d] = %d\n",
4580 __func__, i, sourceTrackingData->polar_activity[i]);
4581 }
4582
4583 ret = 0;
4584
4585done:
4586 pr_debug("%s: Exit, ret=%d\n", __func__, ret);
4587
4588 return ret;
4589}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304590EXPORT_SYMBOL(adm_get_source_tracking);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304591
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304592int __init adm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304593{
4594 int i = 0, j;
4595
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304596 this_adm.ec_ref_rx = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304597 init_waitqueue_head(&this_adm.matrix_map_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304598 init_waitqueue_head(&this_adm.adm_wait);
4599
4600 for (i = 0; i < AFE_MAX_PORTS; i++) {
4601 for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
4602 atomic_set(&this_adm.copp.id[i][j], RESET_COPP_ID);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304603 init_waitqueue_head(&this_adm.copp.wait[i][j]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304604 init_waitqueue_head(
4605 &this_adm.copp.adm_delay_wait[i][j]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304606 }
4607 }
4608
4609 if (adm_init_cal_data())
4610 pr_err("%s: could not init cal data!\n", __func__);
4611
Banajit Goswami08bb7362017-11-03 22:48:23 -07004612 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304613 this_adm.sourceTrackingData.memmap.size = 0;
4614 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
4615 this_adm.sourceTrackingData.memmap.paddr = 0;
4616 this_adm.sourceTrackingData.apr_cmd_status = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304617
4618 return 0;
4619}
4620
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05304621void adm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304622{
Laxminath Kasam30ad7512017-11-28 12:40:22 +05304623 if (this_adm.apr)
4624 adm_reset_data();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304625 adm_delete_cal_data();
4626}