ASoC: msm: add support for AVS 2.7 in native drivers

In Q6 asm and afe drivers, add API support
for AVS 2.7. Update compress driver to use
ASM volume gain compatible to verion used

Change-Id: I152a3410c99cfa37dca0eadb30b97f121f5d0a89
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
Signed-off-by: Divya Narayanan Poojary <dnaray@codeaurora.org>
This commit is contained in:
Laxminath Kasam 2016-05-14 15:16:05 +05:30 committed by Divya Narayanan Poojary
parent 2e6a457e55
commit d990217def
7 changed files with 867 additions and 42 deletions

View File

@ -26,6 +26,7 @@
#include <linux/debugfs.h>
#include <linux/msm_audio_ion.h>
#include <linux/compat.h>
#include <sound/q6core.h>
#include "audio_utils_aio.h"
#ifdef CONFIG_USE_DEV_CTRL_VOLUME
#include <linux/qdsp6v2/audio_dev_ctl.h>
@ -1561,7 +1562,26 @@ static long audio_aio_ioctl(struct file *file, unsigned int cmd,
memset(&stats, 0, sizeof(struct msm_audio_stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
rc = q6asm_get_session_time(audio->ac, &timestamp);
switch (q6core_get_avs_version()) {
case (Q6_SUBSYS_AVS2_7):
{
rc = q6asm_get_session_time(audio->ac, &timestamp);
break;
}
case (Q6_SUBSYS_AVS2_6):
{
rc = q6asm_get_session_time_legacy(audio->ac,
&timestamp);
break;
}
case (Q6_SUBSYS_INVALID):
default:
{
pr_err("%s: UNKNOWN AVS IMAGE VERSION\n", __func__);
rc = -EINVAL;
break;
}
}
if (rc >= 0)
memcpy(&stats.unused[0], &timestamp, sizeof(timestamp));
else
@ -1859,7 +1879,26 @@ static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd,
memset(&stats, 0, sizeof(struct msm_audio_stats32));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
rc = q6asm_get_session_time(audio->ac, &timestamp);
switch (q6core_get_avs_version()) {
case (Q6_SUBSYS_AVS2_7):
{
rc = q6asm_get_session_time(audio->ac, &timestamp);
break;
}
case (Q6_SUBSYS_AVS2_6):
{
rc = q6asm_get_session_time_legacy(audio->ac,
&timestamp);
break;
}
case (Q6_SUBSYS_INVALID):
default:
{
pr_err("%s: UNKNOWN AVS IMAGE VERSION\n", __func__);
rc = -EINVAL;
break;
}
}
if (rc >= 0)
memcpy(&stats.unused[0], &timestamp, sizeof(timestamp));
else

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, 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
@ -3022,7 +3022,8 @@ struct asm_multi_channel_pcm_enc_cfg_v3 {
};
/* @brief Multichannel PCM encoder configuration structure used
* in the #ASM_STREAM_CMD_OPEN_READ_V2 command.
* in the #ASM_STREAM_CMD_OPEN_READ_V2(for AVS2.6 image) OR
* ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2(FOR AVS2.7 image) command.
*/
struct asm_multi_channel_pcm_enc_cfg_v2 {
@ -3502,7 +3503,8 @@ struct asm_v13k_enc_cfg {
#define ASM_MEDIA_FMT_EVRC_FS 0x00010BEE
/* EVRC encoder configuration structure used in the
* #ASM_STREAM_CMD_OPEN_READ_V2 command.
* #ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2(for AVS2.6 image)
* #ASM_STREAM_CMD_OPEN_READ_V2(for AVS2.7 image) command.
*/
struct asm_evrc_enc_cfg {
struct apr_hdr hdr;
@ -3711,6 +3713,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_DEC 0x00010BF6
#define ASM_MEDIA_FMT_EAC3_DEC 0x00010C3C
#define ASM_MEDIA_FMT_DTS 0x00010D88
@ -4457,6 +4461,8 @@ struct asm_stream_cmd_open_write_v3 {
* - #ASM_MEDIA_FMT_SBC
* - #ASM_MEDIA_FMT_WMA_V10PRO_V2
* - #ASM_MEDIA_FMT_WMA_V9_V2
* - #ASM_MEDIA_FMT_AC3
* - #ASM_MEDIA_FMT_EAC3
* - #ASM_MEDIA_FMT_AC3_DEC
* - #ASM_MEDIA_FMT_EAC3_DEC
* - #ASM_MEDIA_FMT_G711_ALAW_FS
@ -4698,6 +4704,7 @@ struct asm_stream_cmd_open_readwrite_v2 {
* - #ASM_MEDIA_FMT_WMA_V10PRO_V2
* - #ASM_MEDIA_FMT_WMA_V9_V2
* - #ASM_MEDIA_FMT_AMR_WB_PLUS_V2
* - #ASM_MEDIA_FMT_AC3
* - #ASM_MEDIA_FMT_AC3_DEC
* - #ASM_MEDIA_FMT_G711_ALAW_FS
* - #ASM_MEDIA_FMT_G711_MLAW_FS
@ -5314,6 +5321,8 @@ struct asm_stream_cmd_open_write_compressed {
* Supported values:
* - #ASM_MEDIA_FMT_AC3_DEC
* - #ASM_MEDIA_FMT_EAC3_DEC
* - #ASM_MEDIA_FMT_AC3
* - #ASM_MEDIA_FMT_EAC3
* - #ASM_MEDIA_FMT_DTS
* - #ASM_MEDIA_FMT_ATRAC
* - #ASM_MEDIA_FMT_MAT
@ -6134,6 +6143,7 @@ struct audproc_topology_module_id_info_t {
* This module supports the following parameter IDs:
* - #ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN
* - #ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN
* - #ASM_PARAM_ID_MULTICHANNEL_GAIN
* - #ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG
* - #ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
* - #ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS
@ -6160,6 +6170,7 @@ struct audproc_topology_module_id_info_t {
* @messagepayload
* @structure{asm_volume_ctrl_lr_chan_gain}
* @tablespace
* @inputtable{Audio_Postproc_ASM_PARAM_ID_MULTICHANNEL_GAIN.tex}
* @inputtable{Audio_Postproc_ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN.tex}
*/
#define ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN 0x00010C00
@ -6364,12 +6375,10 @@ struct asm_soft_pause_params {
*/
struct asm_volume_ctrl_channelype_gain_pair {
struct apr_hdr hdr;
struct asm_stream_cmd_set_pp_params_v2 param;
struct asm_stream_param_data_v2 data;
uint8_t channelype;
/*< Channel type for which the gain setting is to be applied.
struct asm_volume_ctrl_channeltype_gain_pair {
uint8_t channeltype;
/*
*< Channel type for which the gain setting is to be applied.
* Supported values:
* - #PCM_CHANNEL_L
* - #PCM_CHANNEL_R
@ -6399,7 +6408,8 @@ struct asm_volume_ctrl_channelype_gain_pair {
/*< Clients must set this field to zero. */
uint32_t gain;
/*< Gain value for this channel in Q28 format.
/*
*< Gain value for this channel in Q28 format.
* Supported values: Any
*/
} __packed;
@ -6418,14 +6428,14 @@ struct asm_volume_ctrl_multichannel_gain {
struct asm_stream_cmd_set_pp_params_v2 param;
struct asm_stream_param_data_v2 data;
uint32_t num_channels;
/*< Number of channels for which gain values are provided. Any
/*
*< Number of channels for which gain values are provided. Any
* channels present in the data for which gain is not provided are
* set to unity gain.
* Supported values: 1 to 8
*/
struct asm_volume_ctrl_channelype_gain_pair
struct asm_volume_ctrl_channeltype_gain_pair
gain_data[VOLUME_CONTROL_MAX_CHANNELS];
/*< Array of channel type/gain pairs.*/
} __packed;
@ -7664,6 +7674,154 @@ enum afe_lpass_clk_mode {
Q6AFE_LPASS_MODE_BOTH_VALID,
} __packed;
/* Clock ID Enumeration Define. */
/* Clock ID for Primary I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100
/* Clock ID for Primary I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT 0x101
/* Clock ID for Secondary I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT 0x102
/* Clock ID for Secondary I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT 0x103
/* Clock ID for Tertiary I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT 0x104
/* Clock ID for Tertiary I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT 0x105
/* Clock ID for Quartnery I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT 0x106
/* Clock ID for Quartnery I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT 0x107
/* Clock ID for Speaker I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_IBIT 0x108
/* Clock ID for Speaker I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_EBIT 0x109
/* Clock ID for Speaker I2S OSR */
#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR 0x10A
/* Clock ID for QUINARY I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT 0x10B
/* Clock ID for QUINARY I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_EBIT 0x10C
/* Clock ID for SENARY I2S IBIT */
#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT 0x10D
/* Clock ID for SENARY I2S EBIT */
#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT 0x10E
/* Clock ID for Primary PCM IBIT */
#define Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT 0x200
/* Clock ID for Primary PCM EBIT */
#define Q6AFE_LPASS_CLK_ID_PRI_PCM_EBIT 0x201
/* Clock ID for Secondary PCM IBIT */
#define Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT 0x202
/* Clock ID for Secondary PCM EBIT */
#define Q6AFE_LPASS_CLK_ID_SEC_PCM_EBIT 0x203
/* Clock ID for Tertiary PCM IBIT */
#define Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT 0x204
/* Clock ID for Tertiary PCM EBIT */
#define Q6AFE_LPASS_CLK_ID_TER_PCM_EBIT 0x205
/* Clock ID for Quartery PCM IBIT */
#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT 0x206
/* Clock ID for Quartery PCM EBIT */
#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_EBIT 0x207
/** Clock ID for Primary TDM IBIT */
#define Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT 0x200
/** Clock ID for Primary TDM EBIT */
#define Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT 0x201
/** Clock ID for Secondary TDM IBIT */
#define Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT 0x202
/** Clock ID for Secondary TDM EBIT */
#define Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT 0x203
/** Clock ID for Tertiary TDM IBIT */
#define Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT 0x204
/** Clock ID for Tertiary TDM EBIT */
#define Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT 0x205
/** Clock ID for Quartery TDM IBIT */
#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT 0x206
/** Clock ID for Quartery TDM EBIT */
#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT 0x207
/* Clock ID for MCLK1 */
#define Q6AFE_LPASS_CLK_ID_MCLK_1 0x300
/* Clock ID for MCLK2 */
#define Q6AFE_LPASS_CLK_ID_MCLK_2 0x301
/* Clock ID for MCLK3 */
#define Q6AFE_LPASS_CLK_ID_MCLK_3 0x302
/* Clock ID for Internal Digital Codec Core */
#define Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 0x303
/* Clock ID for AHB HDMI input */
#define Q6AFE_LPASS_CLK_ID_AHB_HDMI_INPUT 0x400
/* Clock ID for SPDIF core */
#define Q6AFE_LPASS_CLK_ID_SPDIF_CORE 0x500
/* Clock attribute for invalid use (reserved for internal usage) */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVALID 0x0
/* Clock attribute for no couple case */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
/* Clock attribute for dividend couple case */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2
/* Clock attribute for divisor couple case */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3
/* Clock attribute for invert and no couple case */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO 0x4
/* Clock set API version */
#define Q6AFE_LPASS_CLK_CONFIG_API_VERSION 0x1
struct afe_clk_set {
/*
* Minor version used for tracking clock set.
* @values #AFE_API_VERSION_CLOCK_SET
*/
uint32_t clk_set_minor_version;
/*
* Clock ID
* @values
* - 0x100 to 0x10A - MSM8996
* - 0x200 to 0x207 - MSM8996
* - 0x300 to 0x302 - MSM8996 @tablebulletend
*/
uint32_t clk_id;
/*
* Clock frequency (in Hertz) to be set.
* @values
* - >= 0 for clock frequency to set @tablebulletend
*/
uint32_t clk_freq_in_hz;
/* Use to specific divider for two clocks if needed.
* Set to Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO for no divider
* relation clocks
* @values
* - #Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO
* - #Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND
* - #Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR @tablebulletend
*/
uint16_t clk_attri;
/*
* Specifies the root clock source.
* Currently, only Q6AFE_LPASS_CLK_ROOT_DEFAULT is valid
* @values
* - 0 @tablebulletend
*/
uint16_t clk_root;
/*
* for enable and disable clock.
* "clk_freq_in_hz", "clk_attri", and "clk_root"
* are ignored in disable clock case.
* @values
* - 0 -- Disabled
* - 1 -- Enabled @tablebulletend
*/
uint32_t enable;
};
struct afe_clk_cfg {
/* Minor version used for tracking the version of the I2S
* configuration interface.
@ -7701,7 +7859,8 @@ struct afe_clk_cfg {
/* This param id is used to configure I2S clk */
#define AFE_PARAM_ID_LPAIF_CLK_CONFIG 0x00010238
#define AFE_MODULE_CLOCK_SET 0x0001028F
#define AFE_PARAM_ID_CLOCK_SET 0x00010290
struct afe_lpass_clk_config_command {
struct apr_hdr hdr;
@ -7868,6 +8027,13 @@ struct afe_svc_cmd_set_param {
uint32_t mem_map_handle;
} __packed;
struct afe_svc_param_data {
uint32_t module_id;
uint32_t param_id;
uint16_t param_size;
uint16_t reserved;
} __packed;
struct afe_param_hw_mad_ctrl {
uint32_t minor_version;
uint16_t mad_type;
@ -7899,6 +8065,13 @@ struct afe_param_cdc_reg_cfg_payload {
struct afe_param_cdc_reg_cfg reg_cfg;
} __packed;
struct afe_lpass_clk_config_command_v2 {
struct apr_hdr hdr;
struct afe_svc_cmd_set_param param;
struct afe_svc_param_data pdata;
struct afe_clk_set clk_cfg;
} __packed;
/*
* reg_data's size can be up to AFE_MAX_CDC_REGISTERS_TO_CONFIG
*/
@ -8117,6 +8290,149 @@ struct asm_mtmx_strtr_params {
u32 window_lsw;
u32 window_msw;
} __packed;
/* Command for Matrix or Stream Router */
#define ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2 0x00010DCE
/* Module for AVSYNC */
#define ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC 0x00010DC6
/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to specify the
* render window start value. This parameter is supported only for a Set
* command (not a Get command) in the Rx direction
* (#ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2).
* Render window start is a value (session time minus timestamp, or ST-TS)
* below which frames are held, and after which frames are immediately
* rendered.
*/
#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2 0x00010DD1
/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to specify the
* render window end value. This parameter is supported only for a Set
* command (not a Get command) in the Rx direction
* (#ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2). Render window end is a value
* (session time minus timestamp) above which frames are dropped, and below
* which frames are immediately rendered.
*/
#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2 0x00010DD2
/* Generic payload of the window parameters in the
* #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC module.
* This payload is supported only for a Set command
* (not a Get command) on the Rx path.
*/
#define ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2 0x00010DCF
#define ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2 0x00010DD0
#define ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3 0x00012F0B
#define ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK (0x80000000UL)
struct asm_session_cmd_get_mtmx_strstr_params_v2 {
uint32_t data_payload_addr_lsw;
/* Lower 32 bits of the 64-bit data payload address. */
uint32_t data_payload_addr_msw;
/*
* Upper 32 bits of the 64-bit data payload address.
* If the address is not sent (NULL), the message is in the payload.
* If the address is sent (non-NULL), the parameter data payloads
* begin at the specified address.
*/
uint32_t mem_map_handle;
/*
* Unique identifier for an address. This memory map handle is returned
* by the aDSP through the #ASM_CMD_SHARED_MEM_MAP_REGIONS command.
* values
* - NULL -- Parameter data payloads are within the message payload
* (in-band).
* - Non-NULL -- Parameter data payloads begin at the address specified
* in the data_payload_addr_lsw and data_payload_addr_msw fields
* (out-of-band).
*/
uint32_t direction;
/*
* Direction of the entity (matrix mixer or stream router) on which
* the parameter is to be set.
* values
* - 0 -- Rx (for Rx stream router or Rx matrix mixer)
* - 1 -- Tx (for Tx stream router or Tx matrix mixer)
*/
uint32_t module_id;
/* Unique module ID. */
uint32_t param_id;
/* Unique parameter ID. */
uint32_t param_max_size;
};
struct asm_session_mtmx_strtr_param_session_time_v3_t {
uint32_t session_time_lsw;
/* Lower 32 bits of the current session time in microseconds */
uint32_t session_time_msw;
/*
* Upper 32 bits of the current session time in microseconds.
* The 64-bit number formed by session_time_lsw and session_time_msw
* is treated as signed.
*/
uint32_t absolute_time_lsw;
/*
* Lower 32 bits of the 64-bit absolute time in microseconds.
* This is the time when the sample corresponding to the
* session_time_lsw is rendered to the hardware. This absolute
* time can be slightly in the future or past.
*/
uint32_t absolute_time_msw;
/*
* Upper 32 bits of the 64-bit absolute time in microseconds.
* This is the time when the sample corresponding to the
* session_time_msw is rendered to hardware. This absolute
* time can be slightly in the future or past. The 64-bit number
* formed by absolute_time_lsw and absolute_time_msw is treated as
* unsigned.
*/
uint32_t time_stamp_lsw;
/* Lower 32 bits of the last processed timestamp in microseconds */
uint32_t time_stamp_msw;
/*
* Upper 32 bits of the last processed timestamp in microseconds.
* The 64-bit number formed by time_stamp_lsw and time_stamp_lsw
* is treated as unsigned.
*/
uint32_t flags;
/*
* Keeps track of any additional flags needed.
* @values{for bit 31}
* - 0 -- Uninitialized/invalid
* - 1 -- Valid
* All other bits are reserved; clients must set them to zero.
*/
};
union asm_session_mtmx_strtr_data_type {
struct asm_session_mtmx_strtr_param_session_time_v3_t session_time;
};
struct asm_mtmx_strtr_get_params {
struct apr_hdr hdr;
struct asm_session_cmd_get_mtmx_strstr_params_v2 param_info;
} __packed;
struct asm_mtmx_strtr_get_params_cmdrsp {
uint32_t err_code;
struct asm_stream_param_data_v2 param_info;
union asm_session_mtmx_strtr_data_type param_data;
} __packed;
#define AUDPROC_MODULE_ID_RESAMPLER 0x00010719
enum {

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, 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
@ -209,6 +209,7 @@ int afe_convert_virtual_to_portid(u16 port_id);
int afe_pseudo_port_start_nowait(u16 port_id);
int afe_pseudo_port_stop_nowait(u16 port_id);
int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg);
int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg);
int afe_set_digital_codec_core_clock(u16 port_id,
struct afe_digital_clk_cfg *cfg);
int afe_set_lpass_internal_digital_codec_clock(u16 port_id,

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, 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
@ -500,10 +500,18 @@ int q6asm_set_softvolume_v2(struct audio_client *ac,
/* Send left-right channel gain */
int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain);
/* Send multi channel gain */
int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
uint32_t *gains, uint8_t *ch_map, bool use_default);
int q6asm_set_lr_gain(struct asm_volume_ctrl_lr_chan_gain *lr,
struct audio_client *ac, int left_gain, int right_gain);
int q6asm_set_mchgain(struct asm_volume_ctrl_multichannel_gain *mch,
struct audio_client *ac, int left_gain, int right_gain);
/* Enable Mute/unmute flag */
int q6asm_set_mute(struct audio_client *ac, int muteflag);
int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp);
int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp);
int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
uint32_t params_length);

View File

@ -35,6 +35,7 @@
#include <sound/timer.h>
#include <sound/tlv.h>
#include <sound/q6core.h>
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
@ -213,8 +214,13 @@ static int msm_compr_set_volume(struct snd_compr_stream *cstream,
uint32_t volume_l, uint32_t volume_r)
{
struct msm_compr_audio *prtd;
int rc = 0;
uint32_t avg_vol;
int i, rc = -1;
uint32_t avg_vol, gain_list[VOLUME_CONTROL_MAX_CHANNELS];
uint32_t num_channels;
struct snd_soc_pcm_runtime *rtd;
struct msm_compr_pdata *pdata;
bool use_default = true;
u8 *chmap = NULL;
pr_debug("%s: volume_l %d volume_r %d\n",
__func__, volume_l, volume_r);
@ -222,18 +228,30 @@ static int msm_compr_set_volume(struct snd_compr_stream *cstream,
pr_err("%s: session not active\n", __func__);
return -EPERM;
}
rtd = cstream->private_data;
prtd = cstream->runtime->private_data;
if (!prtd || !prtd->audio_client) {
pr_err("%s: invalid session prtd or no audio client", __func__);
pr_err("%s: invalid session/rtd, prtd or no audio client",
__func__);
return rc;
}
pdata = snd_soc_platform_get_drvdata(rtd->platform);
if (prtd->compr_passthr != LEGACY_PCM) {
pr_debug("%s: No volume config for passthrough %d\n",
__func__, prtd->compr_passthr);
return rc;
}
use_default = !(pdata->ch_map[rtd->dai_link->be_id]->set_ch_map);
chmap = pdata->ch_map[rtd->dai_link->be_id]->channel_map;
num_channels = prtd->num_channels;
pr_debug("%s: call q6asm_set_volume volume_l(%d)volume_r(%d)num of channels(%d)\n",
__func__, volume_l, volume_r, prtd->num_channels);
pr_debug("%s: AVS version(%d): 0 for AVS2.6, 1 for AVS2.7\n",
__func__, q6core_get_avs_version());
if (prtd->num_channels > 2) {
/*
* Currently the left and right gains are averaged an applied
@ -244,18 +262,51 @@ static int msm_compr_set_volume(struct snd_compr_stream *cstream,
* channel gains.
*
*/
pr_debug("%s: call q6asm_set_volume for multichannel\n",
__func__);
avg_vol = (volume_l + volume_r) / 2;
rc = q6asm_set_volume(prtd->audio_client, avg_vol);
switch (q6core_get_avs_version()) {
case Q6_SUBSYS_AVS2_7:
avg_vol = (volume_l + volume_r) / 2;
for (i = 0; i < prtd->num_channels; i++)
gain_list[i] = avg_vol;
rc = q6asm_set_multich_gain(prtd->audio_client,
num_channels, gain_list, chmap, use_default);
break;
case Q6_SUBSYS_AVS2_6:
avg_vol = (volume_l + volume_r) / 2;
rc = q6asm_set_volume(prtd->audio_client, avg_vol);
break;
case Q6_SUBSYS_INVALID:
default:
pr_err("%s: UNKNOWN AVS IMAGE\n", __func__);
return rc;
}
} else {
pr_debug("%s: call q6asm_set_lrgain\n", __func__);
rc = q6asm_set_lrgain(prtd->audio_client, volume_l, volume_r);
if (rc < 0)
pr_err("%s: Send LR gain command failed rc=%d\n",
__func__, rc);
switch (q6core_get_avs_version()) {
case Q6_SUBSYS_AVS2_7:
gain_list[0] = volume_l;
gain_list[1] = volume_r;
/* force sending FR/FL/FC volume for mono */
if (prtd->num_channels == 1) {
gain_list[2] = volume_l;
num_channels = 3;
use_default = true;
}
rc = q6asm_set_multich_gain(prtd->audio_client,
num_channels, gain_list, chmap, use_default);
break;
case Q6_SUBSYS_AVS2_6:
pr_debug("%s: call q6asm_set_lrgain\n", __func__);
rc = q6asm_set_lrgain(prtd->audio_client,
volume_l, volume_r);
if (rc < 0)
pr_err("%s: Send LR gain command failed rc=%d\n",
__func__, rc);
break;
case Q6_SUBSYS_INVALID:
default:
pr_err("%s: UNKNOWN AVS IMAGE\n", __func__);
return rc;
}
}
if (rc < 0)
pr_err("%s: Send vol gain command failed rc=%d\n",
__func__, rc);
@ -1761,9 +1812,29 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
/*
* Cache this time as last known time
*/
q6asm_get_session_time(prtd->audio_client,
switch (q6core_get_avs_version()) {
case (Q6_SUBSYS_AVS2_7):
{
q6asm_get_session_time(prtd->audio_client,
&prtd->marker_timestamp);
break;
}
case (Q6_SUBSYS_AVS2_6):
{
q6asm_get_session_time_legacy(
prtd->audio_client, &prtd->marker_timestamp);
break;
}
case (Q6_SUBSYS_INVALID):
default:
{
pr_err("%s: UNKNOWN AVS IMAGE VERSION\n",
__func__);
break;
}
}
spin_lock_irqsave(&prtd->lock, flags);
/*
* Don't reset these as these vars map to
* total_bytes_transferred and total_bytes_available.
@ -1928,7 +1999,27 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream,
pr_debug("%s session time in gapless transition",
__func__);
rc = q6asm_get_session_time(prtd->audio_client, &timestamp);
switch (q6core_get_avs_version()) {
case (Q6_SUBSYS_AVS2_7):
{
rc = q6asm_get_session_time(prtd->audio_client,
&timestamp);
break;
}
case (Q6_SUBSYS_AVS2_6):
{
rc = q6asm_get_session_time_legacy(
prtd->audio_client, &timestamp);
break;
}
case (Q6_SUBSYS_INVALID):
default:
{
pr_err("%s: UNKNOWN AVS IMAGE VERSION\n", __func__);
rc = -EINVAL;
break;
}
}
if (rc < 0) {
pr_err("%s: Get Session Time return value =%lld\n",
__func__, timestamp);

View File

@ -4135,6 +4135,113 @@ fail_cmd:
return ret;
}
int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg)
{
struct afe_lpass_clk_config_command_v2 clk_cfg;
int ret = 0;
if (!cfg) {
pr_err("%s: clock cfg is NULL\n", __func__);
ret = -EINVAL;
return ret;
}
if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: index[%d] invalid!\n", __func__, index);
return -EINVAL;
}
ret = afe_q6_interface_prepare();
if (ret != 0) {
pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
return ret;
}
mutex_lock(&this_afe.afe_cmd_lock);
clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
clk_cfg.hdr.src_port = 0;
clk_cfg.hdr.dest_port = 0;
clk_cfg.hdr.token = index;
clk_cfg.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
- sizeof(clk_cfg.param);
clk_cfg.param.payload_address_lsw = 0x00;
clk_cfg.param.payload_address_msw = 0x00;
clk_cfg.param.mem_map_handle = 0x00;
clk_cfg.pdata.module_id = AFE_MODULE_CLOCK_SET;
clk_cfg.pdata.param_id = AFE_PARAM_ID_CLOCK_SET;
clk_cfg.pdata.param_size = sizeof(clk_cfg.clk_cfg);
clk_cfg.clk_cfg = *cfg;
pr_debug("%s: Minor version =0x%x clk id = %d\n"
"clk freq (Hz) = %d, clk attri = 0x%x\n"
"clk root = 0x%x clk enable = 0x%x\n",
__func__, cfg->clk_set_minor_version,
cfg->clk_id, cfg->clk_freq_in_hz, cfg->clk_attri,
cfg->clk_root, cfg->enable);
atomic_set(&this_afe.state, 1);
atomic_set(&this_afe.status, 0);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
if (ret < 0) {
pr_err("%s: AFE clk cfg failed with ret %d\n",
__func__, ret);
ret = -EINVAL;
goto fail_cmd;
}
ret = wait_event_timeout(this_afe.wait[index],
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto fail_cmd;
} else {
/* set ret to 0 as no timeout happened */
ret = 0;
}
if (atomic_read(&this_afe.status) != 0) {
pr_err("%s: config cmd failed\n", __func__);
ret = -EINVAL;
goto fail_cmd;
}
fail_cmd:
mutex_unlock(&this_afe.afe_cmd_lock);
return ret;
}
int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
{
int index = 0;
int ret = 0;
index = q6audio_get_port_index(port_id);
if (index < 0 || index > AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
__func__, index);
return -EINVAL;
}
ret = q6audio_is_digital_pcm_interface(port_id);
if (ret < 0) {
pr_err("%s: q6audio_is_digital_pcm_interface fail %d\n",
__func__, ret);
return -EINVAL;
}
ret = afe_set_lpass_clk_cfg(index, cfg);
if (ret)
pr_err("%s: afe_set_lpass_clk_cfg_v2 failed %d\n",
__func__, ret);
return ret;
}
int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
struct afe_digital_clk_cfg *cfg)
{

View File

@ -38,6 +38,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
#include <sound/q6core.h>
#include <sound/q6audio-v2.h>
#include <sound/audio_cal_utils.h>
#include <sound/msm-dts-eagle.h>
@ -1443,6 +1444,57 @@ static int32_t is_no_wait_cmd_rsp(uint32_t opcode, uint32_t *cmd_type)
return 0;
}
static void q6asm_process_mtmx_get_param_rsp(struct audio_client *ac,
struct asm_mtmx_strtr_get_params_cmdrsp *cmdrsp)
{
struct asm_session_mtmx_strtr_param_session_time_v3_t *time;
if (cmdrsp->err_code) {
dev_err_ratelimited(ac->dev,
"%s: err=%x, mod_id=%x, param_id=%x\n",
__func__, cmdrsp->err_code,
cmdrsp->param_info.module_id,
cmdrsp->param_info.param_id);
return;
}
dev_dbg_ratelimited(ac->dev,
"%s: mod_id=%x, param_id=%x\n", __func__,
cmdrsp->param_info.module_id,
cmdrsp->param_info.param_id);
switch (cmdrsp->param_info.module_id) {
case ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC:
switch (cmdrsp->param_info.param_id) {
case ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3:
time = &cmdrsp->param_data.session_time;
dev_vdbg(ac->dev, "%s: GET_TIME_V3, time_lsw=%x, time_msw=%x\n",
__func__, time->session_time_lsw,
time->session_time_msw);
ac->time_stamp = (uint64_t)(((uint64_t)
time->session_time_msw << 32) |
time->session_time_lsw);
if (time->flags &
ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK)
dev_warn_ratelimited(ac->dev,
"%s: recv inval tstmp\n",
__func__);
if (atomic_cmpxchg(&ac->time_flag, 1, 0))
wake_up(&ac->time_wait);
break;
default:
dev_err(ac->dev, "%s: unexpected param_id %x\n",
__func__, cmdrsp->param_info.param_id);
break;
}
break;
default:
dev_err(ac->dev, "%s: unexpected mod_id %x\n", __func__,
cmdrsp->param_info.module_id);
break;
}
}
static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
{
int i = 0;
@ -1780,6 +1832,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
payload[0], payload[1], payload[2],
payload[3]);
break;
case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
break;
case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
__func__, ac->session, payload[0], payload[2],
@ -2218,14 +2273,35 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
switch (format) {
case FORMAT_AC3:
open.fmt_id = ASM_MEDIA_FMT_AC3_DEC;
break;
switch (q6core_get_avs_version()) {
case Q6_SUBSYS_AVS2_7:
open.fmt_id = ASM_MEDIA_FMT_AC3;
break;
case Q6_SUBSYS_AVS2_6:
open.fmt_id = ASM_MEDIA_FMT_AC3_DEC;
break;
case Q6_SUBSYS_INVALID:
default:
pr_err("%s: Invalid format[%d]\n",
__func__, format);
rc = -EINVAL;
goto fail_cmd;
}
case FORMAT_EAC3:
open.fmt_id = ASM_MEDIA_FMT_EAC3_DEC;
break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
goto fail_cmd;
switch (q6core_get_avs_version()) {
case Q6_SUBSYS_AVS2_7:
open.fmt_id = ASM_MEDIA_FMT_EAC3;
break;
case Q6_SUBSYS_AVS2_6:
open.fmt_id = ASM_MEDIA_FMT_EAC3_DEC;
break;
case Q6_SUBSYS_INVALID:
default:
pr_err("%s: Invalid format[%d]\n",
__func__, format);
rc = -EINVAL;
goto fail_cmd;
}
}
/*Below flag indicates the DSP that Compressed audio input
stream is not IEC 61937 or IEC 60958 packetizied*/
@ -2353,10 +2429,36 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
break;
case FORMAT_AC3:
open.dec_fmt_id = ASM_MEDIA_FMT_EAC3_DEC;
switch (q6core_get_avs_version()) {
case Q6_SUBSYS_AVS2_7:
open.dec_fmt_id = ASM_MEDIA_FMT_AC3;
break;
case Q6_SUBSYS_AVS2_6:
open.dec_fmt_id = ASM_MEDIA_FMT_AC3_DEC;
break;
case Q6_SUBSYS_INVALID:
default:
pr_err("%s: Invalid format[%d]\n",
__func__, format);
rc = -EINVAL;
goto fail_cmd;
}
break;
case FORMAT_EAC3:
open.dec_fmt_id = ASM_MEDIA_FMT_EAC3_DEC;
switch (q6core_get_avs_version()) {
case Q6_SUBSYS_AVS2_7:
open.dec_fmt_id = ASM_MEDIA_FMT_EAC3;
break;
case Q6_SUBSYS_AVS2_6:
open.dec_fmt_id = ASM_MEDIA_FMT_EAC3_DEC;
break;
case Q6_SUBSYS_INVALID:
default:
pr_err("%s: Invalid format[%d]\n",
__func__, format);
rc = -EINVAL;
goto fail_cmd;
}
break;
case FORMAT_MP2:
open.dec_fmt_id = ASM_MEDIA_FMT_MP2;
@ -5215,6 +5317,110 @@ fail_cmd:
return rc;
}
/*
* q6asm_set_multich_gain: set multiple channel gains on an ASM session
* @ac: audio client handle
* @channels: number of channels caller intends to set gains
* @gains: list of gains of audio channels
* @ch_map: list of channel mapping. Only valid if use_default is false
* @use_default: flag to indicate whether to use default mapping
*/
int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
uint32_t *gains, uint8_t *ch_map, bool use_default)
{
struct asm_volume_ctrl_multichannel_gain multich_gain;
int sz = 0;
int rc = 0;
int i;
u8 default_chmap[VOLUME_CONTROL_MAX_CHANNELS];
if (ac == NULL) {
pr_err("%s: ac is NULL\n", __func__);
rc = -EINVAL;
goto done;
}
if (ac->apr == NULL) {
dev_err(ac->dev, "%s: AC APR handle NULL\n", __func__);
rc = -EINVAL;
goto done;
}
if (gains == NULL) {
dev_err(ac->dev, "%s: gain_list is NULL\n", __func__);
rc = -EINVAL;
goto done;
}
if (channels > VOLUME_CONTROL_MAX_CHANNELS) {
dev_err(ac->dev, "%s: Invalid channel count %d\n",
__func__, channels);
rc = -EINVAL;
goto done;
}
if (!use_default && ch_map == NULL) {
dev_err(ac->dev, "%s: NULL channel map\n", __func__);
rc = -EINVAL;
goto done;
}
memset(&multich_gain, 0, sizeof(multich_gain));
sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
atomic_set(&ac->cmd_state, 1);
multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
multich_gain.param.data_payload_addr_lsw = 0;
multich_gain.param.data_payload_addr_msw = 0;
multich_gain.param.mem_map_handle = 0;
multich_gain.param.data_payload_size = sizeof(multich_gain) -
sizeof(multich_gain.hdr) - sizeof(multich_gain.param);
multich_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
multich_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
multich_gain.data.param_size = multich_gain.param.data_payload_size -
sizeof(multich_gain.data);
multich_gain.data.reserved = 0;
if (use_default) {
rc = q6asm_map_channels(default_chmap, channels, false);
if (rc < 0)
goto done;
for (i = 0; i < channels; i++) {
multich_gain.gain_data[i].channeltype =
default_chmap[i];
multich_gain.gain_data[i].gain = gains[i] << 15;
}
} else {
for (i = 0; i < channels; i++) {
multich_gain.gain_data[i].channeltype = ch_map[i];
multich_gain.gain_data[i].gain = gains[i] << 15;
}
}
multich_gain.num_channels = channels;
rc = apr_send_pkt(ac->apr, (uint32_t *) &multich_gain);
if (rc < 0) {
pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
__func__, multich_gain.data.param_id, rc);
goto done;
}
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__,
multich_gain.data.param_id);
rc = -EINVAL;
goto done;
}
if (atomic_read(&ac->cmd_state) < 0) {
pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
__func__, atomic_read(&ac->cmd_state),
multich_gain.data.param_id);
rc = -EINVAL;
goto done;
}
rc = 0;
done:
return rc;
}
int q6asm_set_mute(struct audio_client *ac, int muteflag)
{
struct asm_volume_ctrl_mute_config mute;
@ -6259,6 +6465,63 @@ fail_cmd:
}
int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
{
struct asm_mtmx_strtr_get_params mtmx_params;
int rc;
if (ac == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
if (ac->apr == NULL) {
pr_err("%s: AC APR handle NULL\n", __func__);
return -EINVAL;
}
if (tstamp == NULL) {
pr_err("%s: tstamp NULL\n", __func__);
return -EINVAL;
}
q6asm_add_hdr(ac, &mtmx_params.hdr, sizeof(mtmx_params), TRUE);
mtmx_params.hdr.opcode = ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2;
mtmx_params.param_info.data_payload_addr_lsw = 0;
mtmx_params.param_info.data_payload_addr_msw = 0;
mtmx_params.param_info.mem_map_handle = 0;
mtmx_params.param_info.direction = (ac->io_mode & TUN_READ_IO_MODE
? 1 : 0);
mtmx_params.param_info.module_id =
ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
mtmx_params.param_info.param_id =
ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3;
mtmx_params.param_info.param_max_size =
sizeof(struct asm_stream_param_data_v2) +
sizeof(struct asm_session_mtmx_strtr_param_session_time_v3_t);
atomic_set(&ac->time_flag, 1);
dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
ac->session, mtmx_params.hdr.opcode);
rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
if (rc < 0) {
pr_err("%s: Commmand 0x%x failed %d\n", __func__,
mtmx_params.hdr.opcode, rc);
goto fail_cmd;
}
rc = wait_event_timeout(ac->time_wait,
(atomic_read(&ac->time_flag) == 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout in getting session time from DSP\n",
__func__);
goto fail_cmd;
}
*tstamp = ac->time_stamp;
return 0;
fail_cmd:
return -EINVAL;
}
int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp)
{
struct apr_hdr hdr;
int rc;