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