From: Dmitry Osipenko <digetx@gmail.com> To: "Thierry Reding" <thierry.reding@gmail.com>, "Jonathan Hunter" <jonathanh@nvidia.com>, "Ulf Hansson" <ulf.hansson@linaro.org>, "Viresh Kumar" <vireshk@kernel.org>, "Stephen Boyd" <sboyd@kernel.org>, "Peter De Schrijver" <pdeschrijver@nvidia.com>, "Mikko Perttunen" <mperttunen@nvidia.com>, "Lee Jones" <lee.jones@linaro.org>, "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Nishanth Menon" <nm@ti.com>, "Adrian Hunter" <adrian.hunter@intel.com>, "Michael Turquette" <mturquette@baylibre.com> Cc: linux-pwm@vger.kernel.org, linux-pm@vger.kernel.org, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, David Heidelberg <david@ixit.cz>, linux-tegra@vger.kernel.org, linux-clk@vger.kernel.org Subject: [PATCH v16 08/40] gpu: host1x: Add initial runtime PM and OPP support Date: Wed, 1 Dec 2021 02:23:15 +0300 [thread overview] Message-ID: <20211130232347.950-9-digetx@gmail.com> (raw) In-Reply-To: <20211130232347.950-1-digetx@gmail.com> Add runtime PM and OPP support to the Host1x driver. 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 are missing the RPM handling and we're going to remove some of these paths in the future. Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> 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> --- drivers/gpu/host1x/debug.c | 15 +++ drivers/gpu/host1x/dev.c | 150 +++++++++++++++++++++++------ drivers/gpu/host1x/dev.h | 3 +- drivers/gpu/host1x/hw/channel_hw.c | 44 ++++----- drivers/gpu/host1x/intr.c | 3 - drivers/gpu/host1x/syncpt.c | 5 +- 6 files changed, 164 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index 8a14880c61bb..18d9c8d206e3 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c @@ -7,6 +7,7 @@ */ #include <linux/debugfs.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/uaccess.h> @@ -52,6 +53,11 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) { struct host1x *m = dev_get_drvdata(ch->dev->parent); struct output *o = data; + int err; + + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return err; mutex_lock(&ch->cdma.lock); mutex_lock(&debug_lock); @@ -64,6 +70,8 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) mutex_unlock(&debug_lock); mutex_unlock(&ch->cdma.lock); + pm_runtime_put(m->dev); + return 0; } @@ -71,9 +79,14 @@ static void show_syncpts(struct host1x *m, struct output *o) { struct list_head *pos; unsigned int i; + int err; host1x_debug_output(o, "---- syncpts ----\n"); + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return; + for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { u32 max = host1x_syncpt_read_max(m->syncpt + i); u32 min = host1x_syncpt_load(m->syncpt + i); @@ -101,6 +114,8 @@ static void show_syncpts(struct host1x *m, struct output *o) base_val); } + pm_runtime_put(m->dev); + host1x_debug_output(o, "\n"); } diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 3d4cabdbc78d..c42ab78327e7 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -6,14 +6,18 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/list.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> +#include <soc/tegra/common.h> + #define CREATE_TRACE_POINTS #include <trace/events/host1x.h> #undef CREATE_TRACE_POINTS @@ -208,6 +212,9 @@ static void host1x_setup_sid_table(struct host1x *host) const struct host1x_info *info = host->info; unsigned int i; + if (!info->has_hypervisor) + return; + for (i = 0; i < info->num_sid_entries; i++) { const struct host1x_sid_entry *entry = &info->sid_table[i]; @@ -365,6 +372,27 @@ static void host1x_iommu_exit(struct host1x *host) } } +static int host1x_get_resets(struct host1x *host) +{ + int err; + + host->resets[0].id = "mc"; + host->resets[1].id = "host1x"; + host->nresets = ARRAY_SIZE(host->resets); + + err = devm_reset_control_bulk_get_optional_exclusive_released( + host->dev, host->nresets, host->resets); + if (err) { + dev_err(host->dev, "failed to get reset: %d\n", err); + return err; + } + + if (WARN_ON(!host->resets[1].rstc)) + return -ENOENT; + + return 0; +} + static int host1x_probe(struct platform_device *pdev) { struct host1x *host; @@ -442,12 +470,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) { @@ -462,22 +487,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; - } - 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); @@ -486,10 +499,18 @@ static int host1x_probe(struct platform_device *pdev) goto deinit_syncpt; } - host1x_debug_init(host); + pm_runtime_enable(&pdev->dev); + + err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); + if (err) + goto pm_disable; - 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 (err) + goto pm_disable; + + host1x_debug_init(host); err = host1x_register(host); if (err < 0) @@ -505,13 +526,14 @@ static int host1x_probe(struct platform_device *pdev) host1x_unregister(host); deinit_debugfs: host1x_debug_deinit(host); + + pm_runtime_put_sync_suspend(&pdev->dev); +pm_disable: + pm_runtime_disable(&pdev->dev); + 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: @@ -526,20 +548,94 @@ static int host1x_remove(struct platform_device *pdev) host1x_unregister(host); host1x_debug_deinit(host); + + pm_runtime_force_suspend(&pdev->dev); + host1x_intr_deinit(host); host1x_syncpt_deinit(host); - reset_control_assert(host->rst); - clk_disable_unprepare(host->clk); host1x_iommu_exit(host); host1x_bo_cache_destroy(&host->cache); return 0; } +static int __maybe_unused host1x_runtime_suspend(struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + host1x_intr_stop(host); + host1x_syncpt_save(host); + + err = reset_control_bulk_assert(host->nresets, host->resets); + if (err) { + dev_err(dev, "failed to assert reset: %d\n", err); + goto resume_host1x; + } + + usleep_range(1000, 2000); + + clk_disable_unprepare(host->clk); + reset_control_bulk_release(host->nresets, host->resets); + + return 0; + +resume_host1x: + host1x_setup_sid_table(host); + host1x_syncpt_restore(host); + host1x_intr_start(host); + + return err; +} + +static int __maybe_unused host1x_runtime_resume(struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + err = reset_control_bulk_acquire(host->nresets, host->resets); + if (err) { + dev_err(dev, "failed to acquire reset: %d\n", err); + return err; + } + + err = clk_prepare_enable(host->clk); + if (err) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto release_reset; + } + + err = reset_control_bulk_deassert(host->nresets, host->resets); + if (err < 0) { + dev_err(dev, "failed to deassert reset: %d\n", err); + goto disable_clk; + } + + host1x_setup_sid_table(host); + host1x_syncpt_restore(host); + host1x_intr_start(host); + + return 0; + +disable_clk: + clk_disable_unprepare(host->clk); +release_reset: + reset_control_bulk_release(host->nresets, host->resets); + + return err; +} + +static const struct dev_pm_ops host1x_pm = { + SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, + NULL) + /* TODO: add system suspend-resume once driver will be ready for that */ +}; + static struct platform_driver tegra_host1x_driver = { .driver = { .name = "tegra-host1x", .of_match_table = host1x_of_match, + .pm = &host1x_pm, }, .probe = host1x_probe, .remove = host1x_remove, diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 5b7fdea5d169..ca4b082f0cd4 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -118,7 +118,8 @@ struct host1x { struct host1x_syncpt_base *bases; struct device *dev; struct clk *clk; - struct reset_control *rst; + struct reset_control_bulk_data resets[2]; + unsigned int nresets; struct iommu_group *group; struct iommu_domain *domain; diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 1999780a7203..6b40e9af1e88 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c @@ -159,6 +159,27 @@ static void host1x_channel_set_streamid(struct host1x_channel *channel) #endif } +static void host1x_enable_gather_filter(struct host1x_channel *ch) +{ +#if HOST1X_HW >= 6 + struct host1x *host = dev_get_drvdata(ch->dev->parent); + u32 val; + + if (!host->hv_regs) + return; + + val = host1x_hypervisor_readl( + host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); + val |= BIT(ch->id % 32); + host1x_hypervisor_writel( + host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); +#elif HOST1X_HW >= 4 + host1x_ch_writel(ch, + HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1), + HOST1X_CHANNEL_CHANNELCTRL); +#endif +} + static int channel_submit(struct host1x_job *job) { struct host1x_channel *ch = job->channel; @@ -190,6 +211,7 @@ static int channel_submit(struct host1x_job *job) } host1x_channel_set_streamid(ch); + host1x_enable_gather_filter(ch); /* begin a CDMA submit */ err = host1x_cdma_begin(&ch->cdma, job); @@ -249,27 +271,6 @@ static int channel_submit(struct host1x_job *job) return err; } -static void enable_gather_filter(struct host1x *host, - struct host1x_channel *ch) -{ -#if HOST1X_HW >= 6 - u32 val; - - if (!host->hv_regs) - return; - - val = host1x_hypervisor_readl( - host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); - val |= BIT(ch->id % 32); - host1x_hypervisor_writel( - host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); -#elif HOST1X_HW >= 4 - host1x_ch_writel(ch, - HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1), - HOST1X_CHANNEL_CHANNELCTRL); -#endif -} - static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, unsigned int index) { @@ -278,7 +279,6 @@ static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, #else ch->regs = dev->regs + index * 0x100; #endif - enable_gather_filter(dev, ch); return 0; } diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c index 45b6be927ec4..965ba21818b1 100644 --- a/drivers/gpu/host1x/intr.c +++ b/drivers/gpu/host1x/intr.c @@ -297,14 +297,11 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync) "host1x_sp_%02u", id); } - host1x_intr_start(host); - return 0; } void host1x_intr_deinit(struct host1x *host) { - host1x_intr_stop(host); } void host1x_intr_start(struct host1x *host) diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index d198a10848c6..e08e331e46ae 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -143,6 +143,8 @@ void host1x_syncpt_restore(struct host1x *host) for (i = 0; i < host1x_syncpt_nb_bases(host); i++) host1x_hw_syncpt_restore_wait_base(host, sp_base + i); + host1x_hw_syncpt_enable_protection(host); + wmb(); } @@ -366,9 +368,6 @@ int host1x_syncpt_init(struct host1x *host) host->syncpt = syncpt; host->bases = bases; - host1x_syncpt_restore(host); - host1x_hw_syncpt_enable_protection(host); - /* Allocate sync point to use for clearing waits for expired fences */ host->nop_sp = host1x_syncpt_alloc(host, 0, "reserved-nop"); if (!host->nop_sp) -- 2.33.1
WARNING: multiple messages have this Message-ID (diff)
From: Dmitry Osipenko <digetx@gmail.com> To: "Thierry Reding" <thierry.reding@gmail.com>, "Jonathan Hunter" <jonathanh@nvidia.com>, "Ulf Hansson" <ulf.hansson@linaro.org>, "Viresh Kumar" <vireshk@kernel.org>, "Stephen Boyd" <sboyd@kernel.org>, "Peter De Schrijver" <pdeschrijver@nvidia.com>, "Mikko Perttunen" <mperttunen@nvidia.com>, "Lee Jones" <lee.jones@linaro.org>, "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Nishanth Menon" <nm@ti.com>, "Adrian Hunter" <adrian.hunter@intel.com>, "Michael Turquette" <mturquette@baylibre.com> Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-mmc@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-clk@vger.kernel.org, David Heidelberg <david@ixit.cz> Subject: [PATCH v16 08/40] gpu: host1x: Add initial runtime PM and OPP support Date: Wed, 1 Dec 2021 02:23:15 +0300 [thread overview] Message-ID: <20211130232347.950-9-digetx@gmail.com> (raw) In-Reply-To: <20211130232347.950-1-digetx@gmail.com> Add runtime PM and OPP support to the Host1x driver. 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 are missing the RPM handling and we're going to remove some of these paths in the future. Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> 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> --- drivers/gpu/host1x/debug.c | 15 +++ drivers/gpu/host1x/dev.c | 150 +++++++++++++++++++++++------ drivers/gpu/host1x/dev.h | 3 +- drivers/gpu/host1x/hw/channel_hw.c | 44 ++++----- drivers/gpu/host1x/intr.c | 3 - drivers/gpu/host1x/syncpt.c | 5 +- 6 files changed, 164 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index 8a14880c61bb..18d9c8d206e3 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c @@ -7,6 +7,7 @@ */ #include <linux/debugfs.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/uaccess.h> @@ -52,6 +53,11 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) { struct host1x *m = dev_get_drvdata(ch->dev->parent); struct output *o = data; + int err; + + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return err; mutex_lock(&ch->cdma.lock); mutex_lock(&debug_lock); @@ -64,6 +70,8 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) mutex_unlock(&debug_lock); mutex_unlock(&ch->cdma.lock); + pm_runtime_put(m->dev); + return 0; } @@ -71,9 +79,14 @@ static void show_syncpts(struct host1x *m, struct output *o) { struct list_head *pos; unsigned int i; + int err; host1x_debug_output(o, "---- syncpts ----\n"); + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return; + for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { u32 max = host1x_syncpt_read_max(m->syncpt + i); u32 min = host1x_syncpt_load(m->syncpt + i); @@ -101,6 +114,8 @@ static void show_syncpts(struct host1x *m, struct output *o) base_val); } + pm_runtime_put(m->dev); + host1x_debug_output(o, "\n"); } diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 3d4cabdbc78d..c42ab78327e7 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -6,14 +6,18 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/list.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> +#include <soc/tegra/common.h> + #define CREATE_TRACE_POINTS #include <trace/events/host1x.h> #undef CREATE_TRACE_POINTS @@ -208,6 +212,9 @@ static void host1x_setup_sid_table(struct host1x *host) const struct host1x_info *info = host->info; unsigned int i; + if (!info->has_hypervisor) + return; + for (i = 0; i < info->num_sid_entries; i++) { const struct host1x_sid_entry *entry = &info->sid_table[i]; @@ -365,6 +372,27 @@ static void host1x_iommu_exit(struct host1x *host) } } +static int host1x_get_resets(struct host1x *host) +{ + int err; + + host->resets[0].id = "mc"; + host->resets[1].id = "host1x"; + host->nresets = ARRAY_SIZE(host->resets); + + err = devm_reset_control_bulk_get_optional_exclusive_released( + host->dev, host->nresets, host->resets); + if (err) { + dev_err(host->dev, "failed to get reset: %d\n", err); + return err; + } + + if (WARN_ON(!host->resets[1].rstc)) + return -ENOENT; + + return 0; +} + static int host1x_probe(struct platform_device *pdev) { struct host1x *host; @@ -442,12 +470,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) { @@ -462,22 +487,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; - } - 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); @@ -486,10 +499,18 @@ static int host1x_probe(struct platform_device *pdev) goto deinit_syncpt; } - host1x_debug_init(host); + pm_runtime_enable(&pdev->dev); + + err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); + if (err) + goto pm_disable; - 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 (err) + goto pm_disable; + + host1x_debug_init(host); err = host1x_register(host); if (err < 0) @@ -505,13 +526,14 @@ static int host1x_probe(struct platform_device *pdev) host1x_unregister(host); deinit_debugfs: host1x_debug_deinit(host); + + pm_runtime_put_sync_suspend(&pdev->dev); +pm_disable: + pm_runtime_disable(&pdev->dev); + 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: @@ -526,20 +548,94 @@ static int host1x_remove(struct platform_device *pdev) host1x_unregister(host); host1x_debug_deinit(host); + + pm_runtime_force_suspend(&pdev->dev); + host1x_intr_deinit(host); host1x_syncpt_deinit(host); - reset_control_assert(host->rst); - clk_disable_unprepare(host->clk); host1x_iommu_exit(host); host1x_bo_cache_destroy(&host->cache); return 0; } +static int __maybe_unused host1x_runtime_suspend(struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + host1x_intr_stop(host); + host1x_syncpt_save(host); + + err = reset_control_bulk_assert(host->nresets, host->resets); + if (err) { + dev_err(dev, "failed to assert reset: %d\n", err); + goto resume_host1x; + } + + usleep_range(1000, 2000); + + clk_disable_unprepare(host->clk); + reset_control_bulk_release(host->nresets, host->resets); + + return 0; + +resume_host1x: + host1x_setup_sid_table(host); + host1x_syncpt_restore(host); + host1x_intr_start(host); + + return err; +} + +static int __maybe_unused host1x_runtime_resume(struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + err = reset_control_bulk_acquire(host->nresets, host->resets); + if (err) { + dev_err(dev, "failed to acquire reset: %d\n", err); + return err; + } + + err = clk_prepare_enable(host->clk); + if (err) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto release_reset; + } + + err = reset_control_bulk_deassert(host->nresets, host->resets); + if (err < 0) { + dev_err(dev, "failed to deassert reset: %d\n", err); + goto disable_clk; + } + + host1x_setup_sid_table(host); + host1x_syncpt_restore(host); + host1x_intr_start(host); + + return 0; + +disable_clk: + clk_disable_unprepare(host->clk); +release_reset: + reset_control_bulk_release(host->nresets, host->resets); + + return err; +} + +static const struct dev_pm_ops host1x_pm = { + SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, + NULL) + /* TODO: add system suspend-resume once driver will be ready for that */ +}; + static struct platform_driver tegra_host1x_driver = { .driver = { .name = "tegra-host1x", .of_match_table = host1x_of_match, + .pm = &host1x_pm, }, .probe = host1x_probe, .remove = host1x_remove, diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 5b7fdea5d169..ca4b082f0cd4 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -118,7 +118,8 @@ struct host1x { struct host1x_syncpt_base *bases; struct device *dev; struct clk *clk; - struct reset_control *rst; + struct reset_control_bulk_data resets[2]; + unsigned int nresets; struct iommu_group *group; struct iommu_domain *domain; diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 1999780a7203..6b40e9af1e88 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c @@ -159,6 +159,27 @@ static void host1x_channel_set_streamid(struct host1x_channel *channel) #endif } +static void host1x_enable_gather_filter(struct host1x_channel *ch) +{ +#if HOST1X_HW >= 6 + struct host1x *host = dev_get_drvdata(ch->dev->parent); + u32 val; + + if (!host->hv_regs) + return; + + val = host1x_hypervisor_readl( + host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); + val |= BIT(ch->id % 32); + host1x_hypervisor_writel( + host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); +#elif HOST1X_HW >= 4 + host1x_ch_writel(ch, + HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1), + HOST1X_CHANNEL_CHANNELCTRL); +#endif +} + static int channel_submit(struct host1x_job *job) { struct host1x_channel *ch = job->channel; @@ -190,6 +211,7 @@ static int channel_submit(struct host1x_job *job) } host1x_channel_set_streamid(ch); + host1x_enable_gather_filter(ch); /* begin a CDMA submit */ err = host1x_cdma_begin(&ch->cdma, job); @@ -249,27 +271,6 @@ static int channel_submit(struct host1x_job *job) return err; } -static void enable_gather_filter(struct host1x *host, - struct host1x_channel *ch) -{ -#if HOST1X_HW >= 6 - u32 val; - - if (!host->hv_regs) - return; - - val = host1x_hypervisor_readl( - host, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); - val |= BIT(ch->id % 32); - host1x_hypervisor_writel( - host, val, HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(ch->id / 32)); -#elif HOST1X_HW >= 4 - host1x_ch_writel(ch, - HOST1X_CHANNEL_CHANNELCTRL_KERNEL_FILTER_GBUFFER(1), - HOST1X_CHANNEL_CHANNELCTRL); -#endif -} - static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, unsigned int index) { @@ -278,7 +279,6 @@ static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, #else ch->regs = dev->regs + index * 0x100; #endif - enable_gather_filter(dev, ch); return 0; } diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c index 45b6be927ec4..965ba21818b1 100644 --- a/drivers/gpu/host1x/intr.c +++ b/drivers/gpu/host1x/intr.c @@ -297,14 +297,11 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync) "host1x_sp_%02u", id); } - host1x_intr_start(host); - return 0; } void host1x_intr_deinit(struct host1x *host) { - host1x_intr_stop(host); } void host1x_intr_start(struct host1x *host) diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index d198a10848c6..e08e331e46ae 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -143,6 +143,8 @@ void host1x_syncpt_restore(struct host1x *host) for (i = 0; i < host1x_syncpt_nb_bases(host); i++) host1x_hw_syncpt_restore_wait_base(host, sp_base + i); + host1x_hw_syncpt_enable_protection(host); + wmb(); } @@ -366,9 +368,6 @@ int host1x_syncpt_init(struct host1x *host) host->syncpt = syncpt; host->bases = bases; - host1x_syncpt_restore(host); - host1x_hw_syncpt_enable_protection(host); - /* Allocate sync point to use for clearing waits for expired fences */ host->nop_sp = host1x_syncpt_alloc(host, 0, "reserved-nop"); if (!host->nop_sp) -- 2.33.1
next prev parent reply other threads:[~2021-11-30 23:24 UTC|newest] Thread overview: 118+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-11-30 23:23 [PATCH v16 00/40] NVIDIA Tegra power management patches for 5.17 Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 01/40] soc/tegra: Enable runtime PM during OPP state-syncing Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 02/40] soc/tegra: Add devm_tegra_core_dev_init_opp_table_common() Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 03/40] soc/tegra: Don't print error message when OPPs not available Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 04/40] dt-bindings: clock: tegra-car: Document new clock sub-nodes Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 05/40] clk: tegra: Support runtime PM and power domain Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 06/40] dt-bindings: host1x: Document OPP and power domain properties Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 07/40] dt-bindings: host1x: Document Memory Client resets of Host1x, GR2D and GR3D Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko [this message] 2021-11-30 23:23 ` [PATCH v16 08/40] gpu: host1x: Add initial runtime PM and OPP support Dmitry Osipenko 2021-12-21 18:55 ` Jon Hunter 2021-12-21 18:55 ` Jon Hunter 2021-12-21 20:58 ` Dmitry Osipenko 2021-12-21 20:58 ` Dmitry Osipenko 2021-12-22 9:47 ` Jon Hunter 2021-12-22 9:47 ` Jon Hunter 2021-12-22 18:41 ` Jon Hunter 2021-12-22 18:41 ` Jon Hunter 2021-12-22 19:01 ` Dmitry Osipenko 2021-12-22 19:01 ` Dmitry Osipenko 2021-12-22 19:30 ` Jon Hunter 2021-12-22 19:30 ` Jon Hunter 2021-12-22 19:31 ` Dmitry Osipenko 2021-12-22 19:31 ` Dmitry Osipenko 2022-01-31 20:39 ` Marc Zyngier 2022-01-31 20:39 ` Marc Zyngier 2021-11-30 23:23 ` [PATCH v16 09/40] gpu: host1x: Add host1x_channel_stop() Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 10/40] drm/tegra: submit: Add missing pm_runtime_mark_last_busy() Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 11/40] drm/tegra: dc: Support OPP and SoC core voltage scaling Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 12/40] drm/tegra: hdmi: Add OPP support Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 13/40] drm/tegra: gr2d: Support generic power domain and runtime PM Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 14/40] drm/tegra: gr3d: " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 15/40] drm/tegra: vic: Stop channel on suspend Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 16/40] drm/tegra: nvdec: " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 17/40] drm/tegra: submit: Remove pm_runtime_enabled() checks Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 18/40] drm/tegra: Consolidate runtime PM management of older UAPI codepath Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 19/40] usb: chipidea: tegra: Add runtime PM and OPP support Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 20/40] bus: tegra-gmi: " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 21/40] pwm: tegra: " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2022-02-21 8:17 ` Uwe Kleine-König 2022-02-21 8:17 ` Uwe Kleine-König 2022-02-21 9:53 ` Dmitry Osipenko 2022-02-21 9:53 ` Dmitry Osipenko 2022-02-21 13:37 ` Uwe Kleine-König 2022-02-21 13:37 ` Uwe Kleine-König 2021-11-30 23:23 ` [PATCH v16 22/40] mmc: sdhci-tegra: " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-12-02 8:16 ` Adrian Hunter 2021-12-02 8:16 ` Adrian Hunter 2021-11-30 23:23 ` [PATCH v16 23/40] mtd: rawnand: tegra: " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 24/40] spi: tegra20-slink: Add " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 25/40] media: dt: bindings: tegra-vde: Convert to schema Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 26/40] media: dt: bindings: tegra-vde: Document OPP and power domain Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 27/40] media: staging: tegra-vde: Support generic " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 28/40] soc/tegra: fuse: Reset hardware Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 29/40] soc/tegra: fuse: Use resource-managed helpers Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-12-16 12:59 ` Thierry Reding 2021-12-16 12:59 ` Thierry Reding 2021-11-30 23:23 ` [PATCH v16 30/40] soc/tegra: regulators: Prepare for suspend Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 31/40] soc/tegra: pmc: Rename 3d power domains Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 32/40] soc/tegra: pmc: Rename core power domain Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 33/40] soc/tegra: pmc: Enable core domain support for Tegra20 and Tegra30 Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2022-02-03 17:51 ` Thierry Reding 2022-02-03 17:51 ` Thierry Reding 2021-11-30 23:23 ` [PATCH v16 34/40] ARM: tegra: Rename CPU and EMC OPP table device-tree nodes Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 35/40] ARM: tegra: Add 500MHz entry to Tegra30 memory OPP table Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 36/40] ARM: tegra: Add OPP tables and power domains to Tegra20 device-trees Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 37/40] ARM: tegra: Add OPP tables and power domains to Tegra30 device-trees Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 38/40] ARM: tegra: Add Memory Client resets to Tegra20 GR2D, GR3D and Host1x Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 39/40] ARM: tegra: Add Memory Client resets to Tegra30 " Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-11-30 23:23 ` [PATCH v16 40/40] ARM: tegra20/30: Disable unused host1x hardware Dmitry Osipenko 2021-11-30 23:23 ` Dmitry Osipenko 2021-12-15 15:55 ` [PATCH v16 00/40] NVIDIA Tegra power management patches for 5.17 Thierry Reding 2021-12-15 15:55 ` Thierry Reding 2021-12-15 16:11 ` Dmitry Osipenko 2021-12-15 16:11 ` Dmitry Osipenko 2021-12-16 13:14 ` Thierry Reding 2021-12-16 13:14 ` Thierry Reding 2021-12-16 14:19 ` Dmitry Osipenko 2021-12-16 14:19 ` Dmitry Osipenko
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20211130232347.950-9-digetx@gmail.com \ --to=digetx@gmail.com \ --cc=adrian.hunter@intel.com \ --cc=david@ixit.cz \ --cc=dri-devel@lists.freedesktop.org \ --cc=jonathanh@nvidia.com \ --cc=lee.jones@linaro.org \ --cc=linux-clk@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-mmc@vger.kernel.org \ --cc=linux-pm@vger.kernel.org \ --cc=linux-pwm@vger.kernel.org \ --cc=linux-tegra@vger.kernel.org \ --cc=mperttunen@nvidia.com \ --cc=mturquette@baylibre.com \ --cc=nm@ti.com \ --cc=pdeschrijver@nvidia.com \ --cc=sboyd@kernel.org \ --cc=thierry.reding@gmail.com \ --cc=u.kleine-koenig@pengutronix.de \ --cc=ulf.hansson@linaro.org \ --cc=vireshk@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.