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