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