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 <manish@codeaurora.org>
This commit is contained in:
Manish Dewangan 2016-04-22 12:44:39 +05:30 committed by Kyle Yan
parent e335b6b9da
commit 8b8d412617
6 changed files with 596 additions and 56 deletions

View file

@ -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.
*/

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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__);

View file

@ -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*/);
}
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)
/*
* 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,
stream_id, is_gapless_mode);
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)
{
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,
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)
{