From 774228d053cc54c98fc0da712c5a36e4b816af7b Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Mon, 16 Jan 2017 15:17:50 +0530 Subject: [PATCH 1/2] ALSA: compress: Add APTX format support in ALSA Extend ALSA (Advanced Linux Sound Architecture) compress to support APTX format. CRs-Fixed: 1106128 Change-Id: I301c3fac1f0e267ca82f20a42437bae86a22413c Signed-off-by: Dhanalakshmi Siddani --- include/uapi/sound/compress_params.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index ef96966b2bbe..6a297ad6d380 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -103,7 +103,8 @@ #define SND_AUDIOCODEC_ALAC ((__u32) 0x00000019) #define SND_AUDIOCODEC_APE ((__u32) 0x00000020) #define SND_AUDIOCODEC_DSD ((__u32) 0x00000021) -#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_DSD +#define SND_AUDIOCODEC_APTX ((__u32) 0x00000022) +#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APTX /* * Profile and modes are listed with bit masks. This allows for a * more compact representation of fields that will not evolve @@ -396,6 +397,12 @@ struct snd_dec_ape { __u32 seek_table_present; }; +struct snd_dec_aptx { + __u32 lap; + __u32 uap; + __u32 nap; +}; + union snd_codec_options { struct snd_enc_wma wma; struct snd_enc_vorbis vorbis; @@ -407,6 +414,7 @@ union snd_codec_options { struct snd_dec_vorbis vorbis_dec; struct snd_dec_alac alac; struct snd_dec_ape ape; + struct snd_dec_aptx aptx_dec; }; /** struct snd_codec_desc - description of codec capabilities From 9d558f7ecfa0c4cf393a60f6acbbd00f50b7455f Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Mon, 26 Dec 2016 16:01:43 +0530 Subject: [PATCH 2/2] ASoC: msm: Aptx decoder integration changes Add changes to support aptx decoder in offload mode. Add support to set BT device address and add new mixer control to set license key. CRs-Fixed: 1106128 Change-Id: Idd4ec8ab829883ef4848be8b686e24101ccbed60 Signed-off-by: Dhanalakshmi Siddani --- include/sound/apr_audio-v2.h | 30 +++++- include/sound/q6asm-v2.h | 10 +- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 31 +++++- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 30 ++++++ sound/soc/msm/qdsp6v2/q6asm.c | 117 +++++++++++++++++++++ 5 files changed, 213 insertions(+), 5 deletions(-) diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 38d49a2af8be..651f74b1d955 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -4924,8 +4924,8 @@ struct asm_amrwbplus_fmt_blk_v2 { } __packed; -#define ASM_MEDIA_FMT_AC3 0x00010DEE -#define ASM_MEDIA_FMT_EAC3 0x00010DEF +#define ASM_MEDIA_FMT_AC3 0x00010DEE +#define ASM_MEDIA_FMT_EAC3 0x00010DEF #define ASM_MEDIA_FMT_DTS 0x00010D88 #define ASM_MEDIA_FMT_MP2 0x00010DE9 #define ASM_MEDIA_FMT_FLAC 0x00010C16 @@ -4934,7 +4934,6 @@ struct asm_amrwbplus_fmt_blk_v2 { #define ASM_MEDIA_FMT_APE 0x00012F32 #define ASM_MEDIA_FMT_DSD 0x00012F3E - /* Media format ID for adaptive transform acoustic coding. This * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command * only. @@ -8941,6 +8940,31 @@ struct asm_dts_eagle_param_get { struct asm_stream_cmd_get_pp_params_v2 param; } __packed; +/* Opcode to set BT address and license for aptx decoder */ +#define APTX_DECODER_BT_ADDRESS 0x00013201 +#define APTX_CLASSIC_DEC_LICENSE_ID 0x00013202 + +struct aptx_dec_bt_addr_cfg { + uint32_t lap; + uint32_t uap; + uint32_t nap; +} __packed; + +struct aptx_dec_bt_dev_addr { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct aptx_dec_bt_addr_cfg bt_addr_cfg; +} __packed; + +struct asm_aptx_dec_fmt_blk_v2 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmtblk; + u32 sample_rate; +/* Number of samples per second. + * Supported values: 44100 and 48000 Hz + */ +} __packed; + /* LSM Specific */ #define VW_FEAT_DIM (39) diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index efa5af8e661c..a1f2f00ee690 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -53,6 +53,7 @@ #define FORMAT_G711_MLAW_FS 0x001b #define FORMAT_DTS 0x001c #define FORMAT_DSD 0x001d +#define FORMAT_APTX 0x001e #define ENCDEC_SBCBITRATE 0x0001 #define ENCDEC_IMMEDIATE_DECODE 0x0002 @@ -552,6 +553,9 @@ int q6asm_media_format_block_ape(struct audio_client *ac, int q6asm_media_format_block_dsd(struct audio_client *ac, struct asm_dsd_cfg *cfg, int stream_id); +int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac, + uint32_t sr, int stream_id); + int q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id, int param_value); @@ -574,6 +578,10 @@ int q6asm_dts_eagle_set(struct audio_client *ac, int param_id, uint32_t size, int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size, void *data, struct param_outband *po, int m_id); +/* Send aptx decoder BT address */ +int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac, + struct aptx_dec_bt_addr_cfg *cfg); + /* Set SoftPause Params */ int q6asm_set_softpause(struct audio_client *ac, struct asm_softpause_params *param); diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 9421d03f6a8d..f5b8c396717f 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -754,7 +754,7 @@ static void populate_codec_list(struct msm_compr_audio *prtd) COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; prtd->compr_cap.max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; - prtd->compr_cap.num_codecs = 14; + prtd->compr_cap.num_codecs = 15; prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3; prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC; prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3; @@ -769,6 +769,7 @@ static void populate_codec_list(struct msm_compr_audio *prtd) prtd->compr_cap.codecs[11] = SND_AUDIOCODEC_APE; prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS; prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD; + prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX; } static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, @@ -788,6 +789,7 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, struct asm_alac_cfg alac_cfg; struct asm_ape_cfg ape_cfg; struct asm_dsd_cfg dsd_cfg; + struct aptx_dec_bt_addr_cfg aptx_cfg; union snd_codec_options *codec_options; int ret = 0; @@ -1022,6 +1024,24 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, pr_err("%s: CMD DSD Format block failed ret %d\n", __func__, ret); break; + case FORMAT_APTX: + pr_debug("SND_AUDIOCODEC_APTX\n"); + memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg)); + ret = q6asm_stream_media_format_block_aptx_dec( + prtd->audio_client, + prtd->sample_rate, + stream_id); + if (ret >= 0) { + aptx_cfg.nap = codec_options->aptx_dec.nap; + aptx_cfg.uap = codec_options->aptx_dec.uap; + aptx_cfg.lap = codec_options->aptx_dec.lap; + q6asm_set_aptx_dec_bt_addr(prtd->audio_client, + &aptx_cfg); + } else { + pr_err("%s: CMD Format block failed ret %d\n", + __func__, ret); + } + break; default: pr_debug("%s, unsupported format, skip", __func__); break; @@ -1789,6 +1809,12 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream, break; } + case SND_AUDIOCODEC_APTX: { + pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__); + prtd->codec = FORMAT_APTX; + break; + } + default: pr_err("codec not supported, id =%d\n", params->codec.id); return -EINVAL; @@ -2659,6 +2685,7 @@ static int msm_compr_get_codec_caps(struct snd_compr_stream *cstream, case SND_AUDIOCODEC_DTS: break; case SND_AUDIOCODEC_DSD: + case SND_AUDIOCODEC_APTX: break; default: pr_err("%s: Unsupported audio codec %d\n", @@ -3071,6 +3098,7 @@ static int msm_compr_send_dec_params(struct snd_compr_stream *cstream, switch (prtd->codec) { case FORMAT_MP3: case FORMAT_MPEG4_AAC: + case FORMAT_APTX: pr_debug("%s: no runtime parameters for codec: %d\n", __func__, prtd->codec); break; @@ -3137,6 +3165,7 @@ static int msm_compr_dec_params_put(struct snd_kcontrol *kcontrol, case FORMAT_APE: case FORMAT_DTS: case FORMAT_DSD: + case FORMAT_APTX: pr_debug("%s: no runtime parameters for codec: %d\n", __func__, prtd->codec); break; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 485ffa06f5bd..7d398440226c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -12050,6 +12050,33 @@ static const struct snd_kcontrol_new device_pp_params_mixer_controls[] = { msm_routing_put_device_pp_params_mixer), }; +static int msm_aptx_dec_license_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = + core_get_license_status(ASM_MEDIA_FMT_APTX); + pr_debug("%s: status %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_aptx_dec_license_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int32_t status = 0; + + status = core_set_license(ucontrol->value.integer.value[0], + APTX_CLASSIC_DEC_LICENSE_ID); + pr_debug("%s: status %d\n", __func__, status); + return status; +} + +static const struct snd_kcontrol_new aptx_dec_license_controls[] = { + SOC_SINGLE_EXT("APTX Dec License", SND_SOC_NOPM, 0, + 0xFFFF, 0, msm_aptx_dec_license_control_get, + msm_aptx_dec_license_control_put), +}; + static struct snd_pcm_ops msm_routing_pcm_ops = { .hw_params = msm_pcm_routing_hw_params, .close = msm_pcm_routing_close, @@ -12102,6 +12129,9 @@ static int msm_routing_probe(struct snd_soc_platform *platform) ARRAY_SIZE(msm_source_tracking_controls)); snd_soc_add_platform_controls(platform, adm_channel_config_controls, ARRAY_SIZE(adm_channel_config_controls)); + + snd_soc_add_platform_controls(platform, aptx_dec_license_controls, + ARRAY_SIZE(aptx_dec_license_controls)); return 0; } diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index cfaa562fdaba..d15541548122 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -2661,6 +2661,9 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, case FORMAT_DSD: open.dec_fmt_id = ASM_MEDIA_FMT_DSD; break; + case FORMAT_APTX: + open.dec_fmt_id = ASM_MEDIA_FMT_APTX; + break; default: pr_err("%s: Invalid format 0x%x\n", __func__, format); rc = -EINVAL; @@ -5773,6 +5776,57 @@ done: } EXPORT_SYMBOL(q6asm_media_format_block_dsd); +int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac, + uint32_t srate, int stream_id) +{ + struct asm_aptx_dec_fmt_blk_v2 aptx_fmt; + int rc = 0; + + if (!ac->session) { + pr_err("%s: ac session invalid\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n", + __func__, ac->session, srate, stream_id); + + q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE, + stream_id); + atomic_set(&ac->cmd_state, -1); + + aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) - + sizeof(aptx_fmt.fmtblk); + + aptx_fmt.sample_rate = srate; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt); + if (rc < 0) { + pr_err("%s :Comamnd media format update 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; + } + rc = 0; +fail_cmd: + return rc; +} + static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id, int param_value, int stream_id) { @@ -6802,6 +6856,69 @@ int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance) return __q6asm_set_volume(ac, volume, instance); } +int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac, + struct aptx_dec_bt_addr_cfg *cfg) +{ + struct aptx_dec_bt_dev_addr paylod; + int sz = 0; + int rc = 0; + + pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap, + cfg->uap, cfg->lap); + + if (ac == NULL) { + pr_err("%s: AC handle NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + if (ac->apr == NULL) { + pr_err("%s: AC APR handle NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + + sz = sizeof(struct aptx_dec_bt_dev_addr); + q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS; + paylod.encdec.param_size = sz - sizeof(paylod.hdr) + - sizeof(paylod.encdec); + paylod.bt_addr_cfg.lap = cfg->lap; + paylod.bt_addr_cfg.uap = cfg->uap; + paylod.bt_addr_cfg.nap = cfg->nap; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod); + if (rc < 0) { + pr_err("%s: set-params send failed paramid[0x%x] rc %d\n", + __func__, paylod.encdec.param_id, 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, set-params paramid[0x%x]\n", __func__, + paylod.encdec.param_id); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state)), + paylod.encdec.param_id); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + pr_debug("%s: set BT addr is success\n", __func__); + rc = 0; +fail_cmd: + return rc; +} + int q6asm_set_softpause(struct audio_client *ac, struct asm_softpause_params *pause_param) {