summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-05-10 23:03:35 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-05-10 23:03:35 -0700
commit4cb291c99a103e4db4ab9d5c4f95f30427cc374d (patch)
tree8baa89391caef0af5e3976118230c1c1c046603a
parent3e3619c81e60e4ddb008f746ec45896c6e8a588d (diff)
parentc6911c81c2c0e06fefa57a73c2a76161b54070eb (diff)
Merge "ASoC: msm: qdspv2: Add mixer controls for drift query"
-rw-r--r--include/sound/apr_audio-v2.h23
-rw-r--r--include/sound/q6asm-v2.h8
-rw-r--r--include/uapi/sound/compress_offload.h7
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c41
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c4
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c74
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c142
7 files changed, 297 insertions, 2 deletions
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bcb53faaf678..021b81105c42 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -10320,10 +10320,33 @@ struct asm_session_mtmx_strtr_param_clk_rec_t {
u32 flags;
} __packed;
+
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to
+ * realize smoother adjustment of audio session clock for a specified session.
+ * The desired audio session clock adjustment(in micro seconds) is specified
+ * using the command #ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2.
+ * Delaying/Advancing the session clock would be implemented by inserting
+ * interpolated/dropping audio samples in the playback path respectively.
+ * Also, this parameter has to be configured before the Audio Session is put
+ * to RUN state to avoid cold start latency/glitches in the playback.
+ */
+
+#define ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL 0x00013217
+
+struct asm_session_mtmx_param_adjust_session_time_ctl_t {
+ /* Specifies whether the module is enabled or not
+ * @values
+ * 0 -- disabled
+ * 1 -- enabled
+ */
+ u32 enable;
+};
+
union asm_session_mtmx_strtr_param_config {
struct asm_session_mtmx_strtr_param_window_v2_t window_param;
struct asm_session_mtmx_strtr_param_render_mode_t render_param;
struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
+ struct asm_session_mtmx_param_adjust_session_time_ctl_t adj_time_param;
} __packed;
struct asm_mtmx_strtr_params {
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 41fcdeb50831..b2bb8d493839 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -655,6 +655,10 @@ int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
uint32_t clk_rec_mode);
+/* Enable adjust session clock in DSP */
+int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
+ bool enable);
+
/* Retrieve the current DSP path delay */
int q6asm_get_path_delay(struct audio_client *ac);
@@ -662,4 +666,8 @@ int q6asm_get_path_delay(struct audio_client *ac);
uint8_t q6asm_get_buf_index_from_token(uint32_t token);
uint8_t q6asm_get_stream_id_from_token(uint32_t token);
+/* Adjust session clock in DSP */
+int q6asm_adjust_session_clock(struct audio_client *ac,
+ uint32_t adjust_time_lsw,
+ uint32_t adjust_time_msw);
#endif /* __Q6_ASM_H__ */
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index 30481056cce1..866ec3d2af69 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -149,6 +149,8 @@ struct snd_compr_audio_info {
* @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto)
* @SNDRV_COMPRESS_RENDER_WINDOW: render window
* @SNDRV_COMPRESS_START_DELAY: start delay
+ * @SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK: enable dsp drift correction
+ * @SNDRV_COMPRESS_ADJUST_SESSION_CLOCK: set drift correction value
*/
enum sndrv_compress_encoder {
SNDRV_COMPRESS_ENCODER_PADDING = 1,
@@ -160,6 +162,8 @@ enum sndrv_compress_encoder {
SNDRV_COMPRESS_CLK_REC_MODE = 7,
SNDRV_COMPRESS_RENDER_WINDOW = 8,
SNDRV_COMPRESS_START_DELAY = 9,
+ SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK = 10,
+ SNDRV_COMPRESS_ADJUST_SESSION_CLOCK = 11,
};
#define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY
@@ -167,6 +171,9 @@ enum sndrv_compress_encoder {
#define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE
#define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW
#define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY
+#define SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK \
+ SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK
+#define SNDRV_COMPRESS_ADJUST_SESSION_CLOCK SNDRV_COMPRESS_ADJUST_SESSION_CLOCK
/**
* struct snd_compr_metadata - compressed stream metadata
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 5bd3b6d7014e..a1cb18f53380 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -302,6 +302,39 @@ exit:
return ret;
}
+static int msm_compr_enable_adjust_session_clock(struct audio_client *ac,
+ bool enable)
+{
+ int ret;
+
+ pr_debug("%s, enable adjust_session %d\n", __func__, enable);
+
+ ret = q6asm_send_mtmx_strtr_enable_adjust_session_clock(ac, enable);
+ if (ret)
+ pr_err("%s, adjust session clock can't be set error %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int msm_compr_adjust_session_clock(struct audio_client *ac,
+ uint32_t adjust_session_lsw, uint32_t adjust_session_msw)
+{
+ int ret;
+
+ pr_debug("%s, adjust_session_time_msw 0x%x adjust_session_time_lsw 0x%x\n",
+ __func__, adjust_session_msw, adjust_session_lsw);
+
+ ret = q6asm_adjust_session_clock(ac,
+ adjust_session_lsw,
+ adjust_session_msw);
+ if (ret)
+ pr_err("%s, adjust session clock can't be set error %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
static int msm_compr_set_volume(struct snd_compr_stream *cstream,
uint32_t volume_l, uint32_t volume_r)
{
@@ -2875,6 +2908,14 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream,
} else if (metadata->key == SNDRV_COMPRESS_START_DELAY) {
prtd->start_delay_lsw = metadata->value[0];
prtd->start_delay_msw = metadata->value[1];
+ } else if (metadata->key ==
+ SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK) {
+ return msm_compr_enable_adjust_session_clock(ac,
+ metadata->value[0]);
+ } else if (metadata->key == SNDRV_COMPRESS_ADJUST_SESSION_CLOCK) {
+ return msm_compr_adjust_session_clock(ac,
+ metadata->value[0],
+ metadata->value[1]);
}
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 26b7f3f26b26..45868f508a60 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new hdmi_config_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "HDMI RX Drift",
+ .name = "HDMI Drift",
.info = msm_dai_q6_ext_disp_drift_info,
.get = msm_dai_q6_ext_disp_drift_get,
},
@@ -191,7 +191,7 @@ static const struct snd_kcontrol_new display_port_config_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "DISPLAY Port RX Drift",
+ .name = "DISPLAY_PORT Drift",
.info = msm_dai_q6_ext_disp_drift_info,
.get = msm_dai_q6_ext_disp_drift_get,
},
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 201ca652c10b..9ed61288a3e4 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -2321,6 +2321,44 @@ static const struct snd_kcontrol_new afe_enc_config_controls[] = {
msm_dai_q6_afe_input_bit_format_put),
};
+static int msm_dai_q6_slim_rx_drift_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
+
+ return 0;
+}
+
+static int msm_dai_q6_slim_rx_drift_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = -EINVAL;
+ struct afe_param_id_dev_timing_stats timing_stats;
+ struct snd_soc_dai *dai = kcontrol->private_data;
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_err("%s: afe port not started. dai_data->status_mask = %ld\n",
+ __func__, *dai_data->status_mask);
+ goto done;
+ }
+
+ memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
+ ret = afe_get_av_dev_drift(&timing_stats, dai->id);
+ if (ret) {
+ pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
+ __func__, dai->id, ret);
+
+ goto done;
+ }
+
+ memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
+ sizeof(struct afe_param_id_dev_timing_stats));
+done:
+ return ret;
+}
+
static const char * const afe_cal_mode_text[] = {
"CAL_MODE_DEFAULT", "CAL_MODE_NONE"
};
@@ -2373,6 +2411,29 @@ static const struct snd_kcontrol_new usb_audio_cfg_controls[] = {
msm_dai_q6_usb_audio_endian_cfg_put),
};
+static const struct snd_kcontrol_new avd_drift_config_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SLIMBUS_0_RX DRIFT",
+ .info = msm_dai_q6_slim_rx_drift_info,
+ .get = msm_dai_q6_slim_rx_drift_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SLIMBUS_6_RX DRIFT",
+ .info = msm_dai_q6_slim_rx_drift_info,
+ .get = msm_dai_q6_slim_rx_drift_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SLIMBUS_7_RX DRIFT",
+ .info = msm_dai_q6_slim_rx_drift_info,
+ .get = msm_dai_q6_slim_rx_drift_get,
+ },
+};
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
{
struct msm_dai_q6_dai_data *dai_data;
@@ -2422,6 +2483,9 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(&afe_enc_config_controls[2],
dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&avd_drift_config_controls[2],
+ dai));
break;
case RT_PROXY_DAI_001_RX:
rc = snd_ctl_add(dai->component->card->snd_card,
@@ -2449,6 +2513,16 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
snd_ctl_new1(&usb_audio_cfg_controls[3],
dai_data));
break;
+ case SLIMBUS_0_RX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&avd_drift_config_controls[0],
+ dai));
+ break;
+ case SLIMBUS_6_RX:
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&avd_drift_config_controls[1],
+ dai));
+ break;
}
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "%s: err add config ctl, DAI = %s\n",
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0cf386a3c2fc..d79074d9521b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2062,6 +2062,12 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
(void *)pp_event_package, ac->priv);
kfree(pp_event_package);
return 0;
+ case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
+ pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
+ __func__, ac->session, payload[0], payload[2],
+ payload[1]);
+ wake_up(&ac->cmd_wait);
+ 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],
@@ -8039,6 +8045,80 @@ exit:
return rc;
}
+int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
+ bool enable)
+{
+ struct asm_mtmx_strtr_params matrix;
+ struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
+ int sz = 0;
+ int rc = 0;
+
+ pr_debug("%s: adjust session enable %d\n", __func__, enable);
+
+ if (!ac) {
+ pr_err("%s: audio client handle is NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ adjust_time.enable = enable;
+ memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
+ sz = sizeof(struct asm_mtmx_strtr_params);
+ q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+ matrix.param.data_payload_addr_lsw = 0;
+ matrix.param.data_payload_addr_msw = 0;
+ matrix.param.mem_map_handle = 0;
+ matrix.param.data_payload_size =
+ sizeof(struct asm_stream_param_data_v2) +
+ sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
+ matrix.param.direction = 0; /* RX */
+ matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+ matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
+ matrix.data.param_size =
+ sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
+ matrix.data.reserved = 0;
+ matrix.config.adj_time_param.enable = adjust_time.enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+ if (rc < 0) {
+ pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -ETIMEDOUT;
+ goto exit;
+ }
+
+ 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 exit;
+ }
+ rc = 0;
+exit:
+ return rc;
+}
+
+
static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
{
struct apr_hdr hdr;
@@ -8428,6 +8508,68 @@ fail_cmd:
return -EINVAL;
}
+int q6asm_adjust_session_clock(struct audio_client *ac,
+ uint32_t adjust_time_lsw,
+ uint32_t adjust_time_msw)
+{
+ int rc = 0;
+ int sz = 0;
+ struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;
+
+ pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
+ adjust_time_lsw, adjust_time_msw);
+
+ if (!ac) {
+ pr_err("%s: audio client handle is NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
+ q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;
+
+ adjust_clock.adjustime_lsw = adjust_time_lsw;
+ adjust_clock.adjustime_msw = adjust_time_msw;
+
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
+ if (rc < 0) {
+ pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
+ __func__, adjust_clock.hdr.opcode);
+ 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, adjust_clock paramid[0x%x]\n",
+ __func__, adjust_clock.hdr.opcode);
+ 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;
+}
+
/*
* q6asm_get_path_delay() - get the path delay for an audio session
* @ac: audio client handle