FILE
q6apm-dai.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/qcom/qdsp6/q6apm-dai.c
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2021, Linaro Limited 3 4#include <linux/init.h> 5#include <linux/err.h> 6#include <linux/module.h> 7#include <linux/of.h> 8#include <linux/platform_device.h> 9#include <linux/slab.h> 10#include <sound/soc.h> 11#include <sound/soc-dapm.h> 12#include <linux/spinlock.h> 13#include <sound/pcm.h> 14#include <asm/div64.h> 15#include <asm/dma.h> 16#include <linux/dma-mapping.h> 17#include <sound/pcm_params.h> 18#include "q6apm.h" 19 20#define DRV_NAME "q6apm-dai" 21 22#define PLAYBACK_MIN_NUM_PERIODS 2 23#define PLAYBACK_MAX_NUM_PERIODS 8 24#define PLAYBACK_MAX_PERIOD_SIZE 65536 25#define PLAYBACK_MIN_PERIOD_SIZE 128 26#define CAPTURE_MIN_NUM_PERIODS 2 27#define CAPTURE_MAX_NUM_PERIODS 8 28#define CAPTURE_MAX_PERIOD_SIZE 65536 29#define CAPTURE_MIN_PERIOD_SIZE 6144 30#define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE) 31#define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE) 32#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024) 33#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4) 34#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024) 35#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4) 36#define SID_MASK_DEFAULT 0xF 37 38static const struct snd_compr_codec_caps q6apm_compr_caps = { 39 .num_descriptors = 1, 40 .descriptor[0].max_ch = 2, 41 .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050, 42 24000, 32000, 44100, 48000, 88200, 43 96000, 176400, 192000 }, 44 .descriptor[0].num_sample_rates = 13, 45 .descriptor[0].bit_rate[0] = 320, 46 .descriptor[0].bit_rate[1] = 128, 47 .descriptor[0].num_bitrates = 2, 48 .descriptor[0].profiles = 0, 49 .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO, 50 .descriptor[0].formats = 0, 51}; 52 53enum stream_state { 54 Q6APM_STREAM_IDLE = 0, 55 Q6APM_STREAM_STOPPED, 56 Q6APM_STREAM_RUNNING, 57}; 58 59struct q6apm_dai_rtd { 60 struct snd_pcm_substream *substream; 61 struct snd_compr_stream *cstream; 62 struct snd_codec codec; 63 struct snd_compr_params codec_param; 64 struct snd_dma_buffer dma_buffer; 65 phys_addr_t phys; 66 unsigned int pcm_size; 67 unsigned int pcm_count; 68 unsigned int periods; 69 uint64_t bytes_sent; 70 uint64_t bytes_received; 71 uint64_t copied_total; 72 uint16_t bits_per_sample; 73 snd_pcm_uframes_t queue_ptr; 74 bool next_track; 75 enum stream_state state; 76 struct q6apm_graph *graph; 77 spinlock_t lock; 78 bool notify_on_drain; 79}; 80 81struct q6apm_dai_data { 82 long long sid; 83}; 84 85static const struct snd_pcm_hardware q6apm_dai_hardware_capture = { 86 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | 87 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | 88 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | 89 SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR | 90 SNDRV_PCM_INFO_BATCH), 91 .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), 92 .rates = SNDRV_PCM_RATE_8000_48000, 93 .rate_min = 8000, 94 .rate_max = 48000, 95 .channels_min = 2, 96 .channels_max = 4, 97 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, 98 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, 99 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, 100 .periods_min = CAPTURE_MIN_NUM_PERIODS, 101 .periods_max = CAPTURE_MAX_NUM_PERIODS, 102 .fifo_size = 0, 103}; 104 105static const struct snd_pcm_hardware q6apm_dai_hardware_playback = { 106 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | 107 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | 108 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | 109 SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR | 110 SNDRV_PCM_INFO_BATCH), 111 .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), 112 .rates = SNDRV_PCM_RATE_8000_192000, 113 .rate_min = 8000, 114 .rate_max = 192000, 115 .channels_min = 2, 116 .channels_max = 8, 117 .buffer_bytes_max = (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE), 118 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, 119 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, 120 .periods_min = PLAYBACK_MIN_NUM_PERIODS, 121 .periods_max = PLAYBACK_MAX_NUM_PERIODS, 122 .fifo_size = 0, 123}; 124 125static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv) 126{ 127 struct q6apm_dai_rtd *prtd = priv; 128 struct snd_pcm_substream *substream = prtd->substream; 129 130 switch (opcode) { 131 case APM_CLIENT_EVENT_CMD_EOS_DONE: 132 prtd->state = Q6APM_STREAM_STOPPED; 133 break; 134 case APM_CLIENT_EVENT_DATA_WRITE_DONE: 135 snd_pcm_period_elapsed(substream); 136 137 break; 138 case APM_CLIENT_EVENT_DATA_READ_DONE: 139 snd_pcm_period_elapsed(substream); 140 if (prtd->state == Q6APM_STREAM_RUNNING) 141 q6apm_read(prtd->graph); 142 143 break; 144 default: 145 break; 146 } 147} 148 149static void event_handler_compr(uint32_t opcode, uint32_t token, 150 void *payload, void *priv) 151{ 152 struct q6apm_dai_rtd *prtd = priv; 153 struct snd_compr_stream *substream = prtd->cstream; 154 uint32_t wflags = 0; 155 uint64_t avail; 156 uint32_t bytes_written, bytes_to_write; 157 bool is_last_buffer = false; 158 159 guard(spinlock_irqsave)(&prtd->lock); 160 switch (opcode) { 161 case APM_CLIENT_EVENT_CMD_EOS_DONE: 162 if (prtd->notify_on_drain) { 163 snd_compr_drain_notify(prtd->cstream); 164 prtd->notify_on_drain = false; 165 } else { 166 prtd->state = Q6APM_STREAM_STOPPED; 167 } 168 break; 169 case APM_CLIENT_EVENT_DATA_WRITE_DONE: 170 bytes_written = token >> APM_WRITE_TOKEN_LEN_SHIFT; 171 prtd->copied_total += bytes_written; 172 snd_compr_fragment_elapsed(substream); 173 174 if (prtd->state != Q6APM_STREAM_RUNNING) 175 break; 176 177 avail = prtd->bytes_received - prtd->bytes_sent; 178 179 if (avail > prtd->pcm_count) { 180 bytes_to_write = prtd->pcm_count; 181 } else { 182 if (substream->partial_drain || prtd->notify_on_drain) 183 is_last_buffer = true; 184 bytes_to_write = avail; 185 } 186 187 if (bytes_to_write) { 188 if (substream->partial_drain && is_last_buffer) 189 wflags |= APM_LAST_BUFFER_FLAG; 190 191 q6apm_write_async(prtd->graph, 192 bytes_to_write, 0, 0, wflags); 193 194 prtd->bytes_sent += bytes_to_write; 195 196 if (prtd->notify_on_drain && is_last_buffer) 197 audioreach_shared_memory_send_eos(prtd->graph); 198 } 199 200 break; 201 default: 202 break; 203 } 204} 205 206static int q6apm_dai_prepare(struct snd_soc_component *component, 207 struct snd_pcm_substream *substream) 208{ 209 struct snd_pcm_runtime *runtime = substream->runtime; 210 struct q6apm_dai_rtd *prtd = runtime->private_data; 211 struct audioreach_module_config cfg; 212 struct device *dev = component->dev; 213 struct q6apm_dai_data *pdata; 214 int ret; 215 216 pdata = snd_soc_component_get_drvdata(component); 217 if (!pdata) 218 return -EINVAL; 219 220 if (!prtd || !prtd->graph) { 221 dev_err(dev, "%s: private data null or audio client freed\n", __func__); 222 return -EINVAL; 223 } 224 225 cfg.direction = substream->stream; 226 cfg.sample_rate = runtime->rate; 227 cfg.num_channels = runtime->channels; 228 cfg.bit_width = prtd->bits_per_sample; 229 cfg.fmt = SND_AUDIOCODEC_PCM; 230 audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels); 231 232 if (prtd->state) { 233 /* clear the previous setup if any */ 234 q6apm_graph_stop(prtd->graph); 235 q6apm_unmap_memory_regions(prtd->graph, substream->stream); 236 } 237 238 prtd->pcm_count = snd_pcm_lib_period_bytes(substream); 239 /* rate and channels are sent to audio driver */ 240 ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); 241 if (ret < 0) { 242 dev_err(dev, "%s: q6apm_open_write failed\n", __func__); 243 return ret; 244 } 245 246 ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg); 247 if (ret < 0) 248 dev_err(dev, "%s: CMD Format block failed\n", __func__); 249 250 ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys, 251 (prtd->pcm_size / prtd->periods), prtd->periods); 252 253 if (ret < 0) { 254 dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret); 255 return -ENOMEM; 256 } 257 258 ret = q6apm_graph_prepare(prtd->graph); 259 if (ret) { 260 dev_err(dev, "Failed to prepare Graph %d\n", ret); 261 return ret; 262 } 263 264 ret = q6apm_graph_start(prtd->graph); 265 if (ret) { 266 dev_err(dev, "Failed to Start Graph %d\n", ret); 267 return ret; 268 } 269 270 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 271 int i; 272 /* Queue the buffers for Capture ONLY after graph is started */ 273 for (i = 0; i < runtime->periods; i++) 274 q6apm_read(prtd->graph); 275 276 } 277 278 /* Now that graph as been prepared and started update the internal state accordingly */ 279 prtd->state = Q6APM_STREAM_RUNNING; 280 281 return 0; 282} 283 284static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) 285{ 286 struct snd_pcm_runtime *runtime = substream->runtime; 287 struct q6apm_dai_rtd *prtd = runtime->private_data; 288 int i, ret = 0, avail_periods; 289 290 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 291 avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size; 292 for (i = 0; i < avail_periods; i++) { 293 ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); 294 if (ret < 0) { 295 dev_err(component->dev, "Error queuing playback buffer %d\n", ret); 296 return ret; 297 } 298 prtd->queue_ptr += runtime->period_size; 299 } 300 } 301 302 return ret; 303} 304 305static int q6apm_dai_trigger(struct snd_soc_component *component, 306 struct snd_pcm_substream *substream, int cmd) 307{ 308 struct snd_pcm_runtime *runtime = substream->runtime; 309 struct q6apm_dai_rtd *prtd = runtime->private_data; 310 int ret = 0; 311 312 switch (cmd) { 313 case SNDRV_PCM_TRIGGER_START: 314 case SNDRV_PCM_TRIGGER_RESUME: 315 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 316 break; 317 case SNDRV_PCM_TRIGGER_STOP: 318 /* TODO support be handled via SoftPause Module */ 319 prtd->state = Q6APM_STREAM_STOPPED; 320 break; 321 case SNDRV_PCM_TRIGGER_SUSPEND: 322 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 323 break; 324 default: 325 ret = -EINVAL; 326 break; 327 } 328 329 return ret; 330} 331 332static int q6apm_dai_open(struct snd_soc_component *component, 333 struct snd_pcm_substream *substream) 334{ 335 struct snd_pcm_runtime *runtime = substream->runtime; 336 struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream); 337 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0); 338 struct device *dev = component->dev; 339 struct q6apm_dai_data *pdata; 340 struct q6apm_dai_rtd *prtd; 341 int graph_id, ret; 342 343 graph_id = cpu_dai->driver->id; 344 345 pdata = snd_soc_component_get_drvdata(component); 346 if (!pdata) { 347 dev_err(dev, "Drv data not found ..\n"); 348 return -EINVAL; 349 } 350 351 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); 352 if (prtd == NULL) 353 return -ENOMEM; 354 355 spin_lock_init(&prtd->lock); 356 prtd->substream = substream; 357 prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id); 358 if (IS_ERR(prtd->graph)) { 359 dev_err(dev, "%s: Could not allocate memory\n", __func__); 360 ret = PTR_ERR(prtd->graph); 361 goto err; 362 } 363 364 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 365 runtime->hw = q6apm_dai_hardware_playback; 366 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 367 runtime->hw = q6apm_dai_hardware_capture; 368 369 /* Ensure that buffer size is a multiple of period size */ 370 ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 371 if (ret < 0) { 372 dev_err(dev, "snd_pcm_hw_constraint_integer failed\n"); 373 goto err; 374 } 375 376 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 377 ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 378 BUFFER_BYTES_MIN, BUFFER_BYTES_MAX); 379 if (ret < 0) { 380 dev_err(dev, "constraint for buffer bytes min max ret = %d\n", ret); 381 goto err; 382 } 383 } 384 385 /* setup 10ms latency to accommodate DSP restrictions */ 386 ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480); 387 if (ret < 0) { 388 dev_err(dev, "constraint for period bytes step ret = %d\n", ret); 389 goto err; 390 } 391 392 ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480); 393 if (ret < 0) { 394 dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret); 395 goto err; 396 } 397 398 runtime->private_data = prtd; 399 runtime->dma_bytes = BUFFER_BYTES_MAX; 400 if (pdata->sid < 0) 401 prtd->phys = substream->dma_buffer.addr; 402 else 403 prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32); 404 405 return 0; 406err: 407 kfree(prtd); 408 409 return ret; 410} 411 412static int q6apm_dai_close(struct snd_soc_component *component, 413 struct snd_pcm_substream *substream) 414{ 415 struct snd_pcm_runtime *runtime = substream->runtime; 416 struct q6apm_dai_rtd *prtd = runtime->private_data; 417 418 if (prtd->state) { /* only stop graph that is started */ 419 q6apm_graph_stop(prtd->graph); 420 q6apm_unmap_memory_regions(prtd->graph, substream->stream); 421 } 422 423 q6apm_graph_close(prtd->graph); 424 prtd->graph = NULL; 425 kfree(prtd); 426 runtime->private_data = NULL; 427 428 return 0; 429} 430 431static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component, 432 struct snd_pcm_substream *substream) 433{ 434 struct snd_pcm_runtime *runtime = substream->runtime; 435 struct q6apm_dai_rtd *prtd = runtime->private_data; 436 snd_pcm_uframes_t ptr; 437 438 ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size; 439 if (ptr) 440 return ptr - 1; 441 442 return 0; 443} 444 445static int q6apm_dai_hw_params(struct snd_soc_component *component, 446 struct snd_pcm_substream *substream, 447 struct snd_pcm_hw_params *params) 448{ 449 struct snd_pcm_runtime *runtime = substream->runtime; 450 struct q6apm_dai_rtd *prtd = runtime->private_data; 451 452 prtd->pcm_size = params_buffer_bytes(params); 453 prtd->periods = params_periods(params); 454 455 switch (params_format(params)) { 456 case SNDRV_PCM_FORMAT_S16_LE: 457 prtd->bits_per_sample = 16; 458 break; 459 case SNDRV_PCM_FORMAT_S24_LE: 460 prtd->bits_per_sample = 24; 461 break; 462 default: 463 return -EINVAL; 464 } 465 466 return 0; 467} 468 469static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) 470{ 471 int size = BUFFER_BYTES_MAX; 472 473 return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size); 474} 475 476static int q6apm_dai_compr_open(struct snd_soc_component *component, 477 struct snd_compr_stream *stream) 478{ 479 struct snd_soc_pcm_runtime *rtd = stream->private_data; 480 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 481 struct snd_compr_runtime *runtime = stream->runtime; 482 struct q6apm_dai_rtd *prtd; 483 struct q6apm_dai_data *pdata; 484 struct device *dev = component->dev; 485 int ret, size; 486 int graph_id; 487 488 graph_id = cpu_dai->driver->id; 489 pdata = snd_soc_component_get_drvdata(component); 490 if (!pdata) 491 return -EINVAL; 492 493 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); 494 if (prtd == NULL) 495 return -ENOMEM; 496 497 prtd->cstream = stream; 498 prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id); 499 if (IS_ERR(prtd->graph)) { 500 ret = PTR_ERR(prtd->graph); 501 kfree(prtd); 502 return ret; 503 } 504 505 runtime->private_data = prtd; 506 runtime->dma_bytes = BUFFER_BYTES_MAX; 507 size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE * COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; 508 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &prtd->dma_buffer); 509 if (ret) 510 return ret; 511 512 if (pdata->sid < 0) 513 prtd->phys = prtd->dma_buffer.addr; 514 else 515 prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32); 516 517 snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer); 518 spin_lock_init(&prtd->lock); 519 520 q6apm_enable_compress_module(dev, prtd->graph, true); 521 return 0; 522} 523 524static int q6apm_dai_compr_free(struct snd_soc_component *component, 525 struct snd_compr_stream *stream) 526{ 527 struct snd_compr_runtime *runtime = stream->runtime; 528 struct q6apm_dai_rtd *prtd = runtime->private_data; 529 530 q6apm_graph_stop(prtd->graph); 531 q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK); 532 q6apm_graph_close(prtd->graph); 533 snd_dma_free_pages(&prtd->dma_buffer); 534 prtd->graph = NULL; 535 kfree(prtd); 536 runtime->private_data = NULL; 537 538 return 0; 539} 540 541static int q6apm_dai_compr_get_caps(struct snd_soc_component *component, 542 struct snd_compr_stream *stream, 543 struct snd_compr_caps *caps) 544{ 545 caps->direction = SND_COMPRESS_PLAYBACK; 546 caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE; 547 caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE; 548 caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; 549 caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; 550 caps->num_codecs = 4; 551 caps->codecs[0] = SND_AUDIOCODEC_MP3; 552 caps->codecs[1] = SND_AUDIOCODEC_AAC; 553 caps->codecs[2] = SND_AUDIOCODEC_FLAC; 554 caps->codecs[3] = SND_AUDIOCODEC_OPUS_RAW; 555 556 return 0; 557} 558 559static int q6apm_dai_compr_get_codec_caps(struct snd_soc_component *component, 560 struct snd_compr_stream *stream, 561 struct snd_compr_codec_caps *codec) 562{ 563 switch (codec->codec) { 564 case SND_AUDIOCODEC_MP3: 565 *codec = q6apm_compr_caps; 566 break; 567 default: 568 break; 569 } 570 571 return 0; 572} 573 574static int q6apm_dai_compr_pointer(struct snd_soc_component *component, 575 struct snd_compr_stream *stream, 576 struct snd_compr_tstamp64 *tstamp) 577{ 578 struct snd_compr_runtime *runtime = stream->runtime; 579 struct q6apm_dai_rtd *prtd = runtime->private_data; 580 uint64_t temp_copied_total; 581 582 guard(spinlock_irqsave)(&prtd->lock); 583 tstamp->copied_total = prtd->copied_total; 584 temp_copied_total = tstamp->copied_total; 585 tstamp->byte_offset = do_div(temp_copied_total, prtd->pcm_size); 586 587 return 0; 588} 589 590static int q6apm_dai_compr_trigger(struct snd_soc_component *component, 591 struct snd_compr_stream *stream, int cmd) 592{ 593 struct snd_compr_runtime *runtime = stream->runtime; 594 struct q6apm_dai_rtd *prtd = runtime->private_data; 595 int ret = 0; 596 597 switch (cmd) { 598 case SNDRV_PCM_TRIGGER_START: 599 case SNDRV_PCM_TRIGGER_RESUME: 600 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 601 ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); 602 break; 603 case SNDRV_PCM_TRIGGER_STOP: 604 break; 605 case SNDRV_PCM_TRIGGER_SUSPEND: 606 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 607 break; 608 case SND_COMPR_TRIGGER_NEXT_TRACK: 609 prtd->next_track = true; 610 break; 611 case SND_COMPR_TRIGGER_DRAIN: 612 case SND_COMPR_TRIGGER_PARTIAL_DRAIN: 613 prtd->notify_on_drain = true; 614 break; 615 default: 616 ret = -EINVAL; 617 break; 618 } 619 620 return ret; 621} 622 623static int q6apm_dai_compr_ack(struct snd_soc_component *component, struct snd_compr_stream *stream, 624 size_t count) 625{ 626 struct snd_compr_runtime *runtime = stream->runtime; 627 struct q6apm_dai_rtd *prtd = runtime->private_data; 628 629 guard(spinlock_irqsave)(&prtd->lock); 630 prtd->bytes_received += count; 631 632 return count; 633} 634 635static int q6apm_dai_compr_set_params(struct snd_soc_component *component, 636 struct snd_compr_stream *stream, 637 struct snd_compr_params *params) 638{ 639 struct snd_compr_runtime *runtime = stream->runtime; 640 struct q6apm_dai_rtd *prtd = runtime->private_data; 641 struct q6apm_dai_data *pdata; 642 struct audioreach_module_config cfg; 643 struct snd_codec *codec = ¶ms->codec; 644 int dir = stream->direction; 645 int ret; 646 647 pdata = snd_soc_component_get_drvdata(component); 648 if (!pdata) 649 return -EINVAL; 650 651 prtd->periods = runtime->fragments; 652 prtd->pcm_count = runtime->fragment_size; 653 prtd->pcm_size = runtime->fragments * runtime->fragment_size; 654 prtd->bits_per_sample = 16; 655 656 if (prtd->next_track != true) { 657 memcpy(&prtd->codec, codec, sizeof(*codec)); 658 659 ret = q6apm_set_real_module_id(component->dev, prtd->graph, codec->id); 660 if (ret) 661 return ret; 662 663 cfg.direction = dir; 664 cfg.sample_rate = codec->sample_rate; 665 cfg.num_channels = 2; 666 cfg.bit_width = prtd->bits_per_sample; 667 cfg.fmt = codec->id; 668 audioreach_set_default_channel_mapping(cfg.channel_map, 669 cfg.num_channels); 670 memcpy(&cfg.codec, codec, sizeof(*codec)); 671 672 ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); 673 if (ret < 0) 674 return ret; 675 676 ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg); 677 if (ret) 678 return ret; 679 680 ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK, 681 prtd->phys, (prtd->pcm_size / prtd->periods), 682 prtd->periods); 683 if (ret < 0) 684 return -ENOMEM; 685 686 ret = q6apm_graph_prepare(prtd->graph); 687 if (ret) 688 return ret; 689 690 ret = q6apm_graph_start(prtd->graph); 691 if (ret) 692 return ret; 693 694 } else { 695 cfg.direction = dir; 696 cfg.sample_rate = codec->sample_rate; 697 cfg.num_channels = 2; 698 cfg.bit_width = prtd->bits_per_sample; 699 cfg.fmt = codec->id; 700 memcpy(&cfg.codec, codec, sizeof(*codec)); 701 702 ret = audioreach_compr_set_param(prtd->graph, &cfg); 703 if (ret < 0) 704 return ret; 705 } 706 prtd->state = Q6APM_STREAM_RUNNING; 707 708 return 0; 709} 710 711static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component, 712 struct snd_compr_stream *stream, 713 struct snd_compr_metadata *metadata) 714{ 715 struct snd_compr_runtime *runtime = stream->runtime; 716 struct q6apm_dai_rtd *prtd = runtime->private_data; 717 int ret = 0; 718 719 switch (metadata->key) { 720 case SNDRV_COMPRESS_ENCODER_PADDING: 721 q6apm_remove_trailing_silence(component->dev, prtd->graph, 722 metadata->value[0]); 723 break; 724 case SNDRV_COMPRESS_ENCODER_DELAY: 725 q6apm_remove_initial_silence(component->dev, prtd->graph, 726 metadata->value[0]); 727 break; 728 default: 729 ret = -EINVAL; 730 break; 731 } 732 733 return ret; 734} 735 736static int q6apm_dai_compr_mmap(struct snd_soc_component *component, 737 struct snd_compr_stream *stream, 738 struct vm_area_struct *vma) 739{ 740 struct snd_compr_runtime *runtime = stream->runtime; 741 struct q6apm_dai_rtd *prtd = runtime->private_data; 742 struct device *dev = component->dev; 743 744 return dma_mmap_coherent(dev, vma, prtd->dma_buffer.area, prtd->dma_buffer.addr, 745 prtd->dma_buffer.bytes); 746} 747 748static int q6apm_compr_copy(struct snd_soc_component *component, 749 struct snd_compr_stream *stream, char __user *buf, 750 size_t count) 751{ 752 struct snd_compr_runtime *runtime = stream->runtime; 753 struct q6apm_dai_rtd *prtd = runtime->private_data; 754 void *dstn; 755 size_t copy; 756 u32 wflags = 0; 757 u32 app_pointer; 758 uint64_t bytes_received; 759 uint64_t temp_bytes_received; 760 uint32_t bytes_to_write; 761 uint64_t avail, bytes_in_flight = 0; 762 763 bytes_received = prtd->bytes_received; 764 temp_bytes_received = bytes_received; 765 766 /** 767 * Make sure that next track data pointer is aligned at 32 bit boundary 768 * This is a Mandatory requirement from DSP data buffers alignment 769 */ 770 if (prtd->next_track) { 771 bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count); 772 temp_bytes_received = bytes_received; 773 } 774 775 app_pointer = do_div(temp_bytes_received, prtd->pcm_size); 776 dstn = prtd->dma_buffer.area + app_pointer; 777 778 if (count < prtd->pcm_size - app_pointer) { 779 if (copy_from_user(dstn, buf, count)) 780 return -EFAULT; 781 } else { 782 copy = prtd->pcm_size - app_pointer; 783 if (copy_from_user(dstn, buf, copy)) 784 return -EFAULT; 785 if (copy_from_user(prtd->dma_buffer.area, buf + copy, count - copy)) 786 return -EFAULT; 787 } 788 789 guard(spinlock_irqsave)(&prtd->lock); 790 bytes_in_flight = prtd->bytes_received - prtd->copied_total; 791 792 if (prtd->next_track) { 793 prtd->next_track = false; 794 prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count); 795 prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count); 796 } 797 798 prtd->bytes_received = bytes_received + count; 799 800 /* Kick off the data to dsp if its starving!! */ 801 if (prtd->state == Q6APM_STREAM_RUNNING && (bytes_in_flight == 0)) { 802 bytes_to_write = prtd->pcm_count; 803 avail = prtd->bytes_received - prtd->bytes_sent; 804 805 if (avail < prtd->pcm_count) 806 bytes_to_write = avail; 807 808 q6apm_write_async(prtd->graph, bytes_to_write, 0, 0, wflags); 809 prtd->bytes_sent += bytes_to_write; 810 } 811 812 return count; 813} 814 815static const struct snd_compress_ops q6apm_dai_compress_ops = { 816 .open = q6apm_dai_compr_open, 817 .free = q6apm_dai_compr_free, 818 .get_caps = q6apm_dai_compr_get_caps, 819 .get_codec_caps = q6apm_dai_compr_get_codec_caps, 820 .pointer = q6apm_dai_compr_pointer, 821 .trigger = q6apm_dai_compr_trigger, 822 .ack = q6apm_dai_compr_ack, 823 .set_params = q6apm_dai_compr_set_params, 824 .set_metadata = q6apm_dai_compr_set_metadata, 825 .mmap = q6apm_dai_compr_mmap, 826 .copy = q6apm_compr_copy, 827}; 828 829static const struct snd_soc_component_driver q6apm_fe_dai_component = { 830 .name = DRV_NAME, 831 .open = q6apm_dai_open, 832 .close = q6apm_dai_close, 833 .prepare = q6apm_dai_prepare, 834 .pcm_construct = q6apm_dai_pcm_new, 835 .hw_params = q6apm_dai_hw_params, 836 .pointer = q6apm_dai_pointer, 837 .trigger = q6apm_dai_trigger, 838 .ack = q6apm_dai_ack, 839 .compress_ops = &q6apm_dai_compress_ops, 840 .use_dai_pcm_id = true, 841 .remove_order = SND_SOC_COMP_ORDER_EARLY, 842}; 843 844static int q6apm_dai_probe(struct platform_device *pdev) 845{ 846 struct device *dev = &pdev->dev; 847 struct device_node *node = dev->of_node; 848 struct q6apm_dai_data *pdata; 849 struct of_phandle_args args; 850 int rc; 851 852 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 853 if (!pdata) 854 return -ENOMEM; 855 856 rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args); 857 if (rc < 0) 858 pdata->sid = -1; 859 else 860 pdata->sid = args.args[0] & SID_MASK_DEFAULT; 861 862 dev_set_drvdata(dev, pdata); 863 864 return devm_snd_soc_register_component(dev, &q6apm_fe_dai_component, NULL, 0); 865} 866 867#ifdef CONFIG_OF 868static const struct of_device_id q6apm_dai_device_id[] = { 869 { .compatible = "qcom,q6apm-dais" }, 870 {}, 871}; 872MODULE_DEVICE_TABLE(of, q6apm_dai_device_id); 873#endif 874 875static struct platform_driver q6apm_dai_platform_driver = { 876 .driver = { 877 .name = "q6apm-dai", 878 .of_match_table = of_match_ptr(q6apm_dai_device_id), 879 }, 880 .probe = q6apm_dai_probe, 881}; 882module_platform_driver(q6apm_dai_platform_driver); 883 884MODULE_DESCRIPTION("Q6APM dai driver"); 885MODULE_LICENSE("GPL");
~/
Read-only file preview.