On Tue, 17 Aug 2021 at 03:30, Dmitry Osipenko digetx@gmail.com wrote:
Add runtime PM and OPP support to the Host1x driver. It's required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain. For the starter we will keep host1x always-on because dynamic power management require a major refactoring of the driver code since lot's of code paths will need the RPM handling and we're going to remove some of these paths in the future. Host1x doesn't consume much power so it is good enough, we at least need to resume Host1x in order to initialize the power state.
Tested-by: Peter Geis pgwipeout@gmail.com # Ouya T30 Tested-by: Paul Fertser fercerpav@gmail.com # PAZ00 T20 Tested-by: Nicolas Chauvet kwizart@gmail.com # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar mattmerhar@protonmail.com # Ouya T30 Signed-off-by: Dmitry Osipenko digetx@gmail.com
[...]
static int host1x_probe(struct platform_device *pdev) { struct host1x *host; @@ -394,6 +423,10 @@ static int host1x_probe(struct platform_device *pdev) /* set common host1x device data */ platform_set_drvdata(pdev, host);
err = devm_tegra_core_dev_init_opp_table_simple(&pdev->dev);
if (err)
return err;
host->regs = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(host->regs)) return PTR_ERR(host->regs);
@@ -423,12 +456,9 @@ static int host1x_probe(struct platform_device *pdev) return err; }
host->rst = devm_reset_control_get(&pdev->dev, "host1x");
if (IS_ERR(host->rst)) {
err = PTR_ERR(host->rst);
dev_err(&pdev->dev, "failed to get reset: %d\n", err);
err = host1x_get_resets(host);
if (err) return err;
} err = host1x_iommu_init(host); if (err < 0) {
@@ -443,22 +473,10 @@ static int host1x_probe(struct platform_device *pdev) goto iommu_exit; }
err = clk_prepare_enable(host->clk);
if (err < 0) {
dev_err(&pdev->dev, "failed to enable clock\n");
goto free_channels;
}
err = reset_control_deassert(host->rst);
if (err < 0) {
dev_err(&pdev->dev, "failed to deassert reset: %d\n", err);
goto unprepare_disable;
}
Removing the clk_prepare_enable() and reset_control_deassert() from host1x_probe(), might not be a good idea. See more about why, below.
err = host1x_syncpt_init(host); if (err) { dev_err(&pdev->dev, "failed to initialize syncpts\n");
goto reset_assert;
goto free_channels; } err = host1x_intr_init(host, syncpt_irq);
@@ -467,10 +485,14 @@ static int host1x_probe(struct platform_device *pdev) goto deinit_syncpt; }
host1x_debug_init(host);
pm_runtime_enable(&pdev->dev);
if (host->info->has_hypervisor)
host1x_setup_sid_table(host);
/* the driver's code isn't ready yet for the dynamic RPM */
err = pm_runtime_resume_and_get(&pdev->dev);
If the driver is being built with the CONFIG_PM Kconfig option being unset, pm_runtime_resume_and_get() will return 0 to indicate success - and without calling the ->runtime_resume() callback. In other words, the clock will remain gated and the reset will not be deasserted, likely causing the driver to be malfunctioning.
If the driver isn't ever being built with CONFIG_PM unset, feel free to ignore my above comments.
Otherwise, if it needs to work both with and without CONFIG_PM being set, you may use the following pattern in host1x_probe() to deploy runtime PM support:
"Enable the needed resources to probe the device" pm_runtime_get_noresume() pm_runtime_set_active() pm_runtime_enable()
"Before successfully completing probe" pm_runtime_put()
if (err)
goto deinit_intr;
host1x_debug_init(host); err = host1x_register(host); if (err < 0)
@@ -486,13 +508,13 @@ static int host1x_probe(struct platform_device *pdev) host1x_unregister(host); deinit_debugfs: host1x_debug_deinit(host);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+deinit_intr: host1x_intr_deinit(host); deinit_syncpt: host1x_syncpt_deinit(host); -reset_assert:
reset_control_assert(host->rst);
-unprepare_disable:
clk_disable_unprepare(host->clk);
free_channels: host1x_channel_list_free(&host->channel_list); iommu_exit:
[...]
Kind regards Uffe