Compare commits
10 Commits
fee12cf9e3
...
rel-38_eng
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a34ad11c0a | ||
|
|
e3677b3425 | ||
|
|
5865348c39 | ||
|
|
c79ae7acb3 | ||
|
|
c16f161cd7 | ||
|
|
9cbafdf4c3 | ||
|
|
a7ae04815b | ||
|
|
09c630f285 | ||
|
|
a0eab0226d | ||
|
|
56a7b340cd |
@@ -1425,6 +1425,7 @@ CONFIG_TEGRA_IOMMU_SMMU=y
|
|||||||
CONFIG_ARM_SMMU=y
|
CONFIG_ARM_SMMU=y
|
||||||
CONFIG_ARM_SMMU_V3=y
|
CONFIG_ARM_SMMU_V3=y
|
||||||
CONFIG_ARM_SMMU_V3_SVA=y
|
CONFIG_ARM_SMMU_V3_SVA=y
|
||||||
|
CONFIG_TEGRA241_CMDQV=y
|
||||||
CONFIG_MTK_IOMMU=y
|
CONFIG_MTK_IOMMU=y
|
||||||
CONFIG_QCOM_IOMMU=y
|
CONFIG_QCOM_IOMMU=y
|
||||||
CONFIG_REMOTEPROC=y
|
CONFIG_REMOTEPROC=y
|
||||||
|
|||||||
@@ -483,6 +483,7 @@ CONFIG_PLATFORM_MHU=y
|
|||||||
CONFIG_TEGRA_IOMMU_SMMU=y
|
CONFIG_TEGRA_IOMMU_SMMU=y
|
||||||
CONFIG_ARM_SMMU=y
|
CONFIG_ARM_SMMU=y
|
||||||
CONFIG_ARM_SMMU_V3=y
|
CONFIG_ARM_SMMU_V3=y
|
||||||
|
CONFIG_TEGRA241_CMDQV=y
|
||||||
CONFIG_MTK_IOMMU=y
|
CONFIG_MTK_IOMMU=y
|
||||||
CONFIG_REMOTEPROC=y
|
CONFIG_REMOTEPROC=y
|
||||||
CONFIG_MTK_PMIC_WRAP=y
|
CONFIG_MTK_PMIC_WRAP=y
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ config ARM_SMMU_V3_SVA
|
|||||||
|
|
||||||
config TEGRA241_CMDQV
|
config TEGRA241_CMDQV
|
||||||
bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
|
bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
|
||||||
depends on ACPI
|
depends on ARM_SMMU_V3
|
||||||
help
|
help
|
||||||
Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
|
Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
|
||||||
CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
|
CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
/*
|
/*
|
||||||
* IOMMU API for ARM architected SMMUv3 implementations.
|
* IOMMU API for ARM architected SMMUv3 implementations.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 ARM Limited
|
* SPDX-FileCopyrightText: Copyright (C) 2015 ARM Limited
|
||||||
|
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* Author: Will Deacon <will.deacon@arm.com>
|
* Author: Will Deacon <will.deacon@arm.com>
|
||||||
*
|
*
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_reserved_mem.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/pci-ats.h>
|
#include <linux/pci-ats.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
@@ -3194,6 +3196,15 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
|
|||||||
int ret, nvec = ARM_SMMU_MAX_MSIS;
|
int ret, nvec = ARM_SMMU_MAX_MSIS;
|
||||||
struct device *dev = smmu->dev;
|
struct device *dev = smmu->dev;
|
||||||
|
|
||||||
|
/* Clear the MSI address regs */
|
||||||
|
writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0);
|
||||||
|
writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0);
|
||||||
|
|
||||||
|
if (smmu->features & ARM_SMMU_FEAT_PRI)
|
||||||
|
writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0);
|
||||||
|
else
|
||||||
|
nvec--;
|
||||||
|
|
||||||
if (!(smmu->features & ARM_SMMU_FEAT_MSI))
|
if (!(smmu->features & ARM_SMMU_FEAT_MSI))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -3202,9 +3213,6 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(smmu->features & ARM_SMMU_FEAT_PRI))
|
|
||||||
nvec--;
|
|
||||||
|
|
||||||
/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
|
/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
|
||||||
ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
|
ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -3266,9 +3274,9 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_smmu_reset_irqs(struct arm_smmu_device *smmu)
|
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, irq;
|
||||||
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
|
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
|
||||||
|
|
||||||
/* Disable IRQs first */
|
/* Disable IRQs first */
|
||||||
@@ -3279,35 +3287,7 @@ static int arm_smmu_reset_irqs(struct arm_smmu_device *smmu)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!smmu->combined_irq) {
|
irq = smmu->combined_irq;
|
||||||
/*
|
|
||||||
* Clear the MSI address regs. These registers will be reset
|
|
||||||
* in arm_smmu_write_msi_msg callback function by irq_domain
|
|
||||||
* upon a new MSI message.
|
|
||||||
*/
|
|
||||||
writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0);
|
|
||||||
writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0);
|
|
||||||
|
|
||||||
if (smmu->features & ARM_SMMU_FEAT_PRI)
|
|
||||||
writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smmu->features & ARM_SMMU_FEAT_PRI)
|
|
||||||
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
|
|
||||||
|
|
||||||
/* Enable interrupt generation on the SMMU */
|
|
||||||
ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
|
|
||||||
ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK);
|
|
||||||
if (ret)
|
|
||||||
dev_warn(smmu->dev, "failed to enable irqs\n");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
|
|
||||||
{
|
|
||||||
int ret = 0, irq = smmu->combined_irq;
|
|
||||||
|
|
||||||
if (irq) {
|
if (irq) {
|
||||||
/*
|
/*
|
||||||
* Cavium ThunderX2 implementation doesn't support unique irq
|
* Cavium ThunderX2 implementation doesn't support unique irq
|
||||||
@@ -3323,7 +3303,16 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
|
|||||||
} else
|
} else
|
||||||
arm_smmu_setup_unique_irqs(smmu);
|
arm_smmu_setup_unique_irqs(smmu);
|
||||||
|
|
||||||
return ret;
|
if (smmu->features & ARM_SMMU_FEAT_PRI)
|
||||||
|
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
|
||||||
|
|
||||||
|
/* Enable interrupt generation on the SMMU */
|
||||||
|
ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
|
||||||
|
ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(smmu->dev, "failed to enable irqs\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
|
static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
|
||||||
@@ -3337,7 +3326,7 @@ static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
|
static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u32 reg, enables;
|
u32 reg, enables;
|
||||||
@@ -3445,17 +3434,11 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arm_smmu_reset_irqs(smmu);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(smmu->dev, "failed to reset irqs\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_kdump_kernel())
|
if (is_kdump_kernel())
|
||||||
enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
|
enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
|
||||||
|
|
||||||
/* Enable the SMMU interface, or ensure bypass */
|
/* Enable the SMMU interface, or ensure bypass */
|
||||||
if (!smmu->bypass || disable_bypass) {
|
if (!bypass || disable_bypass) {
|
||||||
enables |= CR0_SMMUEN;
|
enables |= CR0_SMMUEN;
|
||||||
} else {
|
} else {
|
||||||
ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
|
ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
|
||||||
@@ -3469,6 +3452,14 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (smmu->impl_ops && smmu->impl_ops->device_reset) {
|
||||||
|
ret = smmu->impl_ops->device_reset(smmu);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(smmu->dev, "failed to reset impl\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3730,6 +3721,34 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TEGRA241_CMDQV
|
||||||
|
static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
|
||||||
|
struct arm_smmu_device *smmu)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct device_node *np;
|
||||||
|
|
||||||
|
np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
|
||||||
|
if (!np)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pdev = of_find_device_by_node(np);
|
||||||
|
of_node_put(np);
|
||||||
|
if (!pdev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
smmu->impl_dev = &pdev->dev;
|
||||||
|
smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
|
||||||
|
dev_info(smmu->dev, "found companion CMDQV device: %s\n",
|
||||||
|
dev_name(smmu->impl_dev));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
|
||||||
|
struct arm_smmu_device *smmu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
#ifdef CONFIG_TEGRA241_CMDQV
|
#ifdef CONFIG_TEGRA241_CMDQV
|
||||||
static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
|
static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
|
||||||
@@ -3814,6 +3833,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
|
|||||||
u32 cells;
|
u32 cells;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (!of_reserved_mem_device_init(dev))
|
||||||
|
dev_info(dev, "using device-specific reserved memory\n");
|
||||||
|
|
||||||
if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
|
if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
|
||||||
dev_err(dev, "missing #iommu-cells property\n");
|
dev_err(dev, "missing #iommu-cells property\n");
|
||||||
else if (cells != 1)
|
else if (cells != 1)
|
||||||
@@ -3826,6 +3848,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
|
|||||||
if (of_dma_is_coherent(dev->of_node))
|
if (of_dma_is_coherent(dev->of_node))
|
||||||
smmu->features |= ARM_SMMU_FEAT_COHERENCY;
|
smmu->features |= ARM_SMMU_FEAT_COHERENCY;
|
||||||
|
|
||||||
|
tegra_cmdqv_dt_probe(dev->of_node, smmu);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3996,15 +4020,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||||||
/* Check for RMRs and install bypass STEs if any */
|
/* Check for RMRs and install bypass STEs if any */
|
||||||
arm_smmu_rmr_install_bypass_ste(smmu);
|
arm_smmu_rmr_install_bypass_ste(smmu);
|
||||||
|
|
||||||
ret = arm_smmu_setup_irqs(smmu);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Reset the device */
|
/* Reset the device */
|
||||||
ret = arm_smmu_device_reset(smmu);
|
ret = arm_smmu_device_reset(smmu, smmu->bypass);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_disable;
|
goto err_disable;
|
||||||
|
|
||||||
|
ret = arm_smmu_setup_irqs(smmu);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(smmu->dev, "failed to setup irqs\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* And we're up. Go go go! */
|
/* And we're up. Go go go! */
|
||||||
ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
|
ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
|
||||||
"smmu3.%pa", &ioaddr);
|
"smmu3.%pa", &ioaddr);
|
||||||
@@ -4017,14 +4043,6 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||||||
goto err_free_sysfs;
|
goto err_free_sysfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smmu->impl_ops && smmu->impl_ops->device_reset) {
|
|
||||||
ret = smmu->impl_ops->device_reset(smmu);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(smmu->dev, "failed to reset impl\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_free_sysfs:
|
err_free_sysfs:
|
||||||
@@ -4070,11 +4088,32 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
|
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return arm_smmu_device_reset(smmu);
|
dev_dbg(dev, "Resuming\n");
|
||||||
|
arm_smmu_device_reset(smmu, smmu->bypass);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
|
||||||
|
struct arm_smmu_cmdq_ent cmd;
|
||||||
|
|
||||||
|
cmd.opcode = CMDQ_OP_CFGI_ALL;
|
||||||
|
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
|
||||||
|
|
||||||
|
cmd.opcode = CMDQ_OP_TLBI_NSNH_ALL;
|
||||||
|
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
|
||||||
|
|
||||||
|
dev_dbg(dev, "Disabling\n");
|
||||||
|
arm_smmu_device_disable(smmu);
|
||||||
|
|
||||||
|
dev_dbg(dev, "Suspending\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops arm_smmu_pm_ops = {
|
static const struct dev_pm_ops arm_smmu_pm_ops = {
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(NULL, arm_smmu_runtime_resume)
|
SET_LATE_SYSTEM_SLEEP_PM_OPS(arm_smmu_runtime_suspend, arm_smmu_runtime_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_driver arm_smmu_driver = {
|
static struct platform_driver arm_smmu_driver = {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
#include <acpi/acpixf.h>
|
#include <acpi/acpixf.h>
|
||||||
|
|
||||||
@@ -81,7 +83,9 @@
|
|||||||
#define VCMDQ_LOG2SIZE GENMASK(4, 0)
|
#define VCMDQ_LOG2SIZE GENMASK(4, 0)
|
||||||
|
|
||||||
#define TEGRA241_VCMDQ_BASE 0x00000
|
#define TEGRA241_VCMDQ_BASE 0x00000
|
||||||
|
#define TEGRA241_VCMDQ_BASE_H 0x00004
|
||||||
#define TEGRA241_VCMDQ_CONS_INDX_BASE 0x00008
|
#define TEGRA241_VCMDQ_CONS_INDX_BASE 0x00008
|
||||||
|
#define TEGRA241_VCMDQ_CONS_INDX_BASE_H 0x0000C
|
||||||
|
|
||||||
/* VINTF logical-VCMDQ pages */
|
/* VINTF logical-VCMDQ pages */
|
||||||
#define TEGRA241_VINTFi_PAGE0(i) (TEGRA241_VINTF_PAGE_BASE + SZ_128K*(i))
|
#define TEGRA241_VINTFi_PAGE0(i) (TEGRA241_VINTF_PAGE_BASE + SZ_128K*(i))
|
||||||
@@ -365,8 +369,10 @@ static void tegra241_vcmdq_hw_deinit(struct tegra241_vcmdq *vcmdq)
|
|||||||
}
|
}
|
||||||
writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, PROD));
|
writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, PROD));
|
||||||
writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, CONS));
|
writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, CONS));
|
||||||
writeq_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, BASE));
|
writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, BASE_H));
|
||||||
writeq_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, CONS_INDX_BASE));
|
writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, BASE));
|
||||||
|
writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, CONS_INDX_BASE_H));
|
||||||
|
writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, CONS_INDX_BASE));
|
||||||
|
|
||||||
gerrorn = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERRORN));
|
gerrorn = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERRORN));
|
||||||
gerror = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERROR));
|
gerror = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERROR));
|
||||||
@@ -388,7 +394,10 @@ static int tegra241_vcmdq_hw_init(struct tegra241_vcmdq *vcmdq)
|
|||||||
tegra241_vcmdq_hw_deinit(vcmdq);
|
tegra241_vcmdq_hw_deinit(vcmdq);
|
||||||
|
|
||||||
/* Configure and enable VCMDQ */
|
/* Configure and enable VCMDQ */
|
||||||
writeq_relaxed(vcmdq->cmdq.q.q_base, REG_VCMDQ_PAGE1(vcmdq, BASE));
|
writel_relaxed(upper_32_bits(vcmdq->cmdq.q.q_base), REG_VCMDQ_PAGE1(vcmdq, BASE_H));
|
||||||
|
writel_relaxed(lower_32_bits(vcmdq->cmdq.q.q_base), REG_VCMDQ_PAGE1(vcmdq, BASE));
|
||||||
|
writel_relaxed(vcmdq->cmdq.q.llq.prod, REG_VCMDQ_PAGE0(vcmdq, PROD));
|
||||||
|
writel_relaxed(vcmdq->cmdq.q.llq.cons, REG_VCMDQ_PAGE0(vcmdq, CONS));
|
||||||
|
|
||||||
ret = vcmdq_write_config(vcmdq, VCMDQ_EN);
|
ret = vcmdq_write_config(vcmdq, VCMDQ_EN);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -748,6 +757,26 @@ free_list:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct resource *
|
||||||
|
tegra241_cmdqv_find_dt_resource(struct device *dev, int *irq)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res) {
|
||||||
|
dev_err(dev, "no memory resource found for CMDQV\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irq)
|
||||||
|
*irq = platform_get_irq_byname_optional(pdev, "cmdqv");
|
||||||
|
if (!irq || *irq <= 0)
|
||||||
|
dev_warn(dev, "no interrupt. errors will not be reported\n");
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
|
static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
|
||||||
{
|
{
|
||||||
struct tegra241_cmdqv *cmdqv =
|
struct tegra241_cmdqv *cmdqv =
|
||||||
@@ -875,10 +904,13 @@ struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
|
|||||||
|
|
||||||
if (!smmu->dev->of_node)
|
if (!smmu->dev->of_node)
|
||||||
res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
|
res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
|
||||||
|
else
|
||||||
|
res = tegra241_cmdqv_find_dt_resource(smmu->impl_dev, &irq);
|
||||||
if (!res)
|
if (!res)
|
||||||
goto out_fallback;
|
goto out_fallback;
|
||||||
|
|
||||||
new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
|
new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
|
||||||
|
if (!smmu->dev->of_node)
|
||||||
kfree(res);
|
kfree(res);
|
||||||
|
|
||||||
if (new_smmu)
|
if (new_smmu)
|
||||||
@@ -890,3 +922,20 @@ out_fallback:
|
|||||||
put_device(smmu->impl_dev);
|
put_device(smmu->impl_dev);
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id tegra241_cmdqv_of_match[] = {
|
||||||
|
{ .compatible = "nvidia,tegra264-cmdqv" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, tegra241_cmdqv_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver tegra241_cmdqv_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "tegra241-cmdqv",
|
||||||
|
.of_match_table = tegra241_cmdqv_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(tegra241_cmdqv_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("NVIDIA Tegra241 Command Queue Virtualization Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
Reference in New Issue
Block a user