mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
ASoC: tegra-alt: ADSP driver enhancements
1. Fix ADSP crash due to reorder of mixer commands 2. Add support to track the PCM paths constructed, have a record of FE/BE connections made by the user. 3. Support ADSP pipeline breakage, linkage, modifications 4. Plugin params can be set at any time This change depends on http://git-master/r/#/c/709103/ functionality wise. Bug 1605750 Bug 1605316 Bug 200075850 Change-Id: I24af6177f8ae21e7a352a58056a7267a129c3846 Signed-off-by: Arun Shamanna Lakshmi <aruns@nvidia.com> Reviewed-on: http://git-master/r/710448
This commit is contained in:
committed by
Sameer Pujar
parent
fb6932c04a
commit
02d90673d9
@@ -112,6 +112,10 @@ struct tegra210_adsp {
|
|||||||
DECLARE_BITMAP(adma_usage, TEGRA210_ADSP_ADMA_CHANNEL_COUNT);
|
DECLARE_BITMAP(adma_usage, TEGRA210_ADSP_ADMA_CHANNEL_COUNT);
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
int init_done;
|
int init_done;
|
||||||
|
struct tegra210_adsp_path {
|
||||||
|
uint32_t fe_reg;
|
||||||
|
uint32_t be_reg;
|
||||||
|
} pcm_path[ADSP_FE_END+1][2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct snd_pcm_hardware adsp_pcm_hardware = {
|
static const struct snd_pcm_hardware adsp_pcm_hardware = {
|
||||||
@@ -352,6 +356,18 @@ static int tegra210_adsp_send_msg(apm_shared_state_t *apm,
|
|||||||
NVADSP_MBOX_SMSG);
|
NVADSP_MBOX_SMSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tegra210_adsp_send_remove_msg(struct tegra210_adsp_app *app,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
apm_msg_t apm_msg;
|
||||||
|
|
||||||
|
apm_msg.msgq_msg.size = MSGQ_MSG_WSIZE(apm_fx_remove_params_t);
|
||||||
|
apm_msg.msg.call_params.size = sizeof(apm_fx_remove_params_t);
|
||||||
|
apm_msg.msg.call_params.method = nvfx_apm_method_fx_remove_all;
|
||||||
|
|
||||||
|
return tegra210_adsp_send_msg(app->apm, &apm_msg, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra210_adsp_send_connect_msg(struct tegra210_adsp_app *src,
|
static int tegra210_adsp_send_connect_msg(struct tegra210_adsp_app *src,
|
||||||
struct tegra210_adsp_app *dst,
|
struct tegra210_adsp_app *dst,
|
||||||
uint32_t flags)
|
uint32_t flags)
|
||||||
@@ -552,8 +568,6 @@ static void tegra210_adsp_app_deinit(struct tegra210_adsp *adsp,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (app->info && !IS_APM_OUT(app->reg)) {
|
if (app->info && !IS_APM_OUT(app->reg)) {
|
||||||
nvadsp_mbox_close(&app->rx_mbox);
|
|
||||||
nvadsp_app_stop(app->info);
|
|
||||||
app->info = NULL;
|
app->info = NULL;
|
||||||
app->plugin = NULL;
|
app->plugin = NULL;
|
||||||
app->apm = NULL;
|
app->apm = NULL;
|
||||||
@@ -564,6 +578,8 @@ static void tegra210_adsp_app_deinit(struct tegra210_adsp *adsp,
|
|||||||
struct tegra210_adsp_app *apm_out =
|
struct tegra210_adsp_app *apm_out =
|
||||||
&adsp->apps[apm_out_reg];
|
&adsp->apps[apm_out_reg];
|
||||||
|
|
||||||
|
nvadsp_mbox_close(&app->rx_mbox);
|
||||||
|
nvadsp_app_stop(app->info);
|
||||||
apm_out->info = NULL;
|
apm_out->info = NULL;
|
||||||
apm_out->plugin = NULL;
|
apm_out->plugin = NULL;
|
||||||
apm_out->apm = NULL;
|
apm_out->apm = NULL;
|
||||||
@@ -571,9 +587,36 @@ static void tegra210_adsp_app_deinit(struct tegra210_adsp *adsp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recursive function to connect plugins under a APM */
|
/* API to connect two APMs */
|
||||||
|
static int tegra210_adsp_connect_apm(struct tegra210_adsp *adsp,
|
||||||
|
struct tegra210_adsp_app *app)
|
||||||
|
{
|
||||||
|
uint32_t source = tegra210_adsp_get_source(adsp, app->reg);
|
||||||
|
struct tegra210_adsp_app *src = &adsp->apps[source];
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* If both APMs are in connected state no need to
|
||||||
|
send connect message */
|
||||||
|
if (app->connect && src->connect)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev_vdbg(adsp->dev, "Connecting APM 0x%x -> 0x%x",
|
||||||
|
src->reg, app->reg);
|
||||||
|
|
||||||
|
ret = tegra210_adsp_send_connect_msg(src, app,
|
||||||
|
TEGRA210_ADSP_MSG_FLAG_HOLD);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(adsp->dev, "Connect msg failed. err %d.", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recursive function to connect plugins under a APM
|
||||||
|
Returns BE/FE on the pcm path */
|
||||||
static int tegra210_adsp_connect_plugin(struct tegra210_adsp *adsp,
|
static int tegra210_adsp_connect_plugin(struct tegra210_adsp *adsp,
|
||||||
struct tegra210_adsp_app *app)
|
struct tegra210_adsp_app *app,
|
||||||
|
uint32_t *apm_in_src)
|
||||||
{
|
{
|
||||||
struct tegra210_adsp_app *src;
|
struct tegra210_adsp_app *src;
|
||||||
uint32_t source;
|
uint32_t source;
|
||||||
@@ -585,9 +628,30 @@ static int tegra210_adsp_connect_plugin(struct tegra210_adsp *adsp,
|
|||||||
|
|
||||||
src = &adsp->apps[source];
|
src = &adsp->apps[source];
|
||||||
if (!IS_APM_IN(src->reg)) {
|
if (!IS_APM_IN(src->reg)) {
|
||||||
ret = tegra210_adsp_connect_plugin(adsp, src);
|
ret = tegra210_adsp_connect_plugin(adsp, src, apm_in_src);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
} else {
|
||||||
|
source = tegra210_adsp_get_source(adsp, src->reg);
|
||||||
|
if (IS_APM_OUT(source)) {
|
||||||
|
/* connect plugins inside next APM */
|
||||||
|
ret = tegra210_adsp_connect_plugin(adsp,
|
||||||
|
&adsp->apps[source], apm_in_src);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
/* connect APM_IN to APM_OUT */
|
||||||
|
ret = tegra210_adsp_connect_apm(adsp, src);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
/* return if APM_IN is not
|
||||||
|
connected to valid inputs */
|
||||||
|
if (!IS_ADSP_FE(source) &&
|
||||||
|
!IS_ADSP_ADMAIF(source))
|
||||||
|
return -ENODEV;
|
||||||
|
if (apm_in_src)
|
||||||
|
*apm_in_src = source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
app->apm = src->apm;
|
app->apm = src->apm;
|
||||||
|
|
||||||
@@ -611,51 +675,129 @@ static int tegra210_adsp_connect_plugin(struct tegra210_adsp *adsp,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* API to connect two APMs */
|
/* Manages FE/BE plugins and deletes if fe_apm is specified */
|
||||||
static int tegra210_adsp_connect_apm(struct tegra210_adsp *adsp,
|
static void tegra210_adsp_manage_plugin(struct tegra210_adsp *adsp,
|
||||||
struct tegra210_adsp_app *app)
|
uint32_t end_reg, uint32_t apm_out, struct tegra210_adsp_app *fe_apm)
|
||||||
{
|
{
|
||||||
struct tegra210_adsp_app *src;
|
uint32_t j, fe_reg, be_reg;
|
||||||
uint32_t source;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
source = tegra210_adsp_get_source(adsp, app->reg);
|
if (IS_ADSP_FE(end_reg)) {
|
||||||
if (!IS_ADSP_APP(source))
|
/* manage playback path */
|
||||||
return -EPIPE;
|
fe_reg = end_reg;
|
||||||
|
be_reg = 0;
|
||||||
src = &adsp->apps[source];
|
for (j = ADSP_ADMAIF_START; j <= ADSP_ADMAIF_END; j++) {
|
||||||
|
if (tegra210_adsp_get_source(adsp, j) == apm_out) {
|
||||||
if (IS_APM_OUT(src->reg)) {
|
be_reg = j;
|
||||||
/* If both APMs are in connected state no need to
|
break;
|
||||||
send connect message */
|
}
|
||||||
if (app->connect && src->connect)
|
}
|
||||||
return 0;
|
if (be_reg && fe_reg) {
|
||||||
|
if (fe_apm) {
|
||||||
dev_vdbg(adsp->dev, "Connecting APM 0x%x -> 0x%x",
|
dev_vdbg(adsp->dev, "Remove playback FE %d -- BE %d pair",
|
||||||
src->reg, app->reg);
|
fe_reg, be_reg);
|
||||||
|
tegra210_adsp_send_remove_msg(fe_apm,
|
||||||
ret = tegra210_adsp_send_connect_msg(src, app,
|
TEGRA210_ADSP_MSG_FLAG_SEND);
|
||||||
TEGRA210_ADSP_MSG_FLAG_HOLD);
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].fe_reg = 0;
|
||||||
if (ret < 0) {
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].be_reg = 0;
|
||||||
dev_err(adsp->dev, "Connect msg failed. err %d.", ret);
|
} else {
|
||||||
return ret;
|
dev_vdbg(adsp->dev, "Found playback FE %d -- BE %d pair",
|
||||||
|
fe_reg, be_reg);
|
||||||
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].fe_reg = fe_reg;
|
||||||
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_PLAYBACK].be_reg = be_reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (IS_ADSP_ADMAIF(end_reg)) {
|
||||||
|
/* manage record path */
|
||||||
|
fe_reg = 0;
|
||||||
|
be_reg = end_reg;
|
||||||
|
for (j = ADSP_FE_START; j <= ADSP_FE_END; j++) {
|
||||||
|
if (tegra210_adsp_get_source(adsp, j) == apm_out) {
|
||||||
|
fe_reg = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (be_reg && fe_reg) {
|
||||||
|
if (fe_apm) {
|
||||||
|
dev_vdbg(adsp->dev, "Remove record FE %d -- BE %d pair",
|
||||||
|
fe_reg, be_reg);
|
||||||
|
tegra210_adsp_send_remove_msg(fe_apm,
|
||||||
|
TEGRA210_ADSP_MSG_FLAG_SEND);
|
||||||
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].fe_reg = 0;
|
||||||
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].be_reg = 0;
|
||||||
|
} else {
|
||||||
|
dev_vdbg(adsp->dev, "Found playback FE %d -- BE %d pair",
|
||||||
|
fe_reg, be_reg);
|
||||||
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].fe_reg = fe_reg;
|
||||||
|
adsp->pcm_path[fe_reg][SNDRV_PCM_STREAM_CAPTURE].be_reg = be_reg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
return -EPIPE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over all APMs and establish pending connections */
|
/* Iterate over all APMs and establish pending connections */
|
||||||
static int tegra210_adsp_update_connection(struct tegra210_adsp *adsp)
|
static int tegra210_adsp_update_connection(struct tegra210_adsp *adsp)
|
||||||
{
|
{
|
||||||
int i;
|
int i, ret;
|
||||||
|
uint32_t end_reg;
|
||||||
|
|
||||||
for (i = APM_OUT_START; i <= APM_OUT_END; i++)
|
for (i = APM_OUT_START; i <= APM_OUT_END; i++) {
|
||||||
tegra210_adsp_connect_plugin(adsp, &adsp->apps[i]);
|
ret = tegra210_adsp_connect_plugin(adsp, &adsp->apps[i], &end_reg);
|
||||||
|
if (ret >= 0) {
|
||||||
|
/* Record FE/BE pair for every successful connection */
|
||||||
|
tegra210_adsp_manage_plugin(adsp, end_reg, i, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = APM_IN_START; i <= APM_IN_END; i++)
|
return 0;
|
||||||
tegra210_adsp_connect_apm(adsp, &adsp->apps[i]);
|
}
|
||||||
|
|
||||||
|
/* Remove the plugin connections inside associated APM */
|
||||||
|
static int tegra210_adsp_remove_connection(struct tegra210_adsp *adsp,
|
||||||
|
struct tegra210_adsp_app *plugin)
|
||||||
|
{
|
||||||
|
struct tegra210_adsp_app *app;
|
||||||
|
uint32_t i, source, apm_out = 0;
|
||||||
|
|
||||||
|
if (!IS_ADSP_APP(plugin->reg))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = APM_OUT_START; i <= APM_OUT_END; i++) {
|
||||||
|
app = &adsp->apps[i];
|
||||||
|
/* if the path is already broken, do not continue */
|
||||||
|
if (!app->connect)
|
||||||
|
continue;
|
||||||
|
while (app->reg != TEGRA210_ADSP_NONE) {
|
||||||
|
if (app->reg == plugin->reg) {
|
||||||
|
apm_out = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
source = tegra210_adsp_get_source(adsp, app->reg);
|
||||||
|
app = &adsp->apps[source];
|
||||||
|
}
|
||||||
|
if (apm_out != TEGRA210_ADSP_NONE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* if plugin is not part of any APM, return here */
|
||||||
|
if (apm_out == TEGRA210_ADSP_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* disconnect the plugins inside APM */
|
||||||
|
app = &adsp->apps[apm_out];
|
||||||
|
while (!IS_APM_IN(app->reg)) {
|
||||||
|
source = tegra210_adsp_get_source(adsp, app->reg);
|
||||||
|
if (!IS_ADSP_APP(source))
|
||||||
|
break;
|
||||||
|
app->connect = 0;
|
||||||
|
app = &adsp->apps[source];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete the plugins inside APM */
|
||||||
|
if (IS_APM_IN(app->reg)) {
|
||||||
|
/* clear the FE/BE list */
|
||||||
|
tegra210_adsp_manage_plugin(adsp,
|
||||||
|
tegra210_adsp_get_source(adsp, app->reg),
|
||||||
|
apm_out, app);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,6 +887,12 @@ static int tegra210_adsp_compr_open(struct snd_compr_stream *cstream)
|
|||||||
if (!adsp->init_done)
|
if (!adsp->init_done)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (!adsp->pcm_path[fe_reg][cstream->direction].fe_reg ||
|
||||||
|
!adsp->pcm_path[fe_reg][cstream->direction].be_reg) {
|
||||||
|
dev_err(adsp->dev, "Broken Path%d - FE not linked to BE", fe_reg);
|
||||||
|
return -EPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_compr_rtd),
|
prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_compr_rtd),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!prtd) {
|
if (!prtd) {
|
||||||
@@ -1039,6 +1187,12 @@ static int tegra210_adsp_pcm_open(struct snd_pcm_substream *substream)
|
|||||||
|
|
||||||
dev_vdbg(adsp->dev, "%s", __func__);
|
dev_vdbg(adsp->dev, "%s", __func__);
|
||||||
|
|
||||||
|
if (!adsp->pcm_path[fe_reg][substream->stream].fe_reg ||
|
||||||
|
!adsp->pcm_path[fe_reg][substream->stream].be_reg) {
|
||||||
|
dev_err(adsp->dev, "Broken Path%d - FE not linked to BE", fe_reg);
|
||||||
|
return -EPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_pcm_rtd),
|
prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_pcm_rtd),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!prtd) {
|
if (!prtd) {
|
||||||
@@ -1454,8 +1608,13 @@ static int tegra210_adsp_mux_put(struct snd_kcontrol *kcontrol,
|
|||||||
if (IS_ADSP_APP(e->reg)) {
|
if (IS_ADSP_APP(e->reg)) {
|
||||||
app = &adsp->apps[e->reg];
|
app = &adsp->apps[e->reg];
|
||||||
cur_val = tegra210_adsp_get_source(adsp, e->reg);
|
cur_val = tegra210_adsp_get_source(adsp, e->reg);
|
||||||
if (cur_val != val)
|
if (cur_val != val) {
|
||||||
|
if (app->connect) {
|
||||||
|
/* remove existing connections if any */
|
||||||
|
tegra210_adsp_remove_connection(adsp, app);
|
||||||
|
}
|
||||||
app->connect = 0;
|
app->connect = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (val == TEGRA210_ADSP_NONE) {
|
if (val == TEGRA210_ADSP_NONE) {
|
||||||
tegra210_adsp_app_deinit(adsp, app);
|
tegra210_adsp_app_deinit(adsp, app);
|
||||||
@@ -2197,7 +2356,7 @@ static int tegra210_adsp_audio_platform_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
adsp = devm_kzalloc(&pdev->dev, sizeof(*adsp), GFP_KERNEL);
|
adsp = devm_kzalloc(&pdev->dev, sizeof(*adsp), GFP_KERNEL);
|
||||||
if (!adsp) {
|
if (!adsp) {
|
||||||
dev_err(&pdev->dev, "Can't allocate tegra30_adsp_ctx\n");
|
dev_err(&pdev->dev, "Can't allocate tegra210_adsp_ctx\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
dev_set_drvdata(&pdev->dev, adsp);
|
dev_set_drvdata(&pdev->dev, adsp);
|
||||||
|
|||||||
Reference in New Issue
Block a user