diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 19893da9dda0..a047a33334d2 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -4976,8 +4976,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 @@ -4986,7 +4986,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. @@ -8993,6 +8992,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 56a8951faadc..9a3db9aaa25e 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -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/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 diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index d742b160f493..2ba41ac1877f 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; @@ -1794,6 +1814,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; @@ -2664,6 +2690,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", @@ -3076,6 +3103,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; @@ -3142,6 +3170,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 b3d991c82314..a62420a23789 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -12111,6 +12111,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, @@ -12163,6 +12190,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 308a56b6e6ba..9353b2132e15 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -2662,6 +2662,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; @@ -5774,6 +5777,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) { @@ -6803,6 +6857,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) {