From 8b8d412617b7c16579a7c97b70a61353ceff3e83 Mon Sep 17 00:00:00 2001 From: Manish Dewangan Date: Fri, 22 Apr 2016 12:44:39 +0530 Subject: ASoC: msm: qdspv2: add support for MULTI_CHANNEL_PCM_V3 command Driver changes to use ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 command. This command supports playback/record of both 32 bit (24 bit data in 32 bit word) and 24 bit packed. Update platform drivers to use this for SNDRV_PCM_FORMAT_S24_LE record and playback. CRs-Fixed: 1011048 Change-Id: I6f98bf3402a737bc21daff33b13b137850a690ea Signed-off-by: Manish Dewangan --- include/sound/apr_audio-v2.h | 70 +++++ include/sound/q6asm-v2.h | 41 ++- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 24 +- sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c | 23 +- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 63 +++-- sound/soc/msm/qdsp6v2/q6asm.c | 429 ++++++++++++++++++++++++++++- 6 files changed, 595 insertions(+), 55 deletions(-) diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 809d5223b638..8d9016e3557c 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -3432,6 +3432,16 @@ struct asm_multi_channel_pcm_fmt_blk_v3 { */ } __packed; +/* + * Payload of the multichannel PCM configuration parameters in + * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format. + */ +struct asm_multi_channel_pcm_fmt_blk_param_v3 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + struct asm_multi_channel_pcm_fmt_blk_v3 param; +} __packed; + struct asm_stream_cmd_set_encdec_param { u32 param_id; /* ID of the parameter. */ @@ -3467,6 +3477,66 @@ struct asm_dec_ddp_endp_param_v2 { int endp_param_value; } __packed; + +/* + * Payload of the multichannel PCM encoder configuration parameters in + * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format. + */ + +struct asm_multi_channel_pcm_enc_cfg_v3 { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + uint16_t num_channels; + /* + * Number of PCM channels. + * @values + * - 0 -- Native mode + * - 1 -- 8 channels + * Native mode indicates that encoding must be performed with the number + * of channels at the input. + */ + uint16_t bits_per_sample; + /* + * Number of bits per sample per channel. + * @values 16, 24 + */ + uint32_t sample_rate; + /* + * Number of samples per second. + * @values 0, 8000 to 48000 Hz + * A value of 0 indicates the native sampling rate. Encoding is + * performed at the input sampling rate. + */ + uint16_t is_signed; + /* + * Flag that indicates the PCM samples are signed (1). Currently, only + * signed PCM samples are supported. + */ + uint16_t sample_word_size; + /* + * The size in bits of the word that holds a sample of a channel. + * @values 16, 24, 32 + * 16-bit samples are always placed in 16-bit words: + * sample_word_size = 1. + * 24-bit samples can be placed in 32-bit words or in consecutive + * 24-bit words. + * - If sample_word_size = 32, 24-bit samples are placed in the + * most significant 24 bits of a 32-bit word. + * - If sample_word_size = 24, 24-bit samples are placed in + * 24-bit words. @tablebulletend + */ + uint8_t channel_mapping[8]; + /* + * Channel mapping array expected at the encoder output. + * Channel[i] mapping describes channel i inside the buffer, where + * 0 @le i < num_channels. All valid used channels must be present at + * the beginning of the array. + * If Native mode is set for the channels, this field is ignored. + * @values See Section @xref{dox:PcmChannelDefs} + */ +}; + /* @brief Multichannel PCM encoder configuration structure used * in the #ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 command. */ diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 2f3e33fd28df..8339d538d578 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -241,6 +241,9 @@ int q6asm_open_read(struct audio_client *ac, uint32_t format int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample); +int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + int q6asm_open_write(struct audio_client *ac, uint32_t format /*, uint16_t bits_per_sample*/); @@ -250,9 +253,16 @@ int q6asm_open_write_v2(struct audio_client *ac, uint32_t format, int q6asm_open_shared_io(struct audio_client *ac, struct shared_io_config *c, int dir); +int q6asm_open_write_v3(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample, int32_t stream_id, - bool is_gapless_mode); + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode); + +int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode); int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag); @@ -350,10 +360,21 @@ int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac, bool use_default_chmap, bool use_back_flavor, u8 *channel_map); +int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, bool use_default_chmap, + bool use_back_flavor, u8 *channel_map, + uint16_t sample_word_size); + int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample); +int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size); + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels); @@ -394,6 +415,15 @@ int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac, uint16_t bits_per_sample, int stream_id, bool use_default_chmap, char *channel_map); +int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size); + int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map); @@ -404,6 +434,13 @@ int q6asm_media_format_block_multi_ch_pcm_v2( bool use_default_chmap, char *channel_map, uint16_t bits_per_sample); +int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size); + int q6asm_media_format_block_aac(struct audio_client *ac, struct asm_aac_cfg *cfg); diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 5a0de63e806e..2b3609f7230c 100755 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -677,9 +677,10 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, union snd_codec_options *codec_options; int ret = 0; - uint16_t bit_width = 16; + uint16_t bit_width; bool use_default_chmap = true; char *chmap = NULL; + uint16_t sample_word_size; pr_debug("%s: use_gapless_codec_options %d\n", __func__, use_gapless_codec_options); @@ -703,15 +704,26 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, chmap = pdata->ch_map[rtd->dai_link->be_id]->channel_map; } - if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE) + + switch (prtd->codec_param.codec.format) { + case SNDRV_PCM_FORMAT_S24_LE: bit_width = 24; - ret = q6asm_media_format_block_pcm_format_support_v2( + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bit_width = 16; + sample_word_size = 16; + break; + } + ret = q6asm_media_format_block_pcm_format_support_v3( prtd->audio_client, prtd->sample_rate, prtd->num_channels, bit_width, stream_id, use_default_chmap, - chmap); + chmap, + sample_word_size); if (ret < 0) pr_err("%s: CMD Format block failed\n", __func__); @@ -977,7 +989,7 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream) } else { pr_debug("%s: stream_id %d bits_per_sample %d\n", __func__, ac->stream_id, bits_per_sample); - ret = q6asm_stream_open_write_v2(ac, + ret = q6asm_stream_open_write_v3(ac, prtd->codec, bits_per_sample, ac->stream_id, prtd->gapless_state.use_dsp_gapless_mode); @@ -1897,7 +1909,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) pr_debug("%s: open_write stream_id %d bits_per_sample %d", __func__, stream_id, bits_per_sample); - rc = q6asm_stream_open_write_v2(prtd->audio_client, + rc = q6asm_stream_open_write_v3(prtd->audio_client, prtd->codec, bits_per_sample, stream_id, prtd->gapless_state.use_dsp_gapless_mode); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 856f2b368d41..6e5b4e871fe6 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -87,7 +87,8 @@ static struct snd_pcm_hardware msm_pcm_hardware_playback = { SNDRV_PCM_INFO_NO_PERIOD_WAKEUP | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), .rates = SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, .rate_max = 192000, @@ -110,7 +111,8 @@ static struct snd_pcm_hardware msm_pcm_hardware_capture = { SNDRV_PCM_INFO_NO_PERIOD_WAKEUP | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), .rates = SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, @@ -253,7 +255,7 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream, struct audio_buffer *buf; struct shared_io_config config; uint16_t sample_word_size; - uint16_t bits_per_sample = 16; + uint16_t bits_per_sample; int ret; int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT; @@ -280,16 +282,21 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream, return 0; switch (runtime->format) { - case SNDRV_PCM_FORMAT_S16_LE: - bits_per_sample = 16; - break; case SNDRV_PCM_FORMAT_S24_LE: bits_per_sample = 24; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + bits_per_sample = 24; + sample_word_size = 24; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bits_per_sample = 16; + sample_word_size = 16; break; } - sample_word_size = (bits_per_sample == 16) ? 16 : 32; - config.format = FORMAT_LINEAR_PCM; config.bits_per_sample = bits_per_sample; config.rate = params_rate(params); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index c456134b87fa..7dfa5044ab56 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -280,7 +280,8 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) struct msm_plat_data *pdata; struct snd_pcm_hw_params *params; int ret; - uint16_t bits_per_sample = 16; + uint16_t bits_per_sample; + uint16_t sample_word_size; pdata = (struct msm_plat_data *) dev_get_drvdata(soc_prtd->platform->dev); @@ -308,11 +309,21 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) prtd->audio_client->perf_mode = pdata->perf_mode; pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode); - if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S24_LE: bits_per_sample = 24; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bits_per_sample = 16; + sample_word_size = 16; + break; + } + + ret = q6asm_open_write_v3(prtd->audio_client, + FORMAT_LINEAR_PCM, bits_per_sample); - ret = q6asm_open_write_v2(prtd->audio_client, - FORMAT_LINEAR_PCM, bits_per_sample); if (ret < 0) { pr_err("%s: q6asm_open_write_v2 failed\n", __func__); q6asm_audio_client_free(prtd->audio_client); @@ -335,19 +346,11 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) return ret; } - switch (runtime->format) { - case SNDRV_PCM_FORMAT_S16_LE: - bits_per_sample = 16; - break; - case SNDRV_PCM_FORMAT_S24_LE: - bits_per_sample = 24; - break; - } - - ret = q6asm_media_format_block_multi_ch_pcm_v2( - prtd->audio_client, runtime->rate, - runtime->channels, !prtd->set_channel_map, - prtd->channel_map, bits_per_sample); + ret = q6asm_media_format_block_multi_ch_pcm_v3( + prtd->audio_client, runtime->rate, + runtime->channels, !prtd->set_channel_map, + prtd->channel_map, bits_per_sample, + sample_word_size); if (ret < 0) pr_info("%s: CMD Format block failed\n", __func__); @@ -371,6 +374,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) int ret = 0; int i = 0; uint16_t bits_per_sample = 16; + uint16_t sample_word_size; pdata = (struct msm_plat_data *) dev_get_drvdata(soc_prtd->platform->dev); @@ -401,7 +405,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) __func__, params_channels(params), prtd->audio_client->perf_mode); - ret = q6asm_open_read_v2(prtd->audio_client, FORMAT_LINEAR_PCM, + ret = q6asm_open_read_v3(prtd->audio_client, FORMAT_LINEAR_PCM, bits_per_sample); if (ret < 0) { pr_err("%s: q6asm_open_read failed\n", __func__); @@ -447,18 +451,25 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) return 0; switch (runtime->format) { - case SNDRV_PCM_FORMAT_S16_LE: - bits_per_sample = 16; - break; case SNDRV_PCM_FORMAT_S24_LE: bits_per_sample = 24; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bits_per_sample = 16; + sample_word_size = 16; break; } - pr_debug("Samp_rate = %d\n", prtd->samp_rate); - pr_debug("Channel = %d\n", prtd->channel_mode); - ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client, - prtd->samp_rate, prtd->channel_mode, - bits_per_sample); + + pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n", + __func__, prtd->samp_rate, prtd->channel_mode, + bits_per_sample, sample_word_size); + ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client, + prtd->samp_rate, + prtd->channel_mode, + bits_per_sample, + sample_word_size); if (ret < 0) pr_debug("%s: cmd cfg pcm was block failed", __func__); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 761489b1c436..6409b81c0764 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -2226,8 +2226,10 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr, hdr->pkt_size = pkt_size; return; } + static int __q6asm_open_read(struct audio_client *ac, - uint32_t format, uint16_t bits_per_sample) + uint32_t format, uint16_t bits_per_sample, + bool use_v3_format) { int rc = 0x00; struct asm_stream_cmd_open_read_v3 open; @@ -2270,7 +2272,10 @@ static int __q6asm_open_read(struct audio_client *ac, switch (format) { case FORMAT_LINEAR_PCM: open.mode_flags |= 0x00; - open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + if (use_v3_format) + open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; + else + open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; break; case FORMAT_MPEG4_AAC: open.mode_flags |= BUFFER_META_ENABLE; @@ -2332,15 +2337,32 @@ fail_cmd: int q6asm_open_read(struct audio_client *ac, uint32_t format) { - return __q6asm_open_read(ac, format, 16); + return __q6asm_open_read(ac, format, 16, + false /*use_v3_format*/); } int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { - return __q6asm_open_read(ac, format, bits_per_sample); + return __q6asm_open_read(ac, format, bits_per_sample, + false /*use_v3_format*/); } +/* + * asm_open_read_v3 - Opens audio capture session + * + * @ac: Client session handle + * @format: encoder format + * @bits_per_sample: bit width of capture session + */ +int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_read(ac, format, bits_per_sample, + true /*use_v3_format*/); +} +EXPORT_SYMBOL(q6asm_open_read_v3); + int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag) { @@ -2427,8 +2449,8 @@ fail_cmd: } static int __q6asm_open_write(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample, uint32_t stream_id, - bool is_gapless_mode) + uint16_t bits_per_sample, uint32_t stream_id, + bool is_gapless_mode, bool use_v3_format) { int rc = 0x00; struct asm_stream_cmd_open_write_v3 open; @@ -2504,7 +2526,11 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, } switch (format) { case FORMAT_LINEAR_PCM: - open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + if (use_v3_format) + open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; + else + open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; case FORMAT_MPEG4_AAC: open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2; @@ -2579,23 +2605,61 @@ fail_cmd: int q6asm_open_write(struct audio_client *ac, uint32_t format) { return __q6asm_open_write(ac, format, 16, ac->stream_id, - false /*gapless*/); + false /*gapless*/, + false /*use_v3_format*/); } int q6asm_open_write_v2(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample) + uint16_t bits_per_sample) { return __q6asm_open_write(ac, format, bits_per_sample, - ac->stream_id, false /*gapless*/); + ac->stream_id, false /*gapless*/, + false /*use_v3_format*/); } +/* + * q6asm_open_write_v3 - Opens audio playback session + * + * @ac: Client session handle + * @format: decoder format + * @bits_per_sample: bit width of playback session + */ +int q6asm_open_write_v3(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_write(ac, format, bits_per_sample, + ac->stream_id, false /*gapless*/, + true /*use_v3_format*/); +} +EXPORT_SYMBOL(q6asm_open_write_v3); + int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample, int32_t stream_id, - bool is_gapless_mode) + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode) +{ + return __q6asm_open_write(ac, format, bits_per_sample, + stream_id, is_gapless_mode, + false /*use_v3_format*/); +} + +/* + * q6asm_stream_open_write_v3 - Creates audio stream for playback + * + * @ac: Client session handle + * @format: asm playback format + * @bits_per_sample: bit width of requested stream + * @stream_id: stream id of stream to be associated with this session + * @is_gapless_mode: true if gapless mode needs to be enabled + */ +int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode) { return __q6asm_open_write(ac, format, bits_per_sample, - stream_id, is_gapless_mode); + stream_id, is_gapless_mode, + true /*use_v3_format*/); } +EXPORT_SYMBOL(q6asm_stream_open_write_v3); static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, uint32_t wr_format, bool is_meta_data_mode, @@ -3416,6 +3480,103 @@ fail_cmd: return rc; } +/* + * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @use_default_chmap: true if default channel map to be used + * @use_back_flavor: to configure back left and right channel + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + */ +int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, bool use_default_chmap, + bool use_back_flavor, u8 *channel_map, + uint16_t sample_word_size) +{ + struct asm_multi_channel_pcm_enc_cfg_v3 enc_cfg; + struct asm_enc_cfg_blk_param_v2 enc_fg_blk; + u8 *channel_mapping; + u32 frames_per_buf = 0; + int rc; + + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + rc = -EINVAL; + goto fail_cmd; + } + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&enc_cfg, 0, sizeof(enc_cfg)); + q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE); + atomic_set(&ac->cmd_state, -1); + enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; + enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) - + sizeof(enc_cfg.encdec); + enc_cfg.encblk.frames_per_buf = frames_per_buf; + enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size - + sizeof(enc_fg_blk); + enc_cfg.num_channels = channels; + enc_cfg.bits_per_sample = bits_per_sample; + enc_cfg.sample_rate = rate; + enc_cfg.is_signed = 1; + enc_cfg.sample_word_size = sample_word_size; + channel_mapping = enc_cfg.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + pr_debug("%s: setting default channel map for %d channels", + __func__, channels); + if (q6asm_map_channels(channel_mapping, channels, + use_back_flavor)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + pr_debug("%s: Using pre-defined channel map", __func__); + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout opcode[0x%x]\n", + __func__, enc_cfg.hdr.opcode); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v3); + int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample, bool use_default_chmap, bool use_back_flavor, u8 *channel_map) @@ -3495,6 +3656,15 @@ fail_cmd: return rc; } +static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size) +{ + return q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels, + bits_per_sample, true, false, NULL, + sample_word_size); +} static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample) @@ -3515,6 +3685,26 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample); } +/* + * q6asm_enc_cfg_blk_pcm_format_support_v3 - sends encoder configuration + * parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @sample_word_size: Size in bits of the word that holds a sample of a channel + */ +int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size) +{ + return __q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels, + bits_per_sample, sample_word_size); +} +EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3); + int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac, uint32_t rate, uint32_t channels) { @@ -4066,6 +4256,87 @@ fail_cmd: return rc; } +static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size) +{ + struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt; + u8 *channel_mapping; + int rc; + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&fmt, 0, sizeof(fmt)); + q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id); + atomic_set(&ac->cmd_state, -1); + /* + * Updated the token field with stream/session for compressed playback + * Platform driver must know the the stream with which the command is + * associated + */ + if (ac->io_mode & COMPRESSED_STREAM_IO) + fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) | + (stream_id & 0xFF); + + pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n", + __func__, fmt.hdr.token, stream_id, ac->session); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmt_blk); + fmt.param.num_channels = channels; + fmt.param.bits_per_sample = bits_per_sample; + fmt.param.sample_rate = rate; + fmt.param.is_signed = 1; + fmt.param.sample_word_size = sample_word_size; + channel_mapping = fmt.param.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + if (q6asm_map_channels(channel_mapping, channels, false)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for format update\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} + int q6asm_media_format_block_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels) { @@ -4098,6 +4369,41 @@ int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac, use_default_chmap, channel_map); } +/* + * q6asm_media_format_block_pcm_format_support_v3- sends pcm decoder + * configuration parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @stream_id: stream id of stream to be associated with this session + * @use_default_chmap: true if default channel map to be used + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + */ +int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size) +{ + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + return -EINVAL; + } + return __q6asm_media_format_block_pcm_v3(ac, rate, + channels, bits_per_sample, stream_id, + use_default_chmap, channel_map, + sample_word_size); + +} +EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3); + static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map, @@ -4162,6 +4468,76 @@ fail_cmd: return rc; } +static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size) +{ + struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt; + u8 *channel_mapping; + int rc; + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&fmt, 0, sizeof(fmt)); + q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE); + atomic_set(&ac->cmd_state, -1); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmt_blk); + fmt.param.num_channels = channels; + fmt.param.bits_per_sample = bits_per_sample; + fmt.param.sample_rate = rate; + fmt.param.is_signed = 1; + fmt.param.sample_word_size = sample_word_size; + channel_mapping = fmt.param.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + if (q6asm_map_channels(channel_mapping, channels, false)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for format update\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} + + int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map) @@ -4181,6 +4557,33 @@ int q6asm_media_format_block_multi_ch_pcm_v2( bits_per_sample); } +/* + * q6asm_media_format_block_multi_ch_pcm_v3 - sends pcm decoder configuration + * parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @use_default_chmap: true if default channel map to be used + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + */ +int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, + uint32_t rate, uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size) +{ + return __q6asm_media_format_block_multi_ch_pcm_v3(ac, rate, channels, + use_default_chmap, + channel_map, + bits_per_sample, + sample_word_size); +} +EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3); + static int __q6asm_media_format_block_multi_aac(struct audio_client *ac, struct asm_aac_cfg *cfg, int stream_id) { -- cgit v1.2.3