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