dsp: Add support for custom encoder

Add support to set custom encoder in ASM which
can be enabled through compress capture path.

Change-Id: I563c59eb3a0213c26ce69d3c2f8d650cf3c7d32d
Signed-off-by: Vikram Panduranga <vpandura@codeaurora.org>
This commit is contained in:
Vikram Panduranga
2017-11-17 17:36:49 -08:00
committed by Gerrit - the friendly Code Review server
parent 743a507eb0
commit c712c17ab0
5 changed files with 155 additions and 13 deletions

View File

@@ -1432,6 +1432,7 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
int dir = OUT, ret = 0; int dir = OUT, ret = 0;
struct audio_client *ac = prtd->audio_client; struct audio_client *ac = prtd->audio_client;
uint32_t stream_index; uint32_t stream_index;
uint32_t enc_cfg_id = ENC_CFG_ID_NONE;
switch (prtd->codec_param.codec.format) { switch (prtd->codec_param.codec.format) {
case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_LE:
@@ -1450,6 +1451,9 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
default: default:
bits_per_sample = 16; bits_per_sample = 16;
sample_word_size = 16; sample_word_size = 16;
if (prtd->codec == FORMAT_BESPOKE)
enc_cfg_id =
prtd->codec_param.codec.options.generic.reserved[0];
break; break;
} }
@@ -1457,11 +1461,11 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
__func__, ac->stream_id, bits_per_sample); __func__, ac->stream_id, bits_per_sample);
if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) { if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) {
ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, ret = q6asm_open_read_v4(prtd->audio_client, prtd->codec,
bits_per_sample, true); bits_per_sample, true, enc_cfg_id);
} else { } else {
ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, ret = q6asm_open_read_v4(prtd->audio_client, prtd->codec,
bits_per_sample, false); bits_per_sample, false, enc_cfg_id);
} }
if (ret < 0) { if (ret < 0) {
pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret); pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret);
@@ -1521,10 +1525,20 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n", pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n",
__func__, prtd->sample_rate, prtd->num_channels, __func__, prtd->sample_rate, prtd->num_channels,
bits_per_sample, sample_word_size); bits_per_sample, sample_word_size);
ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client, if (prtd->codec == FORMAT_BESPOKE) {
/*
* For BESPOKE codec, encoder specific config params are
* included as part of generic.
*/
ret = q6asm_enc_cfg_blk_custom(prtd->audio_client, prtd->sample_rate,
prtd->num_channels, prtd->codec,
(void *)&prtd->codec_param.codec.options.generic);
} else {
ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client,
prtd->sample_rate, prtd->num_channels, prtd->sample_rate, prtd->num_channels,
bits_per_sample, sample_word_size, bits_per_sample, sample_word_size,
ASM_LITTLE_ENDIAN, DEFAULT_QF); ASM_LITTLE_ENDIAN, DEFAULT_QF);
}
return ret; return ret;
} }
@@ -2043,6 +2057,12 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream,
break; break;
} }
case SND_AUDIOCODEC_BESPOKE: {
pr_debug("%s: SND_AUDIOCODEC_BESPOKE\n", __func__);
prtd->codec = FORMAT_BESPOKE;
break;
}
default: default:
pr_err("codec not supported, id =%d\n", params->codec.id); pr_err("codec not supported, id =%d\n", params->codec.id);
return -EINVAL; return -EINVAL;

View File

@@ -490,7 +490,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
prtd->audio_client->perf_mode); prtd->audio_client->perf_mode);
ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
bits_per_sample, false); bits_per_sample, false, ENC_CFG_ID_NONE);
if (ret < 0) { if (ret < 0) {
pr_err("%s: q6asm_open_read failed\n", __func__); pr_err("%s: q6asm_open_read failed\n", __func__);
q6asm_audio_client_free(prtd->audio_client); q6asm_audio_client_free(prtd->audio_client);

View File

@@ -46,6 +46,8 @@
#define FALSE 0x00 #define FALSE 0x00
#define SESSION_MAX 8 #define SESSION_MAX 8
#define ENC_FRAMES_PER_BUFFER 0x01
enum { enum {
ASM_TOPOLOGY_CAL = 0, ASM_TOPOLOGY_CAL = 0,
ASM_CUSTOM_TOP_CAL, ASM_CUSTOM_TOP_CAL,
@@ -2812,7 +2814,7 @@ EXPORT_SYMBOL(q6asm_set_soft_volume_module_instance_ids);
static int __q6asm_open_read(struct audio_client *ac, 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,
uint32_t pcm_format_block_ver, uint32_t pcm_format_block_ver,
bool ts_mode) bool ts_mode, uint32_t enc_cfg_id)
{ {
int rc = 0x00; int rc = 0x00;
struct asm_stream_cmd_open_read_v3 open; struct asm_stream_cmd_open_read_v3 open;
@@ -2888,6 +2890,12 @@ static int __q6asm_open_read(struct audio_client *ac,
open.mode_flags |= BUFFER_META_ENABLE; open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS; open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
break; break;
case FORMAT_BESPOKE:
open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = enc_cfg_id;
if (ts_mode)
open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
break;
default: default:
pr_err("%s: Invalid format 0x%x\n", pr_err("%s: Invalid format 0x%x\n",
__func__, format); __func__, format);
@@ -2939,7 +2947,7 @@ int q6asm_open_read(struct audio_client *ac,
{ {
return __q6asm_open_read(ac, format, 16, return __q6asm_open_read(ac, format, 16,
PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
false/*ts_mode*/); false/*ts_mode*/, ENC_CFG_ID_NONE);
} }
EXPORT_SYMBOL(q6asm_open_read); EXPORT_SYMBOL(q6asm_open_read);
@@ -2948,7 +2956,7 @@ int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
{ {
return __q6asm_open_read(ac, format, bits_per_sample, return __q6asm_open_read(ac, format, bits_per_sample,
PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
false/*ts_mode*/); false/*ts_mode*/, ENC_CFG_ID_NONE);
} }
/* /*
@@ -2963,7 +2971,7 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
{ {
return __q6asm_open_read(ac, format, bits_per_sample, return __q6asm_open_read(ac, format, bits_per_sample,
PCM_MEDIA_FORMAT_V3/*media fmt block ver*/, PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
false/*ts_mode*/); false/*ts_mode*/, ENC_CFG_ID_NONE);
} }
EXPORT_SYMBOL(q6asm_open_read_v3); EXPORT_SYMBOL(q6asm_open_read_v3);
@@ -2976,11 +2984,12 @@ EXPORT_SYMBOL(q6asm_open_read_v3);
* @ts_mode: timestamp mode * @ts_mode: timestamp mode
*/ */
int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, bool ts_mode) uint16_t bits_per_sample, bool ts_mode,
uint32_t enc_cfg_id)
{ {
return __q6asm_open_read(ac, format, bits_per_sample, return __q6asm_open_read(ac, format, bits_per_sample,
PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/, PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
ts_mode); ts_mode, enc_cfg_id);
} }
EXPORT_SYMBOL(q6asm_open_read_v4); EXPORT_SYMBOL(q6asm_open_read_v4);
@@ -4287,6 +4296,95 @@ int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id); return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
} }
/**
* q6asm_enc_cfg_blk_custom -
* command to set encode cfg block for custom
*
* @ac: Audio client handle
* @sample_rate: Sample rate
* @channels: number of ASM channels
* @format: custom format flag
* @cfg: generic encoder config
*
* Returns 0 on success or error on failure
*/
int q6asm_enc_cfg_blk_custom(struct audio_client *ac,
uint32_t sample_rate, uint32_t channels,
uint32_t format, void *cfg)
{
struct asm_custom_enc_cfg_t_v2 enc_cfg;
int rc = 0;
uint32_t custom_size;
struct snd_enc_generic *enc_generic = (struct snd_enc_generic *) cfg;
custom_size = enc_generic->reserved[1];
pr_debug("%s: session[%d] size[%d] res[2]=[%d] res[3]=[%d]\n",
__func__, ac->session, custom_size, enc_generic->reserved[2],
enc_generic->reserved[3]);
pr_debug("%s: res[4]=[%d] sr[%d] ch[%d] format[%d]\n",
__func__, enc_generic->reserved[4], sample_rate,
channels, format);
memset(&enc_cfg, 0, sizeof(struct asm_custom_enc_cfg_t_v2));
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(struct asm_custom_enc_cfg_t_v2) -
sizeof(struct asm_stream_cmd_set_encdec_param);
enc_cfg.encblk.frames_per_buf = ENC_FRAMES_PER_BUFFER;
enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
sizeof(struct asm_enc_cfg_blk_param_v2);
enc_cfg.num_channels = channels;
enc_cfg.sample_rate = sample_rate;
if (q6asm_map_channels(enc_cfg.channel_mapping, channels, false)) {
pr_err("%s: map channels failed %d\n",
__func__, channels);
rc = -EINVAL;
goto fail_cmd;
}
if (format == FORMAT_BESPOKE && custom_size &&
custom_size <= sizeof(enc_cfg.custom_data)) {
memcpy(enc_cfg.custom_data, &enc_generic->reserved[2],
custom_size);
enc_cfg.custom_size = custom_size;
}
rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
if (rc < 0) {
pr_err("%s: Comamnd %d failed %d\n",
__func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, 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;
}
EXPORT_SYMBOL(q6asm_enc_cfg_blk_custom);
/** /**
* q6asm_enc_cfg_blk_aac - * q6asm_enc_cfg_blk_aac -
* command to set encode cfg block for aac * command to set encode cfg block for aac

View File

@@ -4743,6 +4743,22 @@ struct asm_enc_cfg_blk_param_v2 {
} __packed; } __packed;
struct asm_custom_enc_cfg_t_v2 {
struct apr_hdr hdr;
struct asm_stream_cmd_set_encdec_param encdec;
struct asm_enc_cfg_blk_param_v2 encblk;
uint32_t sample_rate;
uint16_t num_channels;
uint16_t reserved;
/* num_ch == 1, then PCM_CHANNEL_C,
* num_ch == 2, then {PCM_CHANNEL_L, PCM_CHANNEL_R}
*/
uint8_t channel_mapping[8];
uint32_t custom_size;
uint8_t custom_data[15];
} __packed;
/* @brief Dolby Digital Plus end point configuration structure /* @brief Dolby Digital Plus end point configuration structure
*/ */
struct asm_dec_ddp_endp_param_v2 { struct asm_dec_ddp_endp_param_v2 {

View File

@@ -57,11 +57,14 @@
#define FORMAT_GEN_COMPR 0x001f #define FORMAT_GEN_COMPR 0x001f
#define FORMAT_TRUEHD 0x0020 #define FORMAT_TRUEHD 0x0020
#define FORMAT_IEC61937 0x0021 #define FORMAT_IEC61937 0x0021
#define FORMAT_BESPOKE 0x0022
#define ENCDEC_SBCBITRATE 0x0001 #define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002 #define ENCDEC_IMMEDIATE_DECODE 0x0002
#define ENCDEC_CFG_BLK 0x0003 #define ENCDEC_CFG_BLK 0x0003
#define ENC_CFG_ID_NONE 0x0000
#define CMD_PAUSE 0x0001 #define CMD_PAUSE 0x0001
#define CMD_FLUSH 0x0002 #define CMD_FLUSH 0x0002
#define CMD_EOS 0x0003 #define CMD_EOS 0x0003
@@ -290,7 +293,8 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample); uint16_t bits_per_sample);
int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, bool ts_mode); uint16_t bits_per_sample, bool ts_mode,
uint32_t enc_cfg_id);
int q6asm_open_write(struct audio_client *ac, uint32_t format int q6asm_open_write(struct audio_client *ac, uint32_t format
/*, uint16_t bits_per_sample*/); /*, uint16_t bits_per_sample*/);
@@ -454,6 +458,10 @@ int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
uint16_t endianness, uint16_t endianness,
uint16_t mode); uint16_t mode);
int q6asm_enc_cfg_blk_custom(struct audio_client *ac,
uint32_t sample_rate, uint32_t channels,
uint32_t format, void *cfg);
int q6asm_set_encdec_chan_map(struct audio_client *ac, int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels); uint32_t num_channels);