0001
0002
0003
0004
0005 #include <linux/mutex.h>
0006 #include <linux/wait.h>
0007 #include <linux/module.h>
0008 #include <linux/soc/qcom/apr.h>
0009 #include <linux/device.h>
0010 #include <linux/of_platform.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/kref.h>
0013 #include <linux/of.h>
0014 #include <uapi/sound/asound.h>
0015 #include <uapi/sound/compress_params.h>
0016 #include <linux/delay.h>
0017 #include <linux/slab.h>
0018 #include <linux/mm.h>
0019 #include "q6asm.h"
0020 #include "q6core.h"
0021 #include "q6dsp-errno.h"
0022 #include "q6dsp-common.h"
0023
0024 #define ASM_STREAM_CMD_CLOSE 0x00010BCD
0025 #define ASM_STREAM_CMD_FLUSH 0x00010BCE
0026 #define ASM_SESSION_CMD_PAUSE 0x00010BD3
0027 #define ASM_DATA_CMD_EOS 0x00010BDB
0028 #define ASM_DATA_EVENT_RENDERED_EOS 0x00010C1C
0029 #define ASM_NULL_POPP_TOPOLOGY 0x00010C68
0030 #define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09
0031 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
0032 #define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
0033 #define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92
0034 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93
0035 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94
0036 #define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
0037 #define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99
0038 #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
0039 #define ASM_SESSION_CMD_RUN_V2 0x00010DAA
0040 #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
0041 #define ASM_MEDIA_FMT_MP3 0x00010BE9
0042 #define ASM_MEDIA_FMT_FLAC 0x00010C16
0043 #define ASM_MEDIA_FMT_WMA_V9 0x00010DA8
0044 #define ASM_MEDIA_FMT_WMA_V10 0x00010DA7
0045 #define ASM_DATA_CMD_WRITE_V2 0x00010DAB
0046 #define ASM_DATA_CMD_READ_V2 0x00010DAC
0047 #define ASM_SESSION_CMD_SUSPEND 0x00010DEC
0048 #define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3
0049 #define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4
0050 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
0051 #define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D
0052 #define ASM_MEDIA_FMT_ALAC 0x00012f31
0053 #define ASM_MEDIA_FMT_APE 0x00012f32
0054 #define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67
0055 #define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68
0056
0057
0058 #define ASM_LEGACY_STREAM_SESSION 0
0059
0060 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29
0061 #define ASM_END_POINT_DEVICE_MATRIX 0
0062 #define ASM_DEFAULT_APP_TYPE 0
0063 #define ASM_SYNC_IO_MODE 0x0001
0064 #define ASM_ASYNC_IO_MODE 0x0002
0065 #define ASM_TUN_READ_IO_MODE 0x0004
0066 #define ASM_TUN_WRITE_IO_MODE 0x0008
0067 #define ASM_SHIFT_GAPLESS_MODE_FLAG 31
0068 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
0069
0070 struct avs_cmd_shared_mem_map_regions {
0071 u16 mem_pool_id;
0072 u16 num_regions;
0073 u32 property_flag;
0074 } __packed;
0075
0076 struct avs_shared_map_region_payload {
0077 u32 shm_addr_lsw;
0078 u32 shm_addr_msw;
0079 u32 mem_size_bytes;
0080 } __packed;
0081
0082 struct avs_cmd_shared_mem_unmap_regions {
0083 u32 mem_map_handle;
0084 } __packed;
0085
0086 struct asm_data_cmd_media_fmt_update_v2 {
0087 u32 fmt_blk_size;
0088 } __packed;
0089
0090 struct asm_multi_channel_pcm_fmt_blk_v2 {
0091 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
0092 u16 num_channels;
0093 u16 bits_per_sample;
0094 u32 sample_rate;
0095 u16 is_signed;
0096 u16 reserved;
0097 u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
0098 } __packed;
0099
0100 struct asm_flac_fmt_blk_v2 {
0101 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
0102 u16 is_stream_info_present;
0103 u16 num_channels;
0104 u16 min_blk_size;
0105 u16 max_blk_size;
0106 u16 md5_sum[8];
0107 u32 sample_rate;
0108 u32 min_frame_size;
0109 u32 max_frame_size;
0110 u16 sample_size;
0111 u16 reserved;
0112 } __packed;
0113
0114 struct asm_wmastdv9_fmt_blk_v2 {
0115 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
0116 u16 fmtag;
0117 u16 num_channels;
0118 u32 sample_rate;
0119 u32 bytes_per_sec;
0120 u16 blk_align;
0121 u16 bits_per_sample;
0122 u32 channel_mask;
0123 u16 enc_options;
0124 u16 reserved;
0125 } __packed;
0126
0127 struct asm_wmaprov10_fmt_blk_v2 {
0128 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
0129 u16 fmtag;
0130 u16 num_channels;
0131 u32 sample_rate;
0132 u32 bytes_per_sec;
0133 u16 blk_align;
0134 u16 bits_per_sample;
0135 u32 channel_mask;
0136 u16 enc_options;
0137 u16 advanced_enc_options1;
0138 u32 advanced_enc_options2;
0139 } __packed;
0140
0141 struct asm_alac_fmt_blk_v2 {
0142 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
0143 u32 frame_length;
0144 u8 compatible_version;
0145 u8 bit_depth;
0146 u8 pb;
0147 u8 mb;
0148 u8 kb;
0149 u8 num_channels;
0150 u16 max_run;
0151 u32 max_frame_bytes;
0152 u32 avg_bit_rate;
0153 u32 sample_rate;
0154 u32 channel_layout_tag;
0155 } __packed;
0156
0157 struct asm_ape_fmt_blk_v2 {
0158 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
0159 u16 compatible_version;
0160 u16 compression_level;
0161 u32 format_flags;
0162 u32 blocks_per_frame;
0163 u32 final_frame_blocks;
0164 u32 total_frames;
0165 u16 bits_per_sample;
0166 u16 num_channels;
0167 u32 sample_rate;
0168 u32 seek_table_present;
0169 } __packed;
0170
0171 struct asm_stream_cmd_set_encdec_param {
0172 u32 param_id;
0173 u32 param_size;
0174 } __packed;
0175
0176 struct asm_enc_cfg_blk_param_v2 {
0177 u32 frames_per_buf;
0178 u32 enc_cfg_blk_size;
0179 } __packed;
0180
0181 struct asm_multi_channel_pcm_enc_cfg_v2 {
0182 struct asm_stream_cmd_set_encdec_param encdec;
0183 struct asm_enc_cfg_blk_param_v2 encblk;
0184 uint16_t num_channels;
0185 uint16_t bits_per_sample;
0186 uint32_t sample_rate;
0187 uint16_t is_signed;
0188 uint16_t reserved;
0189 uint8_t channel_mapping[8];
0190 } __packed;
0191
0192 struct asm_data_cmd_read_v2 {
0193 u32 buf_addr_lsw;
0194 u32 buf_addr_msw;
0195 u32 mem_map_handle;
0196 u32 buf_size;
0197 u32 seq_id;
0198 } __packed;
0199
0200 struct asm_data_cmd_read_v2_done {
0201 u32 status;
0202 u32 buf_addr_lsw;
0203 u32 buf_addr_msw;
0204 };
0205
0206 struct asm_stream_cmd_open_read_v3 {
0207 u32 mode_flags;
0208 u32 src_endpointype;
0209 u32 preprocopo_id;
0210 u32 enc_cfg_id;
0211 u16 bits_per_sample;
0212 u16 reserved;
0213 } __packed;
0214
0215 struct asm_data_cmd_write_v2 {
0216 u32 buf_addr_lsw;
0217 u32 buf_addr_msw;
0218 u32 mem_map_handle;
0219 u32 buf_size;
0220 u32 seq_id;
0221 u32 timestamp_lsw;
0222 u32 timestamp_msw;
0223 u32 flags;
0224 } __packed;
0225
0226 struct asm_stream_cmd_open_write_v3 {
0227 uint32_t mode_flags;
0228 uint16_t sink_endpointype;
0229 uint16_t bits_per_sample;
0230 uint32_t postprocopo_id;
0231 uint32_t dec_fmt_id;
0232 } __packed;
0233
0234 struct asm_session_cmd_run_v2 {
0235 u32 flags;
0236 u32 time_lsw;
0237 u32 time_msw;
0238 } __packed;
0239
0240 struct audio_buffer {
0241 phys_addr_t phys;
0242 uint32_t size;
0243 };
0244
0245 struct audio_port_data {
0246 struct audio_buffer *buf;
0247 uint32_t num_periods;
0248 uint32_t dsp_buf;
0249 uint32_t mem_map_handle;
0250 };
0251
0252 struct q6asm {
0253 struct apr_device *adev;
0254 struct device *dev;
0255 struct q6core_svc_api_info ainfo;
0256 wait_queue_head_t mem_wait;
0257 spinlock_t slock;
0258 struct audio_client *session[MAX_SESSIONS + 1];
0259 };
0260
0261 struct audio_client {
0262 int session;
0263 q6asm_cb cb;
0264 void *priv;
0265 uint32_t io_mode;
0266 struct apr_device *adev;
0267 struct mutex cmd_lock;
0268 spinlock_t lock;
0269 struct kref refcount;
0270
0271 struct audio_port_data port[2];
0272 wait_queue_head_t cmd_wait;
0273 struct aprv2_ibasic_rsp_result_t result;
0274 int perf_mode;
0275 struct q6asm *q6asm;
0276 struct device *dev;
0277 };
0278
0279 static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
0280 uint32_t pkt_size, bool cmd_flg,
0281 uint32_t stream_id)
0282 {
0283 hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
0284 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
0285 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
0286 hdr->pkt_size = pkt_size;
0287 if (cmd_flg)
0288 hdr->token = ac->session;
0289 }
0290
0291 static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
0292 struct apr_pkt *pkt, uint32_t rsp_opcode)
0293 {
0294 struct apr_hdr *hdr = &pkt->hdr;
0295 int rc;
0296
0297 mutex_lock(&ac->cmd_lock);
0298 ac->result.opcode = 0;
0299 ac->result.status = 0;
0300 rc = apr_send_pkt(a->adev, pkt);
0301 if (rc < 0)
0302 goto err;
0303
0304 if (rsp_opcode)
0305 rc = wait_event_timeout(a->mem_wait,
0306 (ac->result.opcode == hdr->opcode) ||
0307 (ac->result.opcode == rsp_opcode),
0308 5 * HZ);
0309 else
0310 rc = wait_event_timeout(a->mem_wait,
0311 (ac->result.opcode == hdr->opcode),
0312 5 * HZ);
0313
0314 if (!rc) {
0315 dev_err(a->dev, "CMD %x timeout\n", hdr->opcode);
0316 rc = -ETIMEDOUT;
0317 } else if (ac->result.status > 0) {
0318 dev_err(a->dev, "DSP returned error[%x]\n",
0319 ac->result.status);
0320 rc = -EINVAL;
0321 }
0322
0323 err:
0324 mutex_unlock(&ac->cmd_lock);
0325 return rc;
0326 }
0327
0328 static int __q6asm_memory_unmap(struct audio_client *ac,
0329 phys_addr_t buf_add, int dir)
0330 {
0331 struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
0332 struct q6asm *a = dev_get_drvdata(ac->dev->parent);
0333 struct apr_pkt *pkt;
0334 int rc, pkt_size;
0335 void *p;
0336
0337 if (ac->port[dir].mem_map_handle == 0) {
0338 dev_err(ac->dev, "invalid mem handle\n");
0339 return -EINVAL;
0340 }
0341
0342 pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
0343 p = kzalloc(pkt_size, GFP_KERNEL);
0344 if (!p)
0345 return -ENOMEM;
0346
0347 pkt = p;
0348 mem_unmap = p + APR_HDR_SIZE;
0349
0350 pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
0351 pkt->hdr.src_port = 0;
0352 pkt->hdr.dest_port = 0;
0353 pkt->hdr.pkt_size = pkt_size;
0354 pkt->hdr.token = ((ac->session << 8) | dir);
0355
0356 pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
0357 mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
0358
0359 rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
0360 if (rc < 0) {
0361 kfree(pkt);
0362 return rc;
0363 }
0364
0365 ac->port[dir].mem_map_handle = 0;
0366
0367 kfree(pkt);
0368 return 0;
0369 }
0370
0371
0372 static void q6asm_audio_client_free_buf(struct audio_client *ac,
0373 struct audio_port_data *port)
0374 {
0375 unsigned long flags;
0376
0377 spin_lock_irqsave(&ac->lock, flags);
0378 port->num_periods = 0;
0379 kfree(port->buf);
0380 port->buf = NULL;
0381 spin_unlock_irqrestore(&ac->lock, flags);
0382 }
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392 int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
0393 {
0394 struct audio_port_data *port;
0395 int cnt = 0;
0396 int rc = 0;
0397
0398 port = &ac->port[dir];
0399 if (!port->buf) {
0400 rc = -EINVAL;
0401 goto err;
0402 }
0403
0404 cnt = port->num_periods - 1;
0405 if (cnt >= 0) {
0406 rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
0407 if (rc < 0) {
0408 dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
0409 __func__, rc);
0410 goto err;
0411 }
0412 }
0413
0414 q6asm_audio_client_free_buf(ac, port);
0415
0416 err:
0417 return rc;
0418 }
0419 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
0420
0421 static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
0422 size_t period_sz, unsigned int periods,
0423 bool is_contiguous)
0424 {
0425 struct avs_cmd_shared_mem_map_regions *cmd = NULL;
0426 struct avs_shared_map_region_payload *mregions = NULL;
0427 struct q6asm *a = dev_get_drvdata(ac->dev->parent);
0428 struct audio_port_data *port = NULL;
0429 struct audio_buffer *ab = NULL;
0430 struct apr_pkt *pkt;
0431 void *p;
0432 unsigned long flags;
0433 uint32_t num_regions, buf_sz;
0434 int rc, i, pkt_size;
0435
0436 if (is_contiguous) {
0437 num_regions = 1;
0438 buf_sz = period_sz * periods;
0439 } else {
0440 buf_sz = period_sz;
0441 num_regions = periods;
0442 }
0443
0444
0445 buf_sz = ALIGN(buf_sz, 4096);
0446
0447 pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
0448 (sizeof(*mregions) * num_regions);
0449
0450 p = kzalloc(pkt_size, GFP_KERNEL);
0451 if (!p)
0452 return -ENOMEM;
0453
0454 pkt = p;
0455 cmd = p + APR_HDR_SIZE;
0456 mregions = p + APR_HDR_SIZE + sizeof(*cmd);
0457
0458 pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
0459 pkt->hdr.src_port = 0;
0460 pkt->hdr.dest_port = 0;
0461 pkt->hdr.pkt_size = pkt_size;
0462 pkt->hdr.token = ((ac->session << 8) | dir);
0463 pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
0464
0465 cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
0466 cmd->num_regions = num_regions;
0467 cmd->property_flag = 0x00;
0468
0469 spin_lock_irqsave(&ac->lock, flags);
0470 port = &ac->port[dir];
0471
0472 for (i = 0; i < num_regions; i++) {
0473 ab = &port->buf[i];
0474 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
0475 mregions->shm_addr_msw = upper_32_bits(ab->phys);
0476 mregions->mem_size_bytes = buf_sz;
0477 ++mregions;
0478 }
0479 spin_unlock_irqrestore(&ac->lock, flags);
0480
0481 rc = q6asm_apr_send_session_pkt(a, ac, pkt,
0482 ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
0483
0484 kfree(pkt);
0485
0486 return rc;
0487 }
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500 int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
0501 phys_addr_t phys,
0502 size_t period_sz, unsigned int periods)
0503 {
0504 struct audio_buffer *buf;
0505 unsigned long flags;
0506 int cnt;
0507 int rc;
0508
0509 spin_lock_irqsave(&ac->lock, flags);
0510 if (ac->port[dir].buf) {
0511 dev_err(ac->dev, "Buffer already allocated\n");
0512 spin_unlock_irqrestore(&ac->lock, flags);
0513 return 0;
0514 }
0515
0516 buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC);
0517 if (!buf) {
0518 spin_unlock_irqrestore(&ac->lock, flags);
0519 return -ENOMEM;
0520 }
0521
0522
0523 ac->port[dir].buf = buf;
0524
0525 buf[0].phys = phys;
0526 buf[0].size = period_sz;
0527
0528 for (cnt = 1; cnt < periods; cnt++) {
0529 if (period_sz > 0) {
0530 buf[cnt].phys = buf[0].phys + (cnt * period_sz);
0531 buf[cnt].size = period_sz;
0532 }
0533 }
0534 ac->port[dir].num_periods = periods;
0535
0536 spin_unlock_irqrestore(&ac->lock, flags);
0537
0538 rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
0539 if (rc < 0) {
0540 dev_err(ac->dev, "Memory_map_regions failed\n");
0541 q6asm_audio_client_free_buf(ac, &ac->port[dir]);
0542 }
0543
0544 return rc;
0545 }
0546 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
0547
0548 static void q6asm_audio_client_release(struct kref *ref)
0549 {
0550 struct audio_client *ac;
0551 struct q6asm *a;
0552 unsigned long flags;
0553
0554 ac = container_of(ref, struct audio_client, refcount);
0555 a = ac->q6asm;
0556
0557 spin_lock_irqsave(&a->slock, flags);
0558 a->session[ac->session] = NULL;
0559 spin_unlock_irqrestore(&a->slock, flags);
0560
0561 kfree(ac);
0562 }
0563
0564
0565
0566
0567
0568
0569 void q6asm_audio_client_free(struct audio_client *ac)
0570 {
0571 kref_put(&ac->refcount, q6asm_audio_client_release);
0572 }
0573 EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
0574
0575 static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
0576 int session_id)
0577 {
0578 struct audio_client *ac = NULL;
0579 unsigned long flags;
0580
0581 spin_lock_irqsave(&a->slock, flags);
0582 if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
0583 dev_err(a->dev, "invalid session: %d\n", session_id);
0584 goto err;
0585 }
0586
0587
0588 if (!a->session[session_id])
0589 goto err;
0590 else if (a->session[session_id]->session != session_id)
0591 goto err;
0592
0593 ac = a->session[session_id];
0594 kref_get(&ac->refcount);
0595 err:
0596 spin_unlock_irqrestore(&a->slock, flags);
0597 return ac;
0598 }
0599
0600 static int32_t q6asm_stream_callback(struct apr_device *adev,
0601 struct apr_resp_pkt *data,
0602 int session_id)
0603 {
0604 struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
0605 struct aprv2_ibasic_rsp_result_t *result;
0606 struct apr_hdr *hdr = &data->hdr;
0607 struct audio_port_data *port;
0608 struct audio_client *ac;
0609 uint32_t client_event = 0;
0610 int ret = 0;
0611
0612 ac = q6asm_get_audio_client(q6asm, session_id);
0613 if (!ac)
0614 return 0;
0615
0616 result = data->payload;
0617
0618 switch (hdr->opcode) {
0619 case APR_BASIC_RSP_RESULT:
0620 switch (result->opcode) {
0621 case ASM_SESSION_CMD_PAUSE:
0622 client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
0623 break;
0624 case ASM_SESSION_CMD_SUSPEND:
0625 client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
0626 break;
0627 case ASM_STREAM_CMD_FLUSH:
0628 client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
0629 break;
0630 case ASM_SESSION_CMD_RUN_V2:
0631 client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
0632 break;
0633 case ASM_STREAM_CMD_CLOSE:
0634 client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
0635 break;
0636 case ASM_STREAM_CMD_FLUSH_READBUFS:
0637 client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
0638 break;
0639 case ASM_STREAM_CMD_OPEN_WRITE_V3:
0640 case ASM_STREAM_CMD_OPEN_READ_V3:
0641 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
0642 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
0643 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
0644 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
0645 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
0646 if (result->status != 0) {
0647 dev_err(ac->dev,
0648 "cmd = 0x%x returned error = 0x%x\n",
0649 result->opcode, result->status);
0650 ac->result = *result;
0651 wake_up(&ac->cmd_wait);
0652 ret = 0;
0653 goto done;
0654 }
0655 break;
0656 default:
0657 dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
0658 result->opcode);
0659 break;
0660 }
0661
0662 ac->result = *result;
0663 wake_up(&ac->cmd_wait);
0664
0665 if (ac->cb)
0666 ac->cb(client_event, hdr->token,
0667 data->payload, ac->priv);
0668
0669 ret = 0;
0670 goto done;
0671
0672 case ASM_DATA_EVENT_WRITE_DONE_V2:
0673 client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
0674 if (ac->io_mode & ASM_SYNC_IO_MODE) {
0675 phys_addr_t phys;
0676 unsigned long flags;
0677 int token = hdr->token & ASM_WRITE_TOKEN_MASK;
0678
0679 spin_lock_irqsave(&ac->lock, flags);
0680
0681 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
0682
0683 if (!port->buf) {
0684 spin_unlock_irqrestore(&ac->lock, flags);
0685 ret = 0;
0686 goto done;
0687 }
0688
0689 phys = port->buf[token].phys;
0690
0691 if (lower_32_bits(phys) != result->opcode ||
0692 upper_32_bits(phys) != result->status) {
0693 dev_err(ac->dev, "Expected addr %pa\n",
0694 &port->buf[token].phys);
0695 spin_unlock_irqrestore(&ac->lock, flags);
0696 ret = -EINVAL;
0697 goto done;
0698 }
0699 spin_unlock_irqrestore(&ac->lock, flags);
0700 }
0701 break;
0702 case ASM_DATA_EVENT_READ_DONE_V2:
0703 client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
0704 if (ac->io_mode & ASM_SYNC_IO_MODE) {
0705 struct asm_data_cmd_read_v2_done *done = data->payload;
0706 unsigned long flags;
0707 phys_addr_t phys;
0708
0709 spin_lock_irqsave(&ac->lock, flags);
0710 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
0711 if (!port->buf) {
0712 spin_unlock_irqrestore(&ac->lock, flags);
0713 ret = 0;
0714 goto done;
0715 }
0716
0717 phys = port->buf[hdr->token].phys;
0718
0719 if (upper_32_bits(phys) != done->buf_addr_msw ||
0720 lower_32_bits(phys) != done->buf_addr_lsw) {
0721 dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
0722 &port->buf[hdr->token].phys,
0723 done->buf_addr_lsw,
0724 done->buf_addr_msw);
0725 spin_unlock_irqrestore(&ac->lock, flags);
0726 ret = -EINVAL;
0727 goto done;
0728 }
0729 spin_unlock_irqrestore(&ac->lock, flags);
0730 }
0731
0732 break;
0733 case ASM_DATA_EVENT_RENDERED_EOS:
0734 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
0735 break;
0736 }
0737
0738 if (ac->cb)
0739 ac->cb(client_event, hdr->token, data->payload, ac->priv);
0740
0741 done:
0742 kref_put(&ac->refcount, q6asm_audio_client_release);
0743 return ret;
0744 }
0745
0746 static int q6asm_srvc_callback(struct apr_device *adev,
0747 struct apr_resp_pkt *data)
0748 {
0749 struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
0750 struct aprv2_ibasic_rsp_result_t *result;
0751 struct audio_port_data *port;
0752 struct audio_client *ac = NULL;
0753 struct apr_hdr *hdr = &data->hdr;
0754 struct q6asm *a;
0755 uint32_t sid = 0;
0756 uint32_t dir = 0;
0757 int session_id;
0758
0759 session_id = (hdr->dest_port >> 8) & 0xFF;
0760 if (session_id)
0761 return q6asm_stream_callback(adev, data, session_id);
0762
0763 sid = (hdr->token >> 8) & 0x0F;
0764 ac = q6asm_get_audio_client(q6asm, sid);
0765 if (!ac) {
0766 dev_err(&adev->dev, "Audio Client not active\n");
0767 return 0;
0768 }
0769
0770 a = dev_get_drvdata(ac->dev->parent);
0771 dir = (hdr->token & 0x0F);
0772 port = &ac->port[dir];
0773 result = data->payload;
0774
0775 switch (hdr->opcode) {
0776 case APR_BASIC_RSP_RESULT:
0777 switch (result->opcode) {
0778 case ASM_CMD_SHARED_MEM_MAP_REGIONS:
0779 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
0780 ac->result = *result;
0781 wake_up(&a->mem_wait);
0782 break;
0783 default:
0784 dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
0785 result->opcode);
0786 break;
0787 }
0788 goto done;
0789 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
0790 ac->result.status = 0;
0791 ac->result.opcode = hdr->opcode;
0792 port->mem_map_handle = result->opcode;
0793 wake_up(&a->mem_wait);
0794 break;
0795 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
0796 ac->result.opcode = hdr->opcode;
0797 ac->result.status = 0;
0798 port->mem_map_handle = 0;
0799 wake_up(&a->mem_wait);
0800 break;
0801 default:
0802 dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
0803 result->opcode, result->status);
0804 break;
0805 }
0806
0807 if (ac->cb)
0808 ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
0809
0810 done:
0811 kref_put(&ac->refcount, q6asm_audio_client_release);
0812
0813 return 0;
0814 }
0815
0816
0817
0818
0819
0820
0821
0822
0823 int q6asm_get_session_id(struct audio_client *c)
0824 {
0825 return c->session;
0826 }
0827 EXPORT_SYMBOL_GPL(q6asm_get_session_id);
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841 struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
0842 void *priv, int session_id,
0843 int perf_mode)
0844 {
0845 struct q6asm *a = dev_get_drvdata(dev->parent);
0846 struct audio_client *ac;
0847 unsigned long flags;
0848
0849 ac = q6asm_get_audio_client(a, session_id + 1);
0850 if (ac) {
0851 dev_err(dev, "Audio Client already active\n");
0852 return ac;
0853 }
0854
0855 ac = kzalloc(sizeof(*ac), GFP_KERNEL);
0856 if (!ac)
0857 return ERR_PTR(-ENOMEM);
0858
0859 spin_lock_irqsave(&a->slock, flags);
0860 a->session[session_id + 1] = ac;
0861 spin_unlock_irqrestore(&a->slock, flags);
0862 ac->session = session_id + 1;
0863 ac->cb = cb;
0864 ac->dev = dev;
0865 ac->q6asm = a;
0866 ac->priv = priv;
0867 ac->io_mode = ASM_SYNC_IO_MODE;
0868 ac->perf_mode = perf_mode;
0869 ac->adev = a->adev;
0870 kref_init(&ac->refcount);
0871
0872 init_waitqueue_head(&ac->cmd_wait);
0873 mutex_init(&ac->cmd_lock);
0874 spin_lock_init(&ac->lock);
0875
0876 return ac;
0877 }
0878 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
0879
0880 static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
0881 {
0882 struct apr_hdr *hdr = &pkt->hdr;
0883 int rc;
0884
0885 mutex_lock(&ac->cmd_lock);
0886 ac->result.opcode = 0;
0887 ac->result.status = 0;
0888
0889 rc = apr_send_pkt(ac->adev, pkt);
0890 if (rc < 0)
0891 goto err;
0892
0893 rc = wait_event_timeout(ac->cmd_wait,
0894 (ac->result.opcode == hdr->opcode), 5 * HZ);
0895 if (!rc) {
0896 dev_err(ac->dev, "CMD %x timeout\n", hdr->opcode);
0897 rc = -ETIMEDOUT;
0898 goto err;
0899 }
0900
0901 if (ac->result.status > 0) {
0902 dev_err(ac->dev, "DSP returned error[%x]\n",
0903 ac->result.status);
0904 rc = -EINVAL;
0905 } else {
0906 rc = 0;
0907 }
0908
0909
0910 err:
0911 mutex_unlock(&ac->cmd_lock);
0912 return rc;
0913 }
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926 int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
0927 uint32_t format, u32 codec_profile,
0928 uint16_t bits_per_sample, bool is_gapless)
0929 {
0930 struct asm_stream_cmd_open_write_v3 *open;
0931 struct apr_pkt *pkt;
0932 void *p;
0933 int rc, pkt_size;
0934
0935 pkt_size = APR_HDR_SIZE + sizeof(*open);
0936
0937 p = kzalloc(pkt_size, GFP_KERNEL);
0938 if (!p)
0939 return -ENOMEM;
0940
0941 pkt = p;
0942 open = p + APR_HDR_SIZE;
0943 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
0944
0945 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
0946 open->mode_flags = 0x00;
0947 open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
0948 if (is_gapless)
0949 open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG);
0950
0951
0952 open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
0953 open->bits_per_sample = bits_per_sample;
0954 open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
0955
0956 switch (format) {
0957 case SND_AUDIOCODEC_MP3:
0958 open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
0959 break;
0960 case FORMAT_LINEAR_PCM:
0961 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
0962 break;
0963 case SND_AUDIOCODEC_FLAC:
0964 open->dec_fmt_id = ASM_MEDIA_FMT_FLAC;
0965 break;
0966 case SND_AUDIOCODEC_WMA:
0967 switch (codec_profile) {
0968 case SND_AUDIOPROFILE_WMA9:
0969 open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9;
0970 break;
0971 case SND_AUDIOPROFILE_WMA10:
0972 case SND_AUDIOPROFILE_WMA9_PRO:
0973 case SND_AUDIOPROFILE_WMA9_LOSSLESS:
0974 case SND_AUDIOPROFILE_WMA10_LOSSLESS:
0975 open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10;
0976 break;
0977 default:
0978 dev_err(ac->dev, "Invalid codec profile 0x%x\n",
0979 codec_profile);
0980 rc = -EINVAL;
0981 goto err;
0982 }
0983 break;
0984 case SND_AUDIOCODEC_ALAC:
0985 open->dec_fmt_id = ASM_MEDIA_FMT_ALAC;
0986 break;
0987 case SND_AUDIOCODEC_APE:
0988 open->dec_fmt_id = ASM_MEDIA_FMT_APE;
0989 break;
0990 default:
0991 dev_err(ac->dev, "Invalid format 0x%x\n", format);
0992 rc = -EINVAL;
0993 goto err;
0994 }
0995
0996 rc = q6asm_ac_send_cmd_sync(ac, pkt);
0997 if (rc < 0)
0998 goto err;
0999
1000 ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
1001
1002 err:
1003 kfree(pkt);
1004 return rc;
1005 }
1006 EXPORT_SYMBOL_GPL(q6asm_open_write);
1007
1008 static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
1009 uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts,
1010 bool wait)
1011 {
1012 struct asm_session_cmd_run_v2 *run;
1013 struct apr_pkt *pkt;
1014 int pkt_size, rc;
1015 void *p;
1016
1017 pkt_size = APR_HDR_SIZE + sizeof(*run);
1018 p = kzalloc(pkt_size, GFP_ATOMIC);
1019 if (!p)
1020 return -ENOMEM;
1021
1022 pkt = p;
1023 run = p + APR_HDR_SIZE;
1024
1025 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1026
1027 pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
1028 run->flags = flags;
1029 run->time_lsw = lsw_ts;
1030 run->time_msw = msw_ts;
1031 if (wait) {
1032 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1033 } else {
1034 rc = apr_send_pkt(ac->adev, pkt);
1035 if (rc == pkt_size)
1036 rc = 0;
1037 }
1038
1039 kfree(pkt);
1040 return rc;
1041 }
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
1055 uint32_t msw_ts, uint32_t lsw_ts)
1056 {
1057 return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true);
1058 }
1059 EXPORT_SYMBOL_GPL(q6asm_run);
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
1073 uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts)
1074 {
1075 return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false);
1076 }
1077 EXPORT_SYMBOL_GPL(q6asm_run_nowait);
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
1092 uint32_t stream_id,
1093 uint32_t rate, uint32_t channels,
1094 u8 channel_map[PCM_MAX_NUM_CHANNEL],
1095 uint16_t bits_per_sample)
1096 {
1097 struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
1098 struct apr_pkt *pkt;
1099 u8 *channel_mapping;
1100 void *p;
1101 int rc, pkt_size;
1102
1103 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1104 p = kzalloc(pkt_size, GFP_KERNEL);
1105 if (!p)
1106 return -ENOMEM;
1107
1108 pkt = p;
1109 fmt = p + APR_HDR_SIZE;
1110
1111 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1112
1113 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1114 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1115 fmt->num_channels = channels;
1116 fmt->bits_per_sample = bits_per_sample;
1117 fmt->sample_rate = rate;
1118 fmt->is_signed = 1;
1119
1120 channel_mapping = fmt->channel_mapping;
1121
1122 if (channel_map) {
1123 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1124 } else {
1125 if (q6dsp_map_channels(channel_mapping, channels)) {
1126 dev_err(ac->dev, " map channels failed %d\n", channels);
1127 rc = -EINVAL;
1128 goto err;
1129 }
1130 }
1131
1132 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1133
1134 err:
1135 kfree(pkt);
1136 return rc;
1137 }
1138 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1139
1140 int q6asm_stream_media_format_block_flac(struct audio_client *ac,
1141 uint32_t stream_id,
1142 struct q6asm_flac_cfg *cfg)
1143 {
1144 struct asm_flac_fmt_blk_v2 *fmt;
1145 struct apr_pkt *pkt;
1146 void *p;
1147 int rc, pkt_size;
1148
1149 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1150 p = kzalloc(pkt_size, GFP_KERNEL);
1151 if (!p)
1152 return -ENOMEM;
1153
1154 pkt = p;
1155 fmt = p + APR_HDR_SIZE;
1156
1157 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1158
1159 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1160 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1161 fmt->is_stream_info_present = cfg->stream_info_present;
1162 fmt->num_channels = cfg->ch_cfg;
1163 fmt->min_blk_size = cfg->min_blk_size;
1164 fmt->max_blk_size = cfg->max_blk_size;
1165 fmt->sample_rate = cfg->sample_rate;
1166 fmt->min_frame_size = cfg->min_frame_size;
1167 fmt->max_frame_size = cfg->max_frame_size;
1168 fmt->sample_size = cfg->sample_size;
1169
1170 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1171 kfree(pkt);
1172
1173 return rc;
1174 }
1175 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
1176
1177 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
1178 uint32_t stream_id,
1179 struct q6asm_wma_cfg *cfg)
1180 {
1181 struct asm_wmastdv9_fmt_blk_v2 *fmt;
1182 struct apr_pkt *pkt;
1183 void *p;
1184 int rc, pkt_size;
1185
1186 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1187 p = kzalloc(pkt_size, GFP_KERNEL);
1188 if (!p)
1189 return -ENOMEM;
1190
1191 pkt = p;
1192 fmt = p + APR_HDR_SIZE;
1193
1194 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1195
1196 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1197 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1198 fmt->fmtag = cfg->fmtag;
1199 fmt->num_channels = cfg->num_channels;
1200 fmt->sample_rate = cfg->sample_rate;
1201 fmt->bytes_per_sec = cfg->bytes_per_sec;
1202 fmt->blk_align = cfg->block_align;
1203 fmt->bits_per_sample = cfg->bits_per_sample;
1204 fmt->channel_mask = cfg->channel_mask;
1205 fmt->enc_options = cfg->enc_options;
1206 fmt->reserved = 0;
1207
1208 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1209 kfree(pkt);
1210
1211 return rc;
1212 }
1213 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
1214
1215 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
1216 uint32_t stream_id,
1217 struct q6asm_wma_cfg *cfg)
1218 {
1219 struct asm_wmaprov10_fmt_blk_v2 *fmt;
1220 struct apr_pkt *pkt;
1221 void *p;
1222 int rc, pkt_size;
1223
1224 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1225 p = kzalloc(pkt_size, GFP_KERNEL);
1226 if (!p)
1227 return -ENOMEM;
1228
1229 pkt = p;
1230 fmt = p + APR_HDR_SIZE;
1231
1232 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1233
1234 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1235 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1236 fmt->fmtag = cfg->fmtag;
1237 fmt->num_channels = cfg->num_channels;
1238 fmt->sample_rate = cfg->sample_rate;
1239 fmt->bytes_per_sec = cfg->bytes_per_sec;
1240 fmt->blk_align = cfg->block_align;
1241 fmt->bits_per_sample = cfg->bits_per_sample;
1242 fmt->channel_mask = cfg->channel_mask;
1243 fmt->enc_options = cfg->enc_options;
1244 fmt->advanced_enc_options1 = cfg->adv_enc_options;
1245 fmt->advanced_enc_options2 = cfg->adv_enc_options2;
1246
1247 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1248 kfree(pkt);
1249
1250 return rc;
1251 }
1252 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
1253
1254 int q6asm_stream_media_format_block_alac(struct audio_client *ac,
1255 uint32_t stream_id,
1256 struct q6asm_alac_cfg *cfg)
1257 {
1258 struct asm_alac_fmt_blk_v2 *fmt;
1259 struct apr_pkt *pkt;
1260 void *p;
1261 int rc, pkt_size;
1262
1263 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1264 p = kzalloc(pkt_size, GFP_KERNEL);
1265 if (!p)
1266 return -ENOMEM;
1267
1268 pkt = p;
1269 fmt = p + APR_HDR_SIZE;
1270
1271 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1272
1273 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1274 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1275
1276 fmt->frame_length = cfg->frame_length;
1277 fmt->compatible_version = cfg->compatible_version;
1278 fmt->bit_depth = cfg->bit_depth;
1279 fmt->num_channels = cfg->num_channels;
1280 fmt->max_run = cfg->max_run;
1281 fmt->max_frame_bytes = cfg->max_frame_bytes;
1282 fmt->avg_bit_rate = cfg->avg_bit_rate;
1283 fmt->sample_rate = cfg->sample_rate;
1284 fmt->channel_layout_tag = cfg->channel_layout_tag;
1285 fmt->pb = cfg->pb;
1286 fmt->mb = cfg->mb;
1287 fmt->kb = cfg->kb;
1288
1289 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1290 kfree(pkt);
1291
1292 return rc;
1293 }
1294 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
1295
1296 int q6asm_stream_media_format_block_ape(struct audio_client *ac,
1297 uint32_t stream_id,
1298 struct q6asm_ape_cfg *cfg)
1299 {
1300 struct asm_ape_fmt_blk_v2 *fmt;
1301 struct apr_pkt *pkt;
1302 void *p;
1303 int rc, pkt_size;
1304
1305 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1306 p = kzalloc(pkt_size, GFP_KERNEL);
1307 if (!p)
1308 return -ENOMEM;
1309
1310 pkt = p;
1311 fmt = p + APR_HDR_SIZE;
1312
1313 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1314
1315 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1316 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1317
1318 fmt->compatible_version = cfg->compatible_version;
1319 fmt->compression_level = cfg->compression_level;
1320 fmt->format_flags = cfg->format_flags;
1321 fmt->blocks_per_frame = cfg->blocks_per_frame;
1322 fmt->final_frame_blocks = cfg->final_frame_blocks;
1323 fmt->total_frames = cfg->total_frames;
1324 fmt->bits_per_sample = cfg->bits_per_sample;
1325 fmt->num_channels = cfg->num_channels;
1326 fmt->sample_rate = cfg->sample_rate;
1327 fmt->seek_table_present = cfg->seek_table_present;
1328
1329 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1330 kfree(pkt);
1331
1332 return rc;
1333 }
1334 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
1335
1336 static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id,
1337 uint32_t cmd,
1338 uint32_t num_samples)
1339 {
1340 uint32_t *samples;
1341 struct apr_pkt *pkt;
1342 void *p;
1343 int rc, pkt_size;
1344
1345 pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
1346 p = kzalloc(pkt_size, GFP_ATOMIC);
1347 if (!p)
1348 return -ENOMEM;
1349
1350 pkt = p;
1351 samples = p + APR_HDR_SIZE;
1352
1353 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1354
1355 pkt->hdr.opcode = cmd;
1356 *samples = num_samples;
1357 rc = apr_send_pkt(ac->adev, pkt);
1358 if (rc == pkt_size)
1359 rc = 0;
1360
1361 kfree(pkt);
1362
1363 return rc;
1364 }
1365
1366 int q6asm_stream_remove_initial_silence(struct audio_client *ac,
1367 uint32_t stream_id,
1368 uint32_t initial_samples)
1369 {
1370 return q6asm_stream_remove_silence(ac, stream_id,
1371 ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
1372 initial_samples);
1373 }
1374 EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
1375
1376 int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
1377 uint32_t trailing_samples)
1378 {
1379 return q6asm_stream_remove_silence(ac, stream_id,
1380 ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
1381 trailing_samples);
1382 }
1383 EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1397 uint32_t stream_id, uint32_t rate,
1398 uint32_t channels,
1399 uint16_t bits_per_sample)
1400 {
1401 struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg;
1402 struct apr_pkt *pkt;
1403 u8 *channel_mapping;
1404 u32 frames_per_buf = 0;
1405 int pkt_size, rc;
1406 void *p;
1407
1408 pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1409 p = kzalloc(pkt_size, GFP_KERNEL);
1410 if (!p)
1411 return -ENOMEM;
1412
1413 pkt = p;
1414 enc_cfg = p + APR_HDR_SIZE;
1415 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1416
1417 pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1418 enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1419 enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1420 enc_cfg->encblk.frames_per_buf = frames_per_buf;
1421 enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size -
1422 sizeof(struct asm_enc_cfg_blk_param_v2);
1423
1424 enc_cfg->num_channels = channels;
1425 enc_cfg->bits_per_sample = bits_per_sample;
1426 enc_cfg->sample_rate = rate;
1427 enc_cfg->is_signed = 1;
1428 channel_mapping = enc_cfg->channel_mapping;
1429
1430 if (q6dsp_map_channels(channel_mapping, channels)) {
1431 rc = -EINVAL;
1432 goto err;
1433 }
1434
1435 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1436 err:
1437 kfree(pkt);
1438 return rc;
1439 }
1440 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451 int q6asm_read(struct audio_client *ac, uint32_t stream_id)
1452 {
1453 struct asm_data_cmd_read_v2 *read;
1454 struct audio_port_data *port;
1455 struct audio_buffer *ab;
1456 struct apr_pkt *pkt;
1457 unsigned long flags;
1458 int pkt_size;
1459 int rc = 0;
1460 void *p;
1461
1462 pkt_size = APR_HDR_SIZE + sizeof(*read);
1463 p = kzalloc(pkt_size, GFP_ATOMIC);
1464 if (!p)
1465 return -ENOMEM;
1466
1467 pkt = p;
1468 read = p + APR_HDR_SIZE;
1469
1470 spin_lock_irqsave(&ac->lock, flags);
1471 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1472 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
1473 ab = &port->buf[port->dsp_buf];
1474 pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1475 read->buf_addr_lsw = lower_32_bits(ab->phys);
1476 read->buf_addr_msw = upper_32_bits(ab->phys);
1477 read->mem_map_handle = port->mem_map_handle;
1478
1479 read->buf_size = ab->size;
1480 read->seq_id = port->dsp_buf;
1481 pkt->hdr.token = port->dsp_buf;
1482
1483 port->dsp_buf++;
1484
1485 if (port->dsp_buf >= port->num_periods)
1486 port->dsp_buf = 0;
1487
1488 spin_unlock_irqrestore(&ac->lock, flags);
1489 rc = apr_send_pkt(ac->adev, pkt);
1490 if (rc == pkt_size)
1491 rc = 0;
1492 else
1493 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1494
1495 kfree(pkt);
1496 return rc;
1497 }
1498 EXPORT_SYMBOL_GPL(q6asm_read);
1499
1500 static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
1501 uint32_t format, uint16_t bits_per_sample)
1502 {
1503 struct asm_stream_cmd_open_read_v3 *open;
1504 struct apr_pkt *pkt;
1505 int pkt_size, rc;
1506 void *p;
1507
1508 pkt_size = APR_HDR_SIZE + sizeof(*open);
1509 p = kzalloc(pkt_size, GFP_KERNEL);
1510 if (!p)
1511 return -ENOMEM;
1512
1513 pkt = p;
1514 open = p + APR_HDR_SIZE;
1515
1516 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1517 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1518
1519 open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1520
1521 open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1522 open->bits_per_sample = bits_per_sample;
1523 open->mode_flags = 0x0;
1524
1525 open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1526 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1527
1528 switch (format) {
1529 case FORMAT_LINEAR_PCM:
1530 open->mode_flags |= 0x00;
1531 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1532 break;
1533 default:
1534 pr_err("Invalid format[%d]\n", format);
1535 }
1536
1537 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1538
1539 kfree(pkt);
1540 return rc;
1541 }
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553 int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
1554 uint32_t format, uint16_t bits_per_sample)
1555 {
1556 return __q6asm_open_read(ac, stream_id, format, bits_per_sample);
1557 }
1558 EXPORT_SYMBOL_GPL(q6asm_open_read);
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572 int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
1573 uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
1574 {
1575 struct asm_data_cmd_write_v2 *write;
1576 struct audio_port_data *port;
1577 struct audio_buffer *ab;
1578 unsigned long flags;
1579 struct apr_pkt *pkt;
1580 int pkt_size;
1581 int rc = 0;
1582 void *p;
1583
1584 pkt_size = APR_HDR_SIZE + sizeof(*write);
1585 p = kzalloc(pkt_size, GFP_ATOMIC);
1586 if (!p)
1587 return -ENOMEM;
1588
1589 pkt = p;
1590 write = p + APR_HDR_SIZE;
1591
1592 spin_lock_irqsave(&ac->lock, flags);
1593 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1594 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
1595
1596 ab = &port->buf[port->dsp_buf];
1597 pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
1598 pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1599 write->buf_addr_lsw = lower_32_bits(ab->phys);
1600 write->buf_addr_msw = upper_32_bits(ab->phys);
1601 write->buf_size = len;
1602 write->seq_id = port->dsp_buf;
1603 write->timestamp_lsw = lsw_ts;
1604 write->timestamp_msw = msw_ts;
1605 write->mem_map_handle =
1606 ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1607
1608 write->flags = wflags;
1609
1610 port->dsp_buf++;
1611
1612 if (port->dsp_buf >= port->num_periods)
1613 port->dsp_buf = 0;
1614
1615 spin_unlock_irqrestore(&ac->lock, flags);
1616 rc = apr_send_pkt(ac->adev, pkt);
1617 if (rc == pkt_size)
1618 rc = 0;
1619
1620 kfree(pkt);
1621 return rc;
1622 }
1623 EXPORT_SYMBOL_GPL(q6asm_write_async);
1624
1625 static void q6asm_reset_buf_state(struct audio_client *ac)
1626 {
1627 struct audio_port_data *port;
1628 unsigned long flags;
1629
1630 spin_lock_irqsave(&ac->lock, flags);
1631 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1632 port->dsp_buf = 0;
1633 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1634 port->dsp_buf = 0;
1635 spin_unlock_irqrestore(&ac->lock, flags);
1636 }
1637
1638 static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
1639 bool wait)
1640 {
1641 struct apr_pkt pkt;
1642 int rc;
1643
1644 q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1645
1646 switch (cmd) {
1647 case CMD_PAUSE:
1648 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1649 break;
1650 case CMD_SUSPEND:
1651 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1652 break;
1653 case CMD_FLUSH:
1654 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1655 break;
1656 case CMD_OUT_FLUSH:
1657 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1658 break;
1659 case CMD_EOS:
1660 pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1661 break;
1662 case CMD_CLOSE:
1663 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1664 break;
1665 default:
1666 return -EINVAL;
1667 }
1668
1669 if (wait)
1670 rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1671 else
1672 return apr_send_pkt(ac->adev, &pkt);
1673
1674 if (rc < 0)
1675 return rc;
1676
1677 if (cmd == CMD_FLUSH)
1678 q6asm_reset_buf_state(ac);
1679
1680 return 0;
1681 }
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692 int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd)
1693 {
1694 return __q6asm_cmd(ac, stream_id, cmd, true);
1695 }
1696 EXPORT_SYMBOL_GPL(q6asm_cmd);
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707 int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd)
1708 {
1709 return __q6asm_cmd(ac, stream_id, cmd, false);
1710 }
1711 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
1712
1713 static int q6asm_probe(struct apr_device *adev)
1714 {
1715 struct device *dev = &adev->dev;
1716 struct q6asm *q6asm;
1717
1718 q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1719 if (!q6asm)
1720 return -ENOMEM;
1721
1722 q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1723
1724 q6asm->dev = dev;
1725 q6asm->adev = adev;
1726 init_waitqueue_head(&q6asm->mem_wait);
1727 spin_lock_init(&q6asm->slock);
1728 dev_set_drvdata(dev, q6asm);
1729
1730 return devm_of_platform_populate(dev);
1731 }
1732
1733 #ifdef CONFIG_OF
1734 static const struct of_device_id q6asm_device_id[] = {
1735 { .compatible = "qcom,q6asm" },
1736 {},
1737 };
1738 MODULE_DEVICE_TABLE(of, q6asm_device_id);
1739 #endif
1740
1741 static struct apr_driver qcom_q6asm_driver = {
1742 .probe = q6asm_probe,
1743 .callback = q6asm_srvc_callback,
1744 .driver = {
1745 .name = "qcom-q6asm",
1746 .of_match_table = of_match_ptr(q6asm_device_id),
1747 },
1748 };
1749
1750 module_apr_driver(qcom_q6asm_driver);
1751 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1752 MODULE_LICENSE("GPL v2");