tegra-alt: adsp: avoid sleep in send msg
[linux-3.10.git] / sound / soc / tegra-alt / tegra210_adsp_alt.c
1 /*
2  * tegra210_adsp_alt.c - Tegra ADSP audio driver
3  *
4  * Author: Sumit Bhattacharya <sumitb@nvidia.com>
5  * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  */
22
23 #include <linux/module.h>
24 #include <linux/device.h>
25 #include <linux/fs.h>
26 #include <linux/io.h>
27 #include <linux/of.h>
28 #include <../arch/arm/mach-tegra/iomap.h>
29 #include <linux/completion.h>
30 #include <linux/uaccess.h>
31 #include <linux/delay.h>
32 #include <linux/dma-mapping.h>
33 #include <linux/pm_runtime.h>
34 #include <linux/tegra_pm_domains.h>
35 #include <linux/slab.h>
36 #include <linux/platform_device.h>
37 #include <linux/firmware.h>
38 #include <linux/kthread.h>
39 #include <linux/tegra_nvadsp.h>
40 #include <linux/irqchip/tegra-agic.h>
41 #include <linux/of_device.h>
42
43 #include <sound/pcm.h>
44 #include <sound/core.h>
45 #include <sound/pcm_params.h>
46 #include <sound/soc.h>
47 #include <sound/compress_driver.h>
48 #include <sound/dmaengine_pcm.h>
49 #include <sound/tegra_nvfx.h>
50 #include <sound/tegra_nvfx_apm.h>
51 #include <sound/tegra_nvfx_plugin.h>
52
53 #include "tegra210_adsp_alt.h"
54
55 #define DRV_NAME "tegra210-adsp"
56
57 /* Flag to enable/disable loading of ADSP firmware */
58 #define ENABLE_ADSP 1
59
60 #define ADSP_RESPONSE_TIMEOUT   1000 /* in ms */
61
62 static struct tegra210_adsp_app_desc {
63         const char *name;
64         const char *fw_name;
65         const char *wt_name;
66         uint32_t param_type;
67         uint32_t reg_start;
68         uint32_t reg_end;
69         nvadsp_app_handle_t handle;
70 } adsp_app_minimal[] = {
71         {"apm", "nvapm.elf", NULL, SNDRV_CTL_ELEM_TYPE_NONE,
72                 APM_IN_START, APM_IN_END},
73         {"adma", "nvadma.elf", NULL, SNDRV_CTL_ELEM_TYPE_NONE,
74                 ADMA_START, ADMA_END},
75 };
76
77 static struct tegra210_adsp_app_desc *adsp_app_desc;
78 static unsigned int adsp_app_count; /* total number of apps initialized */
79
80 /* ADSP APP specific structure */
81 struct tegra210_adsp_app {
82         struct tegra210_adsp *adsp;
83         const struct tegra210_adsp_app_desc *desc;
84         nvadsp_app_info_t *info;
85         plugin_shared_mem_t *plugin;
86         apm_shared_state_t *apm; /* For a plugin it stores parent apm data */
87         struct nvadsp_mbox apm_mbox;
88         struct completion *msg_complete; /* For ADSP ack wait */
89         uint32_t reg;
90         uint32_t adma_chan; /* Valid for only ADMA app */
91         uint32_t fe:1; /* Whether the app is used as a FE APM */
92         uint32_t connect:1; /* if app is connected to a source */
93         uint32_t priority; /* Valid for only APM app */
94         uint32_t min_adsp_clock; /* Min ADSP clock required in MHz */
95         spinlock_t lock;
96         void *private_data;
97         int (*msg_handler)(struct tegra210_adsp_app *, apm_msg_t *);
98         struct work_struct *override_freq_work;
99 };
100
101 struct tegra210_adsp_pcm_rtd {
102         struct device *dev;
103         struct snd_pcm_substream *substream;
104         struct tegra210_adsp_app *fe_apm;
105 };
106
107 struct tegra210_adsp_compr_rtd {
108         struct device *dev;
109         struct snd_dma_buffer buf;
110         struct snd_compr_stream *cstream;
111         struct snd_codec codec;
112         struct tegra210_adsp_app *fe_apm;
113         int is_draining;
114 };
115
116 struct tegra210_adsp {
117         struct device *dev;
118         struct tegra210_adsp_app apps[TEGRA210_ADSP_VIRT_REG_MAX];
119         atomic_t reg_val[TEGRA210_ADSP_VIRT_REG_MAX];
120         DECLARE_BITMAP(adma_usage, TEGRA210_ADSP_ADMA_CHANNEL_COUNT);
121         struct work_struct override_freq_work;
122         uint32_t i2s_rate;
123         struct mutex mutex;
124         int init_done;
125         int adsp_started;
126
127         struct task_struct *audio_task;
128         int recovery_enabled;
129         int recovery_count;
130
131         struct tegra210_adsp_path {
132                 uint32_t fe_reg;
133                 uint32_t be_reg;
134         } pcm_path[ADSP_FE_END+1][2];
135 };
136
137 static const struct snd_pcm_hardware adsp_pcm_hardware = {
138         .info                   = SNDRV_PCM_INFO_MMAP |
139                                   SNDRV_PCM_INFO_MMAP_VALID |
140                                   SNDRV_PCM_INFO_PAUSE |
141                                   SNDRV_PCM_INFO_RESUME |
142                                   SNDRV_PCM_INFO_INTERLEAVED,
143         .formats                = SNDRV_PCM_FMTBIT_S16_LE,
144         .channels_min           = 1,
145         .channels_max           = 2,
146         .period_bytes_min       = 128,
147         .period_bytes_max       = PAGE_SIZE * 2,
148         .periods_min            = 1,
149         .periods_max            = 8,
150         .buffer_bytes_max       = PAGE_SIZE * 8,
151         .fifo_size              = 4,
152 };
153
154 /* Following structure is ALSA-Compress specific */
155 static struct snd_compr_caps
156         tegra210_adsp_compr_caps[SND_COMPRESS_CAPTURE + 1] = {
157         [SND_COMPRESS_PLAYBACK] = {
158                 .num_codecs = 2,
159                 .direction = SND_COMPRESS_PLAYBACK,
160                 .min_fragment_size = 1024,
161                 .max_fragment_size = 1024 * 1024,        /* 1 MB */
162                 .min_fragments = 2,
163                 .max_fragments = 1024,
164                 .codecs = {
165                         [0] = SND_AUDIOCODEC_MP3,
166                         [1] = SND_AUDIOCODEC_AAC,
167                 },
168         },
169         [SND_COMPRESS_CAPTURE] = {
170                 .num_codecs = 0,
171                 .direction = SND_COMPRESS_CAPTURE,
172         },
173 };
174
175 /* Following structure is ALSA-Compress specific */
176 static struct snd_compr_codec_caps adsp_compr_codec_caps[] = {
177         [SND_AUDIOCODEC_MP3] = {
178                 .codec = SND_AUDIOCODEC_MP3,
179                 .num_descriptors = 1,
180                 .descriptor = {
181                         [0] = {
182                                 .max_ch = 2,
183                                 .sample_rates = {
184                                         [0] = SNDRV_PCM_RATE_8000_48000,
185                                 },
186                                 .bit_rate = {
187                                         [0] = 32000,
188                                         [1] = 64000,
189                                         [2] = 128000,
190                                         [3] = 256000,
191                                         [4] = 320000,
192                                 },
193                                 .num_bitrates = 5,
194                                 .rate_control =
195                                         SND_RATECONTROLMODE_CONSTANTBITRATE |
196                                         SND_RATECONTROLMODE_VARIABLEBITRATE,
197                                 .profiles = 0,
198                                 .modes = SND_AUDIOCHANMODE_MP3_STEREO,
199                                 .formats = SND_AUDIOSTREAMFORMAT_UNDEFINED,
200                                 .min_buffer = 1024,
201                         },
202                 },
203         },
204         [SND_AUDIOCODEC_AAC] = {
205                 .codec = SND_AUDIOCODEC_AAC,
206                 .num_descriptors = 1,
207                 .descriptor = {
208                         [0] = {
209                                 .max_ch = 2,
210                                 .sample_rates = {
211                                         [0] = SNDRV_PCM_RATE_8000_48000,
212                                 },
213                                 .bit_rate = {
214                                         [0] = 32000,
215                                         [1] = 64000,
216                                         [2] = 128000,
217                                         [3] = 256000,
218                                         [4] = 320000,
219                                 },
220                                 .num_bitrates = 5,
221                                 .rate_control =
222                                         SND_RATECONTROLMODE_CONSTANTBITRATE |
223                                         SND_RATECONTROLMODE_VARIABLEBITRATE,
224                                 .profiles = SND_AUDIOPROFILE_AAC,
225                                 .modes = SND_AUDIOMODE_AAC_LC,
226                                 .formats = SND_AUDIOSTREAMFORMAT_MP4ADTS,
227                                 .min_buffer = 1024,
228                         },
229                 },
230         },
231 };
232
233 static status_t tegra210_adsp_msg_handler(uint32_t msg, void *data);
234 static int tegra210_adsp_app_default_msg_handler(struct tegra210_adsp_app *app,
235                                         apm_msg_t *apm_msg);
236 static void tegra210_adsp_crash_handler(void *arg);
237
238 /*
239  * Utility functions
240  */
241 /* ADSP virtual register read/write functions */
242 static uint32_t tegra210_adsp_reg_read(struct tegra210_adsp *adsp, uint32_t reg)
243 {
244         return atomic_read(&adsp->reg_val[reg]);
245 }
246
247 static void tegra210_adsp_reg_write(struct tegra210_adsp *adsp,
248                                 uint32_t reg, uint32_t val)
249 {
250         atomic_set(&adsp->reg_val[reg], val);
251         dev_vdbg(adsp->dev, "%s : 0x%x -> 0x%x\n", __func__, reg, val);
252 }
253
254 static void tegra210_adsp_reg_update_bits(struct tegra210_adsp *adsp,
255                                         uint32_t reg, uint32_t mask,
256                                         uint32_t val)
257 {
258         uint32_t temp;
259
260         temp = tegra210_adsp_reg_read(adsp, reg);
261         val = (val & mask) | (temp & ~mask);
262         tegra210_adsp_reg_write(adsp, reg, val);
263
264         dev_vdbg(adsp->dev, "%s : 0x%x -> 0x%x\n", __func__, reg, val);
265 }
266
267 /* API to get source widget id connected to a widget */
268 static uint32_t tegra210_adsp_get_source(struct tegra210_adsp *adsp,
269                                          uint32_t reg)
270 {
271         uint32_t source;
272
273         source = tegra210_adsp_reg_read(adsp, reg);
274         source &= TEGRA210_ADSP_WIDGET_SOURCE_MASK;
275         source >>= TEGRA210_ADSP_WIDGET_SOURCE_SHIFT;
276
277         return source;
278 }
279 /* ADSP shared memory allocate/free functions */
280 static int tegra210_adsp_preallocate_dma_buffer(struct device *dev, size_t size,
281                                 struct snd_dma_buffer *buf)
282 {
283         dev_vdbg(dev, "%s : size %d.", __func__, (uint32_t)size);
284
285         buf->area = nvadsp_alloc_coherent(size, &buf->addr, GFP_KERNEL);
286         if (!buf->area) {
287                 dev_err(dev, "Failed to pre-allocated DMA buffer.");
288                 return -ENOMEM;
289         }
290
291         buf->bytes = size;
292         buf->private_data = NULL;
293         buf->dev.type = SNDRV_DMA_TYPE_DEV;
294         buf->dev.dev = dev;
295
296         return 0;
297 }
298
299 static void tegra210_adsp_deallocate_dma_buffer(struct snd_dma_buffer *buf)
300 {
301         dev_vdbg(buf->dev.dev, "%s : size %d.", __func__, (uint32_t)buf->bytes);
302
303         if (!buf->area)
304                 return;
305
306         nvadsp_free_coherent(buf->bytes, buf->area, buf->addr);
307         buf->area = NULL;
308         buf->addr = 0;
309 }
310
311 /* ADSP OS boot and init API */
312 static int tegra210_adsp_init(struct tegra210_adsp *adsp)
313 {
314         int i, ret = 0;
315
316         mutex_lock(&adsp->mutex);
317         ret = nvadsp_os_load();
318         if (ret < 0) {
319                 dev_err(adsp->dev, "Failed to load OS.");
320                 goto exit;
321         }
322
323         if (nvadsp_os_start()) {
324                 dev_err(adsp->dev, "Failed to start OS");
325                 goto exit;
326         }
327
328         /* Load ADSP audio apps */
329         for (i = 0; i < adsp_app_count; i++) {
330                 adsp_app_desc[i].handle = nvadsp_app_load(
331                                 adsp_app_desc[i].name,
332                                 adsp_app_desc[i].fw_name);
333                 if (!adsp_app_desc[i].handle) {
334                         dev_err(adsp->dev, "Failed to load app %s",
335                                                 adsp_app_desc[i].name);
336                 }
337         }
338
339         nvadsp_register_crash_handler(tegra210_adsp_crash_handler, adsp);
340
341         /* Suspend OS for now. Resume will happen via runtime pm calls */
342         ret = nvadsp_os_suspend();
343         if (ret < 0) {
344                 dev_err(adsp->dev, "Failed to suspend OS.");
345                 goto exit;
346         }
347
348         adsp->init_done = 1;
349
350 exit:
351         mutex_unlock(&adsp->mutex);
352         return ret;
353 }
354
355 static void tegra210_adsp_deinit(struct tegra210_adsp *adsp)
356 {
357         mutex_lock(&adsp->mutex);
358         if (adsp->init_done) {
359                 int i;
360                 adsp->init_done = 0;
361                 adsp->adsp_started = 0;
362                 bitmap_zero(adsp->adma_usage, TEGRA210_ADSP_ADMA_CHANNEL_COUNT);
363
364                 for (i = 0; i < TEGRA210_ADSP_VIRT_REG_MAX; i++) {
365                         struct tegra210_adsp_app *app = &adsp->apps[i];
366                         app->connect = 0;
367                         app->priority = 0;
368                         app->min_adsp_clock = 0;
369                         app->info = NULL;
370                         app->plugin = NULL;
371                         if (IS_APM_IN(app->reg))
372                                 nvadsp_mbox_close(&app->apm_mbox);
373                 }
374
375                 memset(adsp->reg_val, 0, sizeof(adsp->reg_val));
376                 nvadsp_os_stop();
377         }
378         mutex_unlock(&adsp->mutex);
379 }
380
381 void tegra210_adsp_crash_handler(void *arg)
382 {
383         struct tegra210_adsp *adsp = (struct tegra210_adsp *)arg;
384         tegra210_adsp_deinit(adsp);
385
386         mutex_lock(&adsp->mutex);
387         if (adsp->recovery_enabled && adsp->audio_task) {
388                 send_sig(SIGKILL, adsp->audio_task, 0);
389                 adsp->recovery_count++;
390                 adsp->audio_task = NULL;
391                 dev_err(adsp->dev, "%s recovery count %d\n", __func__,
392                         adsp->recovery_count);
393         }
394         mutex_unlock(&adsp->mutex);
395 }
396
397 /* ADSP-CPU message send-receive utility functions */
398 static int tegra210_adsp_get_msg(apm_shared_state_t *apm, apm_msg_t *apm_msg)
399 {
400         apm_msg->msgq_msg.size = MSGQ_MSG_WSIZE(apm_msg_t) -
401                 MSGQ_MESSAGE_HEADER_WSIZE;
402         return msgq_dequeue_message(&apm->msgq_send.msgq,
403                 &apm_msg->msgq_msg);
404 }
405
406 static int tegra210_adsp_send_msg(struct tegra210_adsp_app *app,
407                                   apm_msg_t *apm_msg, uint32_t flags)
408 {
409         int ret = 0;
410
411         if (!app->adsp->adsp_started) {
412                 pr_err("ADSP not running, not sending message");
413                 return 0;
414         }
415
416         if (flags & TEGRA210_ADSP_MSG_FLAG_NEED_ACK) {
417                 if (flags & TEGRA210_ADSP_MSG_FLAG_HOLD) {
418                         pr_err("%s: ACK requires FLAG_SEND, ignoring\n",
419                                 __func__);
420                         flags &= ~TEGRA210_ADSP_MSG_FLAG_NEED_ACK;
421                 } else {
422                         apm_msg->msg.call_params.method |=
423                                 NVFX_APM_METHOD_ACK_BIT;
424                 }
425         }
426
427         ret = msgq_queue_message(&app->apm->msgq_recv.msgq, &apm_msg->msgq_msg);
428         if (ret < 0) {
429                 /* Wakeup APM to consume messages and give it some time */
430                 ret = nvadsp_mbox_send(&app->apm_mbox, apm_cmd_msg_ready,
431                         NVADSP_MBOX_SMSG, false, 0);
432                 if (ret) {
433                         pr_err("%s: Failed to send mailbox message id %d ret %d\n",
434                                 __func__, app->apm->mbox_id, ret);
435                 }
436                 mdelay(20);
437                 /* Attempt queueing again */
438                 ret = msgq_queue_message(&app->apm->msgq_recv.msgq,
439                                 &apm_msg->msgq_msg);
440                 if (ret < 0) {
441                         pr_err("%s: Failed to queue message app %d ret %d\n",
442                                 __func__, app->reg, ret);
443                         return ret;
444                 }
445         }
446
447         if (flags & TEGRA210_ADSP_MSG_FLAG_HOLD)
448                 return 0;
449
450         ret = nvadsp_mbox_send(&app->apm_mbox, apm_cmd_msg_ready,
451                 NVADSP_MBOX_SMSG, false, 0);
452         if (ret) {
453                 pr_err("%s: Failed to send mailbox message id %d ret %d\n",
454                         __func__, app->apm->mbox_id, ret);
455         }
456
457         if (!(flags & TEGRA210_ADSP_MSG_FLAG_NEED_ACK))
458                 return ret;
459
460         /* Find parent APM to wait for ACK*/
461         if (!IS_APM_IN(app->reg)) {
462                 uint32_t source;
463                 while (IS_ADSP_APP(app->reg) && !IS_APM_IN(app->reg)) {
464                         source = tegra210_adsp_get_source(app->adsp, app->reg);
465                         app = &app->adsp->apps[source];
466                 }
467                 if (!IS_APM_IN(app->reg)) {
468                         pr_err("%s: No APM found, skip ACK wait\n", __func__);
469                         return ret;
470                 }
471         }
472
473         ret = wait_for_completion_interruptible_timeout(
474                 app->msg_complete,
475                 msecs_to_jiffies(ADSP_RESPONSE_TIMEOUT));
476         if (WARN_ON(ret == 0)) {
477                 pr_err("%s: ACK timed out %d\n", __func__, app->reg);
478                 tegra210_adsp_crash_handler(app->adsp);
479         }
480
481         return ret;
482 }
483
484 static int tegra210_adsp_send_remove_msg(struct tegra210_adsp_app *app,
485                                         uint32_t flags)
486 {
487         apm_msg_t apm_msg;
488
489         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_fx_remove_params_t);
490         apm_msg.msg.call_params.size = sizeof(apm_fx_remove_params_t);
491         apm_msg.msg.call_params.method = nvfx_apm_method_fx_remove_all;
492
493         return tegra210_adsp_send_msg(app, &apm_msg, flags);
494 }
495
496 static int tegra210_adsp_send_connect_msg(struct tegra210_adsp_app *src,
497                                         struct tegra210_adsp_app *dst,
498                                         uint32_t flags)
499 {
500         apm_msg_t apm_msg;
501
502         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_fx_connect_params_t);
503         apm_msg.msg.call_params.size = sizeof(apm_fx_connect_params_t);
504         apm_msg.msg.call_params.method = nvfx_apm_method_fx_connect;
505         apm_msg.msg.fx_connect_params.plugin_src.pvoid = IS_APM_IN(src->reg) ?
506                 NULL : src->plugin->plugin.pvoid;
507         apm_msg.msg.fx_connect_params.pin_src = 0;
508         apm_msg.msg.fx_connect_params.plugin_dst.pvoid = IS_APM_OUT(dst->reg) ?
509                 NULL : dst->plugin->plugin.pvoid;
510         apm_msg.msg.fx_connect_params.pin_dst = 0;
511
512         return tegra210_adsp_send_msg(src, &apm_msg, flags);
513 }
514
515 static int tegra210_adsp_send_io_buffer_msg(struct tegra210_adsp_app *app,
516                                         dma_addr_t addr, size_t size,
517                                         uint32_t flags)
518 {
519         apm_msg_t apm_msg;
520
521         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_io_buffer_params_t);
522         apm_msg.msg.call_params.size = sizeof(apm_io_buffer_params_t);
523         apm_msg.msg.call_params.method = nvfx_apm_method_set_io_buffer;
524         apm_msg.msg.io_buffer_params.pin_type = IS_APM_IN(app->reg) ?
525                 NVFX_PIN_TYPE_INPUT : NVFX_PIN_TYPE_OUTPUT;
526         apm_msg.msg.io_buffer_params.pin_id = 0;
527         apm_msg.msg.io_buffer_params.addr.ptr = (uint64_t)addr;
528         apm_msg.msg.io_buffer_params.size = size;
529
530         return tegra210_adsp_send_msg(app, &apm_msg, flags);
531 }
532
533 static int tegra210_adsp_send_period_size_msg(struct tegra210_adsp_app *app,
534                                         size_t size, uint32_t flags)
535 {
536         apm_msg_t apm_msg;
537
538         apm_msg.msgq_msg.size =
539                 MSGQ_MSG_WSIZE(apm_notification_params_t);
540         apm_msg.msg.call_params.size =
541                 sizeof(apm_notification_params_t);
542         apm_msg.msg.call_params.method = nvfx_apm_method_set_notification_size;
543         apm_msg.msg.notification_params.pin_type = IS_APM_IN(app->reg) ?
544                 NVFX_PIN_TYPE_INPUT : NVFX_PIN_TYPE_OUTPUT;
545         apm_msg.msg.notification_params.pin_id = 0;
546         apm_msg.msg.notification_params.size = size;
547
548         return tegra210_adsp_send_msg(app, &apm_msg, flags);
549 }
550
551 static int tegra210_adsp_adma_params_msg(struct tegra210_adsp_app *app,
552                                         nvfx_adma_init_params_t *params,
553                                         uint32_t flags)
554 {
555         apm_msg_t apm_msg;
556
557         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_fx_set_param_params_t);
558         apm_msg.msg.call_params.size = sizeof(apm_fx_set_param_params_t);
559         apm_msg.msg.call_params.method = nvfx_apm_method_fx_set_param;
560         apm_msg.msg.fx_set_param_params.plugin.pvoid =
561                 app->plugin->plugin.pvoid;
562
563         params->call_params.size = sizeof(nvfx_adma_init_params_t);
564         params->call_params.method = nvfx_adma_method_init;
565         memcpy(&apm_msg.msg.fx_set_param_params.params, params,
566                 sizeof(*params));
567
568         return tegra210_adsp_send_msg(app, &apm_msg, flags);
569 }
570
571 static void tegra_adsp_override_freq_worker(struct work_struct *work)
572 {
573         adsp_override_freq(INT_MAX);
574 }
575
576 static int tegra210_adsp_send_state_msg(struct tegra210_adsp_app *app,
577                                         int32_t state, uint32_t flags)
578 {
579         apm_msg_t apm_msg;
580
581         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(nvfx_set_state_params_t);
582         apm_msg.msg.call_params.size = sizeof(nvfx_set_state_params_t);
583         apm_msg.msg.call_params.method = nvfx_method_set_state;
584         apm_msg.msg.state_params.state = state;
585
586         /* Spike ADSP freq to max when app transitions to active */
587         /* state; DFS will thereafter find appropriate rate      */
588         if (state == nvfx_state_active)
589                 schedule_work(app->override_freq_work);
590
591         return tegra210_adsp_send_msg(app, &apm_msg, flags);
592 }
593
594 static int tegra210_adsp_send_flush_msg(struct tegra210_adsp_app *app,
595                                         uint32_t flags)
596 {
597         apm_msg_t apm_msg;
598
599         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(nvfx_flush_params_t);
600         apm_msg.msg.call_params.size = sizeof(nvfx_flush_params_t);
601         apm_msg.msg.call_params.method = nvfx_method_flush;
602
603         return tegra210_adsp_send_msg(app, &apm_msg, flags);
604 }
605
606 static int tegra210_adsp_send_reset_msg(struct tegra210_adsp_app *app,
607                                         uint32_t flags)
608 {
609         apm_msg_t apm_msg;
610
611         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(nvfx_reset_params_t);
612         apm_msg.msg.call_params.size = sizeof(nvfx_reset_params_t);
613         apm_msg.msg.call_params.method = nvfx_method_reset;
614
615         return tegra210_adsp_send_msg(app, &apm_msg, flags);
616 }
617
618 static int tegra210_adsp_send_eos_msg(struct tegra210_adsp_app *app,
619                                         uint32_t flags)
620 {
621         apm_msg_t apm_msg;
622
623         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_eos_params_t);
624         apm_msg.msg.call_params.size = sizeof(apm_eos_params_t);
625         apm_msg.msg.call_params.method = nvfx_apm_method_set_eos;
626
627         return tegra210_adsp_send_msg(app, &apm_msg, flags);
628 }
629
630 static int tegra210_adsp_send_pos_msg(struct tegra210_adsp_app *app,
631                                         uint32_t pos, uint32_t flags)
632 {
633         apm_msg_t apm_msg;
634
635         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_position_params_t);
636         apm_msg.msg.call_params.size = sizeof(apm_position_params_t);
637         apm_msg.msg.call_params.method = nvfx_apm_method_set_position;
638         apm_msg.msg.position_params.pin_type = IS_APM_IN(app->reg) ?
639                 NVFX_PIN_TYPE_INPUT : NVFX_PIN_TYPE_OUTPUT;
640         apm_msg.msg.position_params.pin_id = 0;
641         apm_msg.msg.position_params.offset = pos;
642
643         return tegra210_adsp_send_msg(app, &apm_msg, flags);
644 }
645
646 /* ADSP app init/de-init APIs */
647 static int tegra210_adsp_app_init(struct tegra210_adsp *adsp,
648                                 struct tegra210_adsp_app *app)
649 {
650         int ret = 0;
651
652         /* If app is already open or it is APM output pin don't open app */
653         if (app->info || IS_APM_OUT(app->reg))
654                 return 0;
655
656         if (!app->desc->handle) {
657                 return -ENODEV;
658         }
659
660         app->info = nvadsp_app_init(app->desc->handle, NULL);
661         if (IS_ERR_OR_NULL(app->info)) {
662                 dev_err(adsp->dev, "Failed to init app %s(%s),"
663                         "nvadsp_app_init() returned with error %ld",
664                         app->desc->name, app->desc->fw_name, PTR_ERR(app->info));
665                 app->info = NULL;
666                 return -ENODEV;
667         }
668
669         spin_lock_init(&app->lock);
670
671         app->adsp = adsp;
672         app->msg_handler = tegra210_adsp_app_default_msg_handler;
673         app->override_freq_work = &adsp->override_freq_work;
674         app->plugin = PLUGIN_SHARED_MEM(app->info->mem.shared);
675         if (IS_APM_IN(app->reg)) {
676                 uint32_t apm_out_reg = APM_OUT_START +
677                                         (app->reg - APM_IN_START);
678                 struct tegra210_adsp_app *apm_out = &adsp->apps[apm_out_reg];
679
680                 app->apm = APM_SHARED_STATE(app->info->mem.shared);
681
682                 ret = nvadsp_mbox_open(&app->apm_mbox,
683                         &app->apm->mbox_id,
684                         app->desc->name, tegra210_adsp_msg_handler, app);
685                 if (ret < 0) {
686                         dev_err(adsp->dev, "Failed to open mailbox %s(%s).",
687                                 app->desc->name, app->desc->fw_name);
688                         goto err_app_exit;
689                 }
690
691                 app->msg_complete = devm_kzalloc(adsp->dev,
692                                         sizeof(struct completion), GFP_KERNEL);
693                 if (!app->msg_complete) {
694                         dev_err(adsp->dev, "Failed to allocate completion struct.");
695                         return -ENOMEM;
696                 }
697
698                 init_completion(app->msg_complete);
699
700                 ret = nvadsp_app_start(app->info);
701                 if (ret < 0) {
702                         dev_err(adsp->dev, "Failed to start adsp app");
703                         goto err_mbox_close;
704                 }
705                 /* Copy APM IN app data to APM OUT app */
706                 apm_out->info = app->info;
707                 apm_out->plugin = app->plugin;
708                 apm_out->apm = app->apm;
709                 apm_out->adsp = app->adsp;
710                 apm_out->apm_mbox = app->apm_mbox;
711                 apm_out->msg_complete = app->msg_complete;
712         } else if (IS_ADMA(app->reg)) {
713                 app->adma_chan = find_first_zero_bit(adsp->adma_usage,
714                                         TEGRA210_ADSP_ADMA_CHANNEL_COUNT);
715                 if (app->adma_chan >= TEGRA210_ADSP_ADMA_CHANNEL_COUNT) {
716                         dev_err(adsp->dev, "All ADMA channels are busy");
717                         return -EBUSY;
718                 }
719                 __set_bit(app->adma_chan, adsp->adma_usage);
720
721                 app->adma_chan += TEGRA210_ADSP_ADMA_CHANNEL_START;
722         }
723         return 0;
724
725 err_mbox_close:
726         nvadsp_mbox_close(&app->apm_mbox);
727 err_app_exit:
728         app->info = NULL;
729         return 0;
730 }
731
732 static void tegra210_adsp_app_deinit(struct tegra210_adsp *adsp,
733                                 struct tegra210_adsp_app *app)
734 {
735         /* TODO:
736          * Current usecases use static paths so app_deinit functionality
737          * is not needed and adds overhead of freeing and allocating apps
738          * everytime. Add app deinit functionality properly if needed in
739          * future.
740          */
741         return;
742 }
743
744 /* API to connect two APMs */
745 static int tegra210_adsp_connect_apm(struct tegra210_adsp *adsp,
746                                 struct tegra210_adsp_app *app)
747 {
748         uint32_t source = tegra210_adsp_get_source(adsp, app->reg);
749         struct tegra210_adsp_app *src = &adsp->apps[source];
750         int ret = 0;
751
752         /* If both APMs are in connected state no need to
753            send connect message */
754         if (app->connect && src->connect)
755                 return 0;
756
757         dev_vdbg(adsp->dev, "Connecting APM 0x%x -> 0x%x",
758                 src->reg, app->reg);
759
760         ret = tegra210_adsp_send_connect_msg(src, app,
761                 TEGRA210_ADSP_MSG_FLAG_SEND | TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
762         if (ret < 0) {
763                 dev_err(adsp->dev, "Connect msg failed. err %d.", ret);
764                 return ret;
765         }
766         return 1;
767 }
768
769 /* Recursive function to connect plugins under a APM
770    Returns BE/FE on the pcm path */
771 static int tegra210_adsp_connect_plugin(struct tegra210_adsp *adsp,
772                                         struct tegra210_adsp_app *app,
773                                         uint32_t *apm_in_src)
774 {
775         struct tegra210_adsp_app *src;
776         uint32_t source;
777         int ret = 0;
778
779         source = tegra210_adsp_get_source(adsp, app->reg);
780         if (!IS_ADSP_APP(source))
781                 return -ENODEV;
782
783         src = &adsp->apps[source];
784         if (!IS_APM_IN(src->reg)) {
785                 ret = tegra210_adsp_connect_plugin(adsp, src, apm_in_src);
786                 if (ret < 0)
787                         return ret;
788         } else {
789                 source = tegra210_adsp_get_source(adsp, src->reg);
790                 if (IS_APM_OUT(source)) {
791                         /* connect plugins inside next APM */
792                         ret = tegra210_adsp_connect_plugin(adsp,
793                                 &adsp->apps[source], apm_in_src);
794                         if (ret < 0)
795                                 return ret;
796                         /* connect APM_IN to APM_OUT */
797                         ret = tegra210_adsp_connect_apm(adsp, src);
798                         if (ret < 0)
799                                 return ret;
800                 } else {
801                         /* return if APM_IN is not
802                            connected to valid inputs */
803                         if (!IS_ADSP_FE(source) &&
804                                 !IS_ADSP_ADMAIF(source))
805                                 return -ENODEV;
806                         if (apm_in_src)
807                                 *apm_in_src = source;
808                 }
809         }
810         app->apm = src->apm;
811         app->apm_mbox = src->apm_mbox;
812
813         /* If App is already connected and source connections have not changed
814            no need to again send connect message */
815         if (!ret && app->connect)
816                 return 0;
817
818         dev_vdbg(adsp->dev, "Connecting plugin 0x%x -> 0x%x",
819                 src->reg, app->reg);
820
821         ret = tegra210_adsp_send_connect_msg(src, app,
822                 TEGRA210_ADSP_MSG_FLAG_SEND | TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
823         if (ret < 0) {
824                 dev_err(adsp->dev, "Connect msg failed. err %d.", ret);
825                 return ret;
826         }
827         app->connect = 1;
828
829         /* return 1 if new connection is established */
830         return 1;
831 }
832
833 /* Manages FE/BE plugins and deletes if fe_apm is specified */
834 static void tegra210_adsp_manage_plugin(struct tegra210_adsp *adsp,
835                 uint32_t end_reg, uint32_t apm_out, struct tegra210_adsp_app *fe_apm)
836 {
837         uint32_t j, fe_reg, be_reg;
838
839         if (IS_ADSP_FE(end_reg)) {
840                 /* manage playback path */
841                 fe_reg = end_reg;
842                 be_reg = 0;
843                 for (j = ADSP_ADMAIF_START; j <= ADSP_ADMAIF_END; j++) {
844                         if (tegra210_adsp_get_source(adsp, j) == apm_out) {
845                                 be_reg = j;
846                                 break;
847                         }
848                 }
849                 if (be_reg && fe_reg) {
850                         if (fe_apm) {
851                                 dev_vdbg(adsp->dev, "Remove playback FE %d -- BE %d pair",
852                                         fe_reg, be_reg);
853                                 tegra210_adsp_send_remove_msg(fe_apm,
854                                         TEGRA210_ADSP_MSG_FLAG_SEND |
855                                         TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
856                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].fe_reg = 0;
857                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].be_reg = 0;
858                         } else {
859                                 dev_vdbg(adsp->dev, "Found playback FE %d -- BE %d pair",
860                                         fe_reg, be_reg);
861                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].fe_reg = fe_reg;
862                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].be_reg = be_reg;
863                         }
864                 }
865         } else if (IS_ADSP_ADMAIF(end_reg)) {
866                 /* manage record path */
867                 fe_reg = 0;
868                 be_reg = end_reg;
869                 for (j = ADSP_FE_START; j <= ADSP_FE_END; j++) {
870                         if (tegra210_adsp_get_source(adsp, j) == apm_out) {
871                                 fe_reg = j;
872                                 break;
873                         }
874                 }
875                 if (be_reg && fe_reg) {
876                         if (fe_apm) {
877                                 dev_vdbg(adsp->dev, "Remove record FE %d -- BE %d pair",
878                                         fe_reg, be_reg);
879                                 tegra210_adsp_send_remove_msg(fe_apm,
880                                         TEGRA210_ADSP_MSG_FLAG_SEND |
881                                         TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
882                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].fe_reg = 0;
883                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].be_reg = 0;
884                         } else {
885                                 dev_vdbg(adsp->dev, "Found playback FE %d -- BE %d pair",
886                                         fe_reg, be_reg);
887                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].fe_reg = fe_reg;
888                                 adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].be_reg = be_reg;
889                         }
890                 }
891         }
892 }
893
894 /* Iterate over all APMs and establish pending connections */
895 static int tegra210_adsp_update_connection(struct tegra210_adsp *adsp)
896 {
897         int i, ret;
898         uint32_t end_reg;
899
900         for (i = APM_OUT_START; i <= APM_OUT_END; i++) {
901                 ret = tegra210_adsp_connect_plugin(adsp, &adsp->apps[i], &end_reg);
902                 if (ret >= 0) {
903                         /* Record FE/BE pair for every successful connection */
904                         tegra210_adsp_manage_plugin(adsp, end_reg, i, NULL);
905                 }
906         }
907
908         return 0;
909 }
910
911 /* Remove the plugin connections inside associated APM */
912 static int tegra210_adsp_remove_connection(struct tegra210_adsp *adsp,
913                 struct tegra210_adsp_app *plugin)
914 {
915         struct tegra210_adsp_app *app;
916         uint32_t i, source, apm_out = TEGRA210_ADSP_NONE;
917
918         if (!IS_ADSP_APP(plugin->reg))
919                 return 0;
920
921         for (i = APM_OUT_START; i <= APM_OUT_END; i++) {
922                 app =  &adsp->apps[i];
923                 /* if the path is already broken, do not continue */
924                 if (!app->connect)
925                         continue;
926                 while (IS_ADSP_APP(app->reg)) {
927                         if (app->reg == plugin->reg) {
928                                 apm_out = i;
929                                 break;
930                         }
931                         source = tegra210_adsp_get_source(adsp, app->reg);
932                         app =  &adsp->apps[source];
933                 }
934                 if (apm_out != TEGRA210_ADSP_NONE)
935                         break;
936         }
937         /* if plugin is not part of any APM, return here */
938         if (apm_out == TEGRA210_ADSP_NONE)
939                 return 0;
940
941         /* disconnect the plugins inside APM */
942         app = &adsp->apps[apm_out];
943         while (!IS_APM_IN(app->reg)) {
944                 source = tegra210_adsp_get_source(adsp, app->reg);
945                 if (!IS_ADSP_APP(source))
946                         break;
947                 app->connect = 0;
948                 app = &adsp->apps[source];
949         }
950
951         /* delete the plugins inside APM */
952         if (IS_APM_IN(app->reg)) {
953                 /* clear the FE/BE list */
954                 tegra210_adsp_manage_plugin(adsp,
955                         tegra210_adsp_get_source(adsp, app->reg),
956                         apm_out, app);
957         }
958         return 0;
959 }
960
961 /* ADSP mailbox message handler */
962 static status_t tegra210_adsp_msg_handler(uint32_t msg, void *data)
963 {
964         struct tegra210_adsp_app *app = data;
965         unsigned long flags;
966         apm_msg_t apm_msg;
967         int ret = 0;
968
969         spin_lock_irqsave(&app->lock, flags);
970
971         switch (msg) {
972         case apm_cmd_msg_ready: {
973                 ret = tegra210_adsp_get_msg(app->apm, &apm_msg);
974                 if (ret < 0) {
975                         pr_err("Dequeue failed %d.", ret);
976                         break;
977                 }
978
979                 if (app->msg_handler)
980                         ret = app->msg_handler(app, &apm_msg);
981         }
982         break;
983         default:
984                 pr_err("Unsupported mailbox msg %d.", msg);
985         }
986
987         spin_unlock_irqrestore(&app->lock, flags);
988         return ret;
989 }
990
991 static int tegra210_adsp_app_default_msg_handler(struct tegra210_adsp_app *app,
992                                         apm_msg_t *apm_msg)
993 {
994         switch (apm_msg->msg.call_params.method) {
995         case nvfx_apm_method_ack:
996                 complete(app->msg_complete);
997                 break;
998         default:
999                 pr_err("Unsupported cmd %d.", apm_msg->msg.call_params.method);
1000         }
1001         return 0;
1002 }
1003
1004 static int tegra210_adsp_pcm_msg_handler(struct tegra210_adsp_app *app,
1005                                         apm_msg_t *apm_msg)
1006 {
1007         struct tegra210_adsp_pcm_rtd *prtd = app->private_data;
1008
1009         switch (apm_msg->msg.call_params.method) {
1010         case nvfx_apm_method_set_position:
1011                 snd_pcm_period_elapsed(prtd->substream);
1012                 break;
1013         case nvfx_apm_method_ack:
1014                 complete(app->msg_complete);
1015                 break;
1016         default:
1017                 dev_err(prtd->dev, "Unsupported cmd %d.",
1018                         apm_msg->msg.call_params.method);
1019         }
1020         return 0;
1021 }
1022
1023 static int tegra210_adsp_compr_msg_handler(struct tegra210_adsp_app *app,
1024                                            apm_msg_t *apm_msg)
1025 {
1026         struct tegra210_adsp_compr_rtd *prtd = app->private_data;
1027
1028         if (!prtd) {
1029                 return 0;
1030         }
1031
1032         switch (apm_msg->msg.call_params.method) {
1033         case nvfx_apm_method_set_position:
1034                 snd_compr_fragment_elapsed(prtd->cstream);
1035                 break;
1036         case nvfx_apm_method_set_eos:
1037                 if (!prtd->is_draining) {
1038                         dev_warn(prtd->dev, "EOS reached before drain");
1039                         break;
1040                 }
1041                 snd_compr_drain_notify(prtd->cstream);
1042                 prtd->is_draining = 0;
1043                 break;
1044         case nvfx_apm_method_ack:
1045                 complete(app->msg_complete);
1046                 break;
1047         default:
1048                 dev_err(prtd->dev, "Unsupported cmd %d.",
1049                         apm_msg->msg.call_params.method);
1050         }
1051         return 0;
1052 }
1053
1054 /* Compress call-back APIs */
1055 static int tegra210_adsp_compr_open(struct snd_compr_stream *cstream)
1056 {
1057         struct snd_soc_pcm_runtime *rtd = cstream->device->private_data;
1058         struct tegra210_adsp *adsp =
1059                 snd_soc_platform_get_drvdata(rtd->platform);
1060         struct tegra210_adsp_compr_rtd *prtd;
1061         uint32_t fe_reg = rtd->codec_dai->id;
1062         int ret;
1063         int i;
1064
1065         dev_vdbg(adsp->dev, "%s : DAI ID %d", __func__, rtd->codec_dai->id);
1066
1067         if (!adsp->init_done)
1068                 return -ENODEV;
1069
1070         if (!adsp->pcm_path[fe_reg][cstream->direction].fe_reg ||
1071                 !adsp->pcm_path[fe_reg][cstream->direction].be_reg) {
1072                 dev_err(adsp->dev, "Broken Path%d - FE not linked to BE", fe_reg);
1073                 return -EPIPE;
1074         }
1075
1076         prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_compr_rtd),
1077                 GFP_KERNEL);
1078         if (!prtd) {
1079                 dev_err(adsp->dev, "Failed to allocate adsp rtd.");
1080                 return -ENOMEM;
1081         }
1082
1083         /* Find out the APM connected with ADSP-FE DAI */
1084         for (i = APM_IN_START; i <= APM_IN_END; i++) {
1085                 struct tegra210_adsp_app *app = &adsp->apps[i];
1086                 uint32_t source = tegra210_adsp_get_source(adsp, app->reg);
1087
1088                 if (source == fe_reg) {
1089                         app->msg_handler = tegra210_adsp_compr_msg_handler;
1090                         app->private_data = prtd;
1091                         app->fe = 1;
1092                         prtd->fe_apm = app;
1093                         break;
1094                 }
1095         }
1096
1097         if (!prtd->fe_apm) {
1098                 dev_err(adsp->dev, "No FE APM found\n");
1099                 devm_kfree(adsp->dev, prtd);
1100                 return -ENODEV;
1101         }
1102
1103         prtd->cstream = cstream;
1104         prtd->dev = adsp->dev;
1105         cstream->runtime->private_data = prtd;
1106         ret = pm_runtime_get_sync(adsp->dev);
1107         if (ret < 0) {
1108                 dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
1109                         __func__, ret);
1110         }
1111         return ret;
1112 }
1113
1114 static int tegra210_adsp_compr_free(struct snd_compr_stream *cstream)
1115 {
1116         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1117         unsigned long flags;
1118
1119         if (!prtd)
1120                 return -ENODEV;
1121
1122         tegra210_adsp_send_reset_msg(prtd->fe_apm,
1123                 TEGRA210_ADSP_MSG_FLAG_SEND | TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
1124
1125         pm_runtime_put(prtd->dev);
1126
1127         tegra210_adsp_deallocate_dma_buffer(&prtd->buf);
1128
1129         spin_lock_irqsave(&prtd->fe_apm->lock, flags);
1130
1131         /* Reset msg handler to disable msg processing */
1132         prtd->fe_apm->msg_handler = tegra210_adsp_app_default_msg_handler;
1133
1134         spin_unlock_irqrestore(&prtd->fe_apm->lock, flags);
1135
1136         cstream->runtime->private_data = NULL;
1137         devm_kfree(prtd->dev, prtd);
1138
1139         return 0;
1140 }
1141
1142 static int tegra210_adsp_compr_set_params(struct snd_compr_stream *cstream,
1143                         struct snd_compr_params *params)
1144 {
1145         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1146         int ret = 0;
1147
1148         if (!prtd)
1149                 return -ENODEV;
1150
1151         dev_vdbg(prtd->dev, "%s codec %d rate %d chan %d frag size %d frag %d",
1152                  __func__, params->codec.id,
1153                  snd_pcm_rate_bit_to_rate(params->codec.sample_rate),
1154                  params->codec.ch_in, params->buffer.fragment_size,
1155                  params->buffer.fragments);
1156
1157         ret = tegra210_adsp_preallocate_dma_buffer(prtd->dev,
1158                 params->buffer.fragment_size * params->buffer.fragments,
1159                 &prtd->buf);
1160         if (ret < 0)
1161                 return ret;
1162
1163         ret = tegra210_adsp_send_io_buffer_msg(prtd->fe_apm, prtd->buf.addr,
1164                                         prtd->buf.bytes,
1165                                         TEGRA210_ADSP_MSG_FLAG_SEND);
1166         if (ret < 0) {
1167                 dev_err(prtd->dev, "IO buffer send msg failed. err %d.", ret);
1168                 return ret;
1169         }
1170
1171         ret = tegra210_adsp_send_period_size_msg(prtd->fe_apm,
1172                                         params->buffer.fragment_size,
1173                                         TEGRA210_ADSP_MSG_FLAG_SEND);
1174         if (ret < 0) {
1175                 dev_err(prtd->dev, "Period size send msg failed. err %d.", ret);
1176                 return ret;
1177         }
1178
1179         memcpy(&prtd->codec, &params->codec, sizeof(struct snd_codec));
1180         return 0;
1181 }
1182
1183 static int tegra210_adsp_compr_get_params(struct snd_compr_stream *cstream,
1184                         struct snd_codec *codec)
1185 {
1186         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1187
1188         memcpy(codec, &prtd->codec, sizeof(struct snd_codec));
1189         return 0;
1190 }
1191
1192 static int tegra210_adsp_compr_trigger(struct snd_compr_stream *cstream,
1193                                         int cmd)
1194 {
1195         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1196         int ret = 0;
1197
1198         dev_vdbg(prtd->dev, "%s : cmd %d", __func__, cmd);
1199
1200         switch (cmd) {
1201         case SNDRV_PCM_TRIGGER_START:
1202                 ret = tegra210_adsp_send_state_msg(prtd->fe_apm,
1203                         nvfx_state_active,
1204                         TEGRA210_ADSP_MSG_FLAG_SEND);
1205                 if (ret < 0) {
1206                         dev_err(prtd->dev, "Failed to set state start.");
1207                         return ret;
1208                 }
1209                 break;
1210         case SNDRV_PCM_TRIGGER_RESUME:
1211         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1212                 ret = tegra210_adsp_send_state_msg(prtd->fe_apm,
1213                                 nvfx_state_active,
1214                                 TEGRA210_ADSP_MSG_FLAG_SEND);
1215                 if (ret < 0) {
1216                         dev_err(prtd->dev, "Failed to set state resume");
1217                         return ret;
1218                 }
1219                 break;
1220         case SNDRV_PCM_TRIGGER_STOP:
1221                 ret = tegra210_adsp_send_state_msg(prtd->fe_apm,
1222                         nvfx_state_inactive,
1223                         TEGRA210_ADSP_MSG_FLAG_SEND);
1224                 if (ret < 0) {
1225                         dev_err(prtd->dev, "Failed to set state stop");
1226                         return ret;
1227                 }
1228
1229                 ret = tegra210_adsp_send_flush_msg(prtd->fe_apm,
1230                         TEGRA210_ADSP_MSG_FLAG_SEND);
1231                 if (ret < 0) {
1232                         dev_err(prtd->dev, "Failed to reset");
1233                         return ret;
1234                 }
1235                 break;
1236         case SNDRV_PCM_TRIGGER_SUSPEND:
1237         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1238                 ret = tegra210_adsp_send_state_msg(prtd->fe_apm,
1239                         nvfx_state_inactive,
1240                         TEGRA210_ADSP_MSG_FLAG_SEND);
1241                 if (ret < 0) {
1242                         dev_err(prtd->dev, "Failed to set state pause");
1243                         return ret;
1244                 }
1245                 break;
1246         case SND_COMPR_TRIGGER_DRAIN:
1247                 prtd->is_draining = 1;
1248                 ret = tegra210_adsp_send_eos_msg(prtd->fe_apm,
1249                         TEGRA210_ADSP_MSG_FLAG_SEND);
1250                 if (ret < 0) {
1251                         dev_err(prtd->dev, "Failed to set state drain");
1252                         return ret;
1253                 }
1254                 break;
1255         default:
1256                 dev_err(prtd->dev, "Unsupported state.");
1257                 return -EINVAL;
1258         }
1259         return 0;
1260 }
1261
1262 static int tegra210_adsp_compr_copy(struct snd_compr_stream *cstream,
1263                         char __user *buf, size_t count)
1264 {
1265         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1266         struct snd_compr_runtime *runtime = cstream->runtime;
1267         void *dstn;
1268         size_t copy;
1269         u64 app_pointer;
1270
1271         dev_vdbg(prtd->dev, "%s : size %d", __func__, (uint32_t)count);
1272
1273         if (!prtd->fe_apm->adsp->adsp_started || !count)
1274                 return 0;
1275
1276         app_pointer = div64_u64(runtime->total_bytes_available,
1277                                 runtime->buffer_size);
1278         app_pointer = runtime->total_bytes_available -
1279                         (app_pointer * runtime->buffer_size);
1280         dstn = prtd->buf.area + app_pointer;
1281
1282         if (count < runtime->buffer_size - app_pointer) {
1283                 if (copy_from_user(dstn, buf, count))
1284                         return -EFAULT;
1285         } else {
1286                 copy = runtime->buffer_size - app_pointer;
1287                 if (copy_from_user(dstn, buf, copy))
1288                         return -EFAULT;
1289                 if (copy_from_user(prtd->buf.area, buf + copy, count - copy))
1290                         return -EFAULT;
1291         }
1292         tegra210_adsp_send_pos_msg(prtd->fe_apm,
1293             (runtime->total_bytes_available + count) % runtime->buffer_size,
1294             TEGRA210_ADSP_MSG_FLAG_SEND);
1295
1296         return count;
1297 }
1298
1299 static int tegra210_adsp_compr_pointer(struct snd_compr_stream *cstream,
1300                         struct snd_compr_tstamp *tstamp)
1301 {
1302         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1303         struct snd_soc_pcm_runtime *rtd = cstream->device->private_data;
1304         struct tegra210_adsp *adsp =
1305                 snd_soc_platform_get_drvdata(rtd->platform);
1306         struct tegra210_adsp_app *app = prtd->fe_apm;
1307         nvfx_shared_state_t *shared = &app->apm->nvfx_shared_state;
1308         uint32_t frames_played;
1309
1310         if (!adsp->adsp_started)
1311                 return -ENODEV;
1312
1313         frames_played = ((shared->output[0].bytes >> 2) *
1314                 snd_pcm_rate_bit_to_rate(prtd->codec.sample_rate)) /
1315                 adsp->i2s_rate;
1316
1317         tstamp->byte_offset = shared->input[0].bytes %
1318                 cstream->runtime->buffer_size;
1319         tstamp->copied_total = shared->input[0].bytes;
1320         tstamp->pcm_frames = frames_played;
1321         /* TODO : calculate IO frames correctly */
1322         tstamp->pcm_io_frames = frames_played;
1323         tstamp->sampling_rate =
1324                 snd_pcm_rate_bit_to_rate(prtd->codec.sample_rate);
1325
1326         dev_vdbg(prtd->dev, "%s off %d copied %d pcm %d pcm io %d",
1327                  __func__, (int)tstamp->byte_offset, (int)tstamp->copied_total,
1328                  (int)tstamp->pcm_frames, (int)tstamp->pcm_io_frames);
1329         return 0;
1330 }
1331
1332 static int tegra210_adsp_compr_get_caps(struct snd_compr_stream *cstream,
1333                         struct snd_compr_caps *caps)
1334 {
1335         if (cstream->direction == SND_COMPRESS_PLAYBACK)
1336                 memcpy(caps, &tegra210_adsp_compr_caps[SND_COMPRESS_PLAYBACK],
1337                         sizeof(struct snd_compr_caps));
1338         else
1339                 memcpy(caps, &tegra210_adsp_compr_caps[SND_COMPRESS_CAPTURE],
1340                         sizeof(struct snd_compr_caps));
1341
1342         return 0;
1343 }
1344
1345 static int tegra210_adsp_compr_codec_caps(struct snd_compr_stream *cstream,
1346                         struct snd_compr_codec_caps *codec_caps)
1347 {
1348         struct tegra210_adsp_compr_rtd *prtd = cstream->runtime->private_data;
1349
1350         dev_vdbg(prtd->dev, "%s : codec %d", __func__, codec_caps->codec);
1351
1352         if (!codec_caps->codec)
1353                 codec_caps->codec = prtd->codec.id;
1354
1355         switch (codec_caps->codec) {
1356         case SND_AUDIOCODEC_MP3:
1357                 memcpy(codec_caps, &adsp_compr_codec_caps[SND_AUDIOCODEC_MP3],
1358                         sizeof(struct snd_compr_codec_caps));
1359                 return 0;
1360         case SND_AUDIOCODEC_AAC:
1361                 memcpy(codec_caps, &adsp_compr_codec_caps[SND_AUDIOCODEC_AAC],
1362                         sizeof(struct snd_compr_codec_caps));
1363                 return 0;
1364         default:
1365                 dev_err(prtd->dev, "Unsupported codec %d", codec_caps->codec);
1366                 return -EINVAL;
1367         }
1368         return 0;
1369 }
1370
1371 static struct snd_compr_ops tegra210_adsp_compr_ops = {
1372
1373         .open = tegra210_adsp_compr_open,
1374         .free = tegra210_adsp_compr_free,
1375         .set_params = tegra210_adsp_compr_set_params,
1376         .get_params = tegra210_adsp_compr_get_params,
1377         .trigger = tegra210_adsp_compr_trigger,
1378         .pointer = tegra210_adsp_compr_pointer,
1379         .copy = tegra210_adsp_compr_copy,
1380         .get_caps = tegra210_adsp_compr_get_caps,
1381         .get_codec_caps = tegra210_adsp_compr_codec_caps,
1382 };
1383
1384 /* PCM APIs */
1385 static int tegra210_adsp_pcm_open(struct snd_pcm_substream *substream)
1386 {
1387         struct snd_soc_pcm_runtime *rtd = substream->private_data;
1388         struct tegra210_adsp *adsp =
1389                 snd_soc_platform_get_drvdata(rtd->platform);
1390         struct tegra210_adsp_pcm_rtd *prtd;
1391         uint32_t fe_reg = rtd->codec_dai->id;
1392         uint32_t source;
1393         int i, ret = 0;
1394
1395         dev_vdbg(adsp->dev, "%s", __func__);
1396
1397         if (!adsp->pcm_path[fe_reg][substream->stream].fe_reg ||
1398                 !adsp->pcm_path[fe_reg][substream->stream].be_reg) {
1399                 dev_err(adsp->dev, "Broken Path%d - FE not linked to BE", fe_reg);
1400                 return -EPIPE;
1401         }
1402
1403         prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_pcm_rtd),
1404                 GFP_KERNEL);
1405         if (!prtd) {
1406                 dev_err(adsp->dev, "Failed to allocate adsp rtd.");
1407                 return -ENOMEM;
1408         }
1409
1410         /* Find out the APM connected with ADSP-FE DAI */
1411         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1412                 for (i = APM_IN_START; i < APM_IN_END; i++) {
1413                         struct tegra210_adsp_app *app = &adsp->apps[i];
1414
1415                         source = tegra210_adsp_get_source(adsp, app->reg);
1416                         if (source == fe_reg) {
1417                                 prtd->fe_apm = app;
1418                                 break;
1419                         }
1420                 }
1421         } else {
1422                 source = tegra210_adsp_get_source(adsp, fe_reg);
1423                 if (IS_APM_OUT(source)) {
1424                         uint32_t apm_in_reg =
1425                                 APM_IN_START + (source - APM_OUT_START);
1426                         adsp->apps[apm_in_reg].msg_handler =
1427                                 tegra210_adsp_pcm_msg_handler;
1428                         adsp->apps[apm_in_reg].private_data = prtd;
1429                         prtd->fe_apm = &adsp->apps[source];
1430                 }
1431         }
1432
1433         if (!prtd->fe_apm) {
1434                 dev_err(adsp->dev, "No FE APM found\n");
1435                 devm_kfree(adsp->dev, prtd);
1436                 return -ENODEV;
1437         }
1438         prtd->fe_apm->msg_handler = tegra210_adsp_pcm_msg_handler;
1439         prtd->fe_apm->private_data = prtd;
1440         prtd->fe_apm->fe = 1;
1441
1442         /* Set HW params now that initialization is complete */
1443         snd_soc_set_runtime_hwparams(substream, &adsp_pcm_hardware);
1444
1445         /* Ensure period size is multiple of 4 */
1446         ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
1447                 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x4);
1448         if (ret) {
1449                 dev_err(adsp->dev, "failed to set constraint %d\n", ret);
1450                 return ret;
1451         }
1452         substream->runtime->private_data = prtd;
1453         prtd->substream = substream;
1454         prtd->dev = adsp->dev;
1455
1456         return 0;
1457 }
1458
1459 static int tegra210_adsp_pcm_close(struct snd_pcm_substream *substream)
1460 {
1461         struct tegra210_adsp_pcm_rtd *prtd = substream->runtime->private_data;
1462         unsigned long flags;
1463
1464         dev_vdbg(prtd->dev, "%s", __func__);
1465
1466         if (prtd) {
1467                 tegra210_adsp_send_reset_msg(prtd->fe_apm,
1468                         TEGRA210_ADSP_MSG_FLAG_SEND |
1469                         TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
1470
1471                 spin_lock_irqsave(&prtd->fe_apm->lock, flags);
1472
1473                 /* Reset msg handler to disable msg processing */
1474                 prtd->fe_apm->msg_handler =
1475                         tegra210_adsp_app_default_msg_handler;
1476
1477                 spin_unlock_irqrestore(&prtd->fe_apm->lock, flags);
1478
1479                 prtd->fe_apm->fe = 1;
1480                 substream->runtime->private_data = NULL;
1481                 devm_kfree(prtd->dev, prtd);
1482         }
1483
1484         return 0;
1485 }
1486
1487 static int tegra210_adsp_pcm_hw_params(struct snd_pcm_substream *substream,
1488                                 struct snd_pcm_hw_params *params)
1489 {
1490         struct tegra210_adsp_pcm_rtd *prtd = substream->runtime->private_data;
1491         struct snd_dma_buffer *buf = &substream->dma_buffer;
1492         int ret = 0;
1493
1494         dev_vdbg(prtd->dev, "%s rate %d chan %d bps %d"
1495                 "period size %d buffer size %d",
1496                  __func__, params_rate(params), params_channels(params),
1497                  snd_pcm_format_width(params_format(params)),
1498                  params_period_size(params),
1499                  params_buffer_bytes(params));
1500
1501         ret = tegra210_adsp_send_io_buffer_msg(prtd->fe_apm, buf->addr,
1502                                         params_buffer_bytes(params),
1503                                         TEGRA210_ADSP_MSG_FLAG_SEND);
1504         if (ret < 0)
1505                 return ret;
1506
1507         ret = tegra210_adsp_send_period_size_msg(prtd->fe_apm,
1508                                         params_period_size(params),
1509                                         TEGRA210_ADSP_MSG_FLAG_SEND);
1510         if (ret < 0)
1511                 return ret;
1512
1513         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1514         return 0;
1515 }
1516
1517 static int tegra210_adsp_pcm_hw_free(struct snd_pcm_substream *substream)
1518 {
1519         snd_pcm_set_runtime_buffer(substream, NULL);
1520         return 0;
1521 }
1522
1523 static int tegra210_adsp_pcm_trigger(struct snd_pcm_substream *substream,
1524                                      int cmd)
1525 {
1526         struct tegra210_adsp_pcm_rtd *prtd = substream->runtime->private_data;
1527         int ret = 0;
1528
1529         dev_vdbg(prtd->dev, "%s : state %d", __func__, cmd);
1530
1531         switch (cmd) {
1532         case SNDRV_PCM_TRIGGER_START:
1533         case SNDRV_PCM_TRIGGER_RESUME:
1534         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1535                 ret = tegra210_adsp_send_state_msg(prtd->fe_apm,
1536                         nvfx_state_active,
1537                         TEGRA210_ADSP_MSG_FLAG_SEND);
1538                 if (ret < 0) {
1539                         dev_err(prtd->dev, "Failed to set state");
1540                         return ret;
1541                 }
1542                 break;
1543         case SNDRV_PCM_TRIGGER_STOP:
1544         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1545         case SNDRV_PCM_TRIGGER_SUSPEND:
1546                 ret = tegra210_adsp_send_state_msg(prtd->fe_apm,
1547                         nvfx_state_inactive,
1548                         TEGRA210_ADSP_MSG_FLAG_SEND);
1549                 if (ret < 0) {
1550                         dev_err(prtd->dev, "Failed to set state");
1551                         return ret;
1552                 }
1553
1554                 ret = tegra210_adsp_send_flush_msg(prtd->fe_apm,
1555                         TEGRA210_ADSP_MSG_FLAG_SEND);
1556                 if (ret < 0) {
1557                         dev_err(prtd->dev, "Failed to reset");
1558                         return ret;
1559                 }
1560                 break;
1561         default:
1562                 dev_err(prtd->dev, "Unsupported state.");
1563                 return -EINVAL;
1564         }
1565
1566         return 0;
1567 }
1568
1569 static int tegra210_adsp_pcm_ack(struct snd_pcm_substream *substream)
1570 {
1571         struct tegra210_adsp_pcm_rtd *prtd = substream->runtime->private_data;
1572         struct snd_pcm_runtime *runtime = substream->runtime;
1573         size_t pos;
1574         int ret = 0;
1575
1576         dev_vdbg(prtd->dev, "%s %d", __func__, (int)runtime->control->appl_ptr);
1577
1578         pos = frames_to_bytes(runtime,
1579                 runtime->control->appl_ptr % runtime->buffer_size);
1580         ret = tegra210_adsp_send_pos_msg(prtd->fe_apm, pos,
1581                 TEGRA210_ADSP_MSG_FLAG_SEND);
1582         if (ret < 0) {
1583                 dev_err(prtd->dev, "Failed to send write position.");
1584                 return ret;
1585         }
1586
1587         return ret;
1588 }
1589
1590 static snd_pcm_uframes_t tegra210_adsp_pcm_pointer(
1591                 struct snd_pcm_substream *substream)
1592 {
1593         struct tegra210_adsp_pcm_rtd *prtd = substream->runtime->private_data;
1594         struct tegra210_adsp_app *app = prtd->fe_apm;
1595         size_t bytes, pos;
1596
1597         if (!app->adsp->adsp_started)
1598                 return -ENODEV;
1599
1600         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1601                 bytes = app->apm->nvfx_shared_state.output[0].bytes;
1602         else
1603                 bytes = app->apm->nvfx_shared_state.input[0].bytes;
1604
1605         pos = bytes % frames_to_bytes(substream->runtime,
1606                 substream->runtime->buffer_size);
1607
1608         /* TODO : If SRC in path do size conversion */
1609
1610         dev_vdbg(prtd->dev, "%s bytes %zu position %zu", __func__, bytes, pos);
1611         return bytes_to_frames(substream->runtime, pos);
1612 }
1613
1614 static struct snd_pcm_ops tegra210_adsp_pcm_ops = {
1615         .open           = tegra210_adsp_pcm_open,
1616         .close          = tegra210_adsp_pcm_close,
1617         .ioctl          = snd_pcm_lib_ioctl,
1618         .hw_params      = tegra210_adsp_pcm_hw_params,
1619         .hw_free        = tegra210_adsp_pcm_hw_free,
1620         .trigger        = tegra210_adsp_pcm_trigger,
1621         .pointer        = tegra210_adsp_pcm_pointer,
1622         .ack            = tegra210_adsp_pcm_ack,
1623 };
1624
1625 static int tegra210_adsp_pcm_new(struct snd_soc_pcm_runtime *rtd)
1626 {
1627 #if ENABLE_ADSP
1628         struct snd_card *card = rtd->card->snd_card;
1629         struct snd_pcm *pcm = rtd->pcm;
1630         int ret = 0;
1631
1632         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1633                 struct snd_pcm_substream *substream =
1634                         pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1635
1636                 ret = tegra210_adsp_preallocate_dma_buffer(card->dev,
1637                                         adsp_pcm_hardware.buffer_bytes_max,
1638                                         &substream->dma_buffer);
1639
1640                 if (ret)
1641                         return ret;
1642         }
1643
1644         if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1645                 struct snd_pcm_substream *substream =
1646                         pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
1647
1648                 ret = tegra210_adsp_preallocate_dma_buffer(card->dev,
1649                                         adsp_pcm_hardware.buffer_bytes_max,
1650                                         &substream->dma_buffer);
1651                 if (ret)
1652                         goto err;
1653         }
1654
1655         return 0;
1656
1657 err:
1658         tegra210_adsp_deallocate_dma_buffer(
1659                 &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer);
1660         return ret;
1661 #else
1662         return 0;
1663 #endif
1664 }
1665
1666 static void tegra210_adsp_pcm_free(struct snd_pcm *pcm)
1667 {
1668         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1669                 int stream = SNDRV_PCM_STREAM_PLAYBACK;
1670
1671                 tegra210_adsp_deallocate_dma_buffer(
1672                         &pcm->streams[stream].substream->dma_buffer);
1673         }
1674         if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1675                 int stream = SNDRV_PCM_STREAM_CAPTURE;
1676
1677                 tegra210_adsp_deallocate_dma_buffer(
1678                         &pcm->streams[stream].substream->dma_buffer);
1679         }
1680 }
1681
1682 static int tegra210_adsp_pcm_probe(struct snd_soc_platform *platform)
1683 {
1684         platform->dapm.idle_bias_off = 1;
1685         return 0;
1686 }
1687
1688 /* ADSP-ADMAIF codec driver HW-params. Used for configuring ADMA */
1689 static int tegra210_adsp_admaif_hw_params(struct snd_pcm_substream *substream,
1690                                  struct snd_pcm_hw_params *params,
1691                                  struct snd_soc_dai *dai)
1692 {
1693         struct tegra210_adsp *adsp = snd_soc_dai_get_drvdata(dai);
1694         struct tegra210_adsp_app *app;
1695         nvfx_adma_init_params_t adma_params;
1696         uint32_t be_reg = dai->id;
1697         uint32_t admaif_id = be_reg - ADSP_ADMAIF_START + 1;
1698         uint32_t source;
1699         int i, ret;
1700
1701         dev_vdbg(adsp->dev, "%s : stream %d admaif %d\n",
1702                 __func__, substream->stream, admaif_id);
1703
1704         if (!adsp->adsp_started)
1705                 return -EINVAL;
1706
1707         adma_params.mode = ADMA_MODE_CONTINUOUS;
1708         adma_params.ahub_channel = admaif_id;
1709         adma_params.periods = 2; /* We need ping-pong buffers for ADMA */
1710
1711         /* Set DMA params connected with ADSP-BE */
1712         /* As a COCEC DAI, CAPTURE is transmit */
1713         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1714                 app = &adsp->apps[be_reg];
1715                 source = tegra210_adsp_get_source(adsp, app->reg);
1716
1717                 app = &adsp->apps[source];
1718                 if (!IS_APM_OUT(app->reg))
1719                         return 0;
1720
1721                 source = tegra210_adsp_get_source(adsp, app->reg);
1722                 app = &adsp->apps[source];
1723                 if (!IS_ADMA(app->reg))
1724                         return 0;
1725
1726                 adma_params.adma_channel = app->adma_chan;
1727                 adma_params.direction = ADMA_MEMORY_TO_AHUB;
1728                 adma_params.event.pvoid = app->apm->output_event.pvoid;
1729
1730                 ret = tegra210_adsp_adma_params_msg(app, &adma_params,
1731                         TEGRA210_ADSP_MSG_FLAG_SEND);
1732                 if (ret < 0) {
1733                         dev_err(adsp->dev, "ADMA params msg failed. %d.", ret);
1734                         return ret;
1735                 }
1736         } else {
1737                 for (i = ADMA_START; i <= ADMA_END; i++) {
1738                         app = &adsp->apps[i];
1739                         source = tegra210_adsp_get_source(adsp, app->reg);
1740                         if (!IS_APM_IN(source))
1741                                 continue;
1742
1743                         app = &adsp->apps[source];
1744                         source = tegra210_adsp_get_source(adsp, app->reg);
1745                         if (source != be_reg)
1746                                 continue;
1747
1748                         app = &adsp->apps[i];
1749                         adma_params.adma_channel = app->adma_chan;
1750                         adma_params.direction = ADMA_AHUB_TO_MEMORY;
1751                         adma_params.event.pvoid = app->apm->input_event.pvoid;
1752
1753                         ret = tegra210_adsp_adma_params_msg(app,
1754                                         &adma_params,
1755                                         TEGRA210_ADSP_MSG_FLAG_SEND);
1756                         if (ret < 0) {
1757                                 dev_err(adsp->dev, "ADMA params msg failed");
1758                                 return ret;
1759                         }
1760                 }
1761         }
1762         return 0;
1763 }
1764
1765 #ifdef CONFIG_PM_RUNTIME
1766 static int tegra210_adsp_runtime_suspend(struct device *dev)
1767 {
1768         struct tegra210_adsp *adsp = dev_get_drvdata(dev);
1769         int ret = 0, i;
1770
1771         dev_dbg(adsp->dev, "%s\n", __func__);
1772
1773         if (!adsp->adsp_started)
1774                 return 0;
1775
1776         /* Check for msgq empty before suspend */
1777         for (i = 0; i < TEGRA210_ADSP_VIRT_REG_MAX; i++) {
1778                 struct tegra210_adsp_app *app = &adsp->apps[i];
1779                 if (app->plugin && IS_APM_IN(app->reg)) {
1780                         msgq_t *msgq = &app->apm->msgq_recv.msgq;
1781                         if (msgq->read_index == msgq->write_index)
1782                                 continue;
1783                         pr_err("%s: app %d, msgq not empty rd %d wr %d\n",
1784                                 __func__, app->reg, msgq->read_index,
1785                                 msgq->write_index);
1786                 }
1787         }
1788
1789         ret = nvadsp_os_suspend();
1790         if (ret) {
1791                 dev_err(adsp->dev, "Failed to suspend ADSP OS");
1792                 tegra210_adsp_crash_handler(adsp);
1793         }
1794
1795         adsp->adsp_started = 0;
1796
1797         return ret;
1798 }
1799
1800 static int tegra210_adsp_runtime_resume(struct device *dev)
1801 {
1802         struct tegra210_adsp *adsp = dev_get_drvdata(dev);
1803         int ret = 0;
1804
1805         dev_dbg(adsp->dev, "%s\n", __func__);
1806
1807         if (!adsp->init_done)
1808                 return 0;
1809
1810         ret = nvadsp_os_start();
1811         if (ret) {
1812                 dev_err(adsp->dev, "Failed to start ADSP OS ret 0x%x", ret);
1813                 tegra210_adsp_crash_handler(adsp);
1814                 return ret;
1815         }
1816         adsp->adsp_started = 1;
1817
1818         return ret;
1819 }
1820 #endif
1821
1822 /* ADSP platform driver read/write call-back */
1823 static unsigned int tegra210_adsp_read(struct snd_soc_platform *platform,
1824                 unsigned int reg)
1825 {
1826         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1827
1828         dev_vdbg(adsp->dev, "%s [0x%x] -> 0x%x\n", __func__, reg,
1829                 tegra210_adsp_reg_read(adsp, reg));
1830
1831         return tegra210_adsp_reg_read(adsp, reg);
1832 }
1833
1834 static int tegra210_adsp_write(struct snd_soc_platform *platform,
1835                 unsigned int reg,
1836                 unsigned int val)
1837 {
1838         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1839
1840         dev_vdbg(adsp->dev, "%s [0x%x] -> 0x%x\n", __func__, reg, val);
1841
1842         tegra210_adsp_reg_write(adsp, reg, val);
1843         return 0;
1844 }
1845
1846 /* DAPM ENUM MUX get/put callbacks */
1847 static int tegra210_adsp_mux_get(struct snd_kcontrol *kcontrol,
1848         struct snd_ctl_elem_value *ucontrol)
1849 {
1850         struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1851         struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1852         struct snd_soc_platform *platform = widget->platform;
1853         struct soc_enum *e =
1854                 (struct soc_enum *)kcontrol->private_value;
1855         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1856         uint32_t val = tegra210_adsp_reg_read(adsp, e->reg);
1857
1858         ucontrol->value.integer.value[0] =
1859                 (val & TEGRA210_ADSP_WIDGET_SOURCE_MASK) >> e->shift_l;
1860         return 0;
1861 }
1862
1863 static int tegra210_adsp_mux_put(struct snd_kcontrol *kcontrol,
1864         struct snd_ctl_elem_value *ucontrol)
1865 {
1866         struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1867         struct snd_soc_dapm_widget *w = wlist->widgets[0];
1868         struct snd_soc_platform *platform = w->platform;
1869         uint32_t val = ucontrol->value.enumerated.item[0];
1870         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1871         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1872         struct tegra210_adsp_app *app;
1873         uint32_t cur_val = 0;
1874         int ret = 0;
1875
1876         if (!adsp->init_done)
1877                 return -ENODEV;
1878
1879         if (e->reg >= TEGRA210_ADSP_VIRT_REG_MAX)
1880                 return -EINVAL;
1881
1882         ret = pm_runtime_get_sync(adsp->dev);
1883         if (ret < 0) {
1884                 dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
1885                         __func__, ret);
1886                 return ret;
1887         }
1888
1889         /* Init or de-init app based on connection */
1890         if (IS_ADSP_APP(e->reg)) {
1891                 app = &adsp->apps[e->reg];
1892                 cur_val = tegra210_adsp_get_source(adsp, e->reg);
1893                 if (cur_val != val) {
1894                         if (app->connect) {
1895                                 /* remove existing connections if any */
1896                                 tegra210_adsp_remove_connection(adsp, app);
1897                         }
1898                         app->connect = 0;
1899                 }
1900
1901                 if (val == TEGRA210_ADSP_NONE) {
1902                         tegra210_adsp_app_deinit(adsp, app);
1903                 } else {
1904                         ret = tegra210_adsp_app_init(adsp, app);
1905                         if (ret < 0) {
1906                                 dev_err(adsp->dev, "Failed to init app %s(%s)",
1907                                         app->desc->name, app->desc->fw_name);
1908                                 goto err_put;
1909                         }
1910                 }
1911         }
1912         tegra210_adsp_reg_update_bits(adsp, e->reg,
1913                 TEGRA210_ADSP_WIDGET_SOURCE_MASK, val << e->shift_l);
1914         tegra210_adsp_update_connection(adsp);
1915
1916         snd_soc_dapm_mux_update_power(w, kcontrol, val, e);
1917
1918 err_put:
1919         pm_runtime_put(adsp->dev);
1920         return ret ? ret : 1;
1921 }
1922
1923 /* ALSA control get/put call-back implementation */
1924 static int tegra210_adsp_get(struct snd_kcontrol *kcontrol,
1925         struct snd_ctl_elem_value *ucontrol)
1926 {
1927         struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
1928         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1929
1930         if (strstr(kcontrol->id.name, "ADSP init"))
1931                 ucontrol->value.enumerated.item[0] = adsp->init_done;
1932         else if (strstr(kcontrol->id.name, "ADSP Recovery Enable"))
1933                 ucontrol->value.enumerated.item[0] = adsp->recovery_enabled;
1934         else if (strstr(kcontrol->id.name, "ADSP Recovery Count"))
1935                 ucontrol->value.enumerated.item[0] = adsp->recovery_count;
1936         return 0;
1937 }
1938
1939 static int tegra210_adsp_put(struct snd_kcontrol *kcontrol,
1940         struct snd_ctl_elem_value *ucontrol)
1941 {
1942         struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
1943         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1944         int val = ucontrol->value.enumerated.item[0];
1945         int ret = 0;
1946
1947         if (strstr(kcontrol->id.name, "ADSP init")) {
1948                 adsp->audio_task = current;
1949                 if (val == adsp->init_done)
1950                         return 0;
1951
1952                 if (val) {
1953                         ret = tegra210_adsp_init(adsp);
1954                         if (ret < 0) {
1955                                 dev_err(adsp->dev, "Failed to init ADSP.");
1956                                 return ret;
1957                         }
1958                 } else {
1959                         tegra210_adsp_deinit(adsp);
1960                 }
1961         } else if (strstr(kcontrol->id.name, "ADSP Recovery Enable"))
1962                 adsp->recovery_enabled = val;
1963
1964         return 0;
1965 }
1966
1967 /* DAPM widget event */
1968 static int tegra210_adsp_widget_event(struct snd_soc_dapm_widget *w,
1969                                 struct snd_kcontrol *kcontrol, int event)
1970 {
1971         struct snd_soc_platform *platform = w->platform;
1972         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
1973         struct tegra210_adsp_app *app;
1974         int ret = 0;
1975
1976         if (!IS_ADSP_APP(w->reg))
1977                 return 0;
1978
1979         app = &adsp->apps[w->reg];
1980         /* For FE apm state change will be handled from trigger call back */
1981         if (app->fe)
1982                 return 0;
1983
1984         if (SND_SOC_DAPM_EVENT_ON(event)) {
1985                 if (IS_APM_IN(w->reg)) {
1986                         /* Request higher ADSP clock when starting stream.
1987                          * Actmon takes care of adjusting frequency later. */
1988                         ret = pm_runtime_get_sync(adsp->dev);
1989                         if (ret < 0) {
1990                                 dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
1991                                         __func__, ret);
1992                                 return ret;
1993                         }
1994                         if (app->min_adsp_clock)
1995                                 adsp_update_dfs_min_rate(app->min_adsp_clock * 1000);
1996                         ret = tegra210_adsp_send_state_msg(app, nvfx_state_active,
1997                                 TEGRA210_ADSP_MSG_FLAG_SEND);
1998                         if (ret < 0)
1999                                 dev_err(adsp->dev, "Failed to set state active.");
2000                         pm_runtime_put(adsp->dev);
2001                 }
2002         } else {
2003                 if (IS_APM_IN(w->reg)) {
2004                         ret = pm_runtime_get_sync(adsp->dev);
2005                         if (ret < 0) {
2006                                 dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
2007                                         __func__, ret);
2008                                 return ret;
2009                         }
2010                         ret = tegra210_adsp_send_state_msg(app, nvfx_state_inactive,
2011                                 TEGRA210_ADSP_MSG_FLAG_SEND);
2012                         if (ret < 0)
2013                                 dev_err(adsp->dev, "Failed to set state inactive.");
2014                         ret = tegra210_adsp_send_reset_msg(app,
2015                                 (TEGRA210_ADSP_MSG_FLAG_SEND |
2016                                 TEGRA210_ADSP_MSG_FLAG_NEED_ACK));
2017                         if (ret < 0)
2018                                 dev_err(adsp->dev, "Failed to reset.");
2019                         if (app->min_adsp_clock)
2020                                 adsp_update_dfs_min_rate(0);
2021                         pm_runtime_put(adsp->dev);
2022                 }
2023         }
2024
2025         return ret;
2026 }
2027
2028 static struct snd_soc_dai_ops tegra210_adsp_admaif_dai_ops = {
2029         .hw_params      = tegra210_adsp_admaif_hw_params,
2030 };
2031
2032 static struct snd_soc_dai_driver tegra210_adsp_dai[] = {
2033         {
2034                 .name = "ADSP PCM1",
2035                 .playback = {
2036                         .stream_name = "ADSP PCM1 Receive",
2037                         .channels_min = 1,
2038                         .channels_max = 2,
2039                         .rates = SNDRV_PCM_RATE_8000_48000,
2040                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
2041                 },
2042                 .capture = {
2043                         .stream_name = "ADSP PCM1 Transmit",
2044                         .channels_min = 1,
2045                         .channels_max = 2,
2046                         .rates = SNDRV_PCM_RATE_8000_48000,
2047                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
2048                 },
2049         },
2050         {
2051                 .name = "ADSP PCM2",
2052                 .playback = {
2053                         .stream_name = "ADSP PCM2 Receive",
2054                         .channels_min = 1,
2055                         .channels_max = 2,
2056                         .rates = SNDRV_PCM_RATE_8000_48000,
2057                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
2058                 },
2059                 .capture = {
2060                         .stream_name = "ADSP PCM2 Transmit",
2061                         .channels_min = 1,
2062                         .channels_max = 2,
2063                         .rates = SNDRV_PCM_RATE_8000_48000,
2064                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
2065                 },
2066         },
2067         {
2068                 .name = "ADSP COMPR1",
2069                 .compress_dai = 1,
2070                 .playback = {
2071                         .stream_name = "ADSP COMPR1 Receive",
2072                         .channels_min = 1,
2073                         .channels_max = 2,
2074                         .rates = SNDRV_PCM_RATE_8000_48000,
2075                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
2076                 },
2077         },
2078         {
2079                 .name = "ADSP COMPR2",
2080                 .compress_dai = 1,
2081                 .playback = {
2082                         .stream_name = "ADSP COMPR2 Receive",
2083                         .channels_min = 1,
2084                         .channels_max = 2,
2085                         .rates = SNDRV_PCM_RATE_8000_48000,
2086                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
2087                 },
2088         },
2089 };
2090
2091 #define ADSP_FE_CODEC_DAI(idx)                                  \
2092         {                                                       \
2093                 .name = "ADSP-FE" #idx,                         \
2094                 .id = ADSP_FE_START + (idx - 1),                        \
2095                 .playback = {                                   \
2096                         .stream_name = "ADSP-FE" #idx " Receive",\
2097                         .channels_min = 1,                      \
2098                         .channels_max = 2,                      \
2099                         .rates = SNDRV_PCM_RATE_8000_48000,     \
2100                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
2101                 },                                              \
2102                 .capture = {                                    \
2103                         .stream_name = "ADSP-FE" #idx " Transmit",\
2104                         .channels_min = 1,                      \
2105                         .channels_max = 2,                      \
2106                         .rates = SNDRV_PCM_RATE_8000_48000,     \
2107                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
2108                 },                                              \
2109         }
2110
2111 #define ADSP_ADMAIF_CODEC_DAI(idx)                              \
2112         {                                                       \
2113                 .name = "ADSP-ADMAIF" #idx,                     \
2114                 .id = ADSP_ADMAIF_START + (idx - 1),            \
2115                 .playback = {                                   \
2116                 .stream_name = "ADSP-ADMAIF" #idx " Receive",   \
2117                         .channels_min = 1,                      \
2118                         .channels_max = 2,                      \
2119                         .rates = SNDRV_PCM_RATE_8000_48000,     \
2120                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
2121                 },                                              \
2122                 .capture = {                                    \
2123                         .stream_name = "ADSP-ADMAIF" #idx " Transmit",\
2124                         .channels_min = 1,                      \
2125                         .channels_max = 2,                      \
2126                         .rates = SNDRV_PCM_RATE_8000_48000,     \
2127                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
2128                 },                                              \
2129                 .ops = &tegra210_adsp_admaif_dai_ops,           \
2130         }
2131
2132 static struct snd_soc_dai_driver tegra210_adsp_codec_dai[] = {
2133         ADSP_FE_CODEC_DAI(1),
2134         ADSP_FE_CODEC_DAI(2),
2135         ADSP_FE_CODEC_DAI(3),
2136         ADSP_FE_CODEC_DAI(4),
2137         ADSP_FE_CODEC_DAI(5),
2138         ADSP_ADMAIF_CODEC_DAI(1),
2139         ADSP_ADMAIF_CODEC_DAI(2),
2140         ADSP_ADMAIF_CODEC_DAI(3),
2141         ADSP_ADMAIF_CODEC_DAI(4),
2142         ADSP_ADMAIF_CODEC_DAI(5),
2143         ADSP_ADMAIF_CODEC_DAI(6),
2144         ADSP_ADMAIF_CODEC_DAI(7),
2145         ADSP_ADMAIF_CODEC_DAI(8),
2146         ADSP_ADMAIF_CODEC_DAI(9),
2147         ADSP_ADMAIF_CODEC_DAI(10),
2148 };
2149
2150 /* This array is linked with tegra210_adsp_virt_widgets enum defines. Any thing
2151    changed in enum define should be also reflected here and vice-versa */
2152 static const char * const tegra210_adsp_mux_texts[] = {
2153         "None",
2154         "ADSP-FE1",
2155         "ADSP-FE2",
2156         "ADSP-FE3",
2157         "ADSP-FE4",
2158         "ADSP-FE5",
2159         "ADSP-ADMAIF1",
2160         "ADSP-ADMAIF2",
2161         "ADSP-ADMAIF3",
2162         "ADSP-ADMAIF4",
2163         "ADSP-ADMAIF5",
2164         "ADSP-ADMAIF6",
2165         "ADSP-ADMAIF7",
2166         "ADSP-ADMAIF8",
2167         "ADSP-ADMAIF9",
2168         "ADSP-ADMAIF10",
2169         "APM-IN1",
2170         "APM-IN2",
2171         "APM-IN3",
2172         "APM-IN4",
2173         "APM-IN5",
2174         "APM-IN6",
2175         "APM-IN7",
2176         "APM-IN8",
2177         "APM-OUT1",
2178         "APM-OUT2",
2179         "APM-OUT3",
2180         "APM-OUT4",
2181         "APM-OUT5",
2182         "APM-OUT6",
2183         "APM-OUT7",
2184         "APM-OUT8",
2185         "ADMA1",
2186         "ADMA2",
2187         "ADMA3",
2188         "ADMA4",
2189         "ADMA5",
2190         "ADMA6",
2191         "ADMA7",
2192         "ADMA8",
2193         "ADMA9",
2194         "ADMA10",
2195         "PLUGIN1",
2196         "PLUGIN2",
2197         "PLUGIN3",
2198         "PLUGIN4",
2199         "PLUGIN5",
2200         "PLUGIN6",
2201         "PLUGIN7",
2202         "PLUGIN8",
2203         "PLUGIN9",
2204         "PLUGIN10",
2205 };
2206
2207 #define ADSP_MUX_ENUM_CTRL_DECL(ename, reg)             \
2208         SOC_ENUM_SINGLE_DECL(ename##_enum, reg,         \
2209                 TEGRA210_ADSP_WIDGET_SOURCE_SHIFT,              \
2210                 tegra210_adsp_mux_texts);                               \
2211         static const struct snd_kcontrol_new ename##_ctrl =             \
2212                 SOC_DAPM_ENUM_EXT("ADSP Route", ename##_enum,           \
2213                         tegra210_adsp_mux_get, tegra210_adsp_mux_put)
2214
2215 static ADSP_MUX_ENUM_CTRL_DECL(adsp_fe1, TEGRA210_ADSP_FRONT_END1);
2216 static ADSP_MUX_ENUM_CTRL_DECL(adsp_fe2, TEGRA210_ADSP_FRONT_END2);
2217 static ADSP_MUX_ENUM_CTRL_DECL(adsp_fe3, TEGRA210_ADSP_FRONT_END3);
2218 static ADSP_MUX_ENUM_CTRL_DECL(adsp_fe4, TEGRA210_ADSP_FRONT_END4);
2219 static ADSP_MUX_ENUM_CTRL_DECL(adsp_fe5, TEGRA210_ADSP_FRONT_END5);
2220 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif1, TEGRA210_ADSP_ADMAIF1);
2221 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif2, TEGRA210_ADSP_ADMAIF2);
2222 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif3, TEGRA210_ADSP_ADMAIF3);
2223 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif4, TEGRA210_ADSP_ADMAIF4);
2224 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif5, TEGRA210_ADSP_ADMAIF5);
2225 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif6, TEGRA210_ADSP_ADMAIF6);
2226 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif7, TEGRA210_ADSP_ADMAIF7);
2227 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif8, TEGRA210_ADSP_ADMAIF8);
2228 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif9, TEGRA210_ADSP_ADMAIF9);
2229 static ADSP_MUX_ENUM_CTRL_DECL(adsp_admaif10, TEGRA210_ADSP_ADMAIF10);
2230 static ADSP_MUX_ENUM_CTRL_DECL(apm_in1, TEGRA210_ADSP_APM_IN1);
2231 static ADSP_MUX_ENUM_CTRL_DECL(apm_in2, TEGRA210_ADSP_APM_IN2);
2232 static ADSP_MUX_ENUM_CTRL_DECL(apm_in3, TEGRA210_ADSP_APM_IN3);
2233 static ADSP_MUX_ENUM_CTRL_DECL(apm_in4, TEGRA210_ADSP_APM_IN4);
2234 static ADSP_MUX_ENUM_CTRL_DECL(apm_in5, TEGRA210_ADSP_APM_IN5);
2235 static ADSP_MUX_ENUM_CTRL_DECL(apm_in6, TEGRA210_ADSP_APM_IN6);
2236 static ADSP_MUX_ENUM_CTRL_DECL(apm_in7, TEGRA210_ADSP_APM_IN7);
2237 static ADSP_MUX_ENUM_CTRL_DECL(apm_in8, TEGRA210_ADSP_APM_IN8);
2238 static ADSP_MUX_ENUM_CTRL_DECL(apm_out1, TEGRA210_ADSP_APM_OUT1);
2239 static ADSP_MUX_ENUM_CTRL_DECL(apm_out2, TEGRA210_ADSP_APM_OUT2);
2240 static ADSP_MUX_ENUM_CTRL_DECL(apm_out3, TEGRA210_ADSP_APM_OUT3);
2241 static ADSP_MUX_ENUM_CTRL_DECL(apm_out4, TEGRA210_ADSP_APM_OUT4);
2242 static ADSP_MUX_ENUM_CTRL_DECL(apm_out5, TEGRA210_ADSP_APM_OUT5);
2243 static ADSP_MUX_ENUM_CTRL_DECL(apm_out6, TEGRA210_ADSP_APM_OUT6);
2244 static ADSP_MUX_ENUM_CTRL_DECL(apm_out7, TEGRA210_ADSP_APM_OUT7);
2245 static ADSP_MUX_ENUM_CTRL_DECL(apm_out8, TEGRA210_ADSP_APM_OUT8);
2246 static ADSP_MUX_ENUM_CTRL_DECL(adma1, TEGRA210_ADSP_PLUGIN_ADMA1);
2247 static ADSP_MUX_ENUM_CTRL_DECL(adma2, TEGRA210_ADSP_PLUGIN_ADMA2);
2248 static ADSP_MUX_ENUM_CTRL_DECL(adma3, TEGRA210_ADSP_PLUGIN_ADMA3);
2249 static ADSP_MUX_ENUM_CTRL_DECL(adma4, TEGRA210_ADSP_PLUGIN_ADMA4);
2250 static ADSP_MUX_ENUM_CTRL_DECL(adma5, TEGRA210_ADSP_PLUGIN_ADMA5);
2251 static ADSP_MUX_ENUM_CTRL_DECL(adma6, TEGRA210_ADSP_PLUGIN_ADMA6);
2252 static ADSP_MUX_ENUM_CTRL_DECL(adma7, TEGRA210_ADSP_PLUGIN_ADMA7);
2253 static ADSP_MUX_ENUM_CTRL_DECL(adma8, TEGRA210_ADSP_PLUGIN_ADMA8);
2254 static ADSP_MUX_ENUM_CTRL_DECL(adma9, TEGRA210_ADSP_PLUGIN_ADMA9);
2255 static ADSP_MUX_ENUM_CTRL_DECL(adma10, TEGRA210_ADSP_PLUGIN_ADMA10);
2256 static ADSP_MUX_ENUM_CTRL_DECL(plugin1, TEGRA210_ADSP_PLUGIN1);
2257 static ADSP_MUX_ENUM_CTRL_DECL(plugin2, TEGRA210_ADSP_PLUGIN2);
2258 static ADSP_MUX_ENUM_CTRL_DECL(plugin3, TEGRA210_ADSP_PLUGIN3);
2259 static ADSP_MUX_ENUM_CTRL_DECL(plugin4, TEGRA210_ADSP_PLUGIN4);
2260 static ADSP_MUX_ENUM_CTRL_DECL(plugin5, TEGRA210_ADSP_PLUGIN5);
2261 static ADSP_MUX_ENUM_CTRL_DECL(plugin6, TEGRA210_ADSP_PLUGIN6);
2262 static ADSP_MUX_ENUM_CTRL_DECL(plugin7, TEGRA210_ADSP_PLUGIN7);
2263 static ADSP_MUX_ENUM_CTRL_DECL(plugin8, TEGRA210_ADSP_PLUGIN8);
2264 static ADSP_MUX_ENUM_CTRL_DECL(plugin9, TEGRA210_ADSP_PLUGIN9);
2265 static ADSP_MUX_ENUM_CTRL_DECL(plugin10, TEGRA210_ADSP_PLUGIN10);
2266
2267 #define ADSP_EP_WIDGETS(sname, ename)                                   \
2268         SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0),  \
2269         SND_SOC_DAPM_AIF_OUT(sname " TX", NULL, 0, SND_SOC_NOPM, 0, 0), \
2270         SND_SOC_DAPM_MUX(sname " MUX", SND_SOC_NOPM, 0, 0, &ename##_ctrl)
2271
2272 #define ADSP_WIDGETS(sname, ename, reg)                                 \
2273         SND_SOC_DAPM_AIF_OUT_E(sname " TX", NULL, 0, reg,               \
2274                 TEGRA210_ADSP_WIDGET_EN_SHIFT, 0, tegra210_adsp_widget_event, \
2275                 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),          \
2276         SND_SOC_DAPM_MUX(sname " MUX", SND_SOC_NOPM, 0, 0, &ename##_ctrl)
2277
2278 static const struct snd_soc_dapm_widget tegra210_adsp_widgets[] = {
2279         ADSP_EP_WIDGETS("ADSP-FE1", adsp_fe1),
2280         ADSP_EP_WIDGETS("ADSP-FE2", adsp_fe2),
2281         ADSP_EP_WIDGETS("ADSP-FE3", adsp_fe3),
2282         ADSP_EP_WIDGETS("ADSP-FE4", adsp_fe4),
2283         ADSP_EP_WIDGETS("ADSP-FE5", adsp_fe5),
2284         ADSP_EP_WIDGETS("ADSP-ADMAIF1", adsp_admaif1),
2285         ADSP_EP_WIDGETS("ADSP-ADMAIF2", adsp_admaif2),
2286         ADSP_EP_WIDGETS("ADSP-ADMAIF3", adsp_admaif3),
2287         ADSP_EP_WIDGETS("ADSP-ADMAIF4", adsp_admaif4),
2288         ADSP_EP_WIDGETS("ADSP-ADMAIF5", adsp_admaif5),
2289         ADSP_EP_WIDGETS("ADSP-ADMAIF6", adsp_admaif6),
2290         ADSP_EP_WIDGETS("ADSP-ADMAIF7", adsp_admaif7),
2291         ADSP_EP_WIDGETS("ADSP-ADMAIF8", adsp_admaif8),
2292         ADSP_EP_WIDGETS("ADSP-ADMAIF9", adsp_admaif9),
2293         ADSP_EP_WIDGETS("ADSP-ADMAIF10", adsp_admaif10),
2294         ADSP_WIDGETS("APM-IN1", apm_in1, TEGRA210_ADSP_APM_IN1),
2295         ADSP_WIDGETS("APM-IN2", apm_in2, TEGRA210_ADSP_APM_IN2),
2296         ADSP_WIDGETS("APM-IN3", apm_in3, TEGRA210_ADSP_APM_IN3),
2297         ADSP_WIDGETS("APM-IN4", apm_in4, TEGRA210_ADSP_APM_IN4),
2298         ADSP_WIDGETS("APM-IN5", apm_in5, TEGRA210_ADSP_APM_IN5),
2299         ADSP_WIDGETS("APM-IN6", apm_in6, TEGRA210_ADSP_APM_IN6),
2300         ADSP_WIDGETS("APM-IN7", apm_in7, TEGRA210_ADSP_APM_IN7),
2301         ADSP_WIDGETS("APM-IN8", apm_in8, TEGRA210_ADSP_APM_IN8),
2302         ADSP_WIDGETS("APM-OUT1", apm_out1, TEGRA210_ADSP_APM_OUT1),
2303         ADSP_WIDGETS("APM-OUT2", apm_out2, TEGRA210_ADSP_APM_OUT2),
2304         ADSP_WIDGETS("APM-OUT3", apm_out3, TEGRA210_ADSP_APM_OUT3),
2305         ADSP_WIDGETS("APM-OUT4", apm_out4, TEGRA210_ADSP_APM_OUT4),
2306         ADSP_WIDGETS("APM-OUT5", apm_out5, TEGRA210_ADSP_APM_OUT5),
2307         ADSP_WIDGETS("APM-OUT6", apm_out6, TEGRA210_ADSP_APM_OUT6),
2308         ADSP_WIDGETS("APM-OUT7", apm_out7, TEGRA210_ADSP_APM_OUT7),
2309         ADSP_WIDGETS("APM-OUT8", apm_out8, TEGRA210_ADSP_APM_OUT8),
2310         ADSP_WIDGETS("ADMA1", adma1, TEGRA210_ADSP_PLUGIN_ADMA1),
2311         ADSP_WIDGETS("ADMA2", adma2, TEGRA210_ADSP_PLUGIN_ADMA2),
2312         ADSP_WIDGETS("ADMA3", adma3, TEGRA210_ADSP_PLUGIN_ADMA3),
2313         ADSP_WIDGETS("ADMA4", adma4, TEGRA210_ADSP_PLUGIN_ADMA4),
2314         ADSP_WIDGETS("ADMA5", adma5, TEGRA210_ADSP_PLUGIN_ADMA5),
2315         ADSP_WIDGETS("ADMA6", adma6, TEGRA210_ADSP_PLUGIN_ADMA6),
2316         ADSP_WIDGETS("ADMA7", adma7, TEGRA210_ADSP_PLUGIN_ADMA7),
2317         ADSP_WIDGETS("ADMA8", adma8, TEGRA210_ADSP_PLUGIN_ADMA8),
2318         ADSP_WIDGETS("ADMA9", adma9, TEGRA210_ADSP_PLUGIN_ADMA9),
2319         ADSP_WIDGETS("ADMA10", adma10, TEGRA210_ADSP_PLUGIN_ADMA10),
2320         ADSP_WIDGETS("PLUGIN1", plugin1, TEGRA210_ADSP_PLUGIN1),
2321         ADSP_WIDGETS("PLUGIN2", plugin2, TEGRA210_ADSP_PLUGIN2),
2322         ADSP_WIDGETS("PLUGIN3", plugin3, TEGRA210_ADSP_PLUGIN3),
2323         ADSP_WIDGETS("PLUGIN4", plugin4, TEGRA210_ADSP_PLUGIN4),
2324         ADSP_WIDGETS("PLUGIN5", plugin5, TEGRA210_ADSP_PLUGIN5),
2325         ADSP_WIDGETS("PLUGIN6", plugin6, TEGRA210_ADSP_PLUGIN6),
2326         ADSP_WIDGETS("PLUGIN7", plugin7, TEGRA210_ADSP_PLUGIN7),
2327         ADSP_WIDGETS("PLUGIN8", plugin8, TEGRA210_ADSP_PLUGIN8),
2328         ADSP_WIDGETS("PLUGIN9", plugin9, TEGRA210_ADSP_PLUGIN9),
2329         ADSP_WIDGETS("PLUGIN10", plugin10, TEGRA210_ADSP_PLUGIN10),
2330 };
2331
2332 #define ADSP_EP_ROUTES(name)                                    \
2333         { name " MUX",          "ADSP-FE1", "ADSP-FE1 RX"},     \
2334         { name " MUX",          "ADSP-FE2", "ADSP-FE2 RX"},     \
2335         { name " MUX",          "ADSP-FE3", "ADSP-FE3 RX"},     \
2336         { name " MUX",          "ADSP-FE4", "ADSP-FE4 RX"},     \
2337         { name " MUX",          "ADSP-FE5", "ADSP-FE5 RX"},     \
2338         { name " MUX",          "ADSP-ADMAIF1", "ADSP-ADMAIF1 RX"}, \
2339         { name " MUX",          "ADSP-ADMAIF2", "ADSP-ADMAIF2 RX"}, \
2340         { name " MUX",          "ADSP-ADMAIF3", "ADSP-ADMAIF3 RX"}, \
2341         { name " MUX",          "ADSP-ADMAIF4", "ADSP-ADMAIF4 RX"}, \
2342         { name " MUX",          "ADSP-ADMAIF5", "ADSP-ADMAIF5 RX"}, \
2343         { name " MUX",          "ADSP-ADMAIF6", "ADSP-ADMAIF6 RX"}, \
2344         { name " MUX",          "ADSP-ADMAIF7", "ADSP-ADMAIF7 RX"}, \
2345         { name " MUX",          "ADSP-ADMAIF8", "ADSP-ADMAIF8 RX"}, \
2346         { name " MUX",          "ADSP-ADMAIF9", "ADSP-ADMAIF9 RX"}, \
2347         { name " MUX",          "ADSP-ADMAIF10", "ADSP-ADMAIF10 RX"}
2348
2349 #define ADSP_APM_IN_ROUTES(name)                                \
2350         { name " MUX",  "APM-IN1",      "APM-IN1 TX"},          \
2351         { name " MUX",  "APM-IN2",      "APM-IN2 TX"},          \
2352         { name " MUX",  "APM-IN3",      "APM-IN3 TX"},          \
2353         { name " MUX",  "APM-IN4",      "APM-IN4 TX"},          \
2354         { name " MUX",  "APM-IN5",      "APM-IN5 TX"},          \
2355         { name " MUX",  "APM-IN6",      "APM-IN6 TX"},          \
2356         { name " MUX",  "APM-IN7",      "APM-IN7 TX"},          \
2357         { name " MUX",  "APM-IN8",      "APM-IN8 TX"}
2358
2359 #define ADSP_APM_OUT_ROUTES(name)                               \
2360         { name " MUX",          "APM-OUT1", "APM-OUT1 TX"},     \
2361         { name " MUX",          "APM-OUT2", "APM-OUT2 TX"},     \
2362         { name " MUX",          "APM-OUT3", "APM-OUT3 TX"},     \
2363         { name " MUX",          "APM-OUT4", "APM-OUT4 TX"},     \
2364         { name " MUX",          "APM-OUT5", "APM-OUT5 TX"},     \
2365         { name " MUX",          "APM-OUT6", "APM-OUT6 TX"},     \
2366         { name " MUX",          "APM-OUT7", "APM-OUT7 TX"},     \
2367         { name " MUX",          "APM-OUT8", "APM-OUT8 TX"}
2368
2369 #define ADSP_ADMA_ROUTES(name)                                  \
2370         { name " MUX",  "ADMA1",        "ADMA1 TX"},            \
2371         { name " MUX",  "ADMA2",        "ADMA2 TX"},            \
2372         { name " MUX",  "ADMA3",        "ADMA3 TX"},            \
2373         { name " MUX",  "ADMA4",        "ADMA4 TX"},            \
2374         { name " MUX",  "ADMA5",        "ADMA5 TX"},            \
2375         { name " MUX",  "ADMA6",        "ADMA6 TX"},            \
2376         { name " MUX",  "ADMA7",        "ADMA7 TX"},            \
2377         { name " MUX",  "ADMA8",        "ADMA8 TX"},            \
2378         { name " MUX",  "ADMA9",        "ADMA9 TX"},            \
2379         { name " MUX",  "ADMA10",       "ADMA10 TX"}
2380
2381 #define ADSP_PLUGIN_ROUTES(name)                                        \
2382         { name " MUX",  "PLUGIN1",      "PLUGIN1 TX"},          \
2383         { name " MUX",  "PLUGIN2",      "PLUGIN2 TX"},          \
2384         { name " MUX",  "PLUGIN3",      "PLUGIN3 TX"},          \
2385         { name " MUX",  "PLUGIN4",      "PLUGIN4 TX"},          \
2386         { name " MUX",  "PLUGIN5",      "PLUGIN5 TX"},          \
2387         { name " MUX",  "PLUGIN6",      "PLUGIN6 TX"},          \
2388         { name " MUX",  "PLUGIN7",      "PLUGIN7 TX"},          \
2389         { name " MUX",  "PLUGIN8",      "PLUGIN8 TX"},          \
2390         { name " MUX",  "PLUGIN9",      "PLUGIN9 TX"},          \
2391         { name " MUX",  "PLUGIN10",     "PLUGIN10 TX"}
2392
2393 #define ADSP_EP_MUX_ROUTES(name)                                \
2394         { name " RX",           NULL, name " Receive"},         \
2395         { name " Transmit",     NULL, name " TX"},              \
2396         { name " TX",           NULL, name " MUX"},             \
2397         ADSP_APM_OUT_ROUTES(name)
2398
2399 #define ADSP_APM_IN_MUX_ROUTES(name)                            \
2400         { name " TX",           NULL, name " MUX"},             \
2401         ADSP_EP_ROUTES(name),                                   \
2402         ADSP_APM_OUT_ROUTES(name)
2403
2404 #define ADSP_APM_OUT_MUX_ROUTES(name)                           \
2405         { name " TX",           NULL, name " MUX"},             \
2406         ADSP_ADMA_ROUTES(name),                                 \
2407         ADSP_PLUGIN_ROUTES(name)
2408
2409 #define ADSP_PLUGIN_MUX_ROUTES(name)                            \
2410         { name " TX",           NULL, name " MUX"},             \
2411         ADSP_APM_IN_ROUTES(name),                                       \
2412         ADSP_PLUGIN_ROUTES(name),                                       \
2413         ADSP_ADMA_ROUTES(name)
2414
2415 #define ADSP_ADMA_MUX_ROUTES(name)                              \
2416         { name " TX",           NULL, name " MUX"},             \
2417         ADSP_APM_IN_ROUTES(name),                               \
2418         ADSP_PLUGIN_ROUTES(name)
2419
2420 static const struct snd_soc_dapm_route tegra210_adsp_routes[] = {
2421         ADSP_EP_MUX_ROUTES("ADSP-FE1"),
2422         ADSP_EP_MUX_ROUTES("ADSP-FE2"),
2423         ADSP_EP_MUX_ROUTES("ADSP-FE3"),
2424         ADSP_EP_MUX_ROUTES("ADSP-FE4"),
2425         ADSP_EP_MUX_ROUTES("ADSP-FE5"),
2426         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF1"),
2427         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF2"),
2428         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF3"),
2429         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF4"),
2430         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF5"),
2431         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF6"),
2432         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF7"),
2433         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF8"),
2434         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF9"),
2435         ADSP_EP_MUX_ROUTES("ADSP-ADMAIF10"),
2436
2437         ADSP_APM_IN_MUX_ROUTES("APM-IN1"),
2438         ADSP_APM_IN_MUX_ROUTES("APM-IN2"),
2439         ADSP_APM_IN_MUX_ROUTES("APM-IN3"),
2440         ADSP_APM_IN_MUX_ROUTES("APM-IN4"),
2441         ADSP_APM_IN_MUX_ROUTES("APM-IN5"),
2442         ADSP_APM_IN_MUX_ROUTES("APM-IN6"),
2443         ADSP_APM_IN_MUX_ROUTES("APM-IN7"),
2444         ADSP_APM_IN_MUX_ROUTES("APM-IN8"),
2445
2446         ADSP_APM_OUT_MUX_ROUTES("APM-OUT1"),
2447         ADSP_APM_OUT_MUX_ROUTES("APM-OUT2"),
2448         ADSP_APM_OUT_MUX_ROUTES("APM-OUT3"),
2449         ADSP_APM_OUT_MUX_ROUTES("APM-OUT4"),
2450         ADSP_APM_OUT_MUX_ROUTES("APM-OUT5"),
2451         ADSP_APM_OUT_MUX_ROUTES("APM-OUT6"),
2452         ADSP_APM_OUT_MUX_ROUTES("APM-OUT7"),
2453         ADSP_APM_OUT_MUX_ROUTES("APM-OUT8"),
2454
2455         ADSP_ADMA_MUX_ROUTES("ADMA1"),
2456         ADSP_ADMA_MUX_ROUTES("ADMA2"),
2457         ADSP_ADMA_MUX_ROUTES("ADMA3"),
2458         ADSP_ADMA_MUX_ROUTES("ADMA4"),
2459         ADSP_ADMA_MUX_ROUTES("ADMA5"),
2460         ADSP_ADMA_MUX_ROUTES("ADMA6"),
2461         ADSP_ADMA_MUX_ROUTES("ADMA7"),
2462         ADSP_ADMA_MUX_ROUTES("ADMA8"),
2463         ADSP_ADMA_MUX_ROUTES("ADMA9"),
2464         ADSP_ADMA_MUX_ROUTES("ADMA10"),
2465
2466         ADSP_PLUGIN_MUX_ROUTES("PLUGIN1"),
2467         ADSP_PLUGIN_MUX_ROUTES("PLUGIN2"),
2468         ADSP_PLUGIN_MUX_ROUTES("PLUGIN3"),
2469         ADSP_PLUGIN_MUX_ROUTES("PLUGIN4"),
2470         ADSP_PLUGIN_MUX_ROUTES("PLUGIN5"),
2471         ADSP_PLUGIN_MUX_ROUTES("PLUGIN6"),
2472         ADSP_PLUGIN_MUX_ROUTES("PLUGIN7"),
2473         ADSP_PLUGIN_MUX_ROUTES("PLUGIN8"),
2474         ADSP_PLUGIN_MUX_ROUTES("PLUGIN9"),
2475         ADSP_PLUGIN_MUX_ROUTES("PLUGIN10"),
2476 };
2477
2478 static void tegra210_adsp_wt_replace(char *dest, const char *src)
2479 {
2480         if (!dest || !src)
2481                 return;
2482
2483         if (strstr(dest, " TX")) {
2484                 strcpy(dest, src);
2485                 strcat(dest, " TX");
2486         } else if (strstr(dest, " RX")) {
2487                 strcpy(dest, src);
2488                 strcat(dest, " RX");
2489         } else if (strstr(dest, " MUX")) {
2490                 strcpy(dest, src);
2491                 strcat(dest, " MUX");
2492         } else {
2493                 strcpy(dest, src);
2494         }
2495 }
2496
2497 static void tegra210_adsp_route_modify(const char *wt_default,
2498                                 const char *wt_from_dt)
2499 {
2500         int i;
2501
2502         if (!wt_default || !wt_from_dt)
2503                 return;
2504
2505         /* Modify dapm routing table */
2506         for (i = TEGRA210_ADSP_ROUTE_BASE;
2507                 i < ARRAY_SIZE(tegra210_adsp_routes); i++) {
2508                 /* replace sink name */
2509                 if (tegra210_adsp_routes[i].sink)
2510                         if (strstr(tegra210_adsp_routes[i].sink, wt_default))
2511                                 tegra210_adsp_wt_replace(
2512                                         (char *)tegra210_adsp_routes[i].sink,
2513                                         wt_from_dt);
2514                 /* replace control name */
2515                 if (tegra210_adsp_routes[i].control)
2516                         if (strstr(tegra210_adsp_routes[i].control, wt_default))
2517                                 tegra210_adsp_wt_replace(
2518                                         (char *)tegra210_adsp_routes[i].control,
2519                                         wt_from_dt);
2520                 /* replace source name */
2521                 if (tegra210_adsp_routes[i].source)
2522                         if (strstr(tegra210_adsp_routes[i].source, wt_default))
2523                                 tegra210_adsp_wt_replace(
2524                                         (char *)tegra210_adsp_routes[i].source,
2525                                         wt_from_dt);
2526         }
2527 }
2528
2529 static int tegra210_adsp_param_info(struct snd_kcontrol *kcontrol,
2530                        struct snd_ctl_elem_info *uinfo)
2531 {
2532         struct soc_bytes *params = (void *)kcontrol->private_value;
2533
2534         if (params->mask == SNDRV_CTL_ELEM_TYPE_INTEGER) {
2535                 params->num_regs = 128;
2536                 uinfo->value.integer.min = 0;
2537                 uinfo->value.integer.max = 0x7fffffff;
2538         }
2539         uinfo->type = params->mask;
2540         uinfo->count = params->num_regs;
2541
2542         return 0;
2543 }
2544
2545 static int tegra210_adsp_get_param(struct snd_kcontrol *kcontrol,
2546         struct snd_ctl_elem_value *ucontrol)
2547 {
2548         struct soc_bytes *params = (void *)kcontrol->private_value;
2549
2550         if (params->mask == SNDRV_CTL_ELEM_TYPE_INTEGER)
2551                 memset(ucontrol->value.integer.value, 0,
2552                         params->num_regs * sizeof(long));
2553         else
2554                 memset(ucontrol->value.bytes.data, 0,
2555                         params->num_regs);
2556
2557         return 0;
2558 }
2559
2560 /* tegra210_adsp_set_param - sets plugin parameters
2561  * @default: byte_format
2562  * @byte_format: nvfx_call_params_t based structure
2563  * @int_format: <plugin_method>,<#params>,<param1>,<param2>,....
2564  */
2565 static int tegra210_adsp_set_param(struct snd_kcontrol *kcontrol,
2566         struct snd_ctl_elem_value *ucontrol)
2567 {
2568         struct soc_bytes *params = (void *)kcontrol->private_value;
2569         struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
2570         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
2571         struct tegra210_adsp_app *app = &adsp->apps[params->base];
2572         apm_msg_t apm_msg;
2573         int ret;
2574
2575         if (!adsp->init_done) {
2576                 dev_warn(adsp->dev, "ADSP is not booted yet\n");
2577                 return 0;
2578         }
2579
2580         if (!app->plugin) {
2581                 dev_warn(adsp->dev, "Plugin not yet initialized\n");
2582                 return 0;
2583         }
2584
2585         apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_fx_set_param_params_t);
2586         apm_msg.msg.call_params.size = sizeof(apm_fx_set_param_params_t);
2587         apm_msg.msg.call_params.method = nvfx_apm_method_fx_set_param;
2588         apm_msg.msg.fx_set_param_params.plugin.pvoid =
2589                 app->plugin->plugin.pvoid;
2590
2591         switch (params->mask) {
2592         case SNDRV_CTL_ELEM_TYPE_INTEGER:
2593         {
2594                 int32_t num_params, i;
2595                 /* check number of params to pass */
2596                 num_params = (int32_t)ucontrol->value.integer.value[1];
2597                 if (num_params < 1) {
2598                         dev_warn(adsp->dev, "No params to pass to the plugin\n");
2599                         return 0;
2600                 }
2601                 apm_msg.msg.fx_set_param_params.params[0] =
2602                         (sizeof(nvfx_call_params_t) +
2603                         num_params * sizeof(int32_t));
2604
2605                 /* initialize the method */
2606                 apm_msg.msg.fx_set_param_params.params[1] =
2607                         (int32_t)ucontrol->value.integer.value[0];
2608
2609                 /* copy parameters */
2610                 for (i = 0; i < num_params; i++)
2611                         apm_msg.msg.fx_set_param_params.params[i + 2] =
2612                                 (int32_t)ucontrol->value.integer.value[i + 2];
2613         }
2614         break;
2615
2616         case SNDRV_CTL_ELEM_TYPE_BYTES:
2617         {
2618                 nvfx_call_params_t *call_params =
2619                         (nvfx_call_params_t *)ucontrol->value.bytes.data;
2620
2621                 /* copy parameters */
2622                 memcpy(&apm_msg.msg.fx_set_param_params.params,
2623                         call_params, call_params->size);
2624         }
2625         break;
2626
2627         default:
2628                 return -EINVAL;
2629         }
2630
2631         ret = pm_runtime_get_sync(adsp->dev);
2632         if (ret < 0) {
2633                 dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
2634                         __func__, ret);
2635                 return ret;
2636         }
2637         ret = tegra210_adsp_send_msg(app, &apm_msg,
2638                 TEGRA210_ADSP_MSG_FLAG_SEND | TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
2639         pm_runtime_put(adsp->dev);
2640
2641         return ret;
2642 }
2643
2644 static int tegra210_adsp_apm_get(struct snd_kcontrol *kcontrol,
2645         struct snd_ctl_elem_value *ucontrol)
2646 {
2647         struct soc_mixer_control *mc =
2648                 (struct soc_mixer_control *)kcontrol->private_value;
2649         struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
2650         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
2651         struct tegra210_adsp_app *app = &adsp->apps[mc->reg];
2652
2653         if (strstr(kcontrol->id.name, "Priority")) {
2654                 ucontrol->value.integer.value[0] = app->priority;
2655         } else if (strstr(kcontrol->id.name, "Min ADSP Clock")) {
2656                 ucontrol->value.integer.value[0] = app->min_adsp_clock;
2657         }
2658         return 0;
2659 }
2660
2661 static int tegra210_adsp_apm_put(struct snd_kcontrol *kcontrol,
2662         struct snd_ctl_elem_value *ucontrol)
2663 {
2664         struct soc_mixer_control *mc =
2665                 (struct soc_mixer_control *)kcontrol->private_value;
2666         struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
2667         struct tegra210_adsp *adsp = snd_soc_platform_get_drvdata(platform);
2668         struct tegra210_adsp_app *app = &adsp->apps[mc->reg];
2669         apm_msg_t apm_msg;
2670         int ret = 0;
2671
2672         if (!adsp->init_done) {
2673                 dev_warn(adsp->dev, "ADSP is not booted yet\n");
2674                 return 0;
2675         }
2676
2677         /* Controls here may execute whether or not APM is initialized */
2678         if (strstr(kcontrol->id.name, "Min ADSP Clock")) {
2679                 app->min_adsp_clock = ucontrol->value.integer.value[0];
2680                 return 0;
2681         }
2682
2683         /* Check for APM initialized */
2684         if (!app->plugin) {
2685                 dev_warn(adsp->dev, "APM not yet initialized\n");
2686                 return 0;
2687         }
2688
2689         if (strstr(kcontrol->id.name, "Priority")) {
2690                 apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_set_priority_params_t);
2691                 apm_msg.msg.call_params.size = sizeof(apm_set_priority_params_t);
2692                 apm_msg.msg.call_params.method = nvfx_apm_method_set_priority;
2693                 apm_msg.msg.priority_params.priority =
2694                         ucontrol->value.integer.value[0];
2695                 ret = pm_runtime_get_sync(adsp->dev);
2696                 if (ret < 0) {
2697                         dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
2698                                 __func__, ret);
2699                         return ret;
2700                 }
2701                 ret = tegra210_adsp_send_msg(app, &apm_msg,
2702                                 TEGRA210_ADSP_MSG_FLAG_SEND |
2703                                 TEGRA210_ADSP_MSG_FLAG_NEED_ACK);
2704                 pm_runtime_put(adsp->dev);
2705                 app->priority = ucontrol->value.integer.value[0];
2706         }
2707
2708         return ret;
2709 }
2710
2711 /* Maximum 128 integers or 512 bytes allowed */
2712 #define SND_SOC_PARAM_EXT(xname, xbase)         \
2713 {       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
2714         .name = xname,          \
2715         .info = tegra210_adsp_param_info,               \
2716         .get = tegra210_adsp_get_param,         \
2717         .put = tegra210_adsp_set_param,         \
2718         .private_value =                \
2719                 ((unsigned long)&(struct soc_bytes)             \
2720                 {.base = xbase, .num_regs = 512,                \
2721                 .mask = SNDRV_CTL_ELEM_TYPE_BYTES}) }
2722
2723 #define APM_CONTROL(xname, xmax)        \
2724         SOC_SINGLE_EXT("APM1 " xname, TEGRA210_ADSP_APM_IN1, 0, xmax, 0,\
2725         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2726         SOC_SINGLE_EXT("APM2 " xname, TEGRA210_ADSP_APM_IN2, 0, xmax, 0,\
2727         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2728         SOC_SINGLE_EXT("APM3 " xname, TEGRA210_ADSP_APM_IN3, 0, xmax, 0,\
2729         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2730         SOC_SINGLE_EXT("APM4 " xname, TEGRA210_ADSP_APM_IN4, 0, xmax, 0,\
2731         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2732         SOC_SINGLE_EXT("APM5 " xname, TEGRA210_ADSP_APM_IN5, 0, xmax, 0,\
2733         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2734         SOC_SINGLE_EXT("APM6 " xname, TEGRA210_ADSP_APM_IN6, 0, xmax, 0,\
2735         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2736         SOC_SINGLE_EXT("APM7 " xname, TEGRA210_ADSP_APM_IN7, 0, xmax, 0,\
2737         tegra210_adsp_apm_get, tegra210_adsp_apm_put),  \
2738         SOC_SINGLE_EXT("APM8 " xname, TEGRA210_ADSP_APM_IN8, 0, xmax, 0,\
2739         tegra210_adsp_apm_get, tegra210_adsp_apm_put)
2740
2741 static const struct snd_kcontrol_new tegra210_adsp_controls[] = {
2742         SOC_SINGLE_BOOL_EXT("ADSP init", 0,
2743                 tegra210_adsp_get, tegra210_adsp_put),
2744         SND_SOC_PARAM_EXT("PLUGIN1 set params",
2745                 TEGRA210_ADSP_PLUGIN1),
2746         SND_SOC_PARAM_EXT("PLUGIN2 set params",
2747                 TEGRA210_ADSP_PLUGIN2),
2748         SND_SOC_PARAM_EXT("PLUGIN3 set params",
2749                 TEGRA210_ADSP_PLUGIN3),
2750         SND_SOC_PARAM_EXT("PLUGIN4 set params",
2751                 TEGRA210_ADSP_PLUGIN4),
2752         SND_SOC_PARAM_EXT("PLUGIN5 set params",
2753                 TEGRA210_ADSP_PLUGIN5),
2754         SND_SOC_PARAM_EXT("PLUGIN6 set params",
2755                 TEGRA210_ADSP_PLUGIN6),
2756         SND_SOC_PARAM_EXT("PLUGIN7 set params",
2757                 TEGRA210_ADSP_PLUGIN7),
2758         SND_SOC_PARAM_EXT("PLUGIN8 set params",
2759                 TEGRA210_ADSP_PLUGIN8),
2760         SND_SOC_PARAM_EXT("PLUGIN9 set params",
2761                 TEGRA210_ADSP_PLUGIN9),
2762         SND_SOC_PARAM_EXT("PLUGIN10 set params",
2763                 TEGRA210_ADSP_PLUGIN10),
2764         SND_SOC_PARAM_EXT("ADMA1 set params",
2765                 TEGRA210_ADSP_PLUGIN_ADMA1),
2766         SND_SOC_PARAM_EXT("ADMA2 set params",
2767                 TEGRA210_ADSP_PLUGIN_ADMA2),
2768         SND_SOC_PARAM_EXT("ADMA3 set params",
2769                 TEGRA210_ADSP_PLUGIN_ADMA3),
2770         SND_SOC_PARAM_EXT("ADMA4 set params",
2771                 TEGRA210_ADSP_PLUGIN_ADMA4),
2772         SND_SOC_PARAM_EXT("ADMA5 set params",
2773                 TEGRA210_ADSP_PLUGIN_ADMA5),
2774         SND_SOC_PARAM_EXT("ADMA6 set params",
2775                 TEGRA210_ADSP_PLUGIN_ADMA6),
2776         SND_SOC_PARAM_EXT("ADMA7 set params",
2777                 TEGRA210_ADSP_PLUGIN_ADMA7),
2778         SND_SOC_PARAM_EXT("ADMA8 set params",
2779                 TEGRA210_ADSP_PLUGIN_ADMA8),
2780         SND_SOC_PARAM_EXT("ADMA9 set params",
2781                 TEGRA210_ADSP_PLUGIN_ADMA9),
2782         SND_SOC_PARAM_EXT("ADMA10 set params",
2783                 TEGRA210_ADSP_PLUGIN_ADMA10),
2784         APM_CONTROL("Priority", APM_PRIORITY_MAX),
2785         APM_CONTROL("Min ADSP Clock", INT_MAX),
2786         SOC_SINGLE_EXT("ADSP Recovery Enable", 0, 0, 1, 0,
2787                 tegra210_adsp_get, tegra210_adsp_put),
2788         SOC_SINGLE_EXT("ADSP Recovery Count", 0, 0, INT_MAX, 0,
2789                 tegra210_adsp_get, NULL),
2790 };
2791
2792 static const struct snd_soc_component_driver tegra210_adsp_component = {
2793         .name           = "tegra210-adsp",
2794 };
2795
2796 static int tegra210_adsp_codec_probe(struct snd_soc_codec *codec)
2797 {
2798         return 0;
2799 }
2800
2801 static struct snd_soc_codec_driver tegra210_adsp_codec = {
2802         .probe = tegra210_adsp_codec_probe,
2803         .idle_bias_off = 1,
2804 };
2805
2806 static struct snd_soc_platform_driver tegra210_adsp_platform = {
2807         .ops                    = &tegra210_adsp_pcm_ops,
2808         .compr_ops              = &tegra210_adsp_compr_ops,
2809         .pcm_new                = tegra210_adsp_pcm_new,
2810         .pcm_free               = tegra210_adsp_pcm_free,
2811         .probe                  = tegra210_adsp_pcm_probe,
2812         .read                   = tegra210_adsp_read,
2813         .write                  = tegra210_adsp_write,
2814         .dapm_widgets           = tegra210_adsp_widgets,
2815         .num_dapm_widgets       = ARRAY_SIZE(tegra210_adsp_widgets),
2816         .dapm_routes            = tegra210_adsp_routes,
2817         .num_dapm_routes        = ARRAY_SIZE(tegra210_adsp_routes),
2818         .controls               = tegra210_adsp_controls,
2819         .num_controls           = ARRAY_SIZE(tegra210_adsp_controls),
2820 };
2821
2822 static u64 tegra_dma_mask = DMA_BIT_MASK(32);
2823
2824 static const struct of_device_id tegra210_adsp_audio_of_match[] = {
2825         { .compatible = "nvidia,tegra210-adsp-audio", },
2826         {},
2827 };
2828
2829 static int tegra210_adsp_audio_platform_probe(struct platform_device *pdev)
2830 {
2831         struct device_node *np = pdev->dev.of_node, *subnp;
2832         const struct of_device_id *match;
2833         struct soc_bytes *controls;
2834         struct tegra210_adsp *adsp;
2835         int i, j, wt_idx, mux_idx, ret = 0;
2836         unsigned int compr_ops = 1;
2837         char plugin_info[20];
2838
2839         pr_info("tegra210_adsp_audio_platform_probe: platform probe started\n");
2840
2841         match = of_match_device(tegra210_adsp_audio_of_match, &pdev->dev);
2842         if (!match) {
2843                 dev_err(&pdev->dev, "Error: No device match found\n");
2844                 return -ENODEV;
2845         }
2846
2847         adsp = devm_kzalloc(&pdev->dev, sizeof(*adsp), GFP_KERNEL);
2848         if (!adsp) {
2849                 dev_err(&pdev->dev, "Can't allocate tegra210_adsp_ctx\n");
2850                 return -ENOMEM;
2851         }
2852         dev_set_drvdata(&pdev->dev, adsp);
2853         adsp->dev = &pdev->dev;
2854
2855         /* TODO: Add mixer control to set I2S playback rate */
2856         adsp->i2s_rate = 48000;
2857         adsp->recovery_enabled = 0;
2858         adsp->recovery_count = 0;
2859         INIT_WORK(&adsp->override_freq_work, tegra_adsp_override_freq_worker);
2860         mutex_init(&adsp->mutex);
2861         pdev->dev.dma_mask = &tegra_dma_mask;
2862         pdev->dev.coherent_dma_mask = tegra_dma_mask;
2863
2864         pm_runtime_enable(&pdev->dev);
2865         if (!pm_runtime_enabled(&pdev->dev))
2866                 goto err_pm_disable;
2867
2868         /* HACK : Should be handled through dma-engine */
2869         tegra_adsp_pd_add_device(&pdev->dev);
2870         pm_runtime_get_sync(&pdev->dev);
2871         for (i = 0; i < TEGRA210_ADSP_ADMA_CHANNEL_COUNT; i++) {
2872                 ret = tegra_agic_route_interrupt(
2873                         INT_ADMA_EOT0 + TEGRA210_ADSP_ADMA_CHANNEL_START + i,
2874                         TEGRA_AGIC_ADSP);
2875                 if (ret < 0) {
2876                         dev_err(&pdev->dev, "Failed to route INT to ADSP");
2877                         goto err_pm_disable;
2878                 }
2879         }
2880         pm_runtime_put(&pdev->dev);
2881         tegra_adsp_pd_remove_device(&pdev->dev);
2882         /* HACK end */
2883
2884         for (i = 0; i < TEGRA210_ADSP_VIRT_REG_MAX; i++) {
2885                 adsp->apps[i].reg = i;
2886                 adsp->apps[i].priority = 0;
2887                 adsp->apps[i].min_adsp_clock = 0;
2888         }
2889
2890         /* get the plugin count */
2891         if (of_property_read_u32(pdev->dev.of_node,
2892                                 "num-plugin",
2893                                 &adsp_app_count) < 0) {
2894                 dev_warn(&pdev->dev, "Missing ADSP plugin count\n");
2895                 adsp_app_count = 0;
2896         }
2897
2898         /* allocate memory for app descritors */
2899         adsp_app_desc = devm_kzalloc(&pdev->dev,
2900                                 (adsp_app_count + ARRAY_SIZE(adsp_app_minimal))
2901                                 * sizeof(*adsp_app_desc), GFP_KERNEL);
2902         if (!adsp_app_desc) {
2903                 dev_err(&pdev->dev, "Can't allocate tegra210_adsp_app descriptor\n");
2904                 ret = -ENOMEM;
2905                 goto err_pm_disable;
2906         }
2907
2908         /* parse the plugin, firmware, widget names and params */
2909         for (i = 0; i < adsp_app_count; i++) {
2910                 memset((void *)plugin_info, '\0', 20);
2911                 sprintf(plugin_info, "plugin-info-%d", i+1);
2912                 subnp = of_get_child_by_name(np, plugin_info);
2913                 if (subnp) {
2914                         if (of_property_read_string(subnp, "plugin-name",
2915                                 &adsp_app_desc[i].name)) {
2916                                 dev_err(&pdev->dev,
2917                                         "Missing property plugin-name\n");
2918                                 ret = -EINVAL;
2919                                 goto err_pm_disable;
2920                         }
2921                         if (of_property_read_string(subnp, "firmware-name",
2922                                 &adsp_app_desc[i].fw_name)) {
2923                                 dev_err(&pdev->dev,
2924                                         "Missing property firmware-name\n");
2925                                 ret = -EINVAL;
2926                                 goto err_pm_disable;
2927                         }
2928                         if (of_property_read_string(subnp, "widget-name",
2929                                 &adsp_app_desc[i].wt_name)) {
2930                                 dev_warn(&pdev->dev,
2931                                         "Missing property widget-name for %s\n",
2932                                         adsp_app_desc[i].name);
2933                                 adsp_app_desc[i].wt_name = NULL;
2934                         } else {
2935                                 if (adsp_app_desc[i].wt_name) {
2936                                         /* override the widget names from DT if any */
2937                                         mux_idx = TEGRA210_ADSP_PLUGIN1 + i;
2938                                         wt_idx = TEGRA210_ADSP_WIDGET_BASE + (2*i);
2939                                         tegra210_adsp_route_modify(
2940                                                 tegra210_adsp_mux_texts[mux_idx],
2941                                                 adsp_app_desc[i].wt_name);
2942                                         strcpy((char *)tegra210_adsp_widgets[wt_idx].name,
2943                                                 adsp_app_desc[i].wt_name);
2944                                         strcpy((char *)tegra210_adsp_widgets[wt_idx+1].name,
2945                                                 adsp_app_desc[i].wt_name);
2946                                         strcpy((char *)tegra210_adsp_controls[i+1].name,
2947                                                 adsp_app_desc[i].wt_name);
2948                                         strcat((char *)tegra210_adsp_widgets[wt_idx].name,
2949                                                 " TX");
2950                                         strcat((char *)tegra210_adsp_widgets[wt_idx+1].name,
2951                                                 " MUX");
2952                                         strcat((char *)tegra210_adsp_controls[i+1].name,
2953                                                 " set params");
2954                                         strcpy((char *)tegra210_adsp_mux_texts[mux_idx],
2955                                                 adsp_app_desc[i].wt_name);
2956                                 }
2957                         }
2958                         if (of_property_read_u32(subnp, "param-type",
2959                                 &adsp_app_desc[i].param_type)) {
2960                                 dev_warn(&pdev->dev,
2961                                         "Default param-type to BYTE for %s\n",
2962                                         adsp_app_desc[i].name);
2963                                 adsp_app_desc[i].param_type =
2964                                         SNDRV_CTL_ELEM_TYPE_BYTES;
2965                         } else {
2966                                 /* override the param-type from DT if any */
2967                                 controls =
2968                                         (void *)tegra210_adsp_controls[i+1].private_value;
2969                                 controls->mask = adsp_app_desc[i].param_type;
2970                         }
2971                         adsp_app_desc[i].reg_start = TEGRA210_ADSP_PLUGIN1 + i;
2972                         adsp_app_desc[i].reg_end = TEGRA210_ADSP_PLUGIN1 + i;
2973                 } else {
2974                         dev_err(&pdev->dev,
2975                                 "Property '%s' missing or invalid\n",
2976                                 plugin_info);
2977                         ret = -EINVAL;
2978                         goto err_pm_disable;
2979                 }
2980         }
2981
2982         /* copy basic apps needed */
2983         memcpy(&adsp_app_desc[adsp_app_count],
2984                         &adsp_app_minimal[0], sizeof(adsp_app_minimal));
2985         adsp_app_count += ARRAY_SIZE(adsp_app_minimal);
2986
2987         for (i = 0; i < adsp_app_count; i++) {
2988                 for (j = adsp_app_desc[i].reg_start;
2989                         j <= adsp_app_desc[i].reg_end; j++)
2990                         adsp->apps[j].desc = &adsp_app_desc[i];
2991         }
2992
2993         /* enable/disable compr-ops from DT */
2994         of_property_read_u32(pdev->dev.of_node, "compr-ops", &compr_ops);
2995         if (!compr_ops)
2996                 tegra210_adsp_platform.compr_ops = NULL;
2997
2998         ret = snd_soc_register_platform(&pdev->dev, &tegra210_adsp_platform);
2999         if (ret) {
3000                 dev_err(&pdev->dev, "Could not register platform: %d\n", ret);
3001                 goto err_pm_disable;
3002         }
3003
3004         ret = snd_soc_register_component(&pdev->dev, &tegra210_adsp_component,
3005                         tegra210_adsp_dai, ARRAY_SIZE(tegra210_adsp_dai));
3006         if (ret) {
3007                 dev_err(&pdev->dev, "Could not register component: %d\n", ret);
3008                 goto err_unregister_platform;
3009         }
3010
3011         ret = snd_soc_register_codec(&pdev->dev, &tegra210_adsp_codec,
3012                                      tegra210_adsp_codec_dai,
3013                                      ARRAY_SIZE(tegra210_adsp_codec_dai));
3014         if (ret != 0) {
3015                 dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
3016                 goto err_unregister_platform;
3017         }
3018
3019         pr_info("tegra210_adsp_audio_platform_probe probe successfull.");
3020         return 0;
3021
3022 err_unregister_platform:
3023         snd_soc_unregister_platform(&pdev->dev);
3024 err_pm_disable:
3025         pm_runtime_disable(&pdev->dev);
3026         return ret;
3027 }
3028
3029 static int tegra210_adsp_audio_platform_remove(struct platform_device *pdev)
3030 {
3031         pm_runtime_disable(&pdev->dev);
3032         snd_soc_unregister_platform(&pdev->dev);
3033         return 0;
3034 }
3035
3036 static const struct dev_pm_ops tegra210_adsp_pm_ops = {
3037         SET_RUNTIME_PM_OPS(tegra210_adsp_runtime_suspend,
3038                            tegra210_adsp_runtime_resume, NULL)
3039 };
3040
3041 static struct platform_driver tegra210_adsp_audio_driver = {
3042         .driver = {
3043                 .name = DRV_NAME,
3044                 .owner = THIS_MODULE,
3045                 .of_match_table = tegra210_adsp_audio_of_match,
3046                 .pm = &tegra210_adsp_pm_ops,
3047         },
3048         .probe = tegra210_adsp_audio_platform_probe,
3049         .remove = tegra210_adsp_audio_platform_remove,
3050 };
3051 module_platform_driver(tegra210_adsp_audio_driver);
3052
3053 MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
3054 MODULE_DESCRIPTION("Tegra210 ADSP Audio driver");
3055 MODULE_LICENSE("GPL");
3056 MODULE_ALIAS("platform:" DRV_NAME);
3057 MODULE_DEVICE_TABLE(of, tegra210_adsp_audio_of_match);
3058