mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
gpu: host1x: Update to Linux v5.19-rc1
Update the host1x driver to align with the latest upstream host1x driver from Linux v5.19-rc1. Please note that the context bus support is not included, because this needs to be built into the kernel. Bug 3724727 Change-Id: Ic6fbe001462d160d1bb24f76038dd755c5550690 Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2739538 Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com> Reviewed-by: Bibek Basu <bbasu@nvidia.com>
This commit is contained in:
committed by
Laxman Dewangan
parent
0955b8b8a5
commit
9edef092b1
@@ -6,18 +6,27 @@
|
||||
*/
|
||||
|
||||
#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 <linux/version.h>
|
||||
|
||||
#include <soc/tegra/common.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/host1x.h>
|
||||
#undef CREATE_TRACE_POINTS
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
|
||||
#include <asm/dma-iommu.h>
|
||||
#endif
|
||||
|
||||
#include "bus.h"
|
||||
#include "channel.h"
|
||||
#include "debug.h"
|
||||
@@ -250,6 +259,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];
|
||||
|
||||
@@ -298,6 +310,17 @@ static struct iommu_domain *host1x_iommu_attach(struct host1x *host)
|
||||
struct iommu_domain *domain = iommu_get_domain_for_dev(host->dev);
|
||||
int err;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
|
||||
if (host->dev->archdata.mapping) {
|
||||
struct dma_iommu_mapping *mapping =
|
||||
to_dma_iommu_mapping(host->dev);
|
||||
arm_iommu_detach_device(host->dev);
|
||||
arm_iommu_release_mapping(mapping);
|
||||
|
||||
domain = iommu_get_domain_for_dev(host->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We may not always want to enable IOMMU support (for example if the
|
||||
* host1x firewall is already enabled and we don't support addressing
|
||||
@@ -407,6 +430,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;
|
||||
@@ -446,7 +490,6 @@ static int host1x_probe(struct platform_device *pdev)
|
||||
if (syncpt_irq < 0)
|
||||
return syncpt_irq;
|
||||
|
||||
host1x_bo_cache_init(&host->cache);
|
||||
mutex_init(&host->devices_lock);
|
||||
INIT_LIST_HEAD(&host->devices);
|
||||
INIT_LIST_HEAD(&host->list);
|
||||
@@ -484,17 +527,16 @@ 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;
|
||||
}
|
||||
|
||||
host1x_bo_cache_init(&host->cache);
|
||||
|
||||
err = host1x_iommu_init(host);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to setup IOMMU: %d\n", err);
|
||||
return err;
|
||||
goto destroy_cache;
|
||||
}
|
||||
|
||||
err = host1x_channel_list_init(&host->channel_list,
|
||||
@@ -504,22 +546,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);
|
||||
@@ -528,10 +558,20 @@ 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);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
||||
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
|
||||
if (err)
|
||||
goto pm_disable;
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
@@ -547,17 +587,20 @@ unregister:
|
||||
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:
|
||||
host1x_iommu_exit(host);
|
||||
destroy_cache:
|
||||
host1x_bo_cache_destroy(&host->cache);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -568,20 +611,95 @@ 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_channel_list_free(&host->channel_list);
|
||||
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_ops = {
|
||||
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_ops,
|
||||
},
|
||||
.probe = host1x_probe,
|
||||
.remove = host1x_remove,
|
||||
|
||||
Reference in New Issue
Block a user