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 70 struct avs_cmd_shared_mem_map_regions { 71 u16 mem_pool_id; 72 u16 num_regions; 73 u32 property_flag; 74 } __packed; 75 76 struct avs_shared_map_region_payload { 77 u32 shm_addr_lsw; 78 u32 shm_addr_msw; 79 u32 mem_size_bytes; 80 } __packed; 81 82 struct avs_cmd_shared_mem_unmap_regions { 83 u32 mem_map_handle; 84 } __packed; 85 86 struct asm_data_cmd_media_fmt_update_v2 { 87 u32 fmt_blk_size; 88 } __packed; 89 90 struct 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 100 struct 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 114 struct 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 127 struct 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 141 struct 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 157 struct 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 171 struct asm_stream_cmd_set_encdec_param { 172 u32 param_id; 173 u32 param_size; 174 } __packed; 175 176 struct asm_enc_cfg_blk_param_v2 { 177 u32 frames_per_buf; 178 u32 enc_cfg_blk_size; 179 } __packed; 180 181 struct 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 192 struct 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 200 struct asm_data_cmd_read_v2_done { 201 u32 status; 202 u32 buf_addr_lsw; 203 u32 buf_addr_msw; 204 }; 205 206 struct 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 215 struct 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 226 struct 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 234 struct asm_session_cmd_run_v2 { 235 u32 flags; 236 u32 time_lsw; 237 u32 time_msw; 238 } __packed; 239 240 struct audio_buffer { 241 phys_addr_t phys; 242 uint32_t size; /* size of buffer */ 243 }; 244 245 struct 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 252 struct 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 261 struct 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 279 static 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 291 static 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 323 err: 324 mutex_unlock(&ac->cmd_lock); 325 return rc; 326 } 327 328 static 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 372 static 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 */ 392 int 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 416 err: 417 return rc; 418 } 419 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions); 420 421 static 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: physcial 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 */ 500 int 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 } 546 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions); 547 548 static 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 */ 569 void q6asm_audio_client_free(struct audio_client *ac) 570 { 571 kref_put(&ac->refcount, q6asm_audio_client_release); 572 } 573 EXPORT_SYMBOL_GPL(q6asm_audio_client_free); 574 575 static 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); 595 err: 596 spin_unlock_irqrestore(&a->slock, flags); 597 return ac; 598 } 599 600 static 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 741 done: 742 kref_put(&ac->refcount, q6asm_audio_client_release); 743 return ret; 744 } 745 746 static 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 810 done: 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 */ 823 int q6asm_get_session_id(struct audio_client *c) 824 { 825 return c->session; 826 } 827 EXPORT_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 */ 841 struct 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 } 878 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); 879 880 static 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 910 err: 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 * @format: audio sample format 919 * @codec_profile: compressed format profile 920 * @bits_per_sample: bits per sample 921 * 922 * Return: Will be an negative value on error or zero on success 923 */ 924 int q6asm_open_write(struct audio_client *ac, uint32_t stream_id, 925 uint32_t format, u32 codec_profile, 926 uint16_t bits_per_sample, bool is_gapless) 927 { 928 struct asm_stream_cmd_open_write_v3 *open; 929 struct apr_pkt *pkt; 930 void *p; 931 int rc, pkt_size; 932 933 pkt_size = APR_HDR_SIZE + sizeof(*open); 934 935 p = kzalloc(pkt_size, GFP_KERNEL); 936 if (!p) 937 return -ENOMEM; 938 939 pkt = p; 940 open = p + APR_HDR_SIZE; 941 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 942 943 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3; 944 open->mode_flags = 0x00; 945 open->mode_flags |= ASM_LEGACY_STREAM_SESSION; 946 if (is_gapless) 947 open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG); 948 949 /* source endpoint : matrix */ 950 open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX; 951 open->bits_per_sample = bits_per_sample; 952 open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; 953 954 switch (format) { 955 case SND_AUDIOCODEC_MP3: 956 open->dec_fmt_id = ASM_MEDIA_FMT_MP3; 957 break; 958 case FORMAT_LINEAR_PCM: 959 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; 960 break; 961 case SND_AUDIOCODEC_FLAC: 962 open->dec_fmt_id = ASM_MEDIA_FMT_FLAC; 963 break; 964 case SND_AUDIOCODEC_WMA: 965 switch (codec_profile) { 966 case SND_AUDIOPROFILE_WMA9: 967 open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9; 968 break; 969 case SND_AUDIOPROFILE_WMA10: 970 case SND_AUDIOPROFILE_WMA9_PRO: 971 case SND_AUDIOPROFILE_WMA9_LOSSLESS: 972 case SND_AUDIOPROFILE_WMA10_LOSSLESS: 973 open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10; 974 break; 975 default: 976 dev_err(ac->dev, "Invalid codec profile 0x%x\n", 977 codec_profile); 978 rc = -EINVAL; 979 goto err; 980 } 981 break; 982 case SND_AUDIOCODEC_ALAC: 983 open->dec_fmt_id = ASM_MEDIA_FMT_ALAC; 984 break; 985 case SND_AUDIOCODEC_APE: 986 open->dec_fmt_id = ASM_MEDIA_FMT_APE; 987 break; 988 default: 989 dev_err(ac->dev, "Invalid format 0x%x\n", format); 990 rc = -EINVAL; 991 goto err; 992 } 993 994 rc = q6asm_ac_send_cmd_sync(ac, pkt); 995 if (rc < 0) 996 goto err; 997 998 ac->io_mode |= ASM_TUN_WRITE_IO_MODE; 999 1000 err: 1001 kfree(pkt); 1002 return rc; 1003 } 1004 EXPORT_SYMBOL_GPL(q6asm_open_write); 1005 1006 static int __q6asm_run(struct audio_client *ac, uint32_t stream_id, 1007 uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts, 1008 bool wait) 1009 { 1010 struct asm_session_cmd_run_v2 *run; 1011 struct apr_pkt *pkt; 1012 int pkt_size, rc; 1013 void *p; 1014 1015 pkt_size = APR_HDR_SIZE + sizeof(*run); 1016 p = kzalloc(pkt_size, GFP_ATOMIC); 1017 if (!p) 1018 return -ENOMEM; 1019 1020 pkt = p; 1021 run = p + APR_HDR_SIZE; 1022 1023 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1024 1025 pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2; 1026 run->flags = flags; 1027 run->time_lsw = lsw_ts; 1028 run->time_msw = msw_ts; 1029 if (wait) { 1030 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1031 } else { 1032 rc = apr_send_pkt(ac->adev, pkt); 1033 if (rc == pkt_size) 1034 rc = 0; 1035 } 1036 1037 kfree(pkt); 1038 return rc; 1039 } 1040 1041 /** 1042 * q6asm_run() - start the audio client 1043 * 1044 * @ac: audio client pointer 1045 * @flags: flags associated with write 1046 * @msw_ts: timestamp msw 1047 * @lsw_ts: timestamp lsw 1048 * 1049 * Return: Will be an negative value on error or zero on success 1050 */ 1051 int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags, 1052 uint32_t msw_ts, uint32_t lsw_ts) 1053 { 1054 return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true); 1055 } 1056 EXPORT_SYMBOL_GPL(q6asm_run); 1057 1058 /** 1059 * q6asm_run_nowait() - start the audio client withou blocking 1060 * 1061 * @ac: audio client pointer 1062 * @stream_id: stream id 1063 * @flags: flags associated with write 1064 * @msw_ts: timestamp msw 1065 * @lsw_ts: timestamp lsw 1066 * 1067 * Return: Will be an negative value on error or zero on success 1068 */ 1069 int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id, 1070 uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts) 1071 { 1072 return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false); 1073 } 1074 EXPORT_SYMBOL_GPL(q6asm_run_nowait); 1075 1076 /** 1077 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration 1078 * 1079 * @ac: audio client pointer 1080 * @stream_id: stream id 1081 * @rate: audio sample rate 1082 * @channels: number of audio channels. 1083 * @channel_map: channel map pointer 1084 * @bits_per_sample: bits per sample 1085 * 1086 * Return: Will be an negative value on error or zero on success 1087 */ 1088 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, 1089 uint32_t stream_id, 1090 uint32_t rate, uint32_t channels, 1091 u8 channel_map[PCM_MAX_NUM_CHANNEL], 1092 uint16_t bits_per_sample) 1093 { 1094 struct asm_multi_channel_pcm_fmt_blk_v2 *fmt; 1095 struct apr_pkt *pkt; 1096 u8 *channel_mapping; 1097 void *p; 1098 int rc, pkt_size; 1099 1100 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1101 p = kzalloc(pkt_size, GFP_KERNEL); 1102 if (!p) 1103 return -ENOMEM; 1104 1105 pkt = p; 1106 fmt = p + APR_HDR_SIZE; 1107 1108 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1109 1110 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1111 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1112 fmt->num_channels = channels; 1113 fmt->bits_per_sample = bits_per_sample; 1114 fmt->sample_rate = rate; 1115 fmt->is_signed = 1; 1116 1117 channel_mapping = fmt->channel_mapping; 1118 1119 if (channel_map) { 1120 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL); 1121 } else { 1122 if (q6dsp_map_channels(channel_mapping, channels)) { 1123 dev_err(ac->dev, " map channels failed %d\n", channels); 1124 rc = -EINVAL; 1125 goto err; 1126 } 1127 } 1128 1129 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1130 1131 err: 1132 kfree(pkt); 1133 return rc; 1134 } 1135 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); 1136 1137 int q6asm_stream_media_format_block_flac(struct audio_client *ac, 1138 uint32_t stream_id, 1139 struct q6asm_flac_cfg *cfg) 1140 { 1141 struct asm_flac_fmt_blk_v2 *fmt; 1142 struct apr_pkt *pkt; 1143 void *p; 1144 int rc, pkt_size; 1145 1146 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1147 p = kzalloc(pkt_size, GFP_KERNEL); 1148 if (!p) 1149 return -ENOMEM; 1150 1151 pkt = p; 1152 fmt = p + APR_HDR_SIZE; 1153 1154 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1155 1156 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1157 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1158 fmt->is_stream_info_present = cfg->stream_info_present; 1159 fmt->num_channels = cfg->ch_cfg; 1160 fmt->min_blk_size = cfg->min_blk_size; 1161 fmt->max_blk_size = cfg->max_blk_size; 1162 fmt->sample_rate = cfg->sample_rate; 1163 fmt->min_frame_size = cfg->min_frame_size; 1164 fmt->max_frame_size = cfg->max_frame_size; 1165 fmt->sample_size = cfg->sample_size; 1166 1167 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1168 kfree(pkt); 1169 1170 return rc; 1171 } 1172 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac); 1173 1174 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, 1175 uint32_t stream_id, 1176 struct q6asm_wma_cfg *cfg) 1177 { 1178 struct asm_wmastdv9_fmt_blk_v2 *fmt; 1179 struct apr_pkt *pkt; 1180 void *p; 1181 int rc, pkt_size; 1182 1183 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1184 p = kzalloc(pkt_size, GFP_KERNEL); 1185 if (!p) 1186 return -ENOMEM; 1187 1188 pkt = p; 1189 fmt = p + APR_HDR_SIZE; 1190 1191 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1192 1193 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1194 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1195 fmt->fmtag = cfg->fmtag; 1196 fmt->num_channels = cfg->num_channels; 1197 fmt->sample_rate = cfg->sample_rate; 1198 fmt->bytes_per_sec = cfg->bytes_per_sec; 1199 fmt->blk_align = cfg->block_align; 1200 fmt->bits_per_sample = cfg->bits_per_sample; 1201 fmt->channel_mask = cfg->channel_mask; 1202 fmt->enc_options = cfg->enc_options; 1203 fmt->reserved = 0; 1204 1205 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1206 kfree(pkt); 1207 1208 return rc; 1209 } 1210 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9); 1211 1212 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, 1213 uint32_t stream_id, 1214 struct q6asm_wma_cfg *cfg) 1215 { 1216 struct asm_wmaprov10_fmt_blk_v2 *fmt; 1217 struct apr_pkt *pkt; 1218 void *p; 1219 int rc, pkt_size; 1220 1221 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1222 p = kzalloc(pkt_size, GFP_KERNEL); 1223 if (!p) 1224 return -ENOMEM; 1225 1226 pkt = p; 1227 fmt = p + APR_HDR_SIZE; 1228 1229 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1230 1231 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1232 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1233 fmt->fmtag = cfg->fmtag; 1234 fmt->num_channels = cfg->num_channels; 1235 fmt->sample_rate = cfg->sample_rate; 1236 fmt->bytes_per_sec = cfg->bytes_per_sec; 1237 fmt->blk_align = cfg->block_align; 1238 fmt->bits_per_sample = cfg->bits_per_sample; 1239 fmt->channel_mask = cfg->channel_mask; 1240 fmt->enc_options = cfg->enc_options; 1241 fmt->advanced_enc_options1 = cfg->adv_enc_options; 1242 fmt->advanced_enc_options2 = cfg->adv_enc_options2; 1243 1244 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1245 kfree(pkt); 1246 1247 return rc; 1248 } 1249 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10); 1250 1251 int q6asm_stream_media_format_block_alac(struct audio_client *ac, 1252 uint32_t stream_id, 1253 struct q6asm_alac_cfg *cfg) 1254 { 1255 struct asm_alac_fmt_blk_v2 *fmt; 1256 struct apr_pkt *pkt; 1257 void *p; 1258 int rc, pkt_size; 1259 1260 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1261 p = kzalloc(pkt_size, GFP_KERNEL); 1262 if (!p) 1263 return -ENOMEM; 1264 1265 pkt = p; 1266 fmt = p + APR_HDR_SIZE; 1267 1268 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1269 1270 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1271 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1272 1273 fmt->frame_length = cfg->frame_length; 1274 fmt->compatible_version = cfg->compatible_version; 1275 fmt->bit_depth = cfg->bit_depth; 1276 fmt->num_channels = cfg->num_channels; 1277 fmt->max_run = cfg->max_run; 1278 fmt->max_frame_bytes = cfg->max_frame_bytes; 1279 fmt->avg_bit_rate = cfg->avg_bit_rate; 1280 fmt->sample_rate = cfg->sample_rate; 1281 fmt->channel_layout_tag = cfg->channel_layout_tag; 1282 fmt->pb = cfg->pb; 1283 fmt->mb = cfg->mb; 1284 fmt->kb = cfg->kb; 1285 1286 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1287 kfree(pkt); 1288 1289 return rc; 1290 } 1291 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac); 1292 1293 int q6asm_stream_media_format_block_ape(struct audio_client *ac, 1294 uint32_t stream_id, 1295 struct q6asm_ape_cfg *cfg) 1296 { 1297 struct asm_ape_fmt_blk_v2 *fmt; 1298 struct apr_pkt *pkt; 1299 void *p; 1300 int rc, pkt_size; 1301 1302 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1303 p = kzalloc(pkt_size, GFP_KERNEL); 1304 if (!p) 1305 return -ENOMEM; 1306 1307 pkt = p; 1308 fmt = p + APR_HDR_SIZE; 1309 1310 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1311 1312 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1313 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1314 1315 fmt->compatible_version = cfg->compatible_version; 1316 fmt->compression_level = cfg->compression_level; 1317 fmt->format_flags = cfg->format_flags; 1318 fmt->blocks_per_frame = cfg->blocks_per_frame; 1319 fmt->final_frame_blocks = cfg->final_frame_blocks; 1320 fmt->total_frames = cfg->total_frames; 1321 fmt->bits_per_sample = cfg->bits_per_sample; 1322 fmt->num_channels = cfg->num_channels; 1323 fmt->sample_rate = cfg->sample_rate; 1324 fmt->seek_table_present = cfg->seek_table_present; 1325 1326 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1327 kfree(pkt); 1328 1329 return rc; 1330 } 1331 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape); 1332 1333 static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id, 1334 uint32_t cmd, 1335 uint32_t num_samples) 1336 { 1337 uint32_t *samples; 1338 struct apr_pkt *pkt; 1339 void *p; 1340 int rc, pkt_size; 1341 1342 pkt_size = APR_HDR_SIZE + sizeof(uint32_t); 1343 p = kzalloc(pkt_size, GFP_ATOMIC); 1344 if (!p) 1345 return -ENOMEM; 1346 1347 pkt = p; 1348 samples = p + APR_HDR_SIZE; 1349 1350 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1351 1352 pkt->hdr.opcode = cmd; 1353 *samples = num_samples; 1354 rc = apr_send_pkt(ac->adev, pkt); 1355 if (rc == pkt_size) 1356 rc = 0; 1357 1358 kfree(pkt); 1359 1360 return rc; 1361 } 1362 1363 int q6asm_stream_remove_initial_silence(struct audio_client *ac, 1364 uint32_t stream_id, 1365 uint32_t initial_samples) 1366 { 1367 return q6asm_stream_remove_silence(ac, stream_id, 1368 ASM_DATA_CMD_REMOVE_INITIAL_SILENCE, 1369 initial_samples); 1370 } 1371 EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence); 1372 1373 int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id, 1374 uint32_t trailing_samples) 1375 { 1376 return q6asm_stream_remove_silence(ac, stream_id, 1377 ASM_DATA_CMD_REMOVE_TRAILING_SILENCE, 1378 trailing_samples); 1379 } 1380 EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence); 1381 1382 /** 1383 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture 1384 * 1385 * @ac: audio client pointer 1386 * @stream_id: stream id 1387 * @rate: audio sample rate 1388 * @channels: number of audio channels. 1389 * @bits_per_sample: bits per sample 1390 * 1391 * Return: Will be an negative value on error or zero on success 1392 */ 1393 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, 1394 uint32_t stream_id, uint32_t rate, 1395 uint32_t channels, 1396 uint16_t bits_per_sample) 1397 { 1398 struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg; 1399 struct apr_pkt *pkt; 1400 u8 *channel_mapping; 1401 u32 frames_per_buf = 0; 1402 int pkt_size, rc; 1403 void *p; 1404 1405 pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg); 1406 p = kzalloc(pkt_size, GFP_KERNEL); 1407 if (!p) 1408 return -ENOMEM; 1409 1410 pkt = p; 1411 enc_cfg = p + APR_HDR_SIZE; 1412 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1413 1414 pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; 1415 enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; 1416 enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec); 1417 enc_cfg->encblk.frames_per_buf = frames_per_buf; 1418 enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size - 1419 sizeof(struct asm_enc_cfg_blk_param_v2); 1420 1421 enc_cfg->num_channels = channels; 1422 enc_cfg->bits_per_sample = bits_per_sample; 1423 enc_cfg->sample_rate = rate; 1424 enc_cfg->is_signed = 1; 1425 channel_mapping = enc_cfg->channel_mapping; 1426 1427 if (q6dsp_map_channels(channel_mapping, channels)) { 1428 rc = -EINVAL; 1429 goto err; 1430 } 1431 1432 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1433 err: 1434 kfree(pkt); 1435 return rc; 1436 } 1437 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); 1438 1439 1440 /** 1441 * q6asm_read() - read data of period size from audio client 1442 * 1443 * @ac: audio client pointer 1444 * @stream_id: stream id 1445 * 1446 * Return: Will be an negative value on error or zero on success 1447 */ 1448 int q6asm_read(struct audio_client *ac, uint32_t stream_id) 1449 { 1450 struct asm_data_cmd_read_v2 *read; 1451 struct audio_port_data *port; 1452 struct audio_buffer *ab; 1453 struct apr_pkt *pkt; 1454 unsigned long flags; 1455 int pkt_size; 1456 int rc = 0; 1457 void *p; 1458 1459 pkt_size = APR_HDR_SIZE + sizeof(*read); 1460 p = kzalloc(pkt_size, GFP_ATOMIC); 1461 if (!p) 1462 return -ENOMEM; 1463 1464 pkt = p; 1465 read = p + APR_HDR_SIZE; 1466 1467 spin_lock_irqsave(&ac->lock, flags); 1468 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 1469 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id); 1470 ab = &port->buf[port->dsp_buf]; 1471 pkt->hdr.opcode = ASM_DATA_CMD_READ_V2; 1472 read->buf_addr_lsw = lower_32_bits(ab->phys); 1473 read->buf_addr_msw = upper_32_bits(ab->phys); 1474 read->mem_map_handle = port->mem_map_handle; 1475 1476 read->buf_size = ab->size; 1477 read->seq_id = port->dsp_buf; 1478 pkt->hdr.token = port->dsp_buf; 1479 1480 port->dsp_buf++; 1481 1482 if (port->dsp_buf >= port->num_periods) 1483 port->dsp_buf = 0; 1484 1485 spin_unlock_irqrestore(&ac->lock, flags); 1486 rc = apr_send_pkt(ac->adev, pkt); 1487 if (rc == pkt_size) 1488 rc = 0; 1489 else 1490 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc); 1491 1492 kfree(pkt); 1493 return rc; 1494 } 1495 EXPORT_SYMBOL_GPL(q6asm_read); 1496 1497 static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id, 1498 uint32_t format, uint16_t bits_per_sample) 1499 { 1500 struct asm_stream_cmd_open_read_v3 *open; 1501 struct apr_pkt *pkt; 1502 int pkt_size, rc; 1503 void *p; 1504 1505 pkt_size = APR_HDR_SIZE + sizeof(*open); 1506 p = kzalloc(pkt_size, GFP_KERNEL); 1507 if (!p) 1508 return -ENOMEM; 1509 1510 pkt = p; 1511 open = p + APR_HDR_SIZE; 1512 1513 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); 1514 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3; 1515 /* Stream prio : High, provide meta info with encoded frames */ 1516 open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX; 1517 1518 open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE; 1519 open->bits_per_sample = bits_per_sample; 1520 open->mode_flags = 0x0; 1521 1522 open->mode_flags |= ASM_LEGACY_STREAM_SESSION << 1523 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ; 1524 1525 switch (format) { 1526 case FORMAT_LINEAR_PCM: 1527 open->mode_flags |= 0x00; 1528 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; 1529 break; 1530 default: 1531 pr_err("Invalid format[%d]\n", format); 1532 } 1533 1534 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1535 1536 kfree(pkt); 1537 return rc; 1538 } 1539 1540 /** 1541 * q6asm_open_read() - Open audio client for reading 1542 * 1543 * @ac: audio client pointer 1544 * @stream_id: stream id 1545 * @format: audio sample format 1546 * @bits_per_sample: bits per sample 1547 * 1548 * Return: Will be an negative value on error or zero on success 1549 */ 1550 int q6asm_open_read(struct audio_client *ac, uint32_t stream_id, 1551 uint32_t format, uint16_t bits_per_sample) 1552 { 1553 return __q6asm_open_read(ac, stream_id, format, bits_per_sample); 1554 } 1555 EXPORT_SYMBOL_GPL(q6asm_open_read); 1556 1557 /** 1558 * q6asm_write_async() - non blocking write 1559 * 1560 * @ac: audio client pointer 1561 * @stream_id: stream id 1562 * @len: length in bytes 1563 * @msw_ts: timestamp msw 1564 * @lsw_ts: timestamp lsw 1565 * @wflags: flags associated with write 1566 * 1567 * Return: Will be an negative value on error or zero on success 1568 */ 1569 int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len, 1570 uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags) 1571 { 1572 struct asm_data_cmd_write_v2 *write; 1573 struct audio_port_data *port; 1574 struct audio_buffer *ab; 1575 unsigned long flags; 1576 struct apr_pkt *pkt; 1577 int pkt_size; 1578 int rc = 0; 1579 void *p; 1580 1581 pkt_size = APR_HDR_SIZE + sizeof(*write); 1582 p = kzalloc(pkt_size, GFP_ATOMIC); 1583 if (!p) 1584 return -ENOMEM; 1585 1586 pkt = p; 1587 write = p + APR_HDR_SIZE; 1588 1589 spin_lock_irqsave(&ac->lock, flags); 1590 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 1591 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id); 1592 1593 ab = &port->buf[port->dsp_buf]; 1594 pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT); 1595 pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2; 1596 write->buf_addr_lsw = lower_32_bits(ab->phys); 1597 write->buf_addr_msw = upper_32_bits(ab->phys); 1598 write->buf_size = len; 1599 write->seq_id = port->dsp_buf; 1600 write->timestamp_lsw = lsw_ts; 1601 write->timestamp_msw = msw_ts; 1602 write->mem_map_handle = 1603 ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle; 1604 1605 write->flags = wflags; 1606 1607 port->dsp_buf++; 1608 1609 if (port->dsp_buf >= port->num_periods) 1610 port->dsp_buf = 0; 1611 1612 spin_unlock_irqrestore(&ac->lock, flags); 1613 rc = apr_send_pkt(ac->adev, pkt); 1614 if (rc == pkt_size) 1615 rc = 0; 1616 1617 kfree(pkt); 1618 return rc; 1619 } 1620 EXPORT_SYMBOL_GPL(q6asm_write_async); 1621 1622 static void q6asm_reset_buf_state(struct audio_client *ac) 1623 { 1624 struct audio_port_data *port = NULL; 1625 unsigned long flags; 1626 1627 spin_lock_irqsave(&ac->lock, flags); 1628 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 1629 port->dsp_buf = 0; 1630 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 1631 port->dsp_buf = 0; 1632 spin_unlock_irqrestore(&ac->lock, flags); 1633 } 1634 1635 static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd, 1636 bool wait) 1637 { 1638 struct apr_pkt pkt; 1639 int rc; 1640 1641 q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id); 1642 1643 switch (cmd) { 1644 case CMD_PAUSE: 1645 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE; 1646 break; 1647 case CMD_SUSPEND: 1648 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND; 1649 break; 1650 case CMD_FLUSH: 1651 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH; 1652 break; 1653 case CMD_OUT_FLUSH: 1654 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS; 1655 break; 1656 case CMD_EOS: 1657 pkt.hdr.opcode = ASM_DATA_CMD_EOS; 1658 break; 1659 case CMD_CLOSE: 1660 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE; 1661 break; 1662 default: 1663 return -EINVAL; 1664 } 1665 1666 if (wait) 1667 rc = q6asm_ac_send_cmd_sync(ac, &pkt); 1668 else 1669 return apr_send_pkt(ac->adev, &pkt); 1670 1671 if (rc < 0) 1672 return rc; 1673 1674 if (cmd == CMD_FLUSH) 1675 q6asm_reset_buf_state(ac); 1676 1677 return 0; 1678 } 1679 1680 /** 1681 * q6asm_cmd() - run cmd on audio client 1682 * 1683 * @ac: audio client pointer 1684 * @stream_id: stream id 1685 * @cmd: command to run on audio client. 1686 * 1687 * Return: Will be an negative value on error or zero on success 1688 */ 1689 int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd) 1690 { 1691 return __q6asm_cmd(ac, stream_id, cmd, true); 1692 } 1693 EXPORT_SYMBOL_GPL(q6asm_cmd); 1694 1695 /** 1696 * q6asm_cmd_nowait() - non blocking, run cmd on audio client 1697 * 1698 * @ac: audio client pointer 1699 * @stream_id: stream id 1700 * @cmd: command to run on audio client. 1701 * 1702 * Return: Will be an negative value on error or zero on success 1703 */ 1704 int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd) 1705 { 1706 return __q6asm_cmd(ac, stream_id, cmd, false); 1707 } 1708 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait); 1709 1710 static int q6asm_probe(struct apr_device *adev) 1711 { 1712 struct device *dev = &adev->dev; 1713 struct q6asm *q6asm; 1714 1715 q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL); 1716 if (!q6asm) 1717 return -ENOMEM; 1718 1719 q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo); 1720 1721 q6asm->dev = dev; 1722 q6asm->adev = adev; 1723 init_waitqueue_head(&q6asm->mem_wait); 1724 spin_lock_init(&q6asm->slock); 1725 dev_set_drvdata(dev, q6asm); 1726 1727 return of_platform_populate(dev->of_node, NULL, NULL, dev); 1728 } 1729 1730 static int q6asm_remove(struct apr_device *adev) 1731 { 1732 of_platform_depopulate(&adev->dev); 1733 1734 return 0; 1735 } 1736 1737 #ifdef CONFIG_OF 1738 static const struct of_device_id q6asm_device_id[] = { 1739 { .compatible = "qcom,q6asm" }, 1740 {}, 1741 }; 1742 MODULE_DEVICE_TABLE(of, q6asm_device_id); 1743 #endif 1744 1745 static struct apr_driver qcom_q6asm_driver = { 1746 .probe = q6asm_probe, 1747 .remove = q6asm_remove, 1748 .callback = q6asm_srvc_callback, 1749 .driver = { 1750 .name = "qcom-q6asm", 1751 .of_match_table = of_match_ptr(q6asm_device_id), 1752 }, 1753 }; 1754 1755 module_apr_driver(qcom_q6asm_driver); 1756 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver"); 1757 MODULE_LICENSE("GPL v2"); 1758