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