Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
0003 // Copyright (c) 2018, Linaro Limited
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 /* Bit shift for the stream_perf_mode subfield. */
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  /* tunnel read write mode */
0066 #define ASM_TUN_WRITE_IO_MODE       0x0008  /* tunnel read write mode */
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;      /* size of buffer */
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     /* idx:1 out port, 0: in port */
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  * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
0386  *
0387  * @dir: direction of audio stream
0388  * @ac: audio client instanace
0389  *
0390  * Return: Will be an negative value on failure or zero on success
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     /* DSP expects size should be aligned to 4K */
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  * q6asm_map_memory_regions() - map memory regions in the dsp.
0491  *
0492  * @dir: direction of audio stream
0493  * @ac: audio client instanace
0494  * @phys: physical address that needs mapping.
0495  * @period_sz: audio period size
0496  * @periods: number of periods
0497  *
0498  * Return: Will be an negative value on failure or zero on success
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  * q6asm_audio_client_free() - Freee allocated audio client
0566  *
0567  * @ac: audio client to free
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     /* check for valid session */
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)/* Audio client might already be freed by now */
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  * q6asm_get_session_id() - get session id for audio client
0818  *
0819  * @c: audio client pointer
0820  *
0821  * Return: Will be an session id of the audio client.
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  * q6asm_audio_client_alloc() - Allocate a new audio client
0831  *
0832  * @dev: Pointer to asm child device.
0833  * @cb: event callback.
0834  * @priv: private data associated with this client.
0835  * @session_id: session id
0836  * @perf_mode: performace mode for this client
0837  *
0838  * Return: Will be an error pointer on error or a valid audio client
0839  * on success.
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  * q6asm_open_write() - Open audio client for writing
0917  * @ac: audio client pointer
0918  * @stream_id: stream id of q6asm session
0919  * @format: audio sample format
0920  * @codec_profile: compressed format profile
0921  * @bits_per_sample: bits per sample
0922  * @is_gapless: flag to indicate if this is a gapless stream
0923  *
0924  * Return: Will be an negative value on error or zero on success
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     /* source endpoint : matrix */
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  * q6asm_run() - start the audio client
1045  *
1046  * @ac: audio client pointer
1047  * @stream_id: stream id of q6asm session
1048  * @flags: flags associated with write
1049  * @msw_ts: timestamp msw
1050  * @lsw_ts: timestamp lsw
1051  *
1052  * Return: Will be an negative value on error or zero on success
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  * q6asm_run_nowait() - start the audio client withou blocking
1063  *
1064  * @ac: audio client pointer
1065  * @stream_id: stream id
1066  * @flags: flags associated with write
1067  * @msw_ts: timestamp msw
1068  * @lsw_ts: timestamp lsw
1069  *
1070  * Return: Will be an negative value on error or zero on success
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  * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
1081  *
1082  * @ac: audio client pointer
1083  * @stream_id: stream id
1084  * @rate: audio sample rate
1085  * @channels: number of audio channels.
1086  * @channel_map: channel map pointer
1087  * @bits_per_sample: bits per sample
1088  *
1089  * Return: Will be an negative value on error or zero on success
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  * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1387  *
1388  * @ac: audio client pointer
1389  * @stream_id: stream id
1390  * @rate: audio sample rate
1391  * @channels: number of audio channels.
1392  * @bits_per_sample: bits per sample
1393  *
1394  * Return: Will be an negative value on error or zero on success
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  * q6asm_read() - read data of period size from audio client
1445  *
1446  * @ac: audio client pointer
1447  * @stream_id: stream id
1448  *
1449  * Return: Will be an negative value on error or zero on success
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     /* Stream prio : High, provide meta info with encoded frames */
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  * q6asm_open_read() - Open audio client for reading
1545  *
1546  * @ac: audio client pointer
1547  * @stream_id: stream id
1548  * @format: audio sample format
1549  * @bits_per_sample: bits per sample
1550  *
1551  * Return: Will be an negative value on error or zero on success
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  * q6asm_write_async() - non blocking write
1562  *
1563  * @ac: audio client pointer
1564  * @stream_id: stream id
1565  * @len: length in bytes
1566  * @msw_ts: timestamp msw
1567  * @lsw_ts: timestamp lsw
1568  * @wflags: flags associated with write
1569  *
1570  * Return: Will be an negative value on error or zero on success
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  * q6asm_cmd() - run cmd on audio client
1685  *
1686  * @ac: audio client pointer
1687  * @stream_id: stream id
1688  * @cmd: command to run on audio client.
1689  *
1690  * Return: Will be an negative value on error or zero on success
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  * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1700  *
1701  * @ac: audio client pointer
1702  * @stream_id: stream id
1703  * @cmd: command to run on audio client.
1704  *
1705  * Return: Will be an negative value on error or zero on success
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");