drm/tegra: Unify logic for suspend and resume

Two main changes for the suspend and resume:
1. Set clock to Fmin/Fmax in suspend/resume cycles
2. Reorder the code in suspend and resume functions and add recovering
   logic when error happens in between

Bug 4224081

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
Change-Id: Iadb0b1f960ca8b9c80094d1769a2d90496263124
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2948452
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Johnny Liu
2023-08-04 05:41:32 +00:00
committed by mobile promotions
parent 61af983ca4
commit 69d9f479a4
4 changed files with 82 additions and 43 deletions

View File

@@ -577,12 +577,14 @@ static __maybe_unused int nvdec_runtime_resume(struct device *dev)
goto disable; goto disable;
} }
err = devfreq_resume_device(nvdec->devfreq);
if (err < 0)
goto disable;
nvdec_actmon_reg_init(nvdec); nvdec_actmon_reg_init(nvdec);
host1x_actmon_enable(&nvdec->client.base); host1x_actmon_enable(&nvdec->client.base);
devfreq_resume_device(nvdec->devfreq);
return 0; return 0;
disable: disable:
@@ -595,21 +597,29 @@ static __maybe_unused int nvdec_runtime_suspend(struct device *dev)
struct nvdec *nvdec = dev_get_drvdata(dev); struct nvdec *nvdec = dev_get_drvdata(dev);
int err; int err;
devfreq_suspend_device(nvdec->devfreq); err = devfreq_suspend_device(nvdec->devfreq);
if (err < 0)
host1x_actmon_disable(&nvdec->client.base); return err;
host1x_channel_stop(nvdec->channel);
clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks);
if (nvdec->icc_write) { if (nvdec->icc_write) {
err = icc_set_bw(nvdec->icc_write, 0, 0); err = icc_set_bw(nvdec->icc_write, 0, 0);
if (err) if (err) {
dev_warn(nvdec->dev, "failed to set icc bw: %d\n", err); dev_warn(nvdec->dev, "failed to set icc bw: %d\n", err);
goto devfreq_resume;
}
} }
clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks);
host1x_channel_stop(nvdec->channel);
host1x_actmon_disable(&nvdec->client.base);
return 0; return 0;
devfreq_resume:
devfreq_resume_device(nvdec->devfreq);
return err;
} }
static int nvdec_open_channel(struct tegra_drm_client *client, static int nvdec_open_channel(struct tegra_drm_client *client,

View File

@@ -467,12 +467,14 @@ static __maybe_unused int nvenc_runtime_resume(struct device *dev)
if (err < 0) if (err < 0)
goto disable; goto disable;
err = devfreq_resume_device(nvenc->devfreq);
if (err < 0)
goto disable;
nvenc_actmon_reg_init(nvenc); nvenc_actmon_reg_init(nvenc);
host1x_actmon_enable(&nvenc->client.base); host1x_actmon_enable(&nvenc->client.base);
devfreq_resume_device(nvenc->devfreq);
return 0; return 0;
disable: disable:
@@ -485,21 +487,29 @@ static __maybe_unused int nvenc_runtime_suspend(struct device *dev)
struct nvenc *nvenc = dev_get_drvdata(dev); struct nvenc *nvenc = dev_get_drvdata(dev);
int err; int err;
devfreq_suspend_device(nvenc->devfreq); err = devfreq_suspend_device(nvenc->devfreq);
if (err < 0)
host1x_actmon_disable(&nvenc->client.base); return err;
host1x_channel_stop(nvenc->channel);
clk_disable_unprepare(nvenc->clk);
if (nvenc->icc_write) { if (nvenc->icc_write) {
err = icc_set_bw(nvenc->icc_write, 0, 0); err = icc_set_bw(nvenc->icc_write, 0, 0);
if (err) if (err) {
dev_warn(nvenc->dev, "failed to set icc bw: %d\n", err); dev_warn(nvenc->dev, "failed to set icc bw: %d\n", err);
goto devfreq_resume;
}
} }
clk_disable_unprepare(nvenc->clk);
host1x_channel_stop(nvenc->channel);
host1x_actmon_disable(&nvenc->client.base);
return 0; return 0;
devfreq_resume:
devfreq_resume_device(nvenc->devfreq);
return err;
} }
static int nvenc_open_channel(struct tegra_drm_client *client, static int nvenc_open_channel(struct tegra_drm_client *client,

View File

@@ -466,12 +466,14 @@ static __maybe_unused int nvjpg_runtime_resume(struct device *dev)
if (err < 0) if (err < 0)
goto disable; goto disable;
err = devfreq_resume_device(nvjpg->devfreq);
if (err < 0)
goto disable;
nvjpg_actmon_reg_init(nvjpg); nvjpg_actmon_reg_init(nvjpg);
host1x_actmon_enable(&nvjpg->client.base); host1x_actmon_enable(&nvjpg->client.base);
devfreq_resume_device(nvjpg->devfreq);
return 0; return 0;
disable: disable:
@@ -484,21 +486,29 @@ static __maybe_unused int nvjpg_runtime_suspend(struct device *dev)
struct nvjpg *nvjpg = dev_get_drvdata(dev); struct nvjpg *nvjpg = dev_get_drvdata(dev);
int err; int err;
devfreq_suspend_device(nvjpg->devfreq); err = devfreq_suspend_device(nvjpg->devfreq);
if (err < 0)
host1x_actmon_disable(&nvjpg->client.base); return err;
host1x_channel_stop(nvjpg->channel);
clk_disable_unprepare(nvjpg->clk);
if (nvjpg->icc_write) { if (nvjpg->icc_write) {
err = icc_set_bw(nvjpg->icc_write, 0, 0); err = icc_set_bw(nvjpg->icc_write, 0, 0);
if (err) if (err) {
dev_warn(nvjpg->dev, "failed to set icc bw: %d\n", err); dev_warn(nvjpg->dev, "failed to set icc bw: %d\n", err);
goto devfreq_resume;
}
} }
clk_disable_unprepare(nvjpg->clk);
host1x_channel_stop(nvjpg->channel);
host1x_actmon_disable(&nvjpg->client.base);
return 0; return 0;
devfreq_resume:
devfreq_resume_device(nvjpg->devfreq);
return err;
} }
static int nvjpg_open_channel(struct tegra_drm_client *client, static int nvjpg_open_channel(struct tegra_drm_client *client,

View File

@@ -524,18 +524,19 @@ static int __maybe_unused vic_runtime_resume(struct device *dev)
if (err < 0) if (err < 0)
goto assert; goto assert;
err = devfreq_resume_device(vic->devfreq);
if (err < 0)
goto assert;
vic_actmon_reg_init(vic); vic_actmon_reg_init(vic);
host1x_actmon_enable(&vic->client.base); host1x_actmon_enable(&vic->client.base);
devfreq_resume_device(vic->devfreq);
return 0; return 0;
assert: assert:
reset_control_assert(vic->rst); reset_control_assert(vic->rst);
disable: disable:
devfreq_suspend_device(vic->devfreq);
clk_disable_unprepare(vic->clk); clk_disable_unprepare(vic->clk);
return err; return err;
} }
@@ -545,27 +546,35 @@ static int __maybe_unused vic_runtime_suspend(struct device *dev)
struct vic *vic = dev_get_drvdata(dev); struct vic *vic = dev_get_drvdata(dev);
int err; int err;
devfreq_suspend_device(vic->devfreq); err = devfreq_suspend_device(vic->devfreq);
if (err < 0)
return err;
host1x_actmon_disable(&vic->client.base); if (vic->icc_write) {
err = icc_set_bw(vic->icc_write, 0, 0);
host1x_channel_stop(vic->channel); if (err) {
dev_warn(vic->dev, "failed to set icc bw: %d\n", err);
goto devfreq_resume;
}
}
err = reset_control_assert(vic->rst); err = reset_control_assert(vic->rst);
if (err < 0) if (err < 0)
return err; goto devfreq_resume;
usleep_range(2000, 4000); usleep_range(2000, 4000);
clk_disable_unprepare(vic->clk); clk_disable_unprepare(vic->clk);
if (vic->icc_write) { host1x_channel_stop(vic->channel);
err = icc_set_bw(vic->icc_write, 0, 0);
if (err) host1x_actmon_disable(&vic->client.base);
dev_warn(vic->dev, "failed to set icc bw: %d\n", err);
}
return 0; return 0;
devfreq_resume:
devfreq_resume_device(vic->devfreq);
return err;
} }
static int vic_open_channel(struct tegra_drm_client *client, static int vic_open_channel(struct tegra_drm_client *client,