diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c index c4fecdefa2b3..c0d8614559f1 100644 --- a/asoc/msm-compress-q6-v2.c +++ b/asoc/msm-compress-q6-v2.c @@ -1432,6 +1432,7 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) int dir = OUT, ret = 0; struct audio_client *ac = prtd->audio_client; uint32_t stream_index; + uint32_t enc_cfg_id = ENC_CFG_ID_NONE; switch (prtd->codec_param.codec.format) { case SNDRV_PCM_FORMAT_S24_LE: @@ -1450,6 +1451,9 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) default: bits_per_sample = 16; sample_word_size = 16; + if (prtd->codec == FORMAT_BESPOKE) + enc_cfg_id = + prtd->codec_param.codec.options.generic.reserved[0]; 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); if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) { - ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, - bits_per_sample, true); + ret = q6asm_open_read_v4(prtd->audio_client, prtd->codec, + bits_per_sample, true, enc_cfg_id); } else { - ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, - bits_per_sample, false); + ret = q6asm_open_read_v4(prtd->audio_client, prtd->codec, + bits_per_sample, false, enc_cfg_id); } if (ret < 0) { 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", __func__, prtd->sample_rate, prtd->num_channels, 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, bits_per_sample, sample_word_size, ASM_LITTLE_ENDIAN, DEFAULT_QF); + } return ret; } @@ -2043,6 +2057,12 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream, break; } + case SND_AUDIOCODEC_BESPOKE: { + pr_debug("%s: SND_AUDIOCODEC_BESPOKE\n", __func__); + prtd->codec = FORMAT_BESPOKE; + break; + } + default: pr_err("codec not supported, id =%d\n", params->codec.id); return -EINVAL; diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c index b82128e7fabe..8ae85b743686 100644 --- a/asoc/msm-pcm-q6-v2.c +++ b/asoc/msm-pcm-q6-v2.c @@ -490,7 +490,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) prtd->audio_client->perf_mode); 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) { pr_err("%s: q6asm_open_read failed\n", __func__); q6asm_audio_client_free(prtd->audio_client); diff --git a/asoc/sm8150.c b/asoc/sm8150.c index f4bc02a0c5cb..df16270e8be6 100644 --- a/asoc/sm8150.c +++ b/asoc/sm8150.c @@ -5668,6 +5668,21 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, + { + .name = "Compress Capture", + .stream_name = "Compress9", + .cpu_dai_name = "MultiMedia17", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA17, + }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { diff --git a/dsp/q6asm.c b/dsp/q6asm.c index a12347966f5a..38ddc88b0f24 100644 --- a/dsp/q6asm.c +++ b/dsp/q6asm.c @@ -46,6 +46,8 @@ #define FALSE 0x00 #define SESSION_MAX 8 +#define ENC_FRAMES_PER_BUFFER 0x01 + enum { ASM_TOPOLOGY_CAL = 0, 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, uint32_t format, uint16_t bits_per_sample, uint32_t pcm_format_block_ver, - bool ts_mode) + bool ts_mode, uint32_t enc_cfg_id) { int rc = 0x00; 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.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS; 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: pr_err("%s: Invalid format 0x%x\n", __func__, format); @@ -2939,7 +2947,7 @@ int q6asm_open_read(struct audio_client *ac, { return __q6asm_open_read(ac, format, 16, PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, - false/*ts_mode*/); + false/*ts_mode*/, ENC_CFG_ID_NONE); } 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, 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, PCM_MEDIA_FORMAT_V3/*media fmt block ver*/, - false/*ts_mode*/); + false/*ts_mode*/, ENC_CFG_ID_NONE); } EXPORT_SYMBOL(q6asm_open_read_v3); @@ -2976,11 +2984,12 @@ EXPORT_SYMBOL(q6asm_open_read_v3); * @ts_mode: timestamp mode */ 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, PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/, - ts_mode); + ts_mode, enc_cfg_id); } 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); } +/** + * 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 - * command to set encode cfg block for aac diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index a282f78b33d6..5f62a2711d6e 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -4743,6 +4743,22 @@ struct asm_enc_cfg_blk_param_v2 { } __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 */ struct asm_dec_ddp_endp_param_v2 { diff --git a/include/dsp/q6asm-v2.h b/include/dsp/q6asm-v2.h index ba35779a5788..e6f021db7e88 100644 --- a/include/dsp/q6asm-v2.h +++ b/include/dsp/q6asm-v2.h @@ -57,11 +57,14 @@ #define FORMAT_GEN_COMPR 0x001f #define FORMAT_TRUEHD 0x0020 #define FORMAT_IEC61937 0x0021 +#define FORMAT_BESPOKE 0x0022 #define ENCDEC_SBCBITRATE 0x0001 #define ENCDEC_IMMEDIATE_DECODE 0x0002 #define ENCDEC_CFG_BLK 0x0003 +#define ENC_CFG_ID_NONE 0x0000 + #define CMD_PAUSE 0x0001 #define CMD_FLUSH 0x0002 #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); 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 /*, 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 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, uint32_t num_channels);