FILE
q6asm.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/qcom/qdsp6/q6asm.c
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. 3// Copyright (c) 2018, Linaro Limited 4 5#include <dt-bindings/sound/qcom,q6asm.h> 6#include <linux/mutex.h> 7#include <linux/wait.h> 8#include <linux/module.h> 9#include <linux/atomic.h> 10#include <linux/soc/qcom/apr.h> 11#include <linux/device.h> 12#include <linux/of_platform.h> 13#include <linux/spinlock.h> 14#include <linux/kref.h> 15#include <linux/of.h> 16#include <uapi/sound/asound.h> 17#include <uapi/sound/compress_params.h> 18#include <linux/delay.h> 19#include <linux/slab.h> 20#include <linux/mm.h> 21#include "q6asm.h" 22#include "q6core.h" 23#include "q6dsp-errno.h" 24#include "q6dsp-common.h" 25 26#define ASM_STREAM_CMD_CLOSE 0x00010BCD 27#define ASM_STREAM_CMD_FLUSH 0x00010BCE 28#define ASM_SESSION_CMD_PAUSE 0x00010BD3 29#define ASM_DATA_CMD_EOS 0x00010BDB 30#define ASM_DATA_EVENT_RENDERED_EOS 0x00010C1C 31#define ASM_NULL_POPP_TOPOLOGY 0x00010C68 32#define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09 33#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10 34#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68 35#define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92 36#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93 37#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94 38#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98 39#define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99 40#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3 41#define ASM_SESSION_CMD_RUN_V2 0x00010DAA 42#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 43#define ASM_MEDIA_FMT_MP3 0x00010BE9 44#define ASM_MEDIA_FMT_FLAC 0x00010C16 45#define ASM_MEDIA_FMT_WMA_V9 0x00010DA8 46#define ASM_MEDIA_FMT_WMA_V10 0x00010DA7 47#define ASM_DATA_CMD_WRITE_V2 0x00010DAB 48#define ASM_DATA_CMD_READ_V2 0x00010DAC 49#define ASM_SESSION_CMD_SUSPEND 0x00010DEC 50#define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3 51#define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4 52#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A 53#define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D 54#define ASM_MEDIA_FMT_ALAC 0x00012f31 55#define ASM_MEDIA_FMT_APE 0x00012f32 56#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67 57#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68 58 59 60#define ASM_LEGACY_STREAM_SESSION 0 61/* Bit shift for the stream_perf_mode subfield. */ 62#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29 63#define ASM_END_POINT_DEVICE_MATRIX 0 64#define ASM_DEFAULT_APP_TYPE 0 65#define ASM_SYNC_IO_MODE 0x0001 66#define ASM_ASYNC_IO_MODE 0x0002 67#define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ 68#define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */ 69#define ASM_SHIFT_GAPLESS_MODE_FLAG 31 70#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3 71 72struct avs_cmd_shared_mem_map_regions { 73 u16 mem_pool_id; 74 u16 num_regions; 75 u32 property_flag; 76} __packed; 77 78struct avs_shared_map_region_payload { 79 u32 shm_addr_lsw; 80 u32 shm_addr_msw; 81 u32 mem_size_bytes; 82} __packed; 83 84struct avs_cmd_shared_mem_unmap_regions { 85 u32 mem_map_handle; 86} __packed; 87 88struct asm_data_cmd_media_fmt_update_v2 { 89 u32 fmt_blk_size; 90} __packed; 91 92struct asm_multi_channel_pcm_fmt_blk_v2 { 93 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 94 u16 num_channels; 95 u16 bits_per_sample; 96 u32 sample_rate; 97 u16 is_signed; 98 u16 reserved; 99 u8 channel_mapping[PCM_MAX_NUM_CHANNEL]; 100} __packed; 101 102struct asm_flac_fmt_blk_v2 { 103 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 104 u16 is_stream_info_present; 105 u16 num_channels; 106 u16 min_blk_size; 107 u16 max_blk_size; 108 u16 md5_sum[8]; 109 u32 sample_rate; 110 u32 min_frame_size; 111 u32 max_frame_size; 112 u16 sample_size; 113 u16 reserved; 114} __packed; 115 116struct asm_wmastdv9_fmt_blk_v2 { 117 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 118 u16 fmtag; 119 u16 num_channels; 120 u32 sample_rate; 121 u32 bytes_per_sec; 122 u16 blk_align; 123 u16 bits_per_sample; 124 u32 channel_mask; 125 u16 enc_options; 126 u16 reserved; 127} __packed; 128 129struct asm_wmaprov10_fmt_blk_v2 { 130 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 131 u16 fmtag; 132 u16 num_channels; 133 u32 sample_rate; 134 u32 bytes_per_sec; 135 u16 blk_align; 136 u16 bits_per_sample; 137 u32 channel_mask; 138 u16 enc_options; 139 u16 advanced_enc_options1; 140 u32 advanced_enc_options2; 141} __packed; 142 143struct asm_alac_fmt_blk_v2 { 144 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 145 u32 frame_length; 146 u8 compatible_version; 147 u8 bit_depth; 148 u8 pb; 149 u8 mb; 150 u8 kb; 151 u8 num_channels; 152 u16 max_run; 153 u32 max_frame_bytes; 154 u32 avg_bit_rate; 155 u32 sample_rate; 156 u32 channel_layout_tag; 157} __packed; 158 159struct asm_ape_fmt_blk_v2 { 160 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 161 u16 compatible_version; 162 u16 compression_level; 163 u32 format_flags; 164 u32 blocks_per_frame; 165 u32 final_frame_blocks; 166 u32 total_frames; 167 u16 bits_per_sample; 168 u16 num_channels; 169 u32 sample_rate; 170 u32 seek_table_present; 171} __packed; 172 173struct asm_stream_cmd_set_encdec_param { 174 u32 param_id; 175 u32 param_size; 176} __packed; 177 178struct asm_enc_cfg_blk_param_v2 { 179 u32 frames_per_buf; 180 u32 enc_cfg_blk_size; 181} __packed; 182 183struct asm_multi_channel_pcm_enc_cfg_v2 { 184 struct asm_stream_cmd_set_encdec_param encdec; 185 struct asm_enc_cfg_blk_param_v2 encblk; 186 uint16_t num_channels; 187 uint16_t bits_per_sample; 188 uint32_t sample_rate; 189 uint16_t is_signed; 190 uint16_t reserved; 191 uint8_t channel_mapping[8]; 192} __packed; 193 194struct asm_data_cmd_read_v2 { 195 u32 buf_addr_lsw; 196 u32 buf_addr_msw; 197 u32 mem_map_handle; 198 u32 buf_size; 199 u32 seq_id; 200} __packed; 201 202struct asm_data_cmd_read_v2_done { 203 u32 status; 204 u32 buf_addr_lsw; 205 u32 buf_addr_msw; 206}; 207 208struct asm_stream_cmd_open_read_v3 { 209 u32 mode_flags; 210 u32 src_endpointype; 211 u32 preprocopo_id; 212 u32 enc_cfg_id; 213 u16 bits_per_sample; 214 u16 reserved; 215} __packed; 216 217struct asm_data_cmd_write_v2 { 218 u32 buf_addr_lsw; 219 u32 buf_addr_msw; 220 u32 mem_map_handle; 221 u32 buf_size; 222 u32 seq_id; 223 u32 timestamp_lsw; 224 u32 timestamp_msw; 225 u32 flags; 226} __packed; 227 228struct asm_stream_cmd_open_write_v3 { 229 uint32_t mode_flags; 230 uint16_t sink_endpointype; 231 uint16_t bits_per_sample; 232 uint32_t postprocopo_id; 233 uint32_t dec_fmt_id; 234} __packed; 235 236struct asm_session_cmd_run_v2 { 237 u32 flags; 238 u32 time_lsw; 239 u32 time_msw; 240} __packed; 241 242struct audio_buffer { 243 phys_addr_t phys; 244 uint32_t size; /* size of buffer */ 245}; 246 247struct audio_port_data { 248 struct audio_buffer *buf; 249 uint32_t num_periods; 250 uint32_t dsp_buf; 251 uint32_t mem_map_handle; 252 atomic_t hw_ptr; 253}; 254 255struct q6asm { 256 struct apr_device *adev; 257 struct device *dev; 258 struct q6core_svc_api_info ainfo; 259 wait_queue_head_t mem_wait; 260 spinlock_t slock; 261 struct audio_client *session[MAX_SESSIONS + 1]; 262}; 263 264struct audio_client { 265 int session; 266 q6asm_cb cb; 267 void *priv; 268 uint32_t io_mode; 269 struct apr_device *adev; 270 struct mutex cmd_lock; 271 spinlock_t lock; 272 struct kref refcount; 273 /* idx:1 out port, 0: in port */ 274 struct audio_port_data port[2]; 275 wait_queue_head_t cmd_wait; 276 struct aprv2_ibasic_rsp_result_t result; 277 int perf_mode; 278 struct q6asm *q6asm; 279 struct device *dev; 280}; 281 282static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, 283 uint32_t pkt_size, bool cmd_flg, 284 uint32_t stream_id) 285{ 286 hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD; 287 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id); 288 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id); 289 hdr->pkt_size = pkt_size; 290 if (cmd_flg) 291 hdr->token = ac->session; 292} 293 294static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac, 295 struct apr_pkt *pkt, uint32_t rsp_opcode) 296{ 297 struct apr_hdr *hdr = &pkt->hdr; 298 int rc; 299 300 mutex_lock(&ac->cmd_lock); 301 ac->result.opcode = 0; 302 ac->result.status = 0; 303 rc = apr_send_pkt(a->adev, pkt); 304 if (rc < 0) 305 goto err; 306 307 if (rsp_opcode) 308 rc = wait_event_timeout(a->mem_wait, 309 (ac->result.opcode == hdr->opcode) || 310 (ac->result.opcode == rsp_opcode), 311 5 * HZ); 312 else 313 rc = wait_event_timeout(a->mem_wait, 314 (ac->result.opcode == hdr->opcode), 315 5 * HZ); 316 317 if (!rc) { 318 dev_err(a->dev, "CMD %x timeout\n", hdr->opcode); 319 rc = -ETIMEDOUT; 320 } else if (ac->result.status > 0) { 321 dev_err(a->dev, "DSP returned error[%x]\n", 322 ac->result.status); 323 rc = -EINVAL; 324 } 325 326err: 327 mutex_unlock(&ac->cmd_lock); 328 return rc; 329} 330 331static int __q6asm_memory_unmap(struct audio_client *ac, 332 phys_addr_t buf_add, int dir) 333{ 334 struct avs_cmd_shared_mem_unmap_regions *mem_unmap; 335 struct q6asm *a = dev_get_drvdata(ac->dev->parent); 336 struct apr_pkt *pkt; 337 int rc, pkt_size; 338 void *p __free(kfree) = NULL; 339 340 if (ac->port[dir].mem_map_handle == 0) { 341 dev_err(ac->dev, "invalid mem handle\n"); 342 return -EINVAL; 343 } 344 345 pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap); 346 p = kzalloc(pkt_size, GFP_KERNEL); 347 if (!p) 348 return -ENOMEM; 349 350 pkt = p; 351 mem_unmap = p + APR_HDR_SIZE; 352 353 pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD; 354 pkt->hdr.src_port = 0; 355 pkt->hdr.dest_port = 0; 356 pkt->hdr.pkt_size = pkt_size; 357 pkt->hdr.token = ((ac->session << 8) | dir); 358 359 pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS; 360 mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle; 361 362 rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0); 363 if (rc < 0) 364 return rc; 365 366 ac->port[dir].mem_map_handle = 0; 367 368 return 0; 369} 370 371 372static void q6asm_audio_client_free_buf(struct audio_client *ac, 373 struct audio_port_data *port) 374{ 375 unsigned long flags; 376 377 spin_lock_irqsave(&ac->lock, flags); 378 port->num_periods = 0; 379 spin_unlock_irqrestore(&ac->lock, flags); 380 kfree(port->buf); 381 port->buf = NULL; 382} 383 384/** 385 * q6asm_unmap_memory_regions() - unmap memory regions in the dsp. 386 * 387 * @dir: direction of audio stream 388 * @ac: audio client instanace 389 * 390 * Return: Will be an negative value on failure or zero on success 391 */ 392int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac) 393{ 394 struct audio_port_data *port; 395 int cnt = 0; 396 int rc = 0; 397 398 port = &ac->port[dir]; 399 if (!port->buf) { 400 rc = -EINVAL; 401 goto err; 402 } 403 404 cnt = port->num_periods - 1; 405 if (cnt >= 0) { 406 rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir); 407 if (rc < 0) { 408 dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n", 409 __func__, rc); 410 goto err; 411 } 412 } 413 414 q6asm_audio_client_free_buf(ac, port); 415 416err: 417 return rc; 418} 419EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions); 420 421static int __q6asm_memory_map_regions(struct audio_client *ac, int dir, 422 size_t period_sz, unsigned int periods, 423 bool is_contiguous) 424{ 425 struct avs_cmd_shared_mem_map_regions *cmd = NULL; 426 struct avs_shared_map_region_payload *mregions = NULL; 427 struct q6asm *a = dev_get_drvdata(ac->dev->parent); 428 struct audio_port_data *port = NULL; 429 struct audio_buffer *ab = NULL; 430 struct apr_pkt *pkt; 431 void *p __free(kfree) = NULL; 432 unsigned long flags; 433 uint32_t num_regions, buf_sz; 434 int i, pkt_size; 435 436 if (is_contiguous) { 437 num_regions = 1; 438 buf_sz = period_sz * periods; 439 } else { 440 buf_sz = period_sz; 441 num_regions = periods; 442 } 443 444 /* DSP expects size should be aligned to 4K */ 445 buf_sz = ALIGN(buf_sz, 4096); 446 447 pkt_size = APR_HDR_SIZE + sizeof(*cmd) + 448 (sizeof(*mregions) * num_regions); 449 450 p = kzalloc(pkt_size, GFP_KERNEL); 451 if (!p) 452 return -ENOMEM; 453 454 pkt = p; 455 cmd = p + APR_HDR_SIZE; 456 mregions = p + APR_HDR_SIZE + sizeof(*cmd); 457 458 pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD; 459 pkt->hdr.src_port = 0; 460 pkt->hdr.dest_port = 0; 461 pkt->hdr.pkt_size = pkt_size; 462 pkt->hdr.token = ((ac->session << 8) | dir); 463 pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS; 464 465 cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL; 466 cmd->num_regions = num_regions; 467 cmd->property_flag = 0x00; 468 469 spin_lock_irqsave(&ac->lock, flags); 470 port = &ac->port[dir]; 471 472 for (i = 0; i < num_regions; i++) { 473 ab = &port->buf[i]; 474 mregions->shm_addr_lsw = lower_32_bits(ab->phys); 475 mregions->shm_addr_msw = upper_32_bits(ab->phys); 476 mregions->mem_size_bytes = buf_sz; 477 ++mregions; 478 } 479 spin_unlock_irqrestore(&ac->lock, flags); 480 481 return q6asm_apr_send_session_pkt(a, ac, pkt, ASM_CMDRSP_SHARED_MEM_MAP_REGIONS); 482} 483 484/** 485 * q6asm_map_memory_regions() - map memory regions in the dsp. 486 * 487 * @dir: direction of audio stream 488 * @ac: audio client instanace 489 * @phys: physical address that needs mapping. 490 * @period_sz: audio period size 491 * @periods: number of periods 492 * 493 * Return: Will be an negative value on failure or zero on success 494 */ 495int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, 496 phys_addr_t phys, 497 size_t period_sz, unsigned int periods) 498{ 499 struct audio_buffer *buf; 500 unsigned long flags; 501 int cnt; 502 int rc; 503 504 spin_lock_irqsave(&ac->lock, flags); 505 if (ac->port[dir].buf) { 506 dev_err(ac->dev, "Buffer already allocated\n"); 507 spin_unlock_irqrestore(&ac->lock, flags); 508 return 0; 509 } 510 511 buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC); 512 if (!buf) { 513 spin_unlock_irqrestore(&ac->lock, flags); 514 return -ENOMEM; 515 } 516 517 518 ac->port[dir].buf = buf; 519 520 buf[0].phys = phys; 521 buf[0].size = period_sz; 522 523 for (cnt = 1; cnt < periods; cnt++) { 524 if (period_sz > 0) { 525 buf[cnt].phys = buf[0].phys + (cnt * period_sz); 526 buf[cnt].size = period_sz; 527 } 528 } 529 ac->port[dir].num_periods = periods; 530 531 spin_unlock_irqrestore(&ac->lock, flags); 532 533 rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1); 534 if (rc < 0) { 535 dev_err(ac->dev, "Memory_map_regions failed\n"); 536 q6asm_audio_client_free_buf(ac, &ac->port[dir]); 537 } 538 539 return rc; 540} 541EXPORT_SYMBOL_GPL(q6asm_map_memory_regions); 542 543static void q6asm_audio_client_release(struct kref *ref) 544{ 545 struct audio_client *ac; 546 struct q6asm *a; 547 unsigned long flags; 548 549 ac = container_of(ref, struct audio_client, refcount); 550 a = ac->q6asm; 551 552 spin_lock_irqsave(&a->slock, flags); 553 a->session[ac->session] = NULL; 554 spin_unlock_irqrestore(&a->slock, flags); 555 556 kfree(ac); 557} 558 559/** 560 * q6asm_audio_client_free() - Freee allocated audio client 561 * 562 * @ac: audio client to free 563 */ 564void q6asm_audio_client_free(struct audio_client *ac) 565{ 566 kref_put(&ac->refcount, q6asm_audio_client_release); 567} 568EXPORT_SYMBOL_GPL(q6asm_audio_client_free); 569 570static struct audio_client *q6asm_get_audio_client(struct q6asm *a, 571 int session_id) 572{ 573 struct audio_client *ac = NULL; 574 575 guard(spinlock_irqsave)(&a->slock); 576 if ((session_id <= 0) || (session_id > MAX_SESSIONS)) { 577 dev_err(a->dev, "invalid session: %d\n", session_id); 578 goto err; 579 } 580 581 /* check for valid session */ 582 if (!a->session[session_id]) 583 goto err; 584 else if (a->session[session_id]->session != session_id) 585 goto err; 586 587 ac = a->session[session_id]; 588 kref_get(&ac->refcount); 589err: 590 return ac; 591} 592 593int q6asm_get_hw_pointer(struct audio_client *ac, unsigned int dir) 594{ 595 struct audio_port_data *data = &ac->port[dir]; 596 597 return (int)atomic_read(&data->hw_ptr); 598} 599EXPORT_SYMBOL_GPL(q6asm_get_hw_pointer); 600 601static int32_t q6asm_stream_callback(struct apr_device *adev, 602 struct apr_resp_pkt *data, 603 int session_id) 604{ 605 struct q6asm *q6asm = dev_get_drvdata(&adev->dev); 606 struct aprv2_ibasic_rsp_result_t *result; 607 struct apr_hdr *hdr = &data->hdr; 608 struct audio_port_data *port; 609 struct audio_client *ac; 610 uint32_t client_event = 0; 611 int ret = 0; 612 613 ac = q6asm_get_audio_client(q6asm, session_id); 614 if (!ac)/* Audio client might already be freed by now */ 615 return 0; 616 617 result = data->payload; 618 619 switch (hdr->opcode) { 620 case APR_BASIC_RSP_RESULT: 621 switch (result->opcode) { 622 case ASM_SESSION_CMD_PAUSE: 623 client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE; 624 break; 625 case ASM_SESSION_CMD_SUSPEND: 626 client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE; 627 break; 628 case ASM_STREAM_CMD_FLUSH: 629 client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE; 630 break; 631 case ASM_SESSION_CMD_RUN_V2: 632 client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE; 633 break; 634 case ASM_STREAM_CMD_CLOSE: 635 client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE; 636 break; 637 case ASM_STREAM_CMD_FLUSH_READBUFS: 638 client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE; 639 break; 640 case ASM_STREAM_CMD_OPEN_WRITE_V3: 641 case ASM_STREAM_CMD_OPEN_READ_V3: 642 case ASM_STREAM_CMD_OPEN_READWRITE_V2: 643 case ASM_STREAM_CMD_SET_ENCDEC_PARAM: 644 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: 645 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: 646 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: 647 if (result->status != 0) { 648 dev_err(ac->dev, 649 "cmd = 0x%x returned error = 0x%x\n", 650 result->opcode, result->status); 651 ac->result = *result; 652 wake_up(&ac->cmd_wait); 653 ret = 0; 654 goto done; 655 } 656 break; 657 case ASM_DATA_CMD_EOS: 658 case ASM_DATA_CMD_READ_V2: 659 case ASM_DATA_CMD_WRITE_V2: 660 /* response as result of close stream */ 661 goto done; 662 default: 663 dev_err(ac->dev, "command[0x%x] not expecting rsp\n", 664 result->opcode); 665 break; 666 } 667 668 ac->result = *result; 669 wake_up(&ac->cmd_wait); 670 671 if (ac->cb) 672 ac->cb(client_event, hdr->token, 673 data->payload, ac->priv); 674 675 ret = 0; 676 goto done; 677 678 case ASM_DATA_EVENT_WRITE_DONE_V2: 679 client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE; 680 if (ac->io_mode & ASM_SYNC_IO_MODE) { 681 phys_addr_t phys; 682 int token = hdr->token & ASM_WRITE_TOKEN_MASK; 683 684 guard(spinlock_irqsave)(&ac->lock); 685 686 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 687 688 if (!port->buf) { 689 ret = 0; 690 goto done; 691 } 692 693 phys = port->buf[token].phys; 694 695 if (lower_32_bits(phys) != result->opcode || 696 upper_32_bits(phys) != result->status) { 697 dev_err(ac->dev, "Expected addr %pa\n", 698 &port->buf[token].phys); 699 ret = -EINVAL; 700 goto done; 701 } 702 atomic_set(&port->hw_ptr, token + 1); 703 } 704 break; 705 case ASM_DATA_EVENT_READ_DONE_V2: 706 client_event = ASM_CLIENT_EVENT_DATA_READ_DONE; 707 if (ac->io_mode & ASM_SYNC_IO_MODE) { 708 struct asm_data_cmd_read_v2_done *done = data->payload; 709 phys_addr_t phys; 710 711 guard(spinlock_irqsave)(&ac->lock); 712 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 713 if (!port->buf) { 714 ret = 0; 715 goto done; 716 } 717 718 phys = port->buf[hdr->token].phys; 719 atomic_set(&port->hw_ptr, hdr->token + 1); 720 721 if (upper_32_bits(phys) != done->buf_addr_msw || 722 lower_32_bits(phys) != done->buf_addr_lsw) { 723 dev_err(ac->dev, "Expected addr %pa %08x-%08x\n", 724 &port->buf[hdr->token].phys, 725 done->buf_addr_lsw, 726 done->buf_addr_msw); 727 ret = -EINVAL; 728 goto done; 729 } 730 } 731 732 break; 733 case ASM_DATA_EVENT_RENDERED_EOS: 734 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE; 735 break; 736 } 737 738 if (ac->cb) 739 ac->cb(client_event, hdr->token, data->payload, ac->priv); 740 741done: 742 kref_put(&ac->refcount, q6asm_audio_client_release); 743 return ret; 744} 745 746static int q6asm_srvc_callback(struct apr_device *adev, 747 struct apr_resp_pkt *data) 748{ 749 struct q6asm *q6asm = dev_get_drvdata(&adev->dev); 750 struct aprv2_ibasic_rsp_result_t *result; 751 struct audio_port_data *port; 752 struct audio_client *ac = NULL; 753 struct apr_hdr *hdr = &data->hdr; 754 struct q6asm *a; 755 uint32_t sid = 0; 756 uint32_t dir = 0; 757 int session_id; 758 759 session_id = (hdr->dest_port >> 8) & 0xFF; 760 if (session_id) 761 return q6asm_stream_callback(adev, data, session_id); 762 763 sid = (hdr->token >> 8) & 0x0F; 764 ac = q6asm_get_audio_client(q6asm, sid); 765 if (!ac) { 766 dev_err(&adev->dev, "Audio Client not active\n"); 767 return 0; 768 } 769 770 a = dev_get_drvdata(ac->dev->parent); 771 dir = (hdr->token & 0x0F); 772 port = &ac->port[dir]; 773 result = data->payload; 774 775 switch (hdr->opcode) { 776 case APR_BASIC_RSP_RESULT: 777 switch (result->opcode) { 778 case ASM_CMD_SHARED_MEM_MAP_REGIONS: 779 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: 780 ac->result = *result; 781 wake_up(&a->mem_wait); 782 break; 783 default: 784 dev_err(&adev->dev, "command[0x%x] not expecting rsp\n", 785 result->opcode); 786 break; 787 } 788 goto done; 789 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS: 790 ac->result.status = 0; 791 ac->result.opcode = hdr->opcode; 792 port->mem_map_handle = result->opcode; 793 wake_up(&a->mem_wait); 794 break; 795 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: 796 ac->result.opcode = hdr->opcode; 797 ac->result.status = 0; 798 port->mem_map_handle = 0; 799 wake_up(&a->mem_wait); 800 break; 801 default: 802 dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n", 803 result->opcode, result->status); 804 break; 805 } 806 807 if (ac->cb) 808 ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv); 809 810done: 811 kref_put(&ac->refcount, q6asm_audio_client_release); 812 813 return 0; 814} 815 816/** 817 * q6asm_get_session_id() - get session id for audio client 818 * 819 * @c: audio client pointer 820 * 821 * Return: Will be an session id of the audio client. 822 */ 823int q6asm_get_session_id(struct audio_client *c) 824{ 825 return c->session; 826} 827EXPORT_SYMBOL_GPL(q6asm_get_session_id); 828 829/** 830 * q6asm_audio_client_alloc() - Allocate a new audio client 831 * 832 * @dev: Pointer to asm child device. 833 * @cb: event callback. 834 * @priv: private data associated with this client. 835 * @session_id: session id 836 * @perf_mode: performace mode for this client 837 * 838 * Return: Will be an error pointer on error or a valid audio client 839 * on success. 840 */ 841struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, 842 void *priv, int session_id, 843 int perf_mode) 844{ 845 struct q6asm *a = dev_get_drvdata(dev->parent); 846 struct audio_client *ac; 847 unsigned long flags; 848 849 ac = q6asm_get_audio_client(a, session_id + 1); 850 if (ac) { 851 dev_err(dev, "Audio Client already active\n"); 852 return ac; 853 } 854 855 ac = kzalloc(sizeof(*ac), GFP_KERNEL); 856 if (!ac) 857 return ERR_PTR(-ENOMEM); 858 859 spin_lock_irqsave(&a->slock, flags); 860 a->session[session_id + 1] = ac; 861 spin_unlock_irqrestore(&a->slock, flags); 862 ac->session = session_id + 1; 863 ac->cb = cb; 864 ac->dev = dev; 865 ac->q6asm = a; 866 ac->priv = priv; 867 ac->io_mode = ASM_SYNC_IO_MODE; 868 ac->perf_mode = perf_mode; 869 ac->adev = a->adev; 870 kref_init(&ac->refcount); 871 872 init_waitqueue_head(&ac->cmd_wait); 873 mutex_init(&ac->cmd_lock); 874 spin_lock_init(&ac->lock); 875 876 return ac; 877} 878EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); 879 880static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt) 881{ 882 struct apr_hdr *hdr = &pkt->hdr; 883 int rc; 884 885 mutex_lock(&ac->cmd_lock); 886 ac->result.opcode = 0; 887 ac->result.status = 0; 888 889 rc = apr_send_pkt(ac->adev, pkt); 890 if (rc < 0) 891 goto err; 892 893 rc = wait_event_timeout(ac->cmd_wait, 894 (ac->result.opcode == hdr->opcode), 5 * HZ); 895 if (!rc) { 896 dev_err(ac->dev, "CMD %x timeout\n", hdr->opcode); 897 rc = -ETIMEDOUT; 898 goto err; 899 } 900 901 if (ac->result.status > 0) { 902 dev_err(ac->dev, "DSP returned error[%x]\n", 903 ac->result.status); 904 rc = -EINVAL; 905 } else { 906 rc = 0; 907 } 908 909 910err: 911 mutex_unlock(&ac->cmd_lock); 912 return rc; 913} 914 915/** 916 * q6asm_open_write() - Open audio client for writing 917 * @ac: audio client pointer 918 * @stream_id: stream id of q6asm session 919 * @format: audio sample format 920 * @codec_profile: compressed format profile 921 * @bits_per_sample: bits per sample 922 * @is_gapless: flag to indicate if this is a gapless stream 923 * 924 * Return: Will be an negative value on error or zero on success 925 */ 926int q6asm_open_write(struct audio_client *ac, uint32_t stream_id, 927 uint32_t format, u32 codec_profile, 928 uint16_t bits_per_sample, bool is_gapless) 929{ 930 struct asm_stream_cmd_open_write_v3 *open; 931 struct apr_pkt *pkt; 932 int rc, pkt_size = APR_HDR_SIZE + sizeof(*open); 933 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 934 if (!p) 935 return -ENOMEM; 936 937 pkt = p; 938 open = p + APR_HDR_SIZE; 939 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 940 941 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3; 942 open->mode_flags = 0x00; 943 open->mode_flags |= ASM_LEGACY_STREAM_SESSION; 944 if (is_gapless) 945 open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG); 946 947 /* source endpoint : matrix */ 948 open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX; 949 open->bits_per_sample = bits_per_sample; 950 open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; 951 952 switch (format) { 953 case SND_AUDIOCODEC_MP3: 954 open->dec_fmt_id = ASM_MEDIA_FMT_MP3; 955 break; 956 case FORMAT_LINEAR_PCM: 957 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; 958 break; 959 case SND_AUDIOCODEC_FLAC: 960 open->dec_fmt_id = ASM_MEDIA_FMT_FLAC; 961 break; 962 case SND_AUDIOCODEC_WMA: 963 switch (codec_profile) { 964 case SND_AUDIOPROFILE_WMA9: 965 open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9; 966 break; 967 case SND_AUDIOPROFILE_WMA10: 968 case SND_AUDIOPROFILE_WMA9_PRO: 969 case SND_AUDIOPROFILE_WMA9_LOSSLESS: 970 case SND_AUDIOPROFILE_WMA10_LOSSLESS: 971 open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10; 972 break; 973 default: 974 dev_err(ac->dev, "Invalid codec profile 0x%x\n", 975 codec_profile); 976 rc = -EINVAL; 977 goto err; 978 } 979 break; 980 case SND_AUDIOCODEC_ALAC: 981 open->dec_fmt_id = ASM_MEDIA_FMT_ALAC; 982 break; 983 case SND_AUDIOCODEC_APE: 984 open->dec_fmt_id = ASM_MEDIA_FMT_APE; 985 break; 986 default: 987 dev_err(ac->dev, "Invalid format 0x%x\n", format); 988 rc = -EINVAL; 989 goto err; 990 } 991 992 rc = q6asm_ac_send_cmd_sync(ac, pkt); 993 if (rc < 0) 994 goto err; 995 996 ac->io_mode |= ASM_TUN_WRITE_IO_MODE; 997 998err: 999 return rc; 1000} 1001EXPORT_SYMBOL_GPL(q6asm_open_write); 1002 1003static int __q6asm_run(struct audio_client *ac, uint32_t stream_id, 1004 uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts, 1005 bool wait) 1006{ 1007 struct asm_session_cmd_run_v2 *run; 1008 struct apr_pkt *pkt; 1009 int rc, pkt_size = APR_HDR_SIZE + sizeof(*run); 1010 void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC); 1011 if (!p) 1012 return -ENOMEM; 1013 1014 pkt = p; 1015 run = p + APR_HDR_SIZE; 1016 1017 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1018 1019 pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2; 1020 run->flags = flags; 1021 run->time_lsw = lsw_ts; 1022 run->time_msw = msw_ts; 1023 if (wait) { 1024 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1025 } else { 1026 rc = apr_send_pkt(ac->adev, pkt); 1027 if (rc == pkt_size) 1028 rc = 0; 1029 } 1030 1031 return rc; 1032} 1033 1034/** 1035 * q6asm_run() - start the audio client 1036 * 1037 * @ac: audio client pointer 1038 * @stream_id: stream id of q6asm session 1039 * @flags: flags associated with write 1040 * @msw_ts: timestamp msw 1041 * @lsw_ts: timestamp lsw 1042 * 1043 * Return: Will be an negative value on error or zero on success 1044 */ 1045int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags, 1046 uint32_t msw_ts, uint32_t lsw_ts) 1047{ 1048 return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true); 1049} 1050EXPORT_SYMBOL_GPL(q6asm_run); 1051 1052/** 1053 * q6asm_run_nowait() - start the audio client withou blocking 1054 * 1055 * @ac: audio client pointer 1056 * @stream_id: stream id 1057 * @flags: flags associated with write 1058 * @msw_ts: timestamp msw 1059 * @lsw_ts: timestamp lsw 1060 * 1061 * Return: Will be an negative value on error or zero on success 1062 */ 1063int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id, 1064 uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts) 1065{ 1066 return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false); 1067} 1068EXPORT_SYMBOL_GPL(q6asm_run_nowait); 1069 1070/** 1071 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration 1072 * 1073 * @ac: audio client pointer 1074 * @stream_id: stream id 1075 * @rate: audio sample rate 1076 * @channels: number of audio channels. 1077 * @channel_map: channel map pointer 1078 * @bits_per_sample: bits per sample 1079 * 1080 * Return: Will be an negative value on error or zero on success 1081 */ 1082int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, 1083 uint32_t stream_id, 1084 uint32_t rate, uint32_t channels, 1085 u8 channel_map[PCM_MAX_NUM_CHANNEL], 1086 uint16_t bits_per_sample) 1087{ 1088 struct asm_multi_channel_pcm_fmt_blk_v2 *fmt; 1089 struct apr_pkt *pkt; 1090 u8 *channel_mapping; 1091 int pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1092 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1093 if (!p) 1094 return -ENOMEM; 1095 1096 pkt = p; 1097 fmt = p + APR_HDR_SIZE; 1098 1099 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1100 1101 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1102 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1103 fmt->num_channels = channels; 1104 fmt->bits_per_sample = bits_per_sample; 1105 fmt->sample_rate = rate; 1106 fmt->is_signed = 1; 1107 1108 channel_mapping = fmt->channel_mapping; 1109 1110 if (channel_map) { 1111 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL); 1112 } else { 1113 if (q6dsp_map_channels(channel_mapping, channels)) { 1114 dev_err(ac->dev, " map channels failed %d\n", channels); 1115 return -EINVAL; 1116 } 1117 } 1118 1119 return q6asm_ac_send_cmd_sync(ac, pkt); 1120} 1121EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); 1122 1123int q6asm_stream_media_format_block_flac(struct audio_client *ac, 1124 uint32_t stream_id, 1125 struct q6asm_flac_cfg *cfg) 1126{ 1127 struct asm_flac_fmt_blk_v2 *fmt; 1128 struct apr_pkt *pkt; 1129 int pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1130 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1131 if (!p) 1132 return -ENOMEM; 1133 1134 pkt = p; 1135 fmt = p + APR_HDR_SIZE; 1136 1137 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1138 1139 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1140 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1141 fmt->is_stream_info_present = cfg->stream_info_present; 1142 fmt->num_channels = cfg->ch_cfg; 1143 fmt->min_blk_size = cfg->min_blk_size; 1144 fmt->max_blk_size = cfg->max_blk_size; 1145 fmt->sample_rate = cfg->sample_rate; 1146 fmt->min_frame_size = cfg->min_frame_size; 1147 fmt->max_frame_size = cfg->max_frame_size; 1148 fmt->sample_size = cfg->sample_size; 1149 1150 return q6asm_ac_send_cmd_sync(ac, pkt); 1151} 1152EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac); 1153 1154int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, 1155 uint32_t stream_id, 1156 struct q6asm_wma_cfg *cfg) 1157{ 1158 struct asm_wmastdv9_fmt_blk_v2 *fmt; 1159 struct apr_pkt *pkt; 1160 int pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1161 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1162 if (!p) 1163 return -ENOMEM; 1164 1165 pkt = p; 1166 fmt = p + APR_HDR_SIZE; 1167 1168 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1169 1170 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1171 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1172 fmt->fmtag = cfg->fmtag; 1173 fmt->num_channels = cfg->num_channels; 1174 fmt->sample_rate = cfg->sample_rate; 1175 fmt->bytes_per_sec = cfg->bytes_per_sec; 1176 fmt->blk_align = cfg->block_align; 1177 fmt->bits_per_sample = cfg->bits_per_sample; 1178 fmt->channel_mask = cfg->channel_mask; 1179 fmt->enc_options = cfg->enc_options; 1180 fmt->reserved = 0; 1181 1182 return q6asm_ac_send_cmd_sync(ac, pkt); 1183} 1184EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9); 1185 1186int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, 1187 uint32_t stream_id, 1188 struct q6asm_wma_cfg *cfg) 1189{ 1190 struct asm_wmaprov10_fmt_blk_v2 *fmt; 1191 struct apr_pkt *pkt; 1192 int pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1193 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1194 if (!p) 1195 return -ENOMEM; 1196 1197 pkt = p; 1198 fmt = p + APR_HDR_SIZE; 1199 1200 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1201 1202 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1203 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1204 fmt->fmtag = cfg->fmtag; 1205 fmt->num_channels = cfg->num_channels; 1206 fmt->sample_rate = cfg->sample_rate; 1207 fmt->bytes_per_sec = cfg->bytes_per_sec; 1208 fmt->blk_align = cfg->block_align; 1209 fmt->bits_per_sample = cfg->bits_per_sample; 1210 fmt->channel_mask = cfg->channel_mask; 1211 fmt->enc_options = cfg->enc_options; 1212 fmt->advanced_enc_options1 = cfg->adv_enc_options; 1213 fmt->advanced_enc_options2 = cfg->adv_enc_options2; 1214 1215 return q6asm_ac_send_cmd_sync(ac, pkt); 1216} 1217EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10); 1218 1219int q6asm_stream_media_format_block_alac(struct audio_client *ac, 1220 uint32_t stream_id, 1221 struct q6asm_alac_cfg *cfg) 1222{ 1223 struct asm_alac_fmt_blk_v2 *fmt; 1224 struct apr_pkt *pkt; 1225 int pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1226 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1227 if (!p) 1228 return -ENOMEM; 1229 1230 pkt = p; 1231 fmt = p + APR_HDR_SIZE; 1232 1233 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1234 1235 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1236 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1237 1238 fmt->frame_length = cfg->frame_length; 1239 fmt->compatible_version = cfg->compatible_version; 1240 fmt->bit_depth = cfg->bit_depth; 1241 fmt->num_channels = cfg->num_channels; 1242 fmt->max_run = cfg->max_run; 1243 fmt->max_frame_bytes = cfg->max_frame_bytes; 1244 fmt->avg_bit_rate = cfg->avg_bit_rate; 1245 fmt->sample_rate = cfg->sample_rate; 1246 fmt->channel_layout_tag = cfg->channel_layout_tag; 1247 fmt->pb = cfg->pb; 1248 fmt->mb = cfg->mb; 1249 fmt->kb = cfg->kb; 1250 1251 return q6asm_ac_send_cmd_sync(ac, pkt); 1252} 1253EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac); 1254 1255int q6asm_stream_media_format_block_ape(struct audio_client *ac, 1256 uint32_t stream_id, 1257 struct q6asm_ape_cfg *cfg) 1258{ 1259 struct asm_ape_fmt_blk_v2 *fmt; 1260 struct apr_pkt *pkt; 1261 int pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1262 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1263 if (!p) 1264 return -ENOMEM; 1265 1266 pkt = p; 1267 fmt = p + APR_HDR_SIZE; 1268 1269 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1270 1271 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1272 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1273 1274 fmt->compatible_version = cfg->compatible_version; 1275 fmt->compression_level = cfg->compression_level; 1276 fmt->format_flags = cfg->format_flags; 1277 fmt->blocks_per_frame = cfg->blocks_per_frame; 1278 fmt->final_frame_blocks = cfg->final_frame_blocks; 1279 fmt->total_frames = cfg->total_frames; 1280 fmt->bits_per_sample = cfg->bits_per_sample; 1281 fmt->num_channels = cfg->num_channels; 1282 fmt->sample_rate = cfg->sample_rate; 1283 fmt->seek_table_present = cfg->seek_table_present; 1284 1285 return q6asm_ac_send_cmd_sync(ac, pkt); 1286} 1287EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape); 1288 1289static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id, 1290 uint32_t cmd, 1291 uint32_t num_samples) 1292{ 1293 uint32_t *samples; 1294 struct apr_pkt *pkt; 1295 int rc, pkt_size = APR_HDR_SIZE + sizeof(uint32_t); 1296 void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC); 1297 if (!p) 1298 return -ENOMEM; 1299 1300 pkt = p; 1301 samples = p + APR_HDR_SIZE; 1302 1303 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1304 1305 pkt->hdr.opcode = cmd; 1306 *samples = num_samples; 1307 rc = apr_send_pkt(ac->adev, pkt); 1308 if (rc == pkt_size) 1309 rc = 0; 1310 1311 return rc; 1312} 1313 1314int q6asm_stream_remove_initial_silence(struct audio_client *ac, 1315 uint32_t stream_id, 1316 uint32_t initial_samples) 1317{ 1318 return q6asm_stream_remove_silence(ac, stream_id, 1319 ASM_DATA_CMD_REMOVE_INITIAL_SILENCE, 1320 initial_samples); 1321} 1322EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence); 1323 1324int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id, 1325 uint32_t trailing_samples) 1326{ 1327 return q6asm_stream_remove_silence(ac, stream_id, 1328 ASM_DATA_CMD_REMOVE_TRAILING_SILENCE, 1329 trailing_samples); 1330} 1331EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence); 1332 1333/** 1334 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture 1335 * 1336 * @ac: audio client pointer 1337 * @stream_id: stream id 1338 * @rate: audio sample rate 1339 * @channels: number of audio channels. 1340 * @bits_per_sample: bits per sample 1341 * 1342 * Return: Will be an negative value on error or zero on success 1343 */ 1344int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, 1345 uint32_t stream_id, uint32_t rate, 1346 uint32_t channels, 1347 uint16_t bits_per_sample) 1348{ 1349 struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg; 1350 struct apr_pkt *pkt; 1351 u8 *channel_mapping; 1352 u32 frames_per_buf = 0; 1353 int pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg); 1354 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1355 if (!p) 1356 return -ENOMEM; 1357 1358 pkt = p; 1359 enc_cfg = p + APR_HDR_SIZE; 1360 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1361 1362 pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; 1363 enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; 1364 enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec); 1365 enc_cfg->encblk.frames_per_buf = frames_per_buf; 1366 enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size - 1367 sizeof(struct asm_enc_cfg_blk_param_v2); 1368 1369 enc_cfg->num_channels = channels; 1370 enc_cfg->bits_per_sample = bits_per_sample; 1371 enc_cfg->sample_rate = rate; 1372 enc_cfg->is_signed = 1; 1373 channel_mapping = enc_cfg->channel_mapping; 1374 1375 if (q6dsp_map_channels(channel_mapping, channels)) 1376 return -EINVAL; 1377 1378 return q6asm_ac_send_cmd_sync(ac, pkt); 1379} 1380EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); 1381 1382 1383/** 1384 * q6asm_read() - read data of period size from audio client 1385 * 1386 * @ac: audio client pointer 1387 * @stream_id: stream id 1388 * 1389 * Return: Will be an negative value on error or zero on success 1390 */ 1391int q6asm_read(struct audio_client *ac, uint32_t stream_id) 1392{ 1393 struct asm_data_cmd_read_v2 *read; 1394 struct audio_port_data *port; 1395 struct audio_buffer *ab; 1396 struct apr_pkt *pkt; 1397 unsigned long flags; 1398 int pkt_size = APR_HDR_SIZE + sizeof(*read); 1399 int rc = 0; 1400 void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC); 1401 if (!p) 1402 return -ENOMEM; 1403 1404 pkt = p; 1405 read = p + APR_HDR_SIZE; 1406 1407 spin_lock_irqsave(&ac->lock, flags); 1408 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 1409 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id); 1410 ab = &port->buf[port->dsp_buf]; 1411 pkt->hdr.opcode = ASM_DATA_CMD_READ_V2; 1412 read->buf_addr_lsw = lower_32_bits(ab->phys); 1413 read->buf_addr_msw = upper_32_bits(ab->phys); 1414 read->mem_map_handle = port->mem_map_handle; 1415 1416 read->buf_size = ab->size; 1417 read->seq_id = port->dsp_buf; 1418 pkt->hdr.token = port->dsp_buf; 1419 1420 port->dsp_buf++; 1421 1422 if (port->dsp_buf >= port->num_periods) 1423 port->dsp_buf = 0; 1424 1425 spin_unlock_irqrestore(&ac->lock, flags); 1426 rc = apr_send_pkt(ac->adev, pkt); 1427 if (rc == pkt_size) 1428 rc = 0; 1429 else 1430 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc); 1431 1432 return rc; 1433} 1434EXPORT_SYMBOL_GPL(q6asm_read); 1435 1436static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id, 1437 uint32_t format, uint16_t bits_per_sample) 1438{ 1439 struct asm_stream_cmd_open_read_v3 *open; 1440 struct apr_pkt *pkt; 1441 int pkt_size = APR_HDR_SIZE + sizeof(*open); 1442 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 1443 if (!p) 1444 return -ENOMEM; 1445 1446 pkt = p; 1447 open = p + APR_HDR_SIZE; 1448 1449 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1450 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3; 1451 /* Stream prio : High, provide meta info with encoded frames */ 1452 open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX; 1453 1454 open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE; 1455 open->bits_per_sample = bits_per_sample; 1456 open->mode_flags = 0x0; 1457 1458 open->mode_flags |= ASM_LEGACY_STREAM_SESSION << 1459 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ; 1460 1461 switch (format) { 1462 case FORMAT_LINEAR_PCM: 1463 open->mode_flags |= 0x00; 1464 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; 1465 break; 1466 default: 1467 pr_err("Invalid format[%d]\n", format); 1468 } 1469 1470 return q6asm_ac_send_cmd_sync(ac, pkt); 1471} 1472 1473/** 1474 * q6asm_open_read() - Open audio client for reading 1475 * 1476 * @ac: audio client pointer 1477 * @stream_id: stream id 1478 * @format: audio sample format 1479 * @bits_per_sample: bits per sample 1480 * 1481 * Return: Will be an negative value on error or zero on success 1482 */ 1483int q6asm_open_read(struct audio_client *ac, uint32_t stream_id, 1484 uint32_t format, uint16_t bits_per_sample) 1485{ 1486 return __q6asm_open_read(ac, stream_id, format, bits_per_sample); 1487} 1488EXPORT_SYMBOL_GPL(q6asm_open_read); 1489 1490/** 1491 * q6asm_write_async() - non blocking write 1492 * 1493 * @ac: audio client pointer 1494 * @stream_id: stream id 1495 * @len: length in bytes 1496 * @msw_ts: timestamp msw 1497 * @lsw_ts: timestamp lsw 1498 * @wflags: flags associated with write 1499 * 1500 * Return: Will be an negative value on error or zero on success 1501 */ 1502int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len, 1503 uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags) 1504{ 1505 struct asm_data_cmd_write_v2 *write; 1506 struct audio_port_data *port; 1507 struct audio_buffer *ab; 1508 unsigned long flags; 1509 struct apr_pkt *pkt; 1510 int pkt_size = APR_HDR_SIZE + sizeof(*write); 1511 int rc = 0; 1512 void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC); 1513 if (!p) 1514 return -ENOMEM; 1515 1516 pkt = p; 1517 write = p + APR_HDR_SIZE; 1518 1519 spin_lock_irqsave(&ac->lock, flags); 1520 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 1521 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id); 1522 1523 ab = &port->buf[port->dsp_buf]; 1524 pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT); 1525 pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2; 1526 write->buf_addr_lsw = lower_32_bits(ab->phys); 1527 write->buf_addr_msw = upper_32_bits(ab->phys); 1528 write->buf_size = len; 1529 write->seq_id = port->dsp_buf; 1530 write->timestamp_lsw = lsw_ts; 1531 write->timestamp_msw = msw_ts; 1532 write->mem_map_handle = 1533 ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle; 1534 1535 write->flags = wflags; 1536 1537 port->dsp_buf++; 1538 1539 if (port->dsp_buf >= port->num_periods) 1540 port->dsp_buf = 0; 1541 1542 spin_unlock_irqrestore(&ac->lock, flags); 1543 rc = apr_send_pkt(ac->adev, pkt); 1544 if (rc == pkt_size) 1545 rc = 0; 1546 1547 return rc; 1548} 1549EXPORT_SYMBOL_GPL(q6asm_write_async); 1550 1551static void q6asm_reset_buf_state(struct audio_client *ac) 1552{ 1553 struct audio_port_data *port; 1554 1555 guard(spinlock_irqsave)(&ac->lock); 1556 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 1557 port->dsp_buf = 0; 1558 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 1559 port->dsp_buf = 0; 1560} 1561 1562static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd, 1563 bool wait) 1564{ 1565 struct apr_pkt pkt; 1566 int rc; 1567 1568 q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id); 1569 1570 switch (cmd) { 1571 case CMD_PAUSE: 1572 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE; 1573 break; 1574 case CMD_SUSPEND: 1575 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND; 1576 break; 1577 case CMD_FLUSH: 1578 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH; 1579 break; 1580 case CMD_OUT_FLUSH: 1581 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS; 1582 break; 1583 case CMD_EOS: 1584 pkt.hdr.opcode = ASM_DATA_CMD_EOS; 1585 break; 1586 case CMD_CLOSE: 1587 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE; 1588 break; 1589 default: 1590 return -EINVAL; 1591 } 1592 1593 if (wait) 1594 rc = q6asm_ac_send_cmd_sync(ac, &pkt); 1595 else 1596 return apr_send_pkt(ac->adev, &pkt); 1597 1598 if (rc < 0) 1599 return rc; 1600 1601 if (cmd == CMD_FLUSH) 1602 q6asm_reset_buf_state(ac); 1603 1604 return 0; 1605} 1606 1607/** 1608 * q6asm_cmd() - run cmd on audio client 1609 * 1610 * @ac: audio client pointer 1611 * @stream_id: stream id 1612 * @cmd: command to run on audio client. 1613 * 1614 * Return: Will be an negative value on error or zero on success 1615 */ 1616int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd) 1617{ 1618 return __q6asm_cmd(ac, stream_id, cmd, true); 1619} 1620EXPORT_SYMBOL_GPL(q6asm_cmd); 1621 1622/** 1623 * q6asm_cmd_nowait() - non blocking, run cmd on audio client 1624 * 1625 * @ac: audio client pointer 1626 * @stream_id: stream id 1627 * @cmd: command to run on audio client. 1628 * 1629 * Return: Will be an negative value on error or zero on success 1630 */ 1631int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd) 1632{ 1633 return __q6asm_cmd(ac, stream_id, cmd, false); 1634} 1635EXPORT_SYMBOL_GPL(q6asm_cmd_nowait); 1636 1637static int q6asm_probe(struct apr_device *adev) 1638{ 1639 struct device *dev = &adev->dev; 1640 struct q6asm *q6asm; 1641 1642 q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL); 1643 if (!q6asm) 1644 return -ENOMEM; 1645 1646 q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo); 1647 1648 q6asm->dev = dev; 1649 q6asm->adev = adev; 1650 init_waitqueue_head(&q6asm->mem_wait); 1651 spin_lock_init(&q6asm->slock); 1652 dev_set_drvdata(dev, q6asm); 1653 1654 return devm_of_platform_populate(dev); 1655} 1656 1657#ifdef CONFIG_OF 1658static const struct of_device_id q6asm_device_id[] = { 1659 { .compatible = "qcom,q6asm" }, 1660 {}, 1661}; 1662MODULE_DEVICE_TABLE(of, q6asm_device_id); 1663#endif 1664 1665static struct apr_driver qcom_q6asm_driver = { 1666 .probe = q6asm_probe, 1667 .callback = q6asm_srvc_callback, 1668 .driver = { 1669 .name = "qcom-q6asm", 1670 .of_match_table = of_match_ptr(q6asm_device_id), 1671 }, 1672}; 1673 1674module_apr_driver(qcom_q6asm_driver); 1675MODULE_DESCRIPTION("Q6 Audio Stream Manager driver"); 1676MODULE_LICENSE("GPL v2");
~/
Read-only file preview.