tegra-alt: ADSP IO to IO support for virt configs

Add handling for IO to IO use cases in ADSP for
virtualized configurations

Jira EMA-497
Bug 1990609

Change-Id: Ied779014ca2c484d6741329d94500c0e51e10b80
Signed-off-by: Hariharan Sivaraman <hariharans@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1589042
(cherry picked from commit ea529d5d074c8ccb577341b5a1d834db2253ded2)
Reviewed-on: https://git-master.nvidia.com/r/1562134
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Uday Gupta <udayg@nvidia.com>
Reviewed-by: Viraj Karandikar <vkarandikar@nvidia.com>
Reviewed-by: Nitin Pai <npai@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Hariharan Sivaraman
2017-06-30 16:40:31 +05:30
committed by Sameer Pujar
parent e8d6a15183
commit fbeffb7043

View File

@@ -184,7 +184,8 @@ struct tegra210_adsp {
} pcm_path[ADSP_FE_COUNT+1][2];
#ifdef CONFIG_SND_SOC_TEGRA_VIRT_IVC_COMM
struct nvaudio_ivc_ctxt *hivc_client;
uint32_t fe_to_admaif_map[ADSP_FE_END - ADSP_FE_START + 1][2];
int32_t fe_to_admaif_map[ADSP_FE_END - ADSP_FE_START + 1][2];
int32_t apm_to_admaif_map[APM_IN_END - APM_IN_START + 1][2];
struct tegra210_adsp_switch switches[MAX_ADSP_SWITCHES];
bool is_fe_set[ADSP_FE_COUNT];
spinlock_t switch_lock;
@@ -1763,7 +1764,7 @@ static int tegra_ivc_start_playback(
msg.cmd = NVAUDIO_START_PLAYBACK;
msg.params.dmaif_info.id = ivc_msg_admaif_id;
msg.ack_required = ack_required;
err = nvaudio_ivc_send(adsp->hivc_client,
err = nvaudio_ivc_send_retry(adsp->hivc_client,
&msg,
sizeof(struct nvaudio_ivc_msg));
if (ack_required && err >= 0) {
@@ -1786,7 +1787,7 @@ static int tegra_ivc_start_capture(
msg.cmd = NVAUDIO_START_CAPTURE;
msg.ack_required = ack_required;
msg.params.dmaif_info.id = ivc_msg_admaif_id;
err = nvaudio_ivc_send(adsp->hivc_client,
err = nvaudio_ivc_send_retry(adsp->hivc_client,
&msg,
sizeof(struct nvaudio_ivc_msg));
if (ack_required && err >= 0) {
@@ -1809,7 +1810,7 @@ static int tegra_ivc_stop_playback(
msg.cmd = NVAUDIO_STOP_PLAYBACK;
msg.params.dmaif_info.id = ivc_msg_admaif_id;
msg.ack_required = ack_required;
err = nvaudio_ivc_send(adsp->hivc_client,
err = nvaudio_ivc_send_retry(adsp->hivc_client,
&msg,
sizeof(struct nvaudio_ivc_msg));
if (ack_required && err >= 0) {
@@ -1832,7 +1833,7 @@ static int tegra_ivc_stop_capture(
msg.cmd = NVAUDIO_STOP_CAPTURE;
msg.params.dmaif_info.id = ivc_msg_admaif_id;
msg.ack_required = ack_required;
err = nvaudio_ivc_send(adsp->hivc_client,
err = nvaudio_ivc_send_retry(adsp->hivc_client,
&msg,
sizeof(struct nvaudio_ivc_msg));
if (ack_required && err >= 0) {
@@ -1843,6 +1844,112 @@ static int tegra_ivc_stop_capture(
return err;
}
/**
* Function that checks for IO to IO path during widget event
* Used to toggle playback/capture through IVC to Audio Server
*/
static int tegra210_adsp_send_hv_state_msg(
struct tegra210_adsp *adsp,
struct tegra210_adsp_app *app,
int32_t state)
{
uint32_t src, i;
int32_t ret = 0;
uint32_t be_to_be_flag = 0;
int32_t apm_in_id = -1, apm_out_id = -1;
int32_t playback_admaif_id = -1, capture_admaif_id = -1;
struct device *dev = adsp->dev;
struct device_node *node = dev->of_node;
/* Only applicable for HV configurations */
if (!of_device_is_compatible(node, "nvidia,tegra210-adsp-audio-hv"))
return 0;
apm_in_id = app->reg - APM_IN_START;
/*
* For IO to IO path, APM-IN input should be ADSP-ADMAIF
* and APM-OUT output should be connected to ADSP-ADMAIF
*/
if (state == nvfx_state_active) {
/* Check source of APM-IN. If not ADSP-ADMAIF, return */
src = tegra210_adsp_get_source(adsp, app->reg);
if (!IS_ADSP_ADMAIF(src)) {
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_PLAYBACK] = -1;
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_CAPTURE] = -1;
return 0;
}
capture_admaif_id = src - ADSP_ADMAIF_START;
/* Check if any ADSP-ADMAIF is connected to same APM output */
for (i = ADSP_ADMAIF_START; i <= ADSP_ADMAIF_END; i++) {
app = &adsp->apps[i];
src = tegra210_adsp_get_source(adsp, app->reg);
if (!IS_APM_OUT(src))
continue;
apm_out_id = src - APM_OUT_START;
if (apm_out_id == apm_in_id) {
be_to_be_flag = 1;
playback_admaif_id = app->reg - ADSP_ADMAIF_START;
break;
}
}
if (be_to_be_flag) {
/* if IO to IO path exists, map APM to ADMAIFs */
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_PLAYBACK] =
playback_admaif_id;
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_CAPTURE] =
capture_admaif_id;
ret = tegra_ivc_start_capture(adsp, capture_admaif_id, false);
if (ret < 0)
dev_err(adsp->dev, "%s: start capture failed\n", __func__);
ret = tegra_ivc_start_playback(adsp, playback_admaif_id, false);
if (ret < 0) {
dev_err(adsp->dev, "%s: start playback failed\n", __func__);
ret = tegra_ivc_stop_capture(adsp, capture_admaif_id, false);
if (ret < 0)
dev_err(adsp->dev, "%s: stop capture failed\n", __func__);
}
} else {
/* No IO to IO path identified. No hv state msg to be sent */
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_PLAYBACK] = -1;
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_CAPTURE] = -1;
}
} else if (state == nvfx_state_inactive) {
playback_admaif_id =
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_PLAYBACK];
capture_admaif_id =
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_CAPTURE];
if ((playback_admaif_id != -1) && (capture_admaif_id != -1)) {
ret = tegra_ivc_stop_playback(adsp, playback_admaif_id, false);
if (ret < 0)
dev_err(adsp->dev, "%s: stop playback failed\n", __func__);
ret = tegra_ivc_stop_capture(adsp, capture_admaif_id, false);
if (ret < 0)
dev_err(adsp->dev, "%s: stop capture failed\n", __func__);
}
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_PLAYBACK] = -1;
adsp->apm_to_admaif_map[apm_in_id][SNDRV_PCM_STREAM_CAPTURE] = -1;
}
return ret;
}
static uint32_t tegra210_adsp_hv_pcm_trigger(
struct tegra210_adsp *adsp,
uint32_t apm_out_in,
@@ -1877,7 +1984,7 @@ static uint32_t tegra210_adsp_hv_pcm_trigger(
}
if (ret < 0) {
pr_err("error on ivc_send\n");
pr_err("%s: error during start_trigger\n", __func__);
return ret;
}
break;
@@ -1893,7 +2000,7 @@ static uint32_t tegra210_adsp_hv_pcm_trigger(
}
if (ret < 0) {
pr_err("error on ivc_send\n");
pr_err("%s: error during stop_trigger\n", __func__);
return ret;
}
break;
@@ -1926,7 +2033,7 @@ static int tegra210_adsp_pcm_trigger(struct snd_pcm_substream *substream,
substream->stream,
cmd);
if (ret < 0) {
pr_err("error on ivc_send\n");
pr_err("%s: error during hv_pcm_trigger\n", __func__);
return ret;
}
}
@@ -2087,21 +2194,53 @@ static void tegra_adsp_set_admaif_id(
uint32_t be_reg,
int s_stream)
{
int i, stream;
int i, j, stream;
uint32_t src;
struct tegra210_adsp_app *app = NULL;
/* ADSP Playback (ADSP-ADMAIF Codec Capture) */
if (s_stream == SNDRV_PCM_STREAM_CAPTURE) {
app = &adsp->apps[be_reg];
src = app->reg;
while (!IS_ADSP_FE(src))
while (src != TEGRA210_ADSP_NONE) {
/* Backtrace path till data source is found */
src = tegra210_adsp_get_source(adsp, src);
i = adsp->apps[src].reg;
stream = SNDRV_PCM_STREAM_PLAYBACK;
adsp->fe_to_admaif_map[i-1][stream] = admaif_id;
dev_vdbg(adsp->dev, "%s : capture fe %d admaif %d\n",
__func__, i, admaif_id);
} else {
/* Check if data source in path is ADSP-FE (Mem to IO) */
if (IS_ADSP_FE(src)) {
i = adsp->apps[src].reg;
stream = SNDRV_PCM_STREAM_PLAYBACK;
adsp->fe_to_admaif_map[i-1][stream] = admaif_id;
dev_vdbg(adsp->dev, "%s : capture fe %d admaif %d\n",
__func__, i, admaif_id);
return;
}
/* Check if data source in path is ADSP-ADMAIF (IO to IO) */
if (IS_ADSP_ADMAIF(src)) {
dev_vdbg(adsp->dev, "%s : start playback on adsp admaif %d\n",
__func__, admaif_id);
/* Clear older FE to ADMAIF mappings for given ADMAIF */
stream = SNDRV_PCM_STREAM_PLAYBACK;
for (j = ADSP_FE_START; j <= ADSP_FE_END; j++) {
if (adsp->fe_to_admaif_map[j-1][stream] == admaif_id)
adsp->fe_to_admaif_map[j-1][stream] = -1;
}
return;
}
}
dev_err(adsp->dev, "%s: no data source for ADSP-ADMAIF %d\n",
__func__, admaif_id);
} else { /* ADSP Capture (ADSP-ADMAIF Codec Playback) */
/* Check if ADSP-FE is sink for given ADSP ADMAIF (IO to Mem) */
for (i = ADSP_FE_START; i <= ADSP_FE_END; i++) {
app = &adsp->apps[i];
src = app->reg;
@@ -2111,12 +2250,43 @@ static void tegra_adsp_set_admaif_id(
}
if (src != be_reg)
continue;
stream = SNDRV_PCM_STREAM_CAPTURE;
adsp->fe_to_admaif_map[i-1][stream] = admaif_id;
dev_vdbg(adsp->dev, "%s : capture fe %d admaif %d\n",
__func__, i, admaif_id);
return;
}
/* Check if ADSP-ADMAIF is sink for given ADSP ADMAIF (IO to IO) */
for (i = ADSP_ADMAIF_START; i <= ADSP_ADMAIF_END; i++) {
app = &adsp->apps[i];
src = app->reg;
while (!IS_ADSP_ADMAIF(src) && src != 0) {
src = tegra210_adsp_get_source(
adsp, src);
}
if (src != be_reg)
continue;
/* Clear older FE to ADMAIF mappings for given ADMAIF */
stream = SNDRV_PCM_STREAM_CAPTURE;
for (j = ADSP_FE_START; j <= ADSP_FE_END; j++) {
if (adsp->fe_to_admaif_map[j-1][stream] == admaif_id)
adsp->fe_to_admaif_map[j-1][stream] = -1;
}
dev_vdbg(adsp->dev, "%s : start capture on adsp admaif %d\n",
__func__, admaif_id);
return;
}
dev_err(adsp->dev, "%s: no data sink for ADSP-ADMAIF %d\n",
__func__, admaif_id);
}
return;
}
static int tegra_adsp_admaif_ivc_set_cif(struct tegra210_adsp *adsp,
@@ -2266,12 +2436,11 @@ static int tegra_adsp_admaif_ivc_set_cif(struct tegra210_adsp *adsp,
else
msg.cmd = NVAUDIO_DMAIF_SET_RXCIF;
ret = nvaudio_ivc_send(adsp->hivc_client,
ret = nvaudio_ivc_send_retry(adsp->hivc_client,
&msg,
sizeof(struct nvaudio_ivc_msg));
if (ret < 0)
pr_err("error on ivc_send\n");
pr_err("%s: error during ivc_send\n", __func__);
return ret;
}
@@ -2292,7 +2461,7 @@ static int tegra210_adsp_admaif_hv_hw_params(
adma_params,
stream);
if (ret < 0) {
pr_err("error on ivc_send\n");
pr_err("%s: error during adsp_admaif_set_cif\n", __func__);
return ret;
}
tegra_adsp_set_admaif_id(adsp,
@@ -2567,7 +2736,7 @@ static int tegra210_adsp_admaif_hw_params(struct snd_pcm_substream *substream,
&adma_params,
substream->stream);
if (ret < 0) {
pr_err("error on ivc_send\n");
pr_err("%s: error during adsp_admaif_hv_hw_params\n", __func__);
return ret;
}
/*End of sending IVC command for admaif cif setting*/
@@ -2954,6 +3123,13 @@ static int tegra210_adsp_widget_event(struct snd_soc_dapm_widget *w,
TEGRA210_ADSP_MSG_FLAG_SEND);
if (ret < 0)
dev_err(adsp->dev, "Failed to set state active.");
#ifdef CONFIG_SND_SOC_TEGRA_VIRT_IVC_COMM
ret = tegra210_adsp_send_hv_state_msg(adsp,
app, nvfx_state_active);
if (ret < 0)
dev_err(adsp->dev, "Failed to send hv state active msg.");
#endif
pm_runtime_put(adsp->dev);
}
} else {
@@ -2968,6 +3144,14 @@ static int tegra210_adsp_widget_event(struct snd_soc_dapm_widget *w,
TEGRA210_ADSP_MSG_FLAG_SEND);
if (ret < 0)
dev_err(adsp->dev, "Failed to set state inactive.");
#ifdef CONFIG_SND_SOC_TEGRA_VIRT_IVC_COMM
ret = tegra210_adsp_send_hv_state_msg(adsp,
app, nvfx_state_inactive);
if (ret < 0)
dev_err(adsp->dev, "Failed to send hv state inactive msg.");
#endif
ret = tegra210_adsp_send_reset_msg(app,
(TEGRA210_ADSP_MSG_FLAG_SEND |
TEGRA210_ADSP_MSG_FLAG_NEED_ACK));
@@ -4101,7 +4285,7 @@ static int tegra210_adsp_set_switch(struct snd_kcontrol *kcontrol,
&adma_params,
SNDRV_PCM_STREAM_CAPTURE);
if (ret < 0) {
pr_err("error on ivc_send\n");
pr_err("%s: error during adsp_admaif_hv_hw_params\n", __func__);
return -EPERM;
}
}