blob: 11e20a35816a4126ab7b1728dada22dd4c52daa8 [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 */
Vignesh Kulothunganaadecdf2018-06-20 15:08:24 -07001068 adm_get_params.apr_hdr.hdr_field =
1069 APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
1070 APR_PKT_VER);
1071 adm_get_params.apr_hdr.pkt_size = sizeof(adm_get_params);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001072 adm_get_params.apr_hdr.src_svc = APR_SVC_ADM;
1073 adm_get_params.apr_hdr.src_domain = APR_DOMAIN_APPS;
1074 adm_get_params.apr_hdr.src_port = port_id;
1075 adm_get_params.apr_hdr.dest_svc = APR_SVC_ADM;
1076 adm_get_params.apr_hdr.dest_domain = APR_DOMAIN_ADSP;
1077 adm_get_params.apr_hdr.dest_port =
1078 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
1079 adm_get_params.apr_hdr.token =
1080 port_idx << 16 | client_id << 8 | copp_idx;
1081
1082 if (q6common_is_instance_id_supported())
1083 adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V6;
1084 else
1085 adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
1086
1087 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
1088 atomic_set(copp_stat, -1);
Vignesh Kulothunganaadecdf2018-06-20 15:08:24 -07001089
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001090 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_params);
Vidyakumar Athotae427c412018-06-16 00:02:46 -07001091 if (ret < 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001092 pr_err("%s: Get params APR send failed port = 0x%x ret %d\n",
1093 __func__, port_id, ret);
1094 ret = -EINVAL;
1095 goto done;
1096 }
1097 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
1098 atomic_read(copp_stat) >= 0,
1099 msecs_to_jiffies(TIMEOUT_MS));
1100 if (!ret) {
1101 pr_err("%s: Get params timed out port = 0x%x\n", __func__,
1102 port_id);
1103 ret = -ETIMEDOUT;
1104 goto done;
1105 }
1106 if (atomic_read(copp_stat) > 0) {
1107 pr_err("%s: DSP returned error[%s]\n", __func__,
1108 adsp_err_get_err_str(atomic_read(copp_stat)));
1109 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
1110 goto done;
1111 }
1112
1113 ret = 0;
1114
1115 /* Copy data to caller if sent in band */
1116 if (!returned_param_data) {
1117 pr_debug("%s: Received NULL pointer for param destination, not copying payload\n",
1118 __func__);
1119 return 0;
1120 }
1121
1122 idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
1123 returned_param_size = adm_get_parameters[idx];
1124 if (returned_param_size < 0 ||
1125 returned_param_size + idx + 1 > get_param_array_sz) {
1126 pr_err("%s: Invalid parameter size %d\n", __func__,
1127 returned_param_size);
1128 return -EINVAL;
1129 }
1130
1131 returned_param_size_in_bytes = returned_param_size * sizeof(uint32_t);
1132 if (param_hdr->param_size < returned_param_size_in_bytes) {
1133 pr_err("%s: Provided buffer is not big enough, provided buffer size(%d) size needed(%d)\n",
1134 __func__, param_hdr->param_size,
1135 returned_param_size_in_bytes);
1136 return -EINVAL;
1137 }
1138
1139 memcpy(returned_param_data, &adm_get_parameters[idx + 1],
1140 returned_param_size_in_bytes);
1141done:
1142 return ret;
1143}
1144EXPORT_SYMBOL(adm_get_pp_params);
1145
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001146int adm_get_pp_topo_module_list_v2(int port_id, int copp_idx,
1147 int32_t param_length,
1148 int32_t *returned_params)
1149{
1150 struct adm_cmd_get_pp_topo_module_list adm_get_module_list;
1151 bool iid_supported = q6common_is_instance_id_supported();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301152 int *topo_list;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001153 int num_modules = 0;
1154 int list_size = 0;
1155 int port_idx, idx;
1156 int i = 0;
1157 atomic_t *copp_stat = NULL;
1158 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301159
1160 pr_debug("%s : port_id %x", __func__, port_id);
1161 port_id = afe_convert_virtual_to_portid(port_id);
1162 port_idx = adm_validate_and_get_port_index(port_id);
1163 if (port_idx < 0) {
1164 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
1165 return -EINVAL;
1166 }
1167
1168 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1169 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
1170 return -EINVAL;
1171 }
1172
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001173 memset(&adm_get_module_list, 0, sizeof(adm_get_module_list));
1174
1175 adm_get_module_list.apr_hdr.pkt_size = sizeof(adm_get_module_list);
1176 adm_get_module_list.apr_hdr.src_svc = APR_SVC_ADM;
1177 adm_get_module_list.apr_hdr.src_domain = APR_DOMAIN_APPS;
1178 adm_get_module_list.apr_hdr.src_port = port_id;
1179 adm_get_module_list.apr_hdr.dest_svc = APR_SVC_ADM;
1180 adm_get_module_list.apr_hdr.dest_domain = APR_DOMAIN_ADSP;
1181 adm_get_module_list.apr_hdr.dest_port =
1182 atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
1183 adm_get_module_list.apr_hdr.token = port_idx << 16 | copp_idx;
1184 /*
1185 * Out of band functionality is not currently utilized.
1186 * Assume in band.
1187 */
1188 if (iid_supported) {
1189 adm_get_module_list.apr_hdr.opcode =
1190 ADM_CMD_GET_PP_TOPO_MODULE_LIST_V2;
1191 adm_get_module_list.param_max_size = param_length;
1192 } else {
1193 adm_get_module_list.apr_hdr.opcode =
1194 ADM_CMD_GET_PP_TOPO_MODULE_LIST;
1195
1196 if (param_length > U16_MAX) {
1197 pr_err("%s: Invalid param length for V1 %d\n", __func__,
1198 param_length);
1199 return -EINVAL;
1200 }
1201 adm_get_module_list.param_max_size = param_length << 16;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301202 }
1203
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001204 copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
1205 atomic_set(copp_stat, -1);
1206 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_module_list);
Vidyakumar Athotae427c412018-06-16 00:02:46 -07001207 if (ret < 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001208 pr_err("%s: APR send pkt failed for port_id: 0x%x failed ret %d\n",
1209 __func__, port_id, ret);
1210 ret = -EINVAL;
1211 goto done;
1212 }
1213 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
1214 atomic_read(copp_stat) >= 0,
1215 msecs_to_jiffies(TIMEOUT_MS));
1216 if (!ret) {
1217 pr_err("%s: Timeout for port_id: 0x%x\n", __func__, port_id);
1218 ret = -ETIMEDOUT;
1219 goto done;
1220 }
1221 if (atomic_read(copp_stat) > 0) {
1222 pr_err("%s: DSP returned error[%s]\n", __func__,
1223 adsp_err_get_err_str(atomic_read(copp_stat)));
1224 ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
1225 goto done;
1226 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301227
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001228 ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301229
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001230 if (returned_params) {
1231 /*
1232 * When processing ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST IID is
1233 * added since it is not present. Therefore, there is no need to
1234 * do anything different if IID is not supported here as it is
1235 * already taken care of.
1236 */
1237 idx = ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH * copp_idx;
1238 num_modules = adm_module_topo_list[idx];
1239 if (num_modules < 0 || num_modules > MAX_MODULES_IN_TOPO) {
1240 pr_err("%s: Invalid number of modules returned %d\n",
1241 __func__, num_modules);
1242 return -EINVAL;
1243 }
1244
1245 list_size = num_modules * sizeof(struct module_instance_info);
1246 if (param_length < list_size) {
1247 pr_err("%s: Provided buffer not big enough to hold module-instance list, provided size %d, needed size %d\n",
1248 __func__, param_length, list_size);
1249 return -EINVAL;
1250 }
1251
1252 topo_list = (int32_t *) (&adm_module_topo_list[idx]);
1253 memcpy(returned_params, topo_list, list_size);
1254 for (i = 1; i <= num_modules; i += 2) {
1255 pr_debug("module = 0x%x instance = 0x%x\n",
1256 returned_params[i], returned_params[i + 1]);
1257 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301258 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001259done:
1260 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301261}
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001262EXPORT_SYMBOL(adm_get_pp_topo_module_list_v2);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301263
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301264static void adm_callback_debug_print(struct apr_client_data *data)
1265{
1266 uint32_t *payload;
1267
1268 payload = data->payload;
1269
1270 if (data->payload_size >= 8)
1271 pr_debug("%s: code = 0x%x PL#0[0x%x], PL#1[0x%x], size = %d\n",
1272 __func__, data->opcode, payload[0], payload[1],
1273 data->payload_size);
1274 else if (data->payload_size >= 4)
1275 pr_debug("%s: code = 0x%x PL#0[0x%x], size = %d\n",
1276 __func__, data->opcode, payload[0],
1277 data->payload_size);
1278 else
1279 pr_debug("%s: code = 0x%x, size = %d\n",
1280 __func__, data->opcode, data->payload_size);
1281}
1282
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301283/**
1284 * adm_set_multi_ch_map -
1285 * Update multi channel map info
1286 *
1287 * @channel_map: pointer with channel map info
1288 * @path: direction or ADM path type
1289 *
1290 * Returns 0 on success or error on failure
1291 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301292int adm_set_multi_ch_map(char *channel_map, int path)
1293{
1294 int idx;
1295
1296 if (path == ADM_PATH_PLAYBACK) {
1297 idx = ADM_MCH_MAP_IDX_PLAYBACK;
1298 } else if (path == ADM_PATH_LIVE_REC) {
1299 idx = ADM_MCH_MAP_IDX_REC;
1300 } else {
1301 pr_err("%s: invalid attempt to set path %d\n", __func__, path);
1302 return -EINVAL;
1303 }
1304
1305 memcpy(multi_ch_maps[idx].channel_mapping, channel_map,
1306 PCM_FORMAT_MAX_NUM_CHANNEL);
1307 multi_ch_maps[idx].set_channel_map = true;
1308
1309 return 0;
1310}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301311EXPORT_SYMBOL(adm_set_multi_ch_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301312
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301313/**
1314 * adm_get_multi_ch_map -
1315 * Retrieves multi channel map info
1316 *
1317 * @channel_map: pointer to be updated with channel map
1318 * @path: direction or ADM path type
1319 *
1320 * Returns 0 on success or error on failure
1321 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301322int adm_get_multi_ch_map(char *channel_map, int path)
1323{
1324 int idx;
1325
1326 if (path == ADM_PATH_PLAYBACK) {
1327 idx = ADM_MCH_MAP_IDX_PLAYBACK;
1328 } else if (path == ADM_PATH_LIVE_REC) {
1329 idx = ADM_MCH_MAP_IDX_REC;
1330 } else {
1331 pr_err("%s: invalid attempt to get path %d\n", __func__, path);
1332 return -EINVAL;
1333 }
1334
1335 if (multi_ch_maps[idx].set_channel_map) {
1336 memcpy(channel_map, multi_ch_maps[idx].channel_mapping,
1337 PCM_FORMAT_MAX_NUM_CHANNEL);
1338 }
1339
1340 return 0;
1341}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301342EXPORT_SYMBOL(adm_get_multi_ch_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301343
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001344static int adm_process_get_param_response(u32 opcode, u32 idx, u32 *payload,
1345 u32 payload_size)
1346{
1347 struct adm_cmd_rsp_get_pp_params_v5 *v5_rsp = NULL;
1348 struct adm_cmd_rsp_get_pp_params_v6 *v6_rsp = NULL;
1349 u32 *param_data = NULL;
1350 int data_size = 0;
1351 int struct_size = 0;
1352
1353 if (payload == NULL) {
1354 pr_err("%s: Payload is NULL\n", __func__);
1355 return -EINVAL;
1356 }
1357
1358 switch (opcode) {
1359 case ADM_CMDRSP_GET_PP_PARAMS_V5:
1360 struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v5);
1361 v5_rsp = (struct adm_cmd_rsp_get_pp_params_v5 *) payload;
1362 data_size = v5_rsp->param_hdr.param_size;
1363 param_data = v5_rsp->param_data;
1364 break;
1365 case ADM_CMDRSP_GET_PP_PARAMS_V6:
1366 struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v6);
1367 v6_rsp = (struct adm_cmd_rsp_get_pp_params_v6 *) payload;
1368 data_size = v6_rsp->param_hdr.param_size;
1369 param_data = v6_rsp->param_data;
1370 break;
1371 default:
1372 pr_err("%s: Invalid opcode %d\n", __func__, opcode);
1373 return -EINVAL;
1374 }
1375
1376 /*
1377 * Just store the returned parameter data, not the header. The calling
1378 * function is expected to know what it asked for. Therefore, there is
1379 * no difference between V5 and V6.
1380 */
1381 if ((payload_size >= struct_size + data_size) &&
1382 (ARRAY_SIZE(adm_get_parameters) > idx) &&
1383 (ARRAY_SIZE(adm_get_parameters) >= idx + 1 + data_size)) {
Vignesh Kulothunganaadecdf2018-06-20 15:08:24 -07001384 pr_debug("%s: Received parameter data in band\n",
1385 __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001386 /*
1387 * data_size is expressed in number of bytes, store in number of
1388 * ints
1389 */
1390 adm_get_parameters[idx] =
1391 data_size / sizeof(*adm_get_parameters);
1392 pr_debug("%s: GET_PP PARAM: received parameter length: 0x%x\n",
1393 __func__, adm_get_parameters[idx]);
1394 /* store params after param_size */
1395 memcpy(&adm_get_parameters[idx + 1], param_data, data_size);
Vignesh Kulothunganaadecdf2018-06-20 15:08:24 -07001396 } else if (payload_size == sizeof(uint32_t)) {
1397 adm_get_parameters[idx] = -1;
1398 pr_debug("%s: Out of band case, setting size to %d\n",
1399 __func__, adm_get_parameters[idx]);
1400 } else {
1401 pr_err("%s: Invalid parameter combination, payload_size %d, idx %d\n",
1402 __func__, payload_size, idx);
1403 return -EINVAL;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001404 }
Vignesh Kulothunganaadecdf2018-06-20 15:08:24 -07001405 return 0;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001406}
1407
1408static int adm_process_get_topo_list_response(u32 opcode, int copp_idx,
1409 u32 num_modules, u32 *payload,
1410 u32 payload_size)
1411{
1412 u32 *fill_list = NULL;
1413 int idx = 0;
1414 int i = 0;
1415 int j = 0;
1416
1417 if (payload == NULL) {
1418 pr_err("%s: Payload is NULL\n", __func__);
1419 return -EINVAL;
1420 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1421 pr_err("%s: Invalid COPP index %d\n", __func__, copp_idx);
1422 return -EINVAL;
1423 }
1424
1425 idx = ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH * copp_idx;
1426 fill_list = adm_module_topo_list + idx;
1427 *fill_list++ = num_modules;
1428 for (i = 0; i < num_modules; i++) {
1429 if (j > payload_size / sizeof(u32)) {
1430 pr_err("%s: Invalid number of modules specified %d\n",
1431 __func__, num_modules);
1432 return -EINVAL;
1433 }
1434
1435 /* store module ID */
1436 *fill_list++ = payload[j];
1437 j++;
1438
1439 switch (opcode) {
1440 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
1441 /* store instance ID */
1442 *fill_list++ = payload[j];
1443 j++;
1444 break;
1445 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
1446 /* Insert IID 0 when repacking */
1447 *fill_list++ = INSTANCE_ID_0;
1448 break;
1449 default:
1450 pr_err("%s: Invalid opcode %d\n", __func__, opcode);
1451 return -EINVAL;
1452 }
1453 }
1454
1455 return 0;
1456}
1457
Laxminath Kasam30ad7512017-11-28 12:40:22 +05301458static void adm_reset_data(void)
1459{
1460 int i, j;
1461
1462 apr_reset(this_adm.apr);
1463 for (i = 0; i < AFE_MAX_PORTS; i++) {
1464 for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
1465 atomic_set(&this_adm.copp.id[i][j],
1466 RESET_COPP_ID);
1467 atomic_set(&this_adm.copp.cnt[i][j], 0);
1468 atomic_set(
1469 &this_adm.copp.topology[i][j], 0);
1470 atomic_set(&this_adm.copp.mode[i][j],
1471 0);
1472 atomic_set(&this_adm.copp.stat[i][j],
1473 0);
1474 atomic_set(&this_adm.copp.rate[i][j],
1475 0);
1476 atomic_set(
1477 &this_adm.copp.channels[i][j],
1478 0);
1479 atomic_set(
1480 &this_adm.copp.bit_width[i][j], 0);
1481 atomic_set(
1482 &this_adm.copp.app_type[i][j], 0);
1483 atomic_set(
1484 &this_adm.copp.acdb_id[i][j], 0);
1485 this_adm.copp.adm_status[i][j] =
1486 ADM_STATUS_CALIBRATION_REQUIRED;
1487 }
1488 }
1489 this_adm.apr = NULL;
1490 cal_utils_clear_cal_block_q6maps(ADM_MAX_CAL_TYPES,
1491 this_adm.cal_data);
1492 mutex_lock(&this_adm.cal_data
1493 [ADM_CUSTOM_TOP_CAL]->lock);
1494 this_adm.set_custom_topology = 1;
1495 mutex_unlock(&this_adm.cal_data[
1496 ADM_CUSTOM_TOP_CAL]->lock);
1497 rtac_clear_mapping(ADM_RTAC_CAL);
1498 /*
1499 * Free the ION memory and clear the map handles
1500 * for Source Tracking
1501 */
1502 if (this_adm.sourceTrackingData.memmap.paddr != 0) {
1503 msm_audio_ion_free(
1504 this_adm.sourceTrackingData.dma_buf);
1505 this_adm.sourceTrackingData.dma_buf = NULL;
1506 this_adm.sourceTrackingData.memmap.size = 0;
1507 this_adm.sourceTrackingData.memmap.kvaddr =
1508 NULL;
1509 this_adm.sourceTrackingData.memmap.paddr = 0;
1510 this_adm.sourceTrackingData.apr_cmd_status = -1;
1511 atomic_set(&this_adm.mem_map_handles[
1512 ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
1513 }
1514}
1515
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301516static int32_t adm_callback(struct apr_client_data *data, void *priv)
1517{
1518 uint32_t *payload;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001519 int port_idx, copp_idx, idx, client_id;
1520 int num_modules;
1521 int ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301522
1523 if (data == NULL) {
1524 pr_err("%s: data parameter is null\n", __func__);
1525 return -EINVAL;
1526 }
1527
1528 payload = data->payload;
1529
1530 if (data->opcode == RESET_EVENTS) {
1531 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1532 __func__,
1533 data->reset_event, data->reset_proc, this_adm.apr);
Laxminath Kasam30ad7512017-11-28 12:40:22 +05301534 if (this_adm.apr)
1535 adm_reset_data();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301536 return 0;
1537 }
1538
1539 adm_callback_debug_print(data);
1540 if (data->payload_size) {
1541 copp_idx = (data->token) & 0XFF;
1542 port_idx = ((data->token) >> 16) & 0xFF;
1543 client_id = ((data->token) >> 8) & 0xFF;
1544 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
1545 pr_err("%s: Invalid port idx %d token %d\n",
1546 __func__, port_idx, data->token);
1547 return 0;
1548 }
1549 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
1550 pr_err("%s: Invalid copp idx %d token %d\n",
1551 __func__, copp_idx, data->token);
1552 return 0;
1553 }
1554 if (client_id < 0 || client_id >= ADM_CLIENT_ID_MAX) {
1555 pr_err("%s: Invalid client id %d\n", __func__,
1556 client_id);
1557 return 0;
1558 }
1559 if (data->opcode == APR_BASIC_RSP_RESULT) {
1560 pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n",
1561 __func__, payload[0]);
1562 if (payload[1] != 0) {
1563 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
1564 __func__, payload[0], payload[1]);
1565 }
1566 switch (payload[0]) {
1567 case ADM_CMD_SET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001568 case ADM_CMD_SET_PP_PARAMS_V6:
1569 pr_debug("%s: ADM_CMD_SET_PP_PARAMS\n",
1570 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301571 if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
1572 this_adm.sourceTrackingData.
1573 apr_cmd_status = payload[1];
1574 else if (rtac_make_adm_callback(payload,
1575 data->payload_size))
1576 break;
1577 /*
1578 * if soft volume is called and already
1579 * interrupted break out of the sequence here
1580 */
1581 case ADM_CMD_DEVICE_OPEN_V5:
1582 case ADM_CMD_DEVICE_CLOSE_V5:
1583 case ADM_CMD_DEVICE_OPEN_V6:
1584 pr_debug("%s: Basic callback received, wake up.\n",
1585 __func__);
1586 atomic_set(&this_adm.copp.stat[port_idx]
1587 [copp_idx], payload[1]);
1588 wake_up(
1589 &this_adm.copp.wait[port_idx][copp_idx]);
1590 break;
1591 case ADM_CMD_ADD_TOPOLOGIES:
1592 pr_debug("%s: callback received, ADM_CMD_ADD_TOPOLOGIES.\n",
1593 __func__);
1594 atomic_set(&this_adm.adm_stat, payload[1]);
1595 wake_up(&this_adm.adm_wait);
1596 break;
1597 case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
1598 case ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5:
1599 pr_debug("%s: Basic callback received, wake up.\n",
1600 __func__);
1601 atomic_set(&this_adm.matrix_map_stat,
1602 payload[1]);
1603 wake_up(&this_adm.matrix_map_wait);
1604 break;
1605 case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
1606 pr_debug("%s: ADM_CMD_SHARED_MEM_UNMAP_REGIONS\n",
1607 __func__);
1608 atomic_set(&this_adm.adm_stat, payload[1]);
1609 wake_up(&this_adm.adm_wait);
1610 break;
1611 case ADM_CMD_SHARED_MEM_MAP_REGIONS:
1612 pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
1613 __func__);
1614 /* Should only come here if there is an APR */
1615 /* error or malformed APR packet. Otherwise */
1616 /* response will be returned as */
1617 if (payload[1] != 0) {
1618 pr_err("%s: ADM map error, resuming\n",
1619 __func__);
1620 atomic_set(&this_adm.adm_stat,
1621 payload[1]);
1622 wake_up(&this_adm.adm_wait);
1623 }
1624 break;
1625 case ADM_CMD_GET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001626 case ADM_CMD_GET_PP_PARAMS_V6:
1627 pr_debug("%s: ADM_CMD_GET_PP_PARAMS\n",
1628 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301629 /* Should only come here if there is an APR */
1630 /* error or malformed APR packet. Otherwise */
1631 /* response will be returned as */
1632 /* ADM_CMDRSP_GET_PP_PARAMS_V5 */
1633 if (client_id ==
1634 ADM_CLIENT_ID_SOURCE_TRACKING) {
1635 this_adm.sourceTrackingData.
1636 apr_cmd_status = payload[1];
1637 if (payload[1] != 0)
1638 pr_err("%s: ADM get param error = %d\n",
1639 __func__, payload[1]);
1640
1641 atomic_set(&this_adm.copp.stat
1642 [port_idx][copp_idx],
1643 payload[1]);
1644 wake_up(&this_adm.copp.wait
1645 [port_idx][copp_idx]);
1646 } else {
1647 if (payload[1] != 0) {
1648 pr_err("%s: ADM get param error = %d, resuming\n",
1649 __func__, payload[1]);
1650
1651 rtac_make_adm_callback(payload,
1652 data->payload_size);
1653 }
1654 }
1655 break;
1656 case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5:
Bhalchandra Gajareeed46bd2018-05-15 16:48:07 -07001657 case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V6:
1658 pr_debug("%s:callback received PSPD MTMX, wake up\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301659 __func__);
1660 atomic_set(&this_adm.copp.stat[port_idx]
1661 [copp_idx], payload[1]);
1662 wake_up(
1663 &this_adm.copp.wait[port_idx][copp_idx]);
1664 break;
1665 case ADM_CMD_GET_PP_TOPO_MODULE_LIST:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001666 case ADM_CMD_GET_PP_TOPO_MODULE_LIST_V2:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301667 pr_debug("%s:ADM_CMD_GET_PP_TOPO_MODULE_LIST\n",
1668 __func__);
1669 if (payload[1] != 0)
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001670 pr_err("%s: ADM get topo list error = %d\n",
1671 __func__, payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301672 break;
1673 default:
1674 pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
1675 payload[0]);
1676 break;
1677 }
1678 return 0;
1679 }
1680
1681 switch (data->opcode) {
1682 case ADM_CMDRSP_DEVICE_OPEN_V5:
1683 case ADM_CMDRSP_DEVICE_OPEN_V6: {
1684 struct adm_cmd_rsp_device_open_v5 *open =
1685 (struct adm_cmd_rsp_device_open_v5 *)data->payload;
1686
1687 if (open->copp_id == INVALID_COPP_ID) {
1688 pr_err("%s: invalid coppid rxed %d\n",
1689 __func__, open->copp_id);
1690 atomic_set(&this_adm.copp.stat[port_idx]
1691 [copp_idx], ADSP_EBADPARAM);
1692 wake_up(
1693 &this_adm.copp.wait[port_idx][copp_idx]);
1694 break;
1695 }
1696 atomic_set(&this_adm.copp.stat
1697 [port_idx][copp_idx], payload[0]);
1698 atomic_set(&this_adm.copp.id[port_idx][copp_idx],
1699 open->copp_id);
1700 pr_debug("%s: coppid rxed=%d\n", __func__,
1701 open->copp_id);
1702 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1703 }
1704 break;
1705 case ADM_CMDRSP_GET_PP_PARAMS_V5:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001706 case ADM_CMDRSP_GET_PP_PARAMS_V6:
1707 pr_debug("%s: ADM_CMDRSP_GET_PP_PARAMS\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301708 if (client_id == ADM_CLIENT_ID_SOURCE_TRACKING)
1709 this_adm.sourceTrackingData.apr_cmd_status =
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001710 payload[0];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301711 else if (rtac_make_adm_callback(payload,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001712 data->payload_size))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301713 break;
1714
1715 idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001716 if (payload[0] == 0 && data->payload_size > 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001717 ret = adm_process_get_param_response(
1718 data->opcode, idx, payload,
1719 data->payload_size);
1720 if (ret)
1721 pr_err("%s: Failed to process get param response, error %d\n",
1722 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301723 } else {
1724 adm_get_parameters[idx] = -1;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001725 pr_err("%s: ADM_CMDRSP_GET_PP_PARAMS returned error 0x%x\n",
1726 __func__, payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301727 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001728 atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
1729 payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301730 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1731 break;
1732 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST:
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001733 case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301734 pr_debug("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST\n",
1735 __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001736 num_modules = payload[1];
1737 pr_debug("%s: Num modules %d\n", __func__, num_modules);
1738 if (payload[0]) {
1739 pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST, error = %d\n",
1740 __func__, payload[0]);
1741 } else if (num_modules > MAX_MODULES_IN_TOPO) {
1742 pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST invalid num modules received, num modules = %d\n",
1743 __func__, num_modules);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301744 } else {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001745 ret = adm_process_get_topo_list_response(
1746 data->opcode, copp_idx, num_modules,
1747 payload, data->payload_size);
1748 if (ret)
1749 pr_err("%s: Failed to process get topo modules list response, error %d\n",
1750 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301751 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08001752 atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
1753 payload[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301754 wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
1755 break;
1756 case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
1757 pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
1758 __func__);
1759 atomic_set(&this_adm.mem_map_handles[
1760 atomic_read(&this_adm.mem_map_index)],
1761 *payload);
1762 atomic_set(&this_adm.adm_stat, 0);
1763 wake_up(&this_adm.adm_wait);
1764 break;
1765 default:
1766 pr_err("%s: Unknown cmd:0x%x\n", __func__,
1767 data->opcode);
1768 break;
1769 }
1770 }
1771 return 0;
1772}
1773
1774static int adm_memory_map_regions(phys_addr_t *buf_add, uint32_t mempool_id,
1775 uint32_t *bufsz, uint32_t bufcnt)
1776{
1777 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
1778 struct avs_shared_map_region_payload *mregions = NULL;
1779 void *mmap_region_cmd = NULL;
1780 void *payload = NULL;
1781 int ret = 0;
1782 int i = 0;
1783 int cmd_size = 0;
1784
1785 pr_debug("%s:\n", __func__);
1786 if (this_adm.apr == NULL) {
1787 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
1788 0xFFFFFFFF, &this_adm);
1789 if (this_adm.apr == NULL) {
1790 pr_err("%s: Unable to register ADM\n", __func__);
1791 ret = -ENODEV;
1792 return ret;
1793 }
1794 rtac_set_adm_handle(this_adm.apr);
1795 }
1796
1797 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
1798 + sizeof(struct avs_shared_map_region_payload)
1799 * bufcnt;
1800
1801 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
1802 if (!mmap_region_cmd)
1803 return -ENOMEM;
1804
1805 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
1806 mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1807 APR_HDR_LEN(APR_HDR_SIZE),
1808 APR_PKT_VER);
1809 mmap_regions->hdr.pkt_size = cmd_size;
1810 mmap_regions->hdr.src_port = 0;
1811
1812 mmap_regions->hdr.dest_port = 0;
1813 mmap_regions->hdr.token = 0;
1814 mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
1815 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
1816 mmap_regions->num_regions = bufcnt & 0x00ff;
1817 mmap_regions->property_flag = 0x00;
1818
1819 pr_debug("%s: map_regions->num_regions = %d\n", __func__,
1820 mmap_regions->num_regions);
1821 payload = ((u8 *) mmap_region_cmd +
1822 sizeof(struct avs_cmd_shared_mem_map_regions));
1823 mregions = (struct avs_shared_map_region_payload *)payload;
1824
1825 for (i = 0; i < bufcnt; i++) {
1826 mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
1827 mregions->shm_addr_msw =
1828 msm_audio_populate_upper_32_bits(buf_add[i]);
1829 mregions->mem_size_bytes = bufsz[i];
1830 ++mregions;
1831 }
1832
1833 atomic_set(&this_adm.adm_stat, -1);
1834 ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
1835 if (ret < 0) {
1836 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
1837 mmap_regions->hdr.opcode, ret);
1838 ret = -EINVAL;
1839 goto fail_cmd;
1840 }
1841
1842 ret = wait_event_timeout(this_adm.adm_wait,
1843 atomic_read(&this_adm.adm_stat) >= 0,
1844 5 * HZ);
1845 if (!ret) {
1846 pr_err("%s: timeout. waited for memory_map\n", __func__);
1847 ret = -EINVAL;
1848 goto fail_cmd;
1849 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1850 pr_err("%s: DSP returned error[%s]\n",
1851 __func__, adsp_err_get_err_str(
1852 atomic_read(&this_adm.adm_stat)));
1853 ret = adsp_err_get_lnx_err_code(
1854 atomic_read(&this_adm.adm_stat));
1855 goto fail_cmd;
1856 }
1857fail_cmd:
1858 kfree(mmap_region_cmd);
1859 return ret;
1860}
1861
1862static int adm_memory_unmap_regions(void)
1863{
1864 struct avs_cmd_shared_mem_unmap_regions unmap_regions;
1865 int ret = 0;
1866
1867 pr_debug("%s:\n", __func__);
1868 if (this_adm.apr == NULL) {
1869 pr_err("%s: APR handle NULL\n", __func__);
1870 return -EINVAL;
1871 }
1872
1873 unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1874 APR_HDR_LEN(APR_HDR_SIZE),
1875 APR_PKT_VER);
1876 unmap_regions.hdr.pkt_size = sizeof(unmap_regions);
1877 unmap_regions.hdr.src_port = 0;
1878 unmap_regions.hdr.dest_port = 0;
1879 unmap_regions.hdr.token = 0;
1880 unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
1881 unmap_regions.mem_map_handle = atomic_read(&this_adm.
1882 mem_map_handles[atomic_read(&this_adm.mem_map_index)]);
1883 atomic_set(&this_adm.adm_stat, -1);
1884 ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
1885 if (ret < 0) {
1886 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
1887 unmap_regions.hdr.opcode, ret);
1888 ret = -EINVAL;
1889 goto fail_cmd;
1890 }
1891
1892 ret = wait_event_timeout(this_adm.adm_wait,
1893 atomic_read(&this_adm.adm_stat) >= 0,
1894 5 * HZ);
1895 if (!ret) {
1896 pr_err("%s: timeout. waited for memory_unmap\n",
1897 __func__);
1898 ret = -EINVAL;
1899 goto fail_cmd;
1900 } else if (atomic_read(&this_adm.adm_stat) > 0) {
1901 pr_err("%s: DSP returned error[%s]\n",
1902 __func__, adsp_err_get_err_str(
1903 atomic_read(&this_adm.adm_stat)));
1904 ret = adsp_err_get_lnx_err_code(
1905 atomic_read(&this_adm.adm_stat));
1906 goto fail_cmd;
1907 } else {
1908 pr_debug("%s: Unmap handle 0x%x succeeded\n", __func__,
1909 unmap_regions.mem_map_handle);
1910 }
1911fail_cmd:
1912 return ret;
1913}
1914
1915static int remap_cal_data(struct cal_block_data *cal_block, int cal_index)
1916{
1917 int ret = 0;
1918
Banajit Goswami08bb7362017-11-03 22:48:23 -07001919 if (cal_block->map_data.dma_buf == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301920 pr_err("%s: No ION allocation for cal index %d!\n",
1921 __func__, cal_index);
1922 ret = -EINVAL;
1923 goto done;
1924 }
1925
1926 if ((cal_block->map_data.map_size > 0) &&
1927 (cal_block->map_data.q6map_handle == 0)) {
1928 atomic_set(&this_adm.mem_map_index, cal_index);
1929 ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
1930 (uint32_t *)&cal_block->map_data.map_size, 1);
1931 if (ret < 0) {
1932 pr_err("%s: ADM mmap did not work! size = %zd ret %d\n",
1933 __func__,
1934 cal_block->map_data.map_size, ret);
1935 pr_debug("%s: ADM mmap did not work! addr = 0x%pK, size = %zd ret %d\n",
1936 __func__,
1937 &cal_block->cal_data.paddr,
1938 cal_block->map_data.map_size, ret);
1939 goto done;
1940 }
1941 cal_block->map_data.q6map_handle = atomic_read(&this_adm.
1942 mem_map_handles[cal_index]);
1943 }
1944done:
1945 return ret;
1946}
1947
1948static void send_adm_custom_topology(void)
1949{
1950 struct cal_block_data *cal_block = NULL;
1951 struct cmd_set_topologies adm_top;
1952 int cal_index = ADM_CUSTOM_TOP_CAL;
1953 int result;
1954
1955 if (this_adm.cal_data[cal_index] == NULL)
1956 goto done;
1957
1958 mutex_lock(&this_adm.cal_data[cal_index]->lock);
1959 if (!this_adm.set_custom_topology)
1960 goto unlock;
1961 this_adm.set_custom_topology = 0;
1962
1963 cal_block = cal_utils_get_only_cal_block(this_adm.cal_data[cal_index]);
Vikram Panduranga770b8382017-09-27 12:17:36 -07001964 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301965 goto unlock;
1966
1967 pr_debug("%s: Sending cal_index %d\n", __func__, cal_index);
1968
1969 result = remap_cal_data(cal_block, cal_index);
1970 if (result) {
1971 pr_err("%s: Remap_cal_data failed for cal %d!\n",
1972 __func__, cal_index);
1973 goto unlock;
1974 }
1975 atomic_set(&this_adm.mem_map_index, cal_index);
1976 atomic_set(&this_adm.mem_map_handles[cal_index],
1977 cal_block->map_data.q6map_handle);
1978
1979 if (cal_block->cal_data.size == 0) {
1980 pr_debug("%s: No ADM cal to send\n", __func__);
1981 goto unlock;
1982 }
1983
1984 adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1985 APR_HDR_LEN(20), APR_PKT_VER);
1986 adm_top.hdr.pkt_size = sizeof(adm_top);
1987 adm_top.hdr.src_svc = APR_SVC_ADM;
1988 adm_top.hdr.src_domain = APR_DOMAIN_APPS;
1989 adm_top.hdr.src_port = 0;
1990 adm_top.hdr.dest_svc = APR_SVC_ADM;
1991 adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
1992 adm_top.hdr.dest_port = 0;
1993 adm_top.hdr.token = 0;
1994 adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
1995 adm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
1996 adm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
1997 cal_block->cal_data.paddr);
1998 adm_top.mem_map_handle = cal_block->map_data.q6map_handle;
1999 adm_top.payload_size = cal_block->cal_data.size;
2000
2001 atomic_set(&this_adm.adm_stat, -1);
2002 pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%pK, size = %d\n",
2003 __func__, &cal_block->cal_data.paddr,
2004 adm_top.payload_size);
2005 result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
2006 if (result < 0) {
2007 pr_err("%s: Set topologies failed payload size = %zd result %d\n",
2008 __func__, cal_block->cal_data.size, result);
2009 goto unlock;
2010 }
2011 /* Wait for the callback */
2012 result = wait_event_timeout(this_adm.adm_wait,
2013 atomic_read(&this_adm.adm_stat) >= 0,
2014 msecs_to_jiffies(TIMEOUT_MS));
2015 if (!result) {
2016 pr_err("%s: Set topologies timed out payload size = %zd\n",
2017 __func__, cal_block->cal_data.size);
2018 goto unlock;
2019 } else if (atomic_read(&this_adm.adm_stat) > 0) {
2020 pr_err("%s: DSP returned error[%s]\n",
2021 __func__, adsp_err_get_err_str(
2022 atomic_read(&this_adm.adm_stat)));
2023 result = adsp_err_get_lnx_err_code(
2024 atomic_read(&this_adm.adm_stat));
2025 goto unlock;
2026 }
2027unlock:
2028 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
2029done:
2030 return;
2031}
2032
2033static int send_adm_cal_block(int port_id, int copp_idx,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002034 struct cal_block_data *cal_block, int perf_mode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302035{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002036 struct mem_mapping_hdr mem_hdr;
2037 int payload_size = 0;
2038 int port_idx = 0;
2039 int topology = 0;
2040 int result = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302041
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002042 pr_debug("%s: Port id 0x%x,\n", __func__, port_id);
2043
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302044 if (!cal_block) {
2045 pr_debug("%s: No ADM cal to send for port_id = 0x%x!\n",
2046 __func__, port_id);
2047 result = -EINVAL;
2048 goto done;
2049 }
2050 if (cal_block->cal_data.size <= 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002051 pr_debug("%s: No ADM cal sent for port_id = 0x%x!\n", __func__,
2052 port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302053 result = -EINVAL;
2054 goto done;
2055 }
2056
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002057 memset(&mem_hdr, 0, sizeof(mem_hdr));
2058 port_id = afe_convert_virtual_to_portid(port_id);
2059 port_idx = adm_validate_and_get_port_index(port_id);
2060 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
2061 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2062 return -EINVAL;
2063 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
2064 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
2065 return -EINVAL;
2066 }
2067
2068 topology = atomic_read(&this_adm.copp.topology[port_idx][copp_idx]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302069 if (perf_mode == LEGACY_PCM_MODE &&
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002070 topology == DS2_ADM_COPP_TOPOLOGY_ID) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302071 pr_err("%s: perf_mode %d, topology 0x%x\n", __func__, perf_mode,
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002072 topology);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302073 goto done;
2074 }
2075
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002076 mem_hdr.data_payload_addr_lsw =
2077 lower_32_bits(cal_block->cal_data.paddr);
2078 mem_hdr.data_payload_addr_msw =
2079 msm_audio_populate_upper_32_bits(cal_block->cal_data.paddr);
2080 mem_hdr.mem_map_handle = cal_block->map_data.q6map_handle;
2081 payload_size = cal_block->cal_data.size;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302082
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002083 adm_set_pp_params(port_id, copp_idx, &mem_hdr, NULL, payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302084
2085done:
2086 return result;
2087}
2088
2089static struct cal_block_data *adm_find_cal_by_path(int cal_index, int path)
2090{
2091 struct list_head *ptr, *next;
2092 struct cal_block_data *cal_block = NULL;
2093 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2094 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2095
2096 pr_debug("%s:\n", __func__);
2097
2098 list_for_each_safe(ptr, next,
2099 &this_adm.cal_data[cal_index]->cal_blocks) {
2100
2101 cal_block = list_entry(ptr,
2102 struct cal_block_data, list);
2103
Vikram Panduranga770b8382017-09-27 12:17:36 -07002104 if (cal_utils_is_cal_stale(cal_block))
2105 continue;
2106
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302107 if (cal_index == ADM_AUDPROC_CAL ||
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002108 cal_index == ADM_LSM_AUDPROC_CAL ||
2109 cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302110 audproc_cal_info = cal_block->cal_info;
2111 if ((audproc_cal_info->path == path) &&
2112 (cal_block->cal_data.size > 0))
2113 return cal_block;
2114 } else if (cal_index == ADM_AUDVOL_CAL) {
2115 audvol_cal_info = cal_block->cal_info;
2116 if ((audvol_cal_info->path == path) &&
2117 (cal_block->cal_data.size > 0))
2118 return cal_block;
2119 }
2120 }
2121 pr_debug("%s: Can't find ADM cal for cal_index %d, path %d\n",
2122 __func__, cal_index, path);
2123 return NULL;
2124}
2125
2126static struct cal_block_data *adm_find_cal_by_app_type(int cal_index, int path,
2127 int app_type)
2128{
2129 struct list_head *ptr, *next;
2130 struct cal_block_data *cal_block = NULL;
2131 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2132 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2133
2134 pr_debug("%s\n", __func__);
2135
2136 list_for_each_safe(ptr, next,
2137 &this_adm.cal_data[cal_index]->cal_blocks) {
2138
2139 cal_block = list_entry(ptr,
2140 struct cal_block_data, list);
2141
Vikram Panduranga770b8382017-09-27 12:17:36 -07002142 if (cal_utils_is_cal_stale(cal_block))
2143 continue;
2144
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302145 if (cal_index == ADM_AUDPROC_CAL ||
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002146 cal_index == ADM_LSM_AUDPROC_CAL ||
2147 cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302148 audproc_cal_info = cal_block->cal_info;
2149 if ((audproc_cal_info->path == path) &&
2150 (audproc_cal_info->app_type == app_type) &&
2151 (cal_block->cal_data.size > 0))
2152 return cal_block;
2153 } else if (cal_index == ADM_AUDVOL_CAL) {
2154 audvol_cal_info = cal_block->cal_info;
2155 if ((audvol_cal_info->path == path) &&
2156 (audvol_cal_info->app_type == app_type) &&
2157 (cal_block->cal_data.size > 0))
2158 return cal_block;
2159 }
2160 }
2161 pr_debug("%s: Can't find ADM cali for cal_index %d, path %d, app %d, defaulting to search by path\n",
2162 __func__, cal_index, path, app_type);
2163 return adm_find_cal_by_path(cal_index, path);
2164}
2165
2166
2167static struct cal_block_data *adm_find_cal(int cal_index, int path,
2168 int app_type, int acdb_id,
2169 int sample_rate)
2170{
2171 struct list_head *ptr, *next;
2172 struct cal_block_data *cal_block = NULL;
2173 struct audio_cal_info_audproc *audproc_cal_info = NULL;
2174 struct audio_cal_info_audvol *audvol_cal_info = NULL;
2175
2176 pr_debug("%s:\n", __func__);
2177
2178 list_for_each_safe(ptr, next,
2179 &this_adm.cal_data[cal_index]->cal_blocks) {
2180
2181 cal_block = list_entry(ptr,
2182 struct cal_block_data, list);
Vikram Panduranga770b8382017-09-27 12:17:36 -07002183 if (cal_utils_is_cal_stale(cal_block))
2184 continue;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302185
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302186 if (cal_index == ADM_AUDPROC_CAL ||
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002187 cal_index == ADM_LSM_AUDPROC_CAL ||
2188 cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302189 audproc_cal_info = cal_block->cal_info;
2190 if ((audproc_cal_info->path == path) &&
2191 (audproc_cal_info->app_type == app_type) &&
2192 (audproc_cal_info->acdb_id == acdb_id) &&
2193 (audproc_cal_info->sample_rate == sample_rate) &&
2194 (cal_block->cal_data.size > 0))
2195 return cal_block;
2196 } else if (cal_index == ADM_AUDVOL_CAL) {
2197 audvol_cal_info = cal_block->cal_info;
2198 if ((audvol_cal_info->path == path) &&
2199 (audvol_cal_info->app_type == app_type) &&
2200 (audvol_cal_info->acdb_id == acdb_id) &&
2201 (cal_block->cal_data.size > 0))
2202 return cal_block;
2203 }
2204 }
2205 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",
2206 __func__, cal_index, path, app_type, acdb_id, sample_rate);
2207 return adm_find_cal_by_app_type(cal_index, path, app_type);
2208}
2209
2210static int adm_remap_and_send_cal_block(int cal_index, int port_id,
2211 int copp_idx, struct cal_block_data *cal_block, int perf_mode,
2212 int app_type, int acdb_id, int sample_rate)
2213{
2214 int ret = 0;
2215
2216 pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
2217 ret = remap_cal_data(cal_block, cal_index);
2218 if (ret) {
2219 pr_err("%s: Remap_cal_data failed for cal %d!\n",
2220 __func__, cal_index);
2221 goto done;
2222 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002223 ret = send_adm_cal_block(port_id, copp_idx, cal_block, perf_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302224 if (ret < 0)
2225 pr_debug("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d sample_rate %d\n",
2226 __func__, cal_index, port_id, ret, sample_rate);
2227done:
2228 return ret;
2229}
2230
2231static void send_adm_cal_type(int cal_index, int path, int port_id,
2232 int copp_idx, int perf_mode, int app_type,
2233 int acdb_id, int sample_rate)
2234{
2235 struct cal_block_data *cal_block = NULL;
2236 int ret;
2237
2238 pr_debug("%s: cal index %d\n", __func__, cal_index);
2239
2240 if (this_adm.cal_data[cal_index] == NULL) {
2241 pr_debug("%s: cal_index %d not allocated!\n",
2242 __func__, cal_index);
2243 goto done;
2244 }
2245
2246 mutex_lock(&this_adm.cal_data[cal_index]->lock);
2247 cal_block = adm_find_cal(cal_index, path, app_type, acdb_id,
2248 sample_rate);
2249 if (cal_block == NULL)
2250 goto unlock;
2251
2252 ret = adm_remap_and_send_cal_block(cal_index, port_id, copp_idx,
2253 cal_block, perf_mode, app_type, acdb_id, sample_rate);
Vikram Panduranga770b8382017-09-27 12:17:36 -07002254
2255 cal_utils_mark_cal_used(cal_block);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302256unlock:
2257 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
2258done:
2259 return;
2260}
2261
2262static int get_cal_path(int path)
2263{
2264 if (path == 0x1)
2265 return RX_DEVICE;
2266 else
2267 return TX_DEVICE;
2268}
2269
2270static void send_adm_cal(int port_id, int copp_idx, int path, int perf_mode,
Aditya Bavanari5106b562018-01-08 13:16:32 +05302271 int app_type, int acdb_id, int sample_rate,
2272 int passthr_mode)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302273{
2274 pr_debug("%s: port id 0x%x copp_idx %d\n", __func__, port_id, copp_idx);
2275
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002276 if (passthr_mode != LISTEN) {
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302277 send_adm_cal_type(ADM_AUDPROC_CAL, path, port_id, copp_idx,
2278 perf_mode, app_type, acdb_id, sample_rate);
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002279 } else {
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05302280 send_adm_cal_type(ADM_LSM_AUDPROC_CAL, path, port_id, copp_idx,
2281 perf_mode, app_type, acdb_id, sample_rate);
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07002282
2283 send_adm_cal_type(ADM_LSM_AUDPROC_PERSISTENT_CAL, path,
2284 port_id, copp_idx, perf_mode, app_type,
2285 acdb_id, sample_rate);
2286 }
2287
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302288 send_adm_cal_type(ADM_AUDVOL_CAL, path, port_id, copp_idx, perf_mode,
2289 app_type, acdb_id, sample_rate);
2290}
2291
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302292/**
2293 * adm_connect_afe_port -
2294 * command to send ADM connect AFE port
2295 *
2296 * @mode: value of mode for ADM connect AFE
2297 * @session_id: session active to connect
2298 * @port_id: Port ID number
2299 *
2300 * Returns 0 on success or error on failure
2301 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302302int adm_connect_afe_port(int mode, int session_id, int port_id)
2303{
2304 struct adm_cmd_connect_afe_port_v5 cmd;
2305 int ret = 0;
2306 int port_idx, copp_idx = 0;
2307
2308 pr_debug("%s: port_id: 0x%x session id:%d mode:%d\n", __func__,
2309 port_id, session_id, mode);
2310
2311 port_id = afe_convert_virtual_to_portid(port_id);
2312 port_idx = adm_validate_and_get_port_index(port_id);
2313 if (port_idx < 0) {
2314 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2315 return -EINVAL;
2316 }
2317
2318 if (this_adm.apr == NULL) {
2319 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
2320 0xFFFFFFFF, &this_adm);
2321 if (this_adm.apr == NULL) {
2322 pr_err("%s: Unable to register ADM\n", __func__);
2323 ret = -ENODEV;
2324 return ret;
2325 }
2326 rtac_set_adm_handle(this_adm.apr);
2327 }
2328 pr_debug("%s: Port ID 0x%x, index %d\n", __func__, port_id, port_idx);
2329
2330 cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2331 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2332 cmd.hdr.pkt_size = sizeof(cmd);
2333 cmd.hdr.src_svc = APR_SVC_ADM;
2334 cmd.hdr.src_domain = APR_DOMAIN_APPS;
2335 cmd.hdr.src_port = port_id;
2336 cmd.hdr.dest_svc = APR_SVC_ADM;
2337 cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
2338 cmd.hdr.dest_port = 0; /* Ignored */
2339 cmd.hdr.token = port_idx << 16 | copp_idx;
2340 cmd.hdr.opcode = ADM_CMD_CONNECT_AFE_PORT_V5;
2341
2342 cmd.mode = mode;
2343 cmd.session_id = session_id;
2344 cmd.afe_port_id = port_id;
2345
2346 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2347 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
2348 if (ret < 0) {
2349 pr_err("%s: ADM enable for port_id: 0x%x failed ret %d\n",
2350 __func__, port_id, ret);
2351 ret = -EINVAL;
2352 goto fail_cmd;
2353 }
2354 /* Wait for the callback with copp id */
2355 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
2356 atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
2357 msecs_to_jiffies(TIMEOUT_MS));
2358 if (!ret) {
2359 pr_err("%s: ADM connect timedout for port_id: 0x%x\n",
2360 __func__, port_id);
2361 ret = -EINVAL;
2362 goto fail_cmd;
2363 } else if (atomic_read(&this_adm.copp.stat
2364 [port_idx][copp_idx]) > 0) {
2365 pr_err("%s: DSP returned error[%s]\n",
2366 __func__, adsp_err_get_err_str(
2367 atomic_read(&this_adm.copp.stat
2368 [port_idx][copp_idx])));
2369 ret = adsp_err_get_lnx_err_code(
2370 atomic_read(&this_adm.copp.stat
2371 [port_idx][copp_idx]));
2372 goto fail_cmd;
2373 }
2374 atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
2375 return 0;
2376
2377fail_cmd:
2378
2379 return ret;
2380}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302381EXPORT_SYMBOL(adm_connect_afe_port);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302382
2383int adm_arrange_mch_map(struct adm_cmd_device_open_v5 *open, int path,
2384 int channel_mode)
2385{
2386 int rc = 0, idx;
2387
Bhalchandra Gajareeed46bd2018-05-15 16:48:07 -07002388 pr_debug("%s: channel mode %d", __func__, channel_mode);
2389
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302390 memset(open->dev_channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
2391 switch (path) {
2392 case ADM_PATH_PLAYBACK:
2393 idx = ADM_MCH_MAP_IDX_PLAYBACK;
2394 break;
2395 case ADM_PATH_LIVE_REC:
2396 case ADM_PATH_NONLIVE_REC:
2397 idx = ADM_MCH_MAP_IDX_REC;
2398 break;
2399 default:
2400 goto non_mch_path;
2401 };
2402 if ((open->dev_num_channel > 2) && multi_ch_maps[idx].set_channel_map) {
2403 memcpy(open->dev_channel_mapping,
2404 multi_ch_maps[idx].channel_mapping,
2405 PCM_FORMAT_MAX_NUM_CHANNEL);
2406 } else {
2407 if (channel_mode == 1) {
2408 open->dev_channel_mapping[0] = PCM_CHANNEL_FC;
2409 } else if (channel_mode == 2) {
2410 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2411 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2412 } else if (channel_mode == 3) {
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_FC;
2416 } else if (channel_mode == 4) {
2417 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2418 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2419 open->dev_channel_mapping[2] = PCM_CHANNEL_LS;
2420 open->dev_channel_mapping[3] = PCM_CHANNEL_RS;
2421 } else if (channel_mode == 5) {
2422 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2423 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2424 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2425 open->dev_channel_mapping[3] = PCM_CHANNEL_LS;
2426 open->dev_channel_mapping[4] = PCM_CHANNEL_RS;
2427 } else if (channel_mode == 6) {
2428 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2429 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2430 open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
2431 open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
2432 open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
2433 open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
2434 } else if (channel_mode == 7) {
2435 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2436 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2437 open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
2438 open->dev_channel_mapping[3] = PCM_CHANNEL_LFE;
2439 open->dev_channel_mapping[4] = PCM_CHANNEL_LB;
2440 open->dev_channel_mapping[5] = PCM_CHANNEL_RB;
2441 open->dev_channel_mapping[6] = PCM_CHANNEL_CS;
2442 } else if (channel_mode == 8) {
2443 open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
2444 open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
2445 open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
2446 open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
2447 open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
2448 open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
2449 open->dev_channel_mapping[6] = PCM_CHANNEL_LB;
2450 open->dev_channel_mapping[7] = PCM_CHANNEL_RB;
2451 } else {
2452 pr_err("%s: invalid num_chan %d\n", __func__,
2453 channel_mode);
2454 rc = -EINVAL;
2455 goto inval_ch_mod;
2456 }
2457 }
2458
2459non_mch_path:
2460inval_ch_mod:
2461 return rc;
2462}
2463
2464int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
2465 int channel_mode)
2466{
2467 int rc = 0;
2468
2469 memset(open_v6->dev_channel_mapping_eid2, 0,
2470 PCM_FORMAT_MAX_NUM_CHANNEL);
2471
2472 if (channel_mode == 1) {
2473 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FC;
2474 } else if (channel_mode == 2) {
2475 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2476 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2477 } else if (channel_mode == 3) {
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_FC;
2481 } else if (channel_mode == 4) {
2482 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2483 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2484 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LS;
2485 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_RS;
2486 } else if (channel_mode == 5) {
2487 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2488 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2489 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
2490 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_LS;
2491 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_RS;
2492 } else if (channel_mode == 6) {
2493 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2494 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2495 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
2496 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
2497 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
2498 open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
2499 } else if (channel_mode == 8) {
2500 open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
2501 open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
2502 open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
2503 open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
2504 open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
2505 open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
2506 open_v6->dev_channel_mapping_eid2[6] = PCM_CHANNEL_LB;
2507 open_v6->dev_channel_mapping_eid2[7] = PCM_CHANNEL_RB;
2508 } else {
2509 pr_err("%s: invalid num_chan %d\n", __func__,
2510 channel_mode);
2511 rc = -EINVAL;
2512 }
2513
2514 return rc;
2515}
2516
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302517/**
2518 * adm_open -
2519 * command to send ADM open
2520 *
2521 * @port_id: port id number
2522 * @path: direction or ADM path type
2523 * @rate: sample rate of session
2524 * @channel_mode: number of channels set
2525 * @topology: topology active for this session
2526 * @perf_mode: performance mode like LL/ULL/..
2527 * @bit_width: bit width to set for copp
2528 * @app_type: App type used for this session
2529 * @acdb_id: ACDB ID of this device
2530 *
2531 * Returns 0 on success or error on failure
2532 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302533int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
2534 int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
2535{
2536 struct adm_cmd_device_open_v5 open;
2537 struct adm_cmd_device_open_v6 open_v6;
2538 int ret = 0;
Asish Bhattacharya34504582017-08-08 12:55:01 +05302539 int port_idx, flags;
2540 int copp_idx = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302541 int tmp_port = q6audio_get_port_id(port_id);
2542
2543 pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n",
2544 __func__, port_id, path, rate, channel_mode, perf_mode,
2545 topology);
2546
2547 port_id = q6audio_convert_virtual_to_portid(port_id);
2548 port_idx = adm_validate_and_get_port_index(port_id);
2549 if (port_idx < 0) {
2550 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
2551 return -EINVAL;
2552 }
2553
2554 if (this_adm.apr == NULL) {
2555 this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
2556 0xFFFFFFFF, &this_adm);
2557 if (this_adm.apr == NULL) {
2558 pr_err("%s: Unable to register ADM\n", __func__);
2559 return -ENODEV;
2560 }
2561 rtac_set_adm_handle(this_adm.apr);
2562 }
2563
2564 if (perf_mode == ULL_POST_PROCESSING_PCM_MODE) {
2565 flags = ADM_ULL_POST_PROCESSING_DEVICE_SESSION;
2566 if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
2567 (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
2568 (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
2569 topology = DEFAULT_COPP_TOPOLOGY;
2570 } else if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
2571 flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
2572 topology = NULL_COPP_TOPOLOGY;
2573 rate = ULL_SUPPORTED_SAMPLE_RATE;
2574 bit_width = ULL_SUPPORTED_BITS_PER_SAMPLE;
2575 } else if (perf_mode == LOW_LATENCY_PCM_MODE) {
2576 flags = ADM_LOW_LATENCY_DEVICE_SESSION;
2577 if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
2578 (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
2579 (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
2580 topology = DEFAULT_COPP_TOPOLOGY;
2581 } else {
2582 if ((path == ADM_PATH_COMPRESSED_RX) ||
2583 (path == ADM_PATH_COMPRESSED_TX))
2584 flags = 0;
2585 else
2586 flags = ADM_LEGACY_DEVICE_SESSION;
2587 }
2588
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +05302589 if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302590 (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
2591 (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
2592 rate = 16000;
2593
Asish Bhattacharya34504582017-08-08 12:55:01 +05302594 /*
2595 * Routing driver reuses the same adm for streams with the same
2596 * app_type, sample_rate etc.
2597 * This isn't allowed for ULL streams as per the DSP interface
2598 */
2599 if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE)
2600 copp_idx = adm_get_idx_if_copp_exists(port_idx, topology,
2601 perf_mode,
2602 rate, bit_width,
2603 app_type);
2604
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302605 if (copp_idx < 0) {
2606 copp_idx = adm_get_next_available_copp(port_idx);
2607 if (copp_idx >= MAX_COPPS_PER_PORT) {
2608 pr_err("%s: exceeded copp id %d\n",
2609 __func__, copp_idx);
2610 return -EINVAL;
2611 }
2612 atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
2613 atomic_set(&this_adm.copp.topology[port_idx][copp_idx],
2614 topology);
2615 atomic_set(&this_adm.copp.mode[port_idx][copp_idx],
2616 perf_mode);
2617 atomic_set(&this_adm.copp.rate[port_idx][copp_idx],
2618 rate);
2619 atomic_set(&this_adm.copp.channels[port_idx][copp_idx],
2620 channel_mode);
2621 atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx],
2622 bit_width);
2623 atomic_set(&this_adm.copp.app_type[port_idx][copp_idx],
2624 app_type);
2625 atomic_set(&this_adm.copp.acdb_id[port_idx][copp_idx],
2626 acdb_id);
2627 set_bit(ADM_STATUS_CALIBRATION_REQUIRED,
2628 (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
2629 if ((path != ADM_PATH_COMPRESSED_RX) &&
2630 (path != ADM_PATH_COMPRESSED_TX))
2631 send_adm_custom_topology();
2632 }
2633
2634 if (this_adm.copp.adm_delay[port_idx][copp_idx] &&
2635 perf_mode == LEGACY_PCM_MODE) {
2636 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
2637 1);
2638 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
2639 wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
2640 }
2641
2642 /* Create a COPP if port id are not enabled */
2643 if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) {
2644 pr_debug("%s: open ADM: port_idx: %d, copp_idx: %d\n", __func__,
2645 port_idx, copp_idx);
2646 if ((topology == SRS_TRUMEDIA_TOPOLOGY_ID) &&
2647 perf_mode == LEGACY_PCM_MODE) {
2648 int res;
2649
2650 atomic_set(&this_adm.mem_map_index, ADM_SRS_TRUMEDIA);
2651 msm_dts_srs_tm_ion_memmap(&this_adm.outband_memmap);
2652 res = adm_memory_map_regions(&this_adm.outband_memmap.paddr, 0,
2653 (uint32_t *)&this_adm.outband_memmap.size, 1);
2654 if (res < 0) {
2655 pr_err("%s: SRS adm_memory_map_regions failed ! addr = 0x%pK, size = %d\n",
2656 __func__, (void *)this_adm.outband_memmap.paddr,
2657 (uint32_t)this_adm.outband_memmap.size);
2658 }
2659 }
2660 open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2661 APR_HDR_LEN(APR_HDR_SIZE),
2662 APR_PKT_VER);
2663 open.hdr.pkt_size = sizeof(open);
2664 open.hdr.src_svc = APR_SVC_ADM;
2665 open.hdr.src_domain = APR_DOMAIN_APPS;
2666 open.hdr.src_port = tmp_port;
2667 open.hdr.dest_svc = APR_SVC_ADM;
2668 open.hdr.dest_domain = APR_DOMAIN_ADSP;
2669 open.hdr.dest_port = tmp_port;
2670 open.hdr.token = port_idx << 16 | copp_idx;
2671 open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
2672 open.flags = flags;
2673 open.mode_of_operation = path;
2674 open.endpoint_id_1 = tmp_port;
2675 open.endpoint_id_2 = 0xFFFF;
2676
2677 if (this_adm.ec_ref_rx && (path != 1)) {
2678 open.endpoint_id_2 = this_adm.ec_ref_rx;
2679 this_adm.ec_ref_rx = -1;
2680 }
2681
2682 open.topology_id = topology;
2683
2684 open.dev_num_channel = channel_mode & 0x00FF;
2685 open.bit_width = bit_width;
2686 WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
2687 (rate != ULL_SUPPORTED_SAMPLE_RATE));
2688 open.sample_rate = rate;
2689
2690 ret = adm_arrange_mch_map(&open, path, channel_mode);
2691
2692 if (ret)
2693 return ret;
2694
2695 pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
2696 __func__, open.endpoint_id_1, open.sample_rate,
2697 open.topology_id);
2698
2699 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2700
2701 if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
2702 (open.endpoint_id_2 != 0xFFFF)) {
2703 memset(&open_v6, 0,
2704 sizeof(struct adm_cmd_device_open_v6));
2705 memcpy(&open_v6, &open,
2706 sizeof(struct adm_cmd_device_open_v5));
2707 open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
2708 open_v6.hdr.pkt_size = sizeof(open_v6);
2709 open_v6.dev_num_channel_eid2 =
2710 this_adm.num_ec_ref_rx_chans;
2711 this_adm.num_ec_ref_rx_chans = 0;
2712
2713 if (this_adm.ec_ref_rx_bit_width != 0) {
2714 open_v6.bit_width_eid2 =
2715 this_adm.ec_ref_rx_bit_width;
2716 this_adm.ec_ref_rx_bit_width = 0;
2717 } else {
2718 open_v6.bit_width_eid2 = bit_width;
2719 }
2720
2721 if (this_adm.ec_ref_rx_sampling_rate != 0) {
2722 open_v6.sample_rate_eid2 =
2723 this_adm.ec_ref_rx_sampling_rate;
2724 this_adm.ec_ref_rx_sampling_rate = 0;
2725 } else {
2726 open_v6.sample_rate_eid2 = rate;
2727 }
2728
2729 pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
2730 __func__, open_v6.dev_num_channel_eid2,
2731 open_v6.bit_width_eid2,
2732 open_v6.sample_rate_eid2);
2733
2734 ret = adm_arrange_mch_ep2_map(&open_v6,
2735 open_v6.dev_num_channel_eid2);
2736
2737 if (ret)
2738 return ret;
2739
2740 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
2741 } else {
2742 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
2743 }
2744 if (ret < 0) {
2745 pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
2746 __func__, tmp_port, port_id, ret);
2747 return -EINVAL;
2748 }
2749 /* Wait for the callback with copp id */
2750 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
2751 atomic_read(&this_adm.copp.stat
2752 [port_idx][copp_idx]) >= 0,
2753 msecs_to_jiffies(TIMEOUT_MS));
2754 if (!ret) {
2755 pr_err("%s: ADM open timedout for port_id: 0x%x for [0x%x]\n",
2756 __func__, tmp_port, port_id);
2757 return -EINVAL;
2758 } else if (atomic_read(&this_adm.copp.stat
2759 [port_idx][copp_idx]) > 0) {
2760 pr_err("%s: DSP returned error[%s]\n",
2761 __func__, adsp_err_get_err_str(
2762 atomic_read(&this_adm.copp.stat
2763 [port_idx][copp_idx])));
2764 return adsp_err_get_lnx_err_code(
2765 atomic_read(&this_adm.copp.stat
2766 [port_idx][copp_idx]));
2767 }
2768 }
2769 atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]);
2770 return copp_idx;
2771}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302772EXPORT_SYMBOL(adm_open);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302773
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302774/**
2775 * adm_copp_mfc_cfg -
2776 * command to send ADM MFC config
2777 *
2778 * @port_id: Port ID number
2779 * @copp_idx: copp index assigned
2780 * @dst_sample_rate: sink sample rate
2781 *
2782 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302783void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate)
2784{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002785 struct audproc_mfc_param_media_fmt mfc_cfg;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302786 struct adm_cmd_device_open_v5 open;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002787 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302788 int port_idx;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302789 int rc = 0;
2790 int i = 0;
2791
2792 port_id = q6audio_convert_virtual_to_portid(port_id);
2793 port_idx = adm_validate_and_get_port_index(port_id);
2794
2795 if (port_idx < 0) {
2796 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
2797 goto fail_cmd;
2798 }
2799
2800 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
2801 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
2802 goto fail_cmd;
2803 }
2804
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002805 memset(&mfc_cfg, 0, sizeof(mfc_cfg));
2806 memset(&open, 0, sizeof(open));
2807 memset(&param_hdr, 0, sizeof(param_hdr));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302808
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002809 param_hdr.module_id = AUDPROC_MODULE_ID_MFC;
2810 param_hdr.instance_id = INSTANCE_ID_0;
2811 param_hdr.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
2812 param_hdr.param_size = sizeof(mfc_cfg);
2813
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302814 mfc_cfg.sampling_rate = dst_sample_rate;
2815 mfc_cfg.bits_per_sample =
2816 atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
2817 open.dev_num_channel = mfc_cfg.num_channels =
2818 atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
2819
2820 rc = adm_arrange_mch_map(&open, ADM_PATH_PLAYBACK,
2821 mfc_cfg.num_channels);
2822 if (rc < 0) {
2823 pr_err("%s: unable to get channal map\n", __func__);
2824 goto fail_cmd;
2825 }
2826
2827 for (i = 0; i < mfc_cfg.num_channels; i++)
2828 mfc_cfg.channel_type[i] =
2829 (uint16_t) open.dev_channel_mapping[i];
2830
2831 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
2832
2833 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",
2834 __func__, port_idx, copp_idx,
2835 atomic_read(&this_adm.copp.rate[port_idx][copp_idx]),
2836 mfc_cfg.bits_per_sample, mfc_cfg.num_channels,
2837 mfc_cfg.sampling_rate);
2838
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08002839 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
2840 (uint8_t *) &mfc_cfg);
2841 if (rc)
2842 pr_err("%s: Failed to set media format configuration data, err %d\n",
2843 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302844
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302845fail_cmd:
2846 return;
2847}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302848EXPORT_SYMBOL(adm_copp_mfc_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302849
2850static void route_set_opcode_matrix_id(
2851 struct adm_cmd_matrix_map_routings_v5 **route_addr,
2852 int path, uint32_t passthr_mode)
2853{
2854 struct adm_cmd_matrix_map_routings_v5 *route = *route_addr;
2855
2856 switch (path) {
2857 case ADM_PATH_PLAYBACK:
2858 route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
2859 route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
2860 break;
2861 case ADM_PATH_LIVE_REC:
2862 if (passthr_mode == LISTEN) {
2863 route->hdr.opcode =
2864 ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2865 route->matrix_id = ADM_MATRIX_ID_LISTEN_TX;
2866 break;
2867 }
2868 /* fall through to set matrix id for non-listen case */
2869 case ADM_PATH_NONLIVE_REC:
2870 route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
2871 route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
2872 break;
2873 case ADM_PATH_COMPRESSED_RX:
2874 route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2875 route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
2876 break;
2877 case ADM_PATH_COMPRESSED_TX:
2878 route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
2879 route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_TX;
2880 break;
2881 default:
2882 pr_err("%s: Wrong path set[%d]\n", __func__, path);
2883 break;
2884 }
2885 pr_debug("%s: opcode 0x%x, matrix id %d\n",
2886 __func__, route->hdr.opcode, route->matrix_id);
2887}
2888
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302889/**
2890 * adm_matrix_map -
2891 * command to send ADM matrix map for ADM copp list
2892 *
2893 * @path: direction or ADM path type
2894 * @payload_map: have info of session id and associated copp_idx/num_copps
2895 * @perf_mode: performance mode like LL/ULL/..
2896 * @passthr_mode: flag to indicate passthrough mode
2897 *
2898 * Returns 0 on success or error on failure
2899 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302900int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
2901 uint32_t passthr_mode)
2902{
2903 struct adm_cmd_matrix_map_routings_v5 *route;
2904 struct adm_session_map_node_v5 *node;
2905 uint16_t *copps_list;
2906 int cmd_size = 0;
2907 int ret = 0, i = 0;
2908 void *payload = NULL;
2909 void *matrix_map = NULL;
2910 int port_idx, copp_idx;
2911
2912 /* Assumes port_ids have already been validated during adm_open */
2913 cmd_size = (sizeof(struct adm_cmd_matrix_map_routings_v5) +
2914 sizeof(struct adm_session_map_node_v5) +
2915 (sizeof(uint32_t) * payload_map.num_copps));
2916 matrix_map = kzalloc(cmd_size, GFP_KERNEL);
2917 if (matrix_map == NULL) {
2918 pr_err("%s: Mem alloc failed\n", __func__);
2919 ret = -EINVAL;
2920 return ret;
2921 }
2922 route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
2923
2924 route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2925 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2926 route->hdr.pkt_size = cmd_size;
2927 route->hdr.src_svc = 0;
2928 route->hdr.src_domain = APR_DOMAIN_APPS;
2929 route->hdr.src_port = 0; /* Ignored */;
2930 route->hdr.dest_svc = APR_SVC_ADM;
2931 route->hdr.dest_domain = APR_DOMAIN_ADSP;
2932 route->hdr.dest_port = 0; /* Ignored */;
2933 route->hdr.token = 0;
2934 route->num_sessions = 1;
2935 route_set_opcode_matrix_id(&route, path, passthr_mode);
2936
2937 payload = ((u8 *)matrix_map +
2938 sizeof(struct adm_cmd_matrix_map_routings_v5));
2939 node = (struct adm_session_map_node_v5 *)payload;
2940
2941 node->session_id = payload_map.session_id;
2942 node->num_copps = payload_map.num_copps;
2943 payload = (u8 *)node + sizeof(struct adm_session_map_node_v5);
2944 copps_list = (uint16_t *)payload;
2945 for (i = 0; i < payload_map.num_copps; i++) {
2946 port_idx =
2947 adm_validate_and_get_port_index(payload_map.port_id[i]);
2948 if (port_idx < 0) {
2949 pr_err("%s: Invalid port_id 0x%x\n", __func__,
2950 payload_map.port_id[i]);
2951 ret = -EINVAL;
2952 goto fail_cmd;
2953 }
2954 copp_idx = payload_map.copp_idx[i];
2955 copps_list[i] = atomic_read(&this_adm.copp.id[port_idx]
2956 [copp_idx]);
2957 }
2958 atomic_set(&this_adm.matrix_map_stat, -1);
2959
2960 ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
2961 if (ret < 0) {
2962 pr_err("%s: routing for syream %d failed ret %d\n",
2963 __func__, payload_map.session_id, ret);
2964 ret = -EINVAL;
2965 goto fail_cmd;
2966 }
2967 ret = wait_event_timeout(this_adm.matrix_map_wait,
2968 atomic_read(&this_adm.matrix_map_stat) >= 0,
2969 msecs_to_jiffies(TIMEOUT_MS));
2970 if (!ret) {
2971 pr_err("%s: routing for syream %d failed\n", __func__,
2972 payload_map.session_id);
2973 ret = -EINVAL;
2974 goto fail_cmd;
2975 } else if (atomic_read(&this_adm.matrix_map_stat) > 0) {
2976 pr_err("%s: DSP returned error[%s]\n", __func__,
2977 adsp_err_get_err_str(atomic_read(
2978 &this_adm.matrix_map_stat)));
2979 ret = adsp_err_get_lnx_err_code(
2980 atomic_read(&this_adm.matrix_map_stat));
2981 goto fail_cmd;
2982 }
2983
2984 if ((perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) &&
2985 (path != ADM_PATH_COMPRESSED_RX)) {
2986 for (i = 0; i < payload_map.num_copps; i++) {
2987 port_idx = afe_get_port_index(payload_map.port_id[i]);
2988 copp_idx = payload_map.copp_idx[i];
2989 if (port_idx < 0 || copp_idx < 0 ||
2990 (copp_idx > MAX_COPPS_PER_PORT - 1)) {
2991 pr_err("%s: Invalid idx port_idx %d copp_idx %d\n",
2992 __func__, port_idx, copp_idx);
2993 continue;
2994 }
2995 rtac_add_adm_device(payload_map.port_id[i],
2996 atomic_read(&this_adm.copp.id
2997 [port_idx][copp_idx]),
2998 get_cal_path(path),
2999 payload_map.session_id,
3000 payload_map.app_type[i],
3001 payload_map.acdb_dev_id[i]);
3002
3003 if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3004 (void *)&this_adm.copp.adm_status[port_idx]
3005 [copp_idx])) {
3006 pr_debug("%s: adm copp[0x%x][%d] already sent",
3007 __func__, port_idx, copp_idx);
3008 continue;
3009 }
3010 send_adm_cal(payload_map.port_id[i], copp_idx,
3011 get_cal_path(path), perf_mode,
3012 payload_map.app_type[i],
3013 payload_map.acdb_dev_id[i],
Aditya Bavanari5106b562018-01-08 13:16:32 +05303014 payload_map.sample_rate[i],
3015 passthr_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303016 /* ADM COPP calibration is already sent */
3017 clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3018 (void *)&this_adm.copp.
3019 adm_status[port_idx][copp_idx]);
3020 pr_debug("%s: copp_id: %d\n", __func__,
3021 atomic_read(&this_adm.copp.id[port_idx]
3022 [copp_idx]));
3023 }
3024 }
3025
3026fail_cmd:
3027 kfree(matrix_map);
3028 return ret;
3029}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303030EXPORT_SYMBOL(adm_matrix_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303031
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303032/**
3033 * adm_ec_ref_rx_id -
3034 * Update EC ref port ID
3035 *
3036 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303037void adm_ec_ref_rx_id(int port_id)
3038{
3039 this_adm.ec_ref_rx = port_id;
3040 pr_debug("%s: ec_ref_rx:%d\n", __func__, this_adm.ec_ref_rx);
3041}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303042EXPORT_SYMBOL(adm_ec_ref_rx_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303043
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303044/**
3045 * adm_num_ec_ref_rx_chans -
3046 * Update EC ref number of channels
3047 *
3048 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303049void adm_num_ec_ref_rx_chans(int num_chans)
3050{
3051 this_adm.num_ec_ref_rx_chans = num_chans;
3052 pr_debug("%s: num_ec_ref_rx_chans:%d\n",
3053 __func__, this_adm.num_ec_ref_rx_chans);
3054}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303055EXPORT_SYMBOL(adm_num_ec_ref_rx_chans);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303056
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303057/**
3058 * adm_ec_ref_rx_bit_width -
3059 * Update EC ref bit_width
3060 *
3061 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303062void adm_ec_ref_rx_bit_width(int bit_width)
3063{
3064 this_adm.ec_ref_rx_bit_width = bit_width;
3065 pr_debug("%s: ec_ref_rx_bit_width:%d\n",
3066 __func__, this_adm.ec_ref_rx_bit_width);
3067}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303068EXPORT_SYMBOL(adm_ec_ref_rx_bit_width);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303069
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303070/**
3071 * adm_ec_ref_rx_sampling_rate -
3072 * Update EC ref sample rate
3073 *
3074 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303075void adm_ec_ref_rx_sampling_rate(int sampling_rate)
3076{
3077 this_adm.ec_ref_rx_sampling_rate = sampling_rate;
3078 pr_debug("%s: ec_ref_rx_sampling_rate:%d\n",
3079 __func__, this_adm.ec_ref_rx_sampling_rate);
3080}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303081EXPORT_SYMBOL(adm_ec_ref_rx_sampling_rate);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303082
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303083/**
3084 * adm_close -
3085 * command to close ADM copp
3086 *
3087 * @port_id: Port ID number
3088 * @perf_mode: performance mode like LL/ULL/..
3089 * @copp_idx: copp index assigned
3090 *
3091 * Returns 0 on success or error on failure
3092 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303093int adm_close(int port_id, int perf_mode, int copp_idx)
3094{
3095 struct apr_hdr close;
3096
3097 int ret = 0, port_idx;
3098 int copp_id = RESET_COPP_ID;
3099
3100 pr_debug("%s: port_id=0x%x perf_mode: %d copp_idx: %d\n", __func__,
3101 port_id, perf_mode, copp_idx);
3102
3103 port_id = q6audio_convert_virtual_to_portid(port_id);
3104 port_idx = adm_validate_and_get_port_index(port_id);
3105 if (port_idx < 0) {
3106 pr_err("%s: Invalid port_id 0x%x\n",
3107 __func__, port_id);
3108 return -EINVAL;
3109 }
3110
3111 if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
3112 pr_err("%s: Invalid copp idx: %d\n", __func__, copp_idx);
3113 return -EINVAL;
3114 }
3115
3116 if (this_adm.copp.adm_delay[port_idx][copp_idx] && perf_mode
3117 == LEGACY_PCM_MODE) {
3118 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx],
3119 1);
3120 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
3121 wake_up(&this_adm.copp.adm_delay_wait[port_idx][copp_idx]);
3122 }
3123
3124 atomic_dec(&this_adm.copp.cnt[port_idx][copp_idx]);
3125 if (!(atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]))) {
3126 copp_id = adm_get_copp_id(port_idx, copp_idx);
3127 pr_debug("%s: Closing ADM port_idx:%d copp_idx:%d copp_id:0x%x\n",
3128 __func__, port_idx, copp_idx, copp_id);
3129 if ((!perf_mode) && (this_adm.outband_memmap.paddr != 0) &&
3130 (atomic_read(&this_adm.copp.topology[port_idx][copp_idx]) ==
3131 SRS_TRUMEDIA_TOPOLOGY_ID)) {
3132 atomic_set(&this_adm.mem_map_index,
3133 ADM_SRS_TRUMEDIA);
3134 ret = adm_memory_unmap_regions();
3135 if (ret < 0) {
3136 pr_err("%s: adm mem unmmap err %d",
3137 __func__, ret);
3138 } else {
3139 atomic_set(&this_adm.mem_map_handles
3140 [ADM_SRS_TRUMEDIA], 0);
3141 }
3142 }
3143
3144
3145 if ((afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) &&
3146 this_adm.sourceTrackingData.memmap.paddr) {
3147 atomic_set(&this_adm.mem_map_index,
3148 ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
3149 ret = adm_memory_unmap_regions();
3150 if (ret < 0) {
3151 pr_err("%s: adm mem unmmap err %d",
3152 __func__, ret);
3153 }
3154 msm_audio_ion_free(
Banajit Goswami08bb7362017-11-03 22:48:23 -07003155 this_adm.sourceTrackingData.dma_buf);
3156 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303157 this_adm.sourceTrackingData.memmap.size = 0;
3158 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
3159 this_adm.sourceTrackingData.memmap.paddr = 0;
3160 this_adm.sourceTrackingData.apr_cmd_status = -1;
3161 atomic_set(&this_adm.mem_map_handles[
3162 ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
3163 }
3164
3165 close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
3166 APR_HDR_LEN(APR_HDR_SIZE),
3167 APR_PKT_VER);
3168 close.pkt_size = sizeof(close);
3169 close.src_svc = APR_SVC_ADM;
3170 close.src_domain = APR_DOMAIN_APPS;
3171 close.src_port = port_id;
3172 close.dest_svc = APR_SVC_ADM;
3173 close.dest_domain = APR_DOMAIN_ADSP;
3174 close.dest_port = copp_id;
3175 close.token = port_idx << 16 | copp_idx;
3176 close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
3177
3178 atomic_set(&this_adm.copp.id[port_idx][copp_idx],
3179 RESET_COPP_ID);
3180 atomic_set(&this_adm.copp.cnt[port_idx][copp_idx], 0);
3181 atomic_set(&this_adm.copp.topology[port_idx][copp_idx], 0);
3182 atomic_set(&this_adm.copp.mode[port_idx][copp_idx], 0);
3183 atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
3184 atomic_set(&this_adm.copp.rate[port_idx][copp_idx], 0);
3185 atomic_set(&this_adm.copp.channels[port_idx][copp_idx], 0);
3186 atomic_set(&this_adm.copp.bit_width[port_idx][copp_idx], 0);
3187 atomic_set(&this_adm.copp.app_type[port_idx][copp_idx], 0);
3188
3189 clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
3190 (void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
3191
3192 ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
3193 if (ret < 0) {
3194 pr_err("%s: ADM close failed %d\n", __func__, ret);
3195 return -EINVAL;
3196 }
3197
3198 ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
3199 atomic_read(&this_adm.copp.stat
3200 [port_idx][copp_idx]) >= 0,
3201 msecs_to_jiffies(TIMEOUT_MS));
3202 if (!ret) {
3203 pr_err("%s: ADM cmd Route timedout for port 0x%x\n",
3204 __func__, port_id);
3205 return -EINVAL;
3206 } else if (atomic_read(&this_adm.copp.stat
3207 [port_idx][copp_idx]) > 0) {
3208 pr_err("%s: DSP returned error[%s]\n",
3209 __func__, adsp_err_get_err_str(
3210 atomic_read(&this_adm.copp.stat
3211 [port_idx][copp_idx])));
3212 return adsp_err_get_lnx_err_code(
3213 atomic_read(&this_adm.copp.stat
3214 [port_idx][copp_idx]));
3215 }
3216 }
3217
3218 if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
3219 pr_debug("%s: remove adm device from rtac\n", __func__);
3220 rtac_remove_adm_device(port_id, copp_id);
3221 }
3222 return 0;
3223}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303224EXPORT_SYMBOL(adm_close);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303225
3226int send_rtac_audvol_cal(void)
3227{
3228 int ret = 0;
3229 int ret2 = 0;
3230 int i = 0;
3231 int copp_idx, port_idx, acdb_id, app_id, path;
3232 struct cal_block_data *cal_block = NULL;
3233 struct audio_cal_info_audvol *audvol_cal_info = NULL;
3234 struct rtac_adm rtac_adm_data;
3235
3236 mutex_lock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
3237
3238 cal_block = cal_utils_get_only_cal_block(
3239 this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]);
Vikram Panduranga770b8382017-09-27 12:17:36 -07003240 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303241 pr_err("%s: can't find cal block!\n", __func__);
3242 goto unlock;
3243 }
3244
3245 audvol_cal_info = cal_block->cal_info;
3246 if (audvol_cal_info == NULL) {
3247 pr_err("%s: audvol_cal_info is NULL!\n", __func__);
3248 goto unlock;
3249 }
3250
3251 get_rtac_adm_data(&rtac_adm_data);
3252 for (; i < rtac_adm_data.num_of_dev; i++) {
3253
3254 acdb_id = rtac_adm_data.device[i].acdb_dev_id;
3255 if (acdb_id == 0)
3256 acdb_id = audvol_cal_info->acdb_id;
3257
3258 app_id = rtac_adm_data.device[i].app_type;
3259 if (app_id == 0)
3260 app_id = audvol_cal_info->app_type;
3261
3262 path = afe_get_port_type(rtac_adm_data.device[i].afe_port);
3263 if ((acdb_id == audvol_cal_info->acdb_id) &&
3264 (app_id == audvol_cal_info->app_type) &&
3265 (path == audvol_cal_info->path)) {
3266
3267 if (adm_get_indexes_from_copp_id(rtac_adm_data.
3268 device[i].copp, &copp_idx, &port_idx) != 0) {
3269 pr_debug("%s: Copp Id %d is not active\n",
3270 __func__,
3271 rtac_adm_data.device[i].copp);
3272 continue;
3273 }
3274
3275 ret2 = adm_remap_and_send_cal_block(ADM_RTAC_AUDVOL_CAL,
3276 rtac_adm_data.device[i].afe_port,
3277 copp_idx, cal_block,
3278 atomic_read(&this_adm.copp.
3279 mode[port_idx][copp_idx]),
3280 audvol_cal_info->app_type,
3281 audvol_cal_info->acdb_id,
3282 atomic_read(&this_adm.copp.
3283 rate[port_idx][copp_idx]));
3284 if (ret2 < 0) {
3285 pr_debug("%s: remap and send failed for copp Id %d, acdb id %d, app type %d, path %d\n",
3286 __func__, rtac_adm_data.device[i].copp,
3287 audvol_cal_info->acdb_id,
3288 audvol_cal_info->app_type,
3289 audvol_cal_info->path);
3290 ret = ret2;
3291 }
3292 }
3293 }
3294unlock:
3295 mutex_unlock(&this_adm.cal_data[ADM_RTAC_AUDVOL_CAL]->lock);
3296 return ret;
3297}
3298
3299int adm_map_rtac_block(struct rtac_cal_block_data *cal_block)
3300{
3301 int result = 0;
3302
3303 pr_debug("%s:\n", __func__);
3304
3305 if (cal_block == NULL) {
3306 pr_err("%s: cal_block is NULL!\n",
3307 __func__);
3308 result = -EINVAL;
3309 goto done;
3310 }
3311
3312 if (cal_block->cal_data.paddr == 0) {
3313 pr_debug("%s: No address to map!\n",
3314 __func__);
3315 result = -EINVAL;
3316 goto done;
3317 }
3318
3319 if (cal_block->map_data.map_size == 0) {
3320 pr_debug("%s: map size is 0!\n",
3321 __func__);
3322 result = -EINVAL;
3323 goto done;
3324 }
3325
3326 /* valid port ID needed for callback use primary I2S */
3327 atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
3328 result = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
3329 &cal_block->map_data.map_size, 1);
3330 if (result < 0) {
3331 pr_err("%s: RTAC mmap did not work! size = %d result %d\n",
3332 __func__,
3333 cal_block->map_data.map_size, result);
3334 pr_debug("%s: RTAC mmap did not work! addr = 0x%pK, size = %d\n",
3335 __func__,
3336 &cal_block->cal_data.paddr,
3337 cal_block->map_data.map_size);
3338 goto done;
3339 }
3340
3341 cal_block->map_data.map_handle = atomic_read(
3342 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]);
3343done:
3344 return result;
3345}
3346
3347int adm_unmap_rtac_block(uint32_t *mem_map_handle)
3348{
3349 int result = 0;
3350
3351 pr_debug("%s:\n", __func__);
3352
3353 if (mem_map_handle == NULL) {
3354 pr_debug("%s: Map handle is NULL, nothing to unmap\n",
3355 __func__);
3356 goto done;
3357 }
3358
3359 if (*mem_map_handle == 0) {
3360 pr_debug("%s: Map handle is 0, nothing to unmap\n",
3361 __func__);
3362 goto done;
3363 }
3364
3365 if (*mem_map_handle != atomic_read(
3366 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL])) {
3367 pr_err("%s: Map handles do not match! Unmapping RTAC, RTAC map 0x%x, ADM map 0x%x\n",
3368 __func__, *mem_map_handle, atomic_read(
3369 &this_adm.mem_map_handles[ADM_RTAC_APR_CAL]));
3370
3371 /* if mismatch use handle passed in to unmap */
3372 atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL],
3373 *mem_map_handle);
3374 }
3375
3376 /* valid port ID needed for callback use primary I2S */
3377 atomic_set(&this_adm.mem_map_index, ADM_RTAC_APR_CAL);
3378 result = adm_memory_unmap_regions();
3379 if (result < 0) {
3380 pr_debug("%s: adm_memory_unmap_regions failed, error %d\n",
3381 __func__, result);
3382 } else {
3383 atomic_set(&this_adm.mem_map_handles[ADM_RTAC_APR_CAL], 0);
3384 *mem_map_handle = 0;
3385 }
3386done:
3387 return result;
3388}
3389
3390static int get_cal_type_index(int32_t cal_type)
3391{
3392 int ret = -EINVAL;
3393
3394 switch (cal_type) {
3395 case ADM_AUDPROC_CAL_TYPE:
3396 ret = ADM_AUDPROC_CAL;
3397 break;
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05303398 case ADM_LSM_AUDPROC_CAL_TYPE:
3399 ret = ADM_LSM_AUDPROC_CAL;
3400 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303401 case ADM_AUDVOL_CAL_TYPE:
3402 ret = ADM_AUDVOL_CAL;
3403 break;
3404 case ADM_CUST_TOPOLOGY_CAL_TYPE:
3405 ret = ADM_CUSTOM_TOP_CAL;
3406 break;
3407 case ADM_RTAC_INFO_CAL_TYPE:
3408 ret = ADM_RTAC_INFO_CAL;
3409 break;
3410 case ADM_RTAC_APR_CAL_TYPE:
3411 ret = ADM_RTAC_APR_CAL;
3412 break;
3413 case ADM_RTAC_AUDVOL_CAL_TYPE:
3414 ret = ADM_RTAC_AUDVOL_CAL;
3415 break;
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07003416 case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE:
3417 ret = ADM_LSM_AUDPROC_PERSISTENT_CAL;
3418 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303419 default:
3420 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
3421 }
3422 return ret;
3423}
3424
3425static int adm_alloc_cal(int32_t cal_type, size_t data_size, void *data)
3426{
3427 int ret = 0;
3428 int cal_index;
3429
3430 pr_debug("%s:\n", __func__);
3431
3432 cal_index = get_cal_type_index(cal_type);
3433 if (cal_index < 0) {
3434 pr_err("%s: could not get cal index %d!\n",
3435 __func__, cal_index);
3436 ret = -EINVAL;
3437 goto done;
3438 }
3439
3440 ret = cal_utils_alloc_cal(data_size, data,
3441 this_adm.cal_data[cal_index], 0, NULL);
3442 if (ret < 0) {
3443 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
3444 __func__, ret, cal_type);
3445 ret = -EINVAL;
3446 goto done;
3447 }
3448done:
3449 return ret;
3450}
3451
3452static int adm_dealloc_cal(int32_t cal_type, size_t data_size, void *data)
3453{
3454 int ret = 0;
3455 int cal_index;
3456
3457 pr_debug("%s:\n", __func__);
3458
3459 cal_index = get_cal_type_index(cal_type);
3460 if (cal_index < 0) {
3461 pr_err("%s: could not get cal index %d!\n",
3462 __func__, cal_index);
3463 ret = -EINVAL;
3464 goto done;
3465 }
3466
3467 ret = cal_utils_dealloc_cal(data_size, data,
3468 this_adm.cal_data[cal_index]);
3469 if (ret < 0) {
3470 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
3471 __func__, ret, cal_type);
3472 ret = -EINVAL;
3473 goto done;
3474 }
3475done:
3476 return ret;
3477}
3478
3479static int adm_set_cal(int32_t cal_type, size_t data_size, void *data)
3480{
3481 int ret = 0;
3482 int cal_index;
3483
3484 pr_debug("%s:\n", __func__);
3485
3486 cal_index = get_cal_type_index(cal_type);
3487 if (cal_index < 0) {
3488 pr_err("%s: could not get cal index %d!\n",
3489 __func__, cal_index);
3490 ret = -EINVAL;
3491 goto done;
3492 }
3493
3494 ret = cal_utils_set_cal(data_size, data,
3495 this_adm.cal_data[cal_index], 0, NULL);
3496 if (ret < 0) {
3497 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
3498 __func__, ret, cal_type);
3499 ret = -EINVAL;
3500 goto done;
3501 }
3502
3503 if (cal_index == ADM_CUSTOM_TOP_CAL) {
3504 mutex_lock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
3505 this_adm.set_custom_topology = 1;
3506 mutex_unlock(&this_adm.cal_data[ADM_CUSTOM_TOP_CAL]->lock);
3507 } else if (cal_index == ADM_RTAC_AUDVOL_CAL) {
3508 send_rtac_audvol_cal();
3509 }
3510done:
3511 return ret;
3512}
3513
3514static int adm_map_cal_data(int32_t cal_type,
3515 struct cal_block_data *cal_block)
3516{
3517 int ret = 0;
3518 int cal_index;
3519
3520 pr_debug("%s:\n", __func__);
3521
3522 cal_index = get_cal_type_index(cal_type);
3523 if (cal_index < 0) {
3524 pr_err("%s: could not get cal index %d!\n",
3525 __func__, cal_index);
3526 ret = -EINVAL;
3527 goto done;
3528 }
3529
3530 atomic_set(&this_adm.mem_map_index, cal_index);
3531 ret = adm_memory_map_regions(&cal_block->cal_data.paddr, 0,
3532 (uint32_t *)&cal_block->map_data.map_size, 1);
3533 if (ret < 0) {
3534 pr_err("%s: map did not work! cal_type %i ret %d\n",
3535 __func__, cal_index, ret);
3536 ret = -ENODEV;
3537 goto done;
3538 }
3539 cal_block->map_data.q6map_handle = atomic_read(&this_adm.
3540 mem_map_handles[cal_index]);
3541done:
3542 return ret;
3543}
3544
3545static int adm_unmap_cal_data(int32_t cal_type,
3546 struct cal_block_data *cal_block)
3547{
3548 int ret = 0;
3549 int cal_index;
3550
3551 pr_debug("%s:\n", __func__);
3552
3553 cal_index = get_cal_type_index(cal_type);
3554 if (cal_index < 0) {
3555 pr_err("%s: could not get cal index %d!\n",
3556 __func__, cal_index);
3557 ret = -EINVAL;
3558 goto done;
3559 }
3560
3561 if (cal_block == NULL) {
3562 pr_err("%s: Cal block is NULL!\n",
3563 __func__);
3564 goto done;
3565 }
3566
3567 if (cal_block->map_data.q6map_handle == 0) {
3568 pr_err("%s: Map handle is NULL, nothing to unmap\n",
3569 __func__);
3570 goto done;
3571 }
3572
3573 atomic_set(&this_adm.mem_map_handles[cal_index],
3574 cal_block->map_data.q6map_handle);
3575 atomic_set(&this_adm.mem_map_index, cal_index);
3576 ret = adm_memory_unmap_regions();
3577 if (ret < 0) {
3578 pr_err("%s: unmap did not work! cal_type %i ret %d\n",
3579 __func__, cal_index, ret);
3580 ret = -ENODEV;
3581 goto done;
3582 }
3583 cal_block->map_data.q6map_handle = 0;
3584done:
3585 return ret;
3586}
3587
3588static void adm_delete_cal_data(void)
3589{
3590 pr_debug("%s:\n", __func__);
3591
3592 cal_utils_destroy_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data);
3593}
3594
3595static int adm_init_cal_data(void)
3596{
3597 int ret = 0;
3598 struct cal_type_info cal_type_info[] = {
3599 {{ADM_CUST_TOPOLOGY_CAL_TYPE,
3600 {adm_alloc_cal, adm_dealloc_cal, NULL,
3601 adm_set_cal, NULL, NULL} },
3602 {adm_map_cal_data, adm_unmap_cal_data,
3603 cal_utils_match_buf_num} },
3604
3605 {{ADM_AUDPROC_CAL_TYPE,
3606 {adm_alloc_cal, adm_dealloc_cal, NULL,
3607 adm_set_cal, NULL, NULL} },
3608 {adm_map_cal_data, adm_unmap_cal_data,
3609 cal_utils_match_buf_num} },
3610
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05303611 {{ADM_LSM_AUDPROC_CAL_TYPE,
3612 {adm_alloc_cal, adm_dealloc_cal, NULL,
3613 adm_set_cal, NULL, NULL} },
3614 {adm_map_cal_data, adm_unmap_cal_data,
3615 cal_utils_match_buf_num} },
3616
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303617 {{ADM_AUDVOL_CAL_TYPE,
3618 {adm_alloc_cal, adm_dealloc_cal, NULL,
3619 adm_set_cal, NULL, NULL} },
3620 {adm_map_cal_data, adm_unmap_cal_data,
3621 cal_utils_match_buf_num} },
3622
3623 {{ADM_RTAC_INFO_CAL_TYPE,
3624 {NULL, NULL, NULL, NULL, NULL, NULL} },
3625 {NULL, NULL, cal_utils_match_buf_num} },
3626
3627 {{ADM_RTAC_APR_CAL_TYPE,
3628 {NULL, NULL, NULL, NULL, NULL, NULL} },
3629 {NULL, NULL, cal_utils_match_buf_num} },
3630
3631 {{SRS_TRUMEDIA_CAL_TYPE,
3632 {NULL, NULL, NULL, NULL, NULL, NULL} },
3633 {NULL, NULL, cal_utils_match_buf_num} },
3634
3635 {{ADM_RTAC_AUDVOL_CAL_TYPE,
3636 {adm_alloc_cal, adm_dealloc_cal, NULL,
3637 adm_set_cal, NULL, NULL} },
3638 {adm_map_cal_data, adm_unmap_cal_data,
3639 cal_utils_match_buf_num} },
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07003640
3641 {{ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE,
3642 {adm_alloc_cal, adm_dealloc_cal, NULL,
3643 adm_set_cal, NULL, NULL} },
3644 {adm_map_cal_data, adm_unmap_cal_data,
3645 cal_utils_match_buf_num} },
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303646 };
3647 pr_debug("%s:\n", __func__);
3648
3649 ret = cal_utils_create_cal_types(ADM_MAX_CAL_TYPES, this_adm.cal_data,
3650 cal_type_info);
3651 if (ret < 0) {
3652 pr_err("%s: could not create cal type! ret %d\n",
3653 __func__, ret);
3654 ret = -EINVAL;
3655 goto err;
3656 }
3657
3658 return ret;
3659err:
3660 adm_delete_cal_data();
3661 return ret;
3662}
3663
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303664/**
3665 * adm_set_volume -
3666 * command to set volume on ADM copp
3667 *
3668 * @port_id: Port ID number
3669 * @copp_idx: copp index assigned
3670 * @volume: gain value to set
3671 *
3672 * Returns 0 on success or error on failure
3673 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303674int adm_set_volume(int port_id, int copp_idx, int volume)
3675{
3676 struct audproc_volume_ctrl_master_gain audproc_vol;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003677 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303678 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303679
3680 pr_debug("%s: port_id %d, volume %d\n", __func__, port_id, volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303681
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003682 memset(&audproc_vol, 0, sizeof(audproc_vol));
3683 memset(&param_hdr, 0, sizeof(param_hdr));
3684 param_hdr.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
3685 param_hdr.instance_id = INSTANCE_ID_0;
3686 param_hdr.param_id = AUDPROC_PARAM_ID_VOL_CTRL_MASTER_GAIN;
3687 param_hdr.param_size = sizeof(audproc_vol);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303688
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303689 audproc_vol.master_gain = volume;
3690
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003691 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3692 (uint8_t *) &audproc_vol);
3693 if (rc)
3694 pr_err("%s: Failed to set volume, err %d\n", __func__, rc);
3695
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303696 return rc;
3697}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303698EXPORT_SYMBOL(adm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303699
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303700/**
3701 * adm_set_softvolume -
3702 * command to set softvolume
3703 *
3704 * @port_id: Port ID number
3705 * @copp_idx: copp index assigned
3706 * @softvol_param: Params to set for softvolume
3707 *
3708 * Returns 0 on success or error on failure
3709 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303710int adm_set_softvolume(int port_id, int copp_idx,
3711 struct audproc_softvolume_params *softvol_param)
3712{
3713 struct audproc_soft_step_volume_params audproc_softvol;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003714 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303715 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303716
3717 pr_debug("%s: period %d step %d curve %d\n", __func__,
3718 softvol_param->period, softvol_param->step,
3719 softvol_param->rampingcurve);
3720
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003721 memset(&audproc_softvol, 0, sizeof(audproc_softvol));
3722 memset(&param_hdr, 0, sizeof(param_hdr));
3723 param_hdr.module_id = AUDPROC_MODULE_ID_VOL_CTRL;
3724 param_hdr.instance_id = INSTANCE_ID_0;
3725 param_hdr.param_id = AUDPROC_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
3726 param_hdr.param_size = sizeof(audproc_softvol);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303727
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303728 audproc_softvol.period = softvol_param->period;
3729 audproc_softvol.step = softvol_param->step;
3730 audproc_softvol.ramping_curve = softvol_param->rampingcurve;
3731
3732 pr_debug("%s: period %d, step %d, curve %d\n", __func__,
3733 audproc_softvol.period, audproc_softvol.step,
3734 audproc_softvol.ramping_curve);
3735
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003736 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3737 (uint8_t *) &audproc_softvol);
3738 if (rc)
3739 pr_err("%s: Failed to set soft volume, err %d\n", __func__, rc);
3740
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303741 return rc;
3742}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303743EXPORT_SYMBOL(adm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303744
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303745/**
3746 * adm_set_mic_gain -
3747 * command to set MIC gain
3748 *
3749 * @port_id: Port ID number
3750 * @copp_idx: copp index assigned
3751 * @volume: gain value to set
3752 *
3753 * Returns 0 on success or error on failure
3754 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303755int adm_set_mic_gain(int port_id, int copp_idx, int volume)
3756{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003757 struct admx_mic_gain mic_gain_params;
3758 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303759 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303760
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003761 pr_debug("%s: Setting mic gain to %d at port_id 0x%x\n", __func__,
3762 volume, port_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303763
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003764 memset(&mic_gain_params, 0, sizeof(mic_gain_params));
3765 memset(&param_hdr, 0, sizeof(param_hdr));
3766 param_hdr.module_id = ADM_MODULE_IDX_MIC_GAIN_CTRL;
3767 param_hdr.instance_id = INSTANCE_ID_0;
3768 param_hdr.param_id = ADM_PARAM_IDX_MIC_GAIN;
3769 param_hdr.param_size = sizeof(mic_gain_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303770
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003771 mic_gain_params.tx_mic_gain = volume;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303772
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003773 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3774 (uint8_t *) &mic_gain_params);
3775 if (rc)
3776 pr_err("%s: Failed to set mic gain, err %d\n", __func__, rc);
3777
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303778 return rc;
3779}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303780EXPORT_SYMBOL(adm_set_mic_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303781
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303782/**
3783 * adm_send_set_multichannel_ec_primary_mic_ch -
3784 * command to set multi-ch EC primary mic
3785 *
3786 * @port_id: Port ID number
3787 * @copp_idx: copp index assigned
3788 * @primary_mic_ch: channel number of primary mic
3789 *
3790 * Returns 0 on success or error on failure
3791 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303792int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
3793 int primary_mic_ch)
3794{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003795 struct admx_sec_primary_mic_ch sec_primary_ch_params;
3796 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303797 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303798
3799 pr_debug("%s port_id 0x%x, copp_idx 0x%x, primary_mic_ch %d\n",
3800 __func__, port_id, copp_idx, primary_mic_ch);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303801
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003802 memset(&sec_primary_ch_params, 0, sizeof(sec_primary_ch_params));
3803 memset(&param_hdr, 0, sizeof(param_hdr));
3804 param_hdr.module_id = AUDPROC_MODULE_ID_VOICE_TX_SECNS;
3805 param_hdr.instance_id = INSTANCE_ID_0;
3806 param_hdr.param_id = AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH;
3807 param_hdr.param_size = sizeof(sec_primary_ch_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303808
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003809 sec_primary_ch_params.version = 0;
3810 sec_primary_ch_params.sec_primary_mic_ch = primary_mic_ch;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303811
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003812 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3813 (uint8_t *) &sec_primary_ch_params);
3814 if (rc)
3815 pr_err("%s: Failed to set primary mic chanel, err %d\n",
3816 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303817
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303818 return rc;
3819}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303820EXPORT_SYMBOL(adm_send_set_multichannel_ec_primary_mic_ch);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303821
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303822/**
3823 * adm_param_enable -
3824 * command to send params to ADM for given module
3825 *
3826 * @port_id: Port ID number
3827 * @copp_idx: copp index assigned
3828 * @module_id: ADM module
3829 * @enable: flag to enable or disable module
3830 *
3831 * Returns 0 on success or error on failure
3832 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303833int adm_param_enable(int port_id, int copp_idx, int module_id, int enable)
3834{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003835 struct module_instance_info mod_inst_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303836
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003837 memset(&mod_inst_info, 0, sizeof(mod_inst_info));
3838 mod_inst_info.module_id = module_id;
3839 mod_inst_info.instance_id = INSTANCE_ID_0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303840
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003841 return adm_param_enable_v2(port_id, copp_idx, mod_inst_info, enable);
3842}
Vidyakumar Athota98464a22018-03-15 20:39:37 -07003843EXPORT_SYMBOL(adm_param_enable);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003844
3845/**
3846 * adm_param_enable_v2 -
3847 * command to send params to ADM for given module
3848 *
3849 * @port_id: Port ID number
3850 * @copp_idx: copp index assigned
3851 * @mod_inst_info: module and instance ID info
3852 * @enable: flag to enable or disable module
3853 *
3854 * Returns 0 on success or error on failure
3855 */
3856int adm_param_enable_v2(int port_id, int copp_idx,
3857 struct module_instance_info mod_inst_info, int enable)
3858{
3859 uint32_t enable_param;
3860 struct param_hdr_v3 param_hdr;
3861 int rc = 0;
3862
3863 if (enable < 0 || enable > 1) {
3864 pr_err("%s: Invalid value for enable %d\n", __func__, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303865 return -EINVAL;
3866 }
3867
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003868 pr_debug("%s port_id %d, module_id 0x%x, instance_id 0x%x, enable %d\n",
3869 __func__, port_id, mod_inst_info.module_id,
3870 mod_inst_info.instance_id, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303871
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003872 memset(&param_hdr, 0, sizeof(param_hdr));
3873 param_hdr.module_id = mod_inst_info.module_id;
3874 param_hdr.instance_id = mod_inst_info.instance_id;
3875 param_hdr.param_id = AUDPROC_PARAM_ID_ENABLE;
3876 param_hdr.param_size = sizeof(enable_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303877
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003878 enable_param = enable;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303879
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003880 rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
3881 (uint8_t *) &enable_param);
3882 if (rc)
3883 pr_err("%s: Failed to set enable of module(%d) instance(%d) to %d, err %d\n",
3884 __func__, mod_inst_info.module_id,
3885 mod_inst_info.instance_id, enable, rc);
3886
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303887 return rc;
3888
3889}
Vidyakumar Athota98464a22018-03-15 20:39:37 -07003890EXPORT_SYMBOL(adm_param_enable_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303891
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303892/**
3893 * adm_send_calibration -
3894 * send ADM calibration to DSP
3895 *
3896 * @port_id: Port ID number
3897 * @copp_idx: copp index assigned
3898 * @path: direction or ADM path type
3899 * @perf_mode: performance mode like LL/ULL/..
3900 * @cal_type: calibration type to use
3901 * @params: pointer with cal data
3902 * @size: cal size
3903 *
3904 * Returns 0 on success or error on failure
3905 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303906int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode,
3907 int cal_type, char *params, int size)
3908{
3909
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003910 int rc = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303911
3912 pr_debug("%s:port_id %d, path %d, perf_mode %d, cal_type %d, size %d\n",
3913 __func__, port_id, path, perf_mode, cal_type, size);
3914
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303915 /* Maps audio_dev_ctrl path definition to ACDB definition */
3916 if (get_cal_path(path) != RX_DEVICE) {
3917 pr_err("%s: acdb_path %d\n", __func__, path);
3918 rc = -EINVAL;
3919 goto end;
3920 }
3921
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08003922 rc = adm_set_pp_params(port_id, copp_idx, NULL, (u8 *) params, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303923
3924end:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303925 return rc;
3926}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303927EXPORT_SYMBOL(adm_send_calibration);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303928
3929/*
3930 * adm_update_wait_parameters must be called with routing driver locks.
3931 * adm_reset_wait_parameters must be called with routing driver locks.
3932 * set and reset parmeters are separated to make sure it is always called
3933 * under routing driver lock.
3934 * adm_wait_timeout is to block until timeout or interrupted. Timeout is
3935 * not a an error.
3936 */
3937int adm_set_wait_parameters(int port_id, int copp_idx)
3938{
3939
3940 int ret = 0, port_idx;
3941
3942 pr_debug("%s: port_id 0x%x, copp_idx %d\n", __func__, port_id,
3943 copp_idx);
3944 port_id = afe_convert_virtual_to_portid(port_id);
3945 port_idx = adm_validate_and_get_port_index(port_id);
3946 if (port_idx < 0) {
3947 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3948 ret = -EINVAL;
3949 goto end;
3950 }
3951
3952 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3953 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3954 return -EINVAL;
3955 }
3956
3957 this_adm.copp.adm_delay[port_idx][copp_idx] = 1;
3958 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 0);
3959
3960end:
3961 return ret;
3962
3963}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303964EXPORT_SYMBOL(adm_set_wait_parameters);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303965
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303966/**
3967 * adm_reset_wait_parameters -
3968 * reset wait parameters or ADM delay value
3969 *
3970 * @port_id: Port ID number
3971 * @copp_idx: copp index assigned
3972 *
3973 * Returns 0 on success or error on failure
3974 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303975int adm_reset_wait_parameters(int port_id, int copp_idx)
3976{
3977 int ret = 0, port_idx;
3978
3979 pr_debug("%s: port_id 0x%x copp_idx %d\n", __func__, port_id,
3980 copp_idx);
3981 port_id = afe_convert_virtual_to_portid(port_id);
3982 port_idx = adm_validate_and_get_port_index(port_id);
3983 if (port_idx < 0) {
3984 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
3985 ret = -EINVAL;
3986 goto end;
3987 }
3988
3989 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
3990 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
3991 return -EINVAL;
3992 }
3993
3994 atomic_set(&this_adm.copp.adm_delay_stat[port_idx][copp_idx], 1);
3995 this_adm.copp.adm_delay[port_idx][copp_idx] = 0;
3996
3997end:
3998 return ret;
3999}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304000EXPORT_SYMBOL(adm_reset_wait_parameters);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304001
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304002/**
4003 * adm_wait_timeout -
4004 * ADM wait command after command send to DSP
4005 *
4006 * @port_id: Port ID number
4007 * @copp_idx: copp index assigned
4008 * @wait_time: value in ms for command timeout
4009 *
4010 * Returns 0 on success or error on failure
4011 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304012int adm_wait_timeout(int port_id, int copp_idx, int wait_time)
4013{
4014 int ret = 0, port_idx;
4015
4016 pr_debug("%s: port_id 0x%x, copp_idx %d, wait_time %d\n", __func__,
4017 port_id, copp_idx, wait_time);
4018 port_id = afe_convert_virtual_to_portid(port_id);
4019 port_idx = adm_validate_and_get_port_index(port_id);
4020 if (port_idx < 0) {
4021 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
4022 ret = -EINVAL;
4023 goto end;
4024 }
4025
4026 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4027 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
4028 return -EINVAL;
4029 }
4030
4031 ret = wait_event_timeout(
4032 this_adm.copp.adm_delay_wait[port_idx][copp_idx],
4033 atomic_read(&this_adm.copp.adm_delay_stat[port_idx][copp_idx]),
4034 msecs_to_jiffies(wait_time));
4035 pr_debug("%s: return %d\n", __func__, ret);
4036 if (ret != 0)
4037 ret = -EINTR;
4038end:
4039 pr_debug("%s: return %d--\n", __func__, ret);
4040 return ret;
4041}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304042EXPORT_SYMBOL(adm_wait_timeout);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304043
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304044/**
4045 * adm_store_cal_data -
4046 * Retrieve calibration data for ADM copp device
4047 *
4048 * @port_id: Port ID number
4049 * @copp_idx: copp index assigned
4050 * @path: direction or copp type
4051 * @perf_mode: performance mode like LL/ULL/..
4052 * @cal_index: calibration index to use
4053 * @params: pointer to store cal data
4054 * @size: pointer to fill with cal size
4055 *
4056 * Returns 0 on success or error on failure
4057 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304058int adm_store_cal_data(int port_id, int copp_idx, int path, int perf_mode,
4059 int cal_index, char *params, int *size)
4060{
4061 int rc = 0;
4062 struct cal_block_data *cal_block = NULL;
4063 int app_type, acdb_id, port_idx, sample_rate;
4064
4065 if (this_adm.cal_data[cal_index] == NULL) {
4066 pr_debug("%s: cal_index %d not allocated!\n",
4067 __func__, cal_index);
4068 goto end;
4069 }
4070
4071 if (get_cal_path(path) != RX_DEVICE) {
4072 pr_debug("%s: Invalid path to store calibration %d\n",
4073 __func__, path);
4074 rc = -EINVAL;
4075 goto end;
4076 }
4077
4078 port_id = afe_convert_virtual_to_portid(port_id);
4079 port_idx = adm_validate_and_get_port_index(port_id);
4080 if (port_idx < 0) {
4081 pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
4082 rc = -EINVAL;
4083 goto end;
4084 }
4085
4086 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4087 pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
4088 return -EINVAL;
4089 }
4090
4091 acdb_id = atomic_read(&this_adm.copp.acdb_id[port_idx][copp_idx]);
4092 app_type = atomic_read(&this_adm.copp.app_type[port_idx][copp_idx]);
4093 sample_rate = atomic_read(&this_adm.copp.rate[port_idx][copp_idx]);
4094
4095 mutex_lock(&this_adm.cal_data[cal_index]->lock);
4096 cal_block = adm_find_cal(cal_index, get_cal_path(path), app_type,
4097 acdb_id, sample_rate);
4098 if (cal_block == NULL)
4099 goto unlock;
4100
4101 if (cal_block->cal_data.size <= 0) {
4102 pr_debug("%s: No ADM cal send for port_id = 0x%x!\n",
4103 __func__, port_id);
4104 rc = -EINVAL;
4105 goto unlock;
4106 }
4107
Aditya Bavanari2a627ae2017-11-21 20:24:53 +05304108 if (cal_index == ADM_AUDPROC_CAL || cal_index == ADM_LSM_AUDPROC_CAL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304109 if (cal_block->cal_data.size > AUD_PROC_BLOCK_SIZE) {
4110 pr_err("%s:audproc:invalid size exp/actual[%zd, %d]\n",
4111 __func__, cal_block->cal_data.size, *size);
4112 rc = -ENOMEM;
4113 goto unlock;
4114 }
Bhalchandra Gajarebbb64142018-05-10 14:16:49 -07004115 } else if (cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
4116 if (cal_block->cal_data.size > AUD_PROC_PERSIST_BLOCK_SIZE) {
4117 pr_err("%s:persist invalid size exp/actual[%zd, %d]\n",
4118 __func__, cal_block->cal_data.size, *size);
4119 rc = -ENOMEM;
4120 goto unlock;
4121 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304122 } else if (cal_index == ADM_AUDVOL_CAL) {
4123 if (cal_block->cal_data.size > AUD_VOL_BLOCK_SIZE) {
4124 pr_err("%s:aud_vol:invalid size exp/actual[%zd, %d]\n",
4125 __func__, cal_block->cal_data.size, *size);
4126 rc = -ENOMEM;
4127 goto unlock;
4128 }
4129 } else {
4130 pr_debug("%s: Not valid calibration for dolby topolgy\n",
4131 __func__);
4132 rc = -EINVAL;
4133 goto unlock;
4134 }
4135 memcpy(params, cal_block->cal_data.kvaddr, cal_block->cal_data.size);
4136 *size = cal_block->cal_data.size;
4137
4138 pr_debug("%s:port_id %d, copp_idx %d, path %d",
4139 __func__, port_id, copp_idx, path);
4140 pr_debug("perf_mode %d, cal_type %d, size %d\n",
4141 perf_mode, cal_index, *size);
4142
4143unlock:
4144 mutex_unlock(&this_adm.cal_data[cal_index]->lock);
4145end:
4146 return rc;
4147}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304148EXPORT_SYMBOL(adm_store_cal_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304149
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304150/**
4151 * adm_send_compressed_device_mute -
4152 * command to send mute for compressed device
4153 *
4154 * @port_id: Port ID number
4155 * @copp_idx: copp index assigned
4156 * @mute_on: flag to indicate mute or unmute
4157 *
4158 * Returns 0 on success or error on failure
4159 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304160int adm_send_compressed_device_mute(int port_id, int copp_idx, bool mute_on)
4161{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004162 u32 mute_param = mute_on ? 1 : 0;
4163 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304164 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304165
4166 pr_debug("%s port_id: 0x%x, copp_idx %d, mute_on: %d\n",
4167 __func__, port_id, copp_idx, mute_on);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304168
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004169 memset(&param_hdr, 0, sizeof(param_hdr));
4170 param_hdr.module_id = AUDPROC_MODULE_ID_COMPRESSED_MUTE;
4171 param_hdr.instance_id = INSTANCE_ID_0;
4172 param_hdr.param_id = AUDPROC_PARAM_ID_COMPRESSED_MUTE;
4173 param_hdr.param_size = sizeof(mute_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304174
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004175 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4176 (uint8_t *) &mute_param);
4177 if (ret)
4178 pr_err("%s: Failed to set mute, err %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304179
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304180 return ret;
4181}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304182EXPORT_SYMBOL(adm_send_compressed_device_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304183
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304184/**
4185 * adm_send_compressed_device_latency -
4186 * command to send latency for compressed device
4187 *
4188 * @port_id: Port ID number
4189 * @copp_idx: copp index assigned
4190 * @latency: latency value to pass
4191 *
4192 * Returns 0 on success or error on failure
4193 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304194int adm_send_compressed_device_latency(int port_id, int copp_idx, int latency)
4195{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004196 u32 latency_param;
4197 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304198 int ret = 0;
4199
4200 pr_debug("%s port_id: 0x%x, copp_idx %d latency: %d\n", __func__,
4201 port_id, copp_idx, latency);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004202
4203 if (latency < 0) {
4204 pr_err("%s: Invalid value for latency %d", __func__, latency);
4205 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304206 }
4207
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004208 memset(&param_hdr, 0, sizeof(param_hdr));
4209 param_hdr.module_id = AUDPROC_MODULE_ID_COMPRESSED_LATENCY;
4210 param_hdr.instance_id = INSTANCE_ID_0;
4211 param_hdr.param_id = AUDPROC_PARAM_ID_COMPRESSED_LATENCY;
4212 param_hdr.param_size = sizeof(latency_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304213
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004214 latency_param = latency;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304215
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004216 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4217 (uint8_t *) &latency_param);
4218 if (ret)
4219 pr_err("%s: Failed to set latency, err %d\n", __func__, ret);
4220
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304221 return ret;
4222}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304223EXPORT_SYMBOL(adm_send_compressed_device_latency);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304224
4225/**
4226 * adm_swap_speaker_channels
4227 *
4228 * Receives port_id, copp_idx, sample rate, spk_swap and
4229 * send MFC command to swap speaker channel.
4230 * Return zero on success. On failure returns nonzero.
4231 *
4232 * port_id - Passed value, port_id for which channels swap is wanted
4233 * copp_idx - Passed value, copp_idx for which channels swap is wanted
4234 * sample_rate - Passed value, sample rate used by app type config
4235 * spk_swap - Passed value, spk_swap for check if swap flag is set
4236 */
4237int adm_swap_speaker_channels(int port_id, int copp_idx,
4238 int sample_rate, bool spk_swap)
4239{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004240 struct audproc_mfc_param_media_fmt mfc_cfg;
4241 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304242 uint16_t num_channels;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004243 int port_idx = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304244 int ret = 0;
4245
4246 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4247 __func__, port_id, copp_idx);
4248 port_id = q6audio_convert_virtual_to_portid(port_id);
4249 port_idx = adm_validate_and_get_port_index(port_id);
4250 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
4251 pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004252 return -EINVAL;
4253 } else if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
4254 pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
4255 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304256 }
4257
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004258 num_channels = atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304259 if (num_channels != 2) {
4260 pr_debug("%s: Invalid number of channels: %d\n",
4261 __func__, num_channels);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004262 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304263 }
4264
4265 memset(&mfc_cfg, 0, sizeof(mfc_cfg));
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004266 memset(&param_hdr, 0, sizeof(param_hdr));
4267
4268 param_hdr.module_id = AUDPROC_MODULE_ID_MFC;
4269 param_hdr.instance_id = INSTANCE_ID_0;
4270 param_hdr.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
4271 param_hdr.param_size = sizeof(mfc_cfg);
4272
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304273 mfc_cfg.sampling_rate = sample_rate;
4274 mfc_cfg.bits_per_sample =
4275 atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
4276 mfc_cfg.num_channels = num_channels;
4277
4278 /* Currently applying speaker swap for only 2 channel use case */
4279 if (spk_swap) {
4280 mfc_cfg.channel_type[0] =
4281 (uint16_t) PCM_CHANNEL_FR;
4282 mfc_cfg.channel_type[1] =
4283 (uint16_t) PCM_CHANNEL_FL;
4284 } else {
4285 mfc_cfg.channel_type[0] =
4286 (uint16_t) PCM_CHANNEL_FL;
4287 mfc_cfg.channel_type[1] =
4288 (uint16_t) PCM_CHANNEL_FR;
4289 }
4290
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004291 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4292 (u8 *) &mfc_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304293 if (ret < 0) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004294 pr_err("%s: Failed to set swap speaker channels on port[0x%x] failed %d\n",
4295 __func__, port_id, ret);
4296 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304297 }
4298
4299 pr_debug("%s: mfc_cfg Set params returned success", __func__);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004300 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304301}
4302EXPORT_SYMBOL(adm_swap_speaker_channels);
4303
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304304/**
4305 * adm_set_sound_focus -
4306 * Update sound focus info
4307 *
4308 * @port_id: Port ID number
4309 * @copp_idx: copp index assigned
4310 * @soundFocusData: sound focus data to pass
4311 *
4312 * Returns 0 on success or error on failure
4313 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304314int adm_set_sound_focus(int port_id, int copp_idx,
4315 struct sound_focus_param soundFocusData)
4316{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004317 struct adm_param_fluence_soundfocus_t soundfocus_params;
4318 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304319 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304320 int i;
4321
4322 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4323 __func__, port_id, copp_idx);
4324
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004325 memset(&param_hdr, 0, sizeof(param_hdr));
4326 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4327 param_hdr.instance_id = INSTANCE_ID_0;
4328 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
4329 param_hdr.param_size = sizeof(soundfocus_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304330
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004331 memset(&(soundfocus_params), 0xFF, sizeof(soundfocus_params));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304332 for (i = 0; i < MAX_SECTORS; i++) {
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004333 soundfocus_params.start_angles[i] =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304334 soundFocusData.start_angle[i];
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004335 soundfocus_params.enables[i] = soundFocusData.enable[i];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304336 pr_debug("%s: start_angle[%d] = %d\n",
4337 __func__, i, soundFocusData.start_angle[i]);
4338 pr_debug("%s: enable[%d] = %d\n",
4339 __func__, i, soundFocusData.enable[i]);
4340 }
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004341 soundfocus_params.gain_step = soundFocusData.gain_step;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304342 pr_debug("%s: gain_step = %d\n", __func__, soundFocusData.gain_step);
4343
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004344 soundfocus_params.reserved = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304345
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004346 ret = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
4347 (uint8_t *) &soundfocus_params);
4348 if (ret)
4349 pr_err("%s: Failed to set sound focus params, err %d\n",
4350 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304351
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304352 pr_debug("%s: Exit, ret=%d\n", __func__, ret);
4353
4354 return ret;
4355}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304356EXPORT_SYMBOL(adm_set_sound_focus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304357
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304358/**
4359 * adm_get_sound_focus -
4360 * Retrieve sound focus info
4361 *
4362 * @port_id: Port ID number
4363 * @copp_idx: copp index assigned
4364 * @soundFocusData: pointer for sound focus data to be updated with
4365 *
4366 * Returns 0 on success or error on failure
4367 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304368int adm_get_sound_focus(int port_id, int copp_idx,
4369 struct sound_focus_param *soundFocusData)
4370{
4371 int ret = 0, i;
4372 char *params_value;
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004373 uint32_t max_param_size = 0;
4374 struct adm_param_fluence_soundfocus_t *soundfocus_params = NULL;
4375 struct param_hdr_v3 param_hdr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304376
4377 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4378 __func__, port_id, copp_idx);
4379
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004380 max_param_size = sizeof(struct adm_param_fluence_soundfocus_t) +
4381 sizeof(union param_hdrs);
4382 params_value = kzalloc(max_param_size, GFP_KERNEL);
4383 if (!params_value)
4384 return -ENOMEM;
4385
4386 memset(&param_hdr, 0, sizeof(param_hdr));
4387 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4388 param_hdr.instance_id = INSTANCE_ID_0;
4389 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOUNDFOCUS;
4390 param_hdr.param_size = max_param_size;
4391 ret = adm_get_pp_params(port_id, copp_idx,
4392 ADM_CLIENT_ID_SOURCE_TRACKING, NULL, &param_hdr,
4393 params_value);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304394 if (ret) {
4395 pr_err("%s: get parameters failed ret:%d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304396 ret = -EINVAL;
4397 goto done;
4398 }
4399
4400 if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
4401 pr_err("%s - get params returned error [%s]\n",
4402 __func__, adsp_err_get_err_str(
4403 this_adm.sourceTrackingData.apr_cmd_status));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304404 ret = adsp_err_get_lnx_err_code(
4405 this_adm.sourceTrackingData.apr_cmd_status);
4406 goto done;
4407 }
4408
4409 soundfocus_params = (struct adm_param_fluence_soundfocus_t *)
4410 params_value;
4411 for (i = 0; i < MAX_SECTORS; i++) {
4412 soundFocusData->start_angle[i] =
4413 soundfocus_params->start_angles[i];
4414 soundFocusData->enable[i] = soundfocus_params->enables[i];
4415 pr_debug("%s: start_angle[%d] = %d\n",
4416 __func__, i, soundFocusData->start_angle[i]);
4417 pr_debug("%s: enable[%d] = %d\n",
4418 __func__, i, soundFocusData->enable[i]);
4419 }
4420 soundFocusData->gain_step = soundfocus_params->gain_step;
4421 pr_debug("%s: gain_step = %d\n", __func__, soundFocusData->gain_step);
4422
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304423done:
4424 pr_debug("%s: Exit, ret = %d\n", __func__, ret);
4425
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004426 kfree(params_value);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304427 return ret;
4428}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304429EXPORT_SYMBOL(adm_get_sound_focus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304430
4431static int adm_source_tracking_alloc_map_memory(void)
4432{
4433 int ret;
4434
4435 pr_debug("%s: Enter\n", __func__);
4436
Banajit Goswami08bb7362017-11-03 22:48:23 -07004437 ret = msm_audio_ion_alloc(&this_adm.sourceTrackingData.dma_buf,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304438 AUD_PROC_BLOCK_SIZE,
4439 &this_adm.sourceTrackingData.memmap.paddr,
4440 &this_adm.sourceTrackingData.memmap.size,
4441 &this_adm.sourceTrackingData.memmap.kvaddr);
4442 if (ret) {
4443 pr_err("%s: failed to allocate memory\n", __func__);
4444
4445 ret = -EINVAL;
4446 goto done;
4447 }
4448
4449 atomic_set(&this_adm.mem_map_index, ADM_MEM_MAP_INDEX_SOURCE_TRACKING);
4450 ret = adm_memory_map_regions(&this_adm.sourceTrackingData.memmap.paddr,
4451 0,
4452 (uint32_t *)&this_adm.sourceTrackingData.memmap.size,
4453 1);
4454 if (ret < 0) {
4455 pr_err("%s: failed to map memory, paddr = 0x%pK, size = %d\n",
4456 __func__,
4457 (void *)this_adm.sourceTrackingData.memmap.paddr,
4458 (uint32_t)this_adm.sourceTrackingData.memmap.size);
4459
Banajit Goswami08bb7362017-11-03 22:48:23 -07004460 msm_audio_ion_free(this_adm.sourceTrackingData.dma_buf);
4461 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304462 this_adm.sourceTrackingData.memmap.size = 0;
4463 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
4464 this_adm.sourceTrackingData.memmap.paddr = 0;
4465 this_adm.sourceTrackingData.apr_cmd_status = -1;
4466 atomic_set(&this_adm.mem_map_handles
4467 [ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0);
4468
4469 ret = -EINVAL;
4470 goto done;
4471 }
4472 ret = 0;
4473 pr_debug("%s: paddr = 0x%pK, size = %d, mem_map_handle = 0x%x\n",
4474 __func__, (void *)this_adm.sourceTrackingData.memmap.paddr,
4475 (uint32_t)this_adm.sourceTrackingData.memmap.size,
4476 atomic_read(&this_adm.mem_map_handles
4477 [ADM_MEM_MAP_INDEX_SOURCE_TRACKING]));
4478
4479done:
4480 pr_debug("%s: Exit, ret = %d\n", __func__, ret);
4481
4482 return ret;
4483}
4484
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304485/**
4486 * adm_get_source_tracking -
4487 * Retrieve source tracking info
4488 *
4489 * @port_id: Port ID number
4490 * @copp_idx: copp index assigned
4491 * @sourceTrackingData: pointer for source track data to be updated with
4492 *
4493 * Returns 0 on success or error on failure
4494 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304495int adm_get_source_tracking(int port_id, int copp_idx,
4496 struct source_tracking_param *sourceTrackingData)
4497{
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004498 struct adm_param_fluence_sourcetracking_t *source_tracking_params =
4499 NULL;
4500 struct mem_mapping_hdr mem_hdr;
4501 struct param_hdr_v3 param_hdr;
4502 int i = 0;
4503 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304504
4505 pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
4506 __func__, port_id, copp_idx);
4507
4508 if (!this_adm.sourceTrackingData.memmap.paddr) {
4509 /* Allocate and map shared memory for out of band usage */
4510 ret = adm_source_tracking_alloc_map_memory();
4511 if (ret != 0) {
4512 ret = -EINVAL;
4513 goto done;
4514 }
4515 }
4516
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004517 memset(&mem_hdr, 0, sizeof(mem_hdr));
4518 memset(&param_hdr, 0, sizeof(param_hdr));
4519 mem_hdr.data_payload_addr_lsw =
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304520 lower_32_bits(this_adm.sourceTrackingData.memmap.paddr);
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004521 mem_hdr.data_payload_addr_msw = msm_audio_populate_upper_32_bits(
4522 this_adm.sourceTrackingData.memmap.paddr);
4523 mem_hdr.mem_map_handle = atomic_read(
4524 &this_adm.mem_map_handles[ADM_MEM_MAP_INDEX_SOURCE_TRACKING]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304525
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004526 param_hdr.module_id = VOICEPROC_MODULE_ID_GENERIC_TX;
4527 param_hdr.instance_id = INSTANCE_ID_0;
4528 param_hdr.param_id = VOICEPROC_PARAM_ID_FLUENCE_SOURCETRACKING;
4529 /*
4530 * This size should be the max size of the calibration data + header.
4531 * Use the union size to ensure max size is used.
4532 */
4533 param_hdr.param_size =
4534 sizeof(struct adm_param_fluence_sourcetracking_t) +
4535 sizeof(union param_hdrs);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304536
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004537 /*
4538 * Retrieving parameters out of band, so no need to provide a buffer for
4539 * the returned parameter data as it will be at the memory location
4540 * provided.
4541 */
4542 ret = adm_get_pp_params(port_id, copp_idx,
4543 ADM_CLIENT_ID_SOURCE_TRACKING, &mem_hdr,
4544 &param_hdr, NULL);
4545 if (ret) {
4546 pr_err("%s: Failed to get params, error %d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304547 goto done;
4548 }
4549
4550 if (this_adm.sourceTrackingData.apr_cmd_status != 0) {
4551 pr_err("%s - get params returned error [%s]\n",
4552 __func__, adsp_err_get_err_str(
4553 this_adm.sourceTrackingData.apr_cmd_status));
4554
4555 ret = adsp_err_get_lnx_err_code(
4556 this_adm.sourceTrackingData.apr_cmd_status);
4557 goto done;
4558 }
4559
Vignesh Kulothungan60cc0352018-01-29 16:21:22 -08004560 /* How do we know what the param data was retrieved with for hdr size */
4561 source_tracking_params =
4562 (struct adm_param_fluence_sourcetracking_t
4563 *) (this_adm.sourceTrackingData.memmap.kvaddr +
4564 sizeof(struct param_hdr_v1));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304565 for (i = 0; i < MAX_SECTORS; i++) {
4566 sourceTrackingData->vad[i] = source_tracking_params->vad[i];
4567 pr_debug("%s: vad[%d] = %d\n",
4568 __func__, i, sourceTrackingData->vad[i]);
4569 }
4570 sourceTrackingData->doa_speech = source_tracking_params->doa_speech;
4571 pr_debug("%s: doa_speech = %d\n",
4572 __func__, sourceTrackingData->doa_speech);
4573
4574 for (i = 0; i < MAX_NOISE_SOURCE_INDICATORS; i++) {
4575 sourceTrackingData->doa_noise[i] =
4576 source_tracking_params->doa_noise[i];
4577 pr_debug("%s: doa_noise[%d] = %d\n",
4578 __func__, i, sourceTrackingData->doa_noise[i]);
4579 }
4580 for (i = 0; i < MAX_POLAR_ACTIVITY_INDICATORS; i++) {
4581 sourceTrackingData->polar_activity[i] =
4582 source_tracking_params->polar_activity[i];
4583 pr_debug("%s: polar_activity[%d] = %d\n",
4584 __func__, i, sourceTrackingData->polar_activity[i]);
4585 }
4586
4587 ret = 0;
4588
4589done:
4590 pr_debug("%s: Exit, ret=%d\n", __func__, ret);
4591
4592 return ret;
4593}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304594EXPORT_SYMBOL(adm_get_source_tracking);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304595
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304596int __init adm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304597{
4598 int i = 0, j;
4599
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304600 this_adm.ec_ref_rx = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304601 init_waitqueue_head(&this_adm.matrix_map_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304602 init_waitqueue_head(&this_adm.adm_wait);
4603
4604 for (i = 0; i < AFE_MAX_PORTS; i++) {
4605 for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
4606 atomic_set(&this_adm.copp.id[i][j], RESET_COPP_ID);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304607 init_waitqueue_head(&this_adm.copp.wait[i][j]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304608 init_waitqueue_head(
4609 &this_adm.copp.adm_delay_wait[i][j]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304610 }
4611 }
4612
4613 if (adm_init_cal_data())
4614 pr_err("%s: could not init cal data!\n", __func__);
4615
Banajit Goswami08bb7362017-11-03 22:48:23 -07004616 this_adm.sourceTrackingData.dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304617 this_adm.sourceTrackingData.memmap.size = 0;
4618 this_adm.sourceTrackingData.memmap.kvaddr = NULL;
4619 this_adm.sourceTrackingData.memmap.paddr = 0;
4620 this_adm.sourceTrackingData.apr_cmd_status = -1;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304621
4622 return 0;
4623}
4624
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05304625void adm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304626{
Laxminath Kasam30ad7512017-11-28 12:40:22 +05304627 if (this_adm.apr)
4628 adm_reset_data();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304629 adm_delete_cal_data();
4630}