On Thu, 3 May 2012 20:58:39 +0200
Stephen Warren <[email protected]> wrote:

> On 05/03/2012 12:28 PM, Stephen Warren wrote:
> > On 04/16/2012 09:04 AM, Thierry Reding wrote:
> >> This commit adds the device node required to probe NVIDIA Tegra 20 GART
> >> hardware from the device tree.
> > 
> >> diff --git a/arch/arm/boot/dts/tegra20.dtsi 
> >> b/arch/arm/boot/dts/tegra20.dtsi
> > 
> >> +  gart: gart@7000f000 {
> >> +          compatible = "nvidia,tegra20-gart";
> >> +          reg = < 0x7000f000 0x00000100    /* controller registers */
> >> +                  0x58000000 0x02000000 >; /* GART aperture */
> >> +  };
> ...
> > As such, I think this node should be more like:
> > 
> > mc: mc@7000f000 {
> >     compatible = "nvidia,tegra20-mc";
> >     reg = <0x7000f000 0x00000100>;
> > };
> > 
> > Then, one of following options can be taken:
> [to represent the fact that MC and GART are essentially the same HW module]
> ...
> 
> Yet another option is to explicitly use the MFD subsystem for this; I
> guess options 1 and 3 that I gave were essentially open-coding MFD anyway.
> 
> Offline, Hiroshi mentioned that he had looked at MFD, and ended up
> thinking it was a rather heavy-weight solution in this case though.

It's because we just spawns a single child device(SMMU) from MC. I
guess that MFD framework would be more beneficial when it spawns
multiple/many children(?). 

Here's my MFD experiment:

>From 720331a8d54052da3ee214dd80193b9c853b9d93 Mon Sep 17 00:00:00 2001
From: Hiroshi DOYU <[email protected]>
Date: Wed, 2 May 2012 13:36:10 +0300
Subject: [PATCH 1/1] ARM: tegra: Memory Controller(MC) adds IOMMU device via
 MFD

Tegra IOMMU devices(GART/SMMU) share some resources with MC. Those
IOMMUs can be considered as a part of MC. MC adds GART/SMMU as its
child device at probe().

Signed-off-by: Hiroshi DOYU <[email protected]>
---
 arch/arm/mach-tegra/tegra-mc.c |   31 +++++++++++++++++++-----
 drivers/iommu/tegra-smmu.c     |   50 +++++++++++++++++++++++++++++----------
 2 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra-mc.c b/arch/arm/mach-tegra/tegra-mc.c
index 7af2a99..eb95dce 100644
--- a/arch/arm/mach-tegra/tegra-mc.c
+++ b/arch/arm/mach-tegra/tegra-mc.c
@@ -25,6 +25,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/mfd/core.h>
 
 #define DRV_NAME "tegra-mc"
 
@@ -107,6 +108,7 @@ struct tegra_mc_info {
        const char * const *client;
        int num_client;
        u32 id_mask;
+       struct mfd_cell iommu;
 };
 
 struct tegra_mc {
@@ -228,6 +230,9 @@ static struct tegra_mc_info tegra20_mc_info = {
        .client = tegra20_mc_client,
        .num_client = ARRAY_SIZE(tegra20_mc_client),
        .id_mask = 0x3f,
+       .iommu = {
+               .name   = "tegra-gart",
+       },
 };
 #else
 static struct tegra_mc_info tegra20_mc_info = {};
@@ -354,6 +359,9 @@ static struct tegra_mc_info tegra30_mc_info = {
        .client = tegra30_mc_client,
        .num_client = ARRAY_SIZE(tegra30_mc_client),
        .id_mask = 0x7f,
+       .iommu = {
+               .name   = "tegra-smmu",
+       },
 };
 
 static u32 tegra_mc_ctx[] = {
@@ -437,7 +445,7 @@ static irqreturn_t tegra_mc_isr(int irq, void *data)
 
 static int __devinit tegra_mc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct resource *mem, *irq;
        struct tegra_mc *mc;
        size_t bytes;
        int err;
@@ -450,17 +458,18 @@ static int __devinit tegra_mc_probe(struct 
platform_device *pdev)
                return -ENOMEM;
        mc->dev = &pdev->dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
                return -ENODEV;
-       mc->regs = devm_request_and_ioremap(&pdev->dev, res);
+       mc->regs = devm_request_and_ioremap(&pdev->dev, mem);
        if (!mc->regs)
                return -EBUSY;
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res)
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq)
                return -ENODEV;
-       err = devm_request_irq(&pdev->dev, res->start, tegra_mc_isr,
+
+       err = devm_request_irq(&pdev->dev, irq->start, tegra_mc_isr,
                               IRQF_SHARED, dev_name(&pdev->dev), mc);
        if (err)
                return -ENODEV;
@@ -473,6 +482,14 @@ static int __devinit tegra_mc_probe(struct platform_device 
*pdev)
        info = id->data;
        if (!info)
                return -EINVAL;
+
+       if (&info->iommu) {
+               err = mfd_add_devices(&pdev->dev, pdev->id, &info->iommu, 1,
+                                     NULL, irq->start);
+               if (err)
+                       return -ENODEV;
+       }
+
        mc->info = info;
        info->intmask |= MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
        mc_writel(mc, info->intmask, MC_INTMASK);
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index c70e4e7..21c15bb 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -31,6 +31,7 @@
 #include <linux/iommu.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 
 #include <asm/page.h>
 #include <asm/cacheflush.h>
@@ -113,7 +114,6 @@
 
 #define SMMU_PDE_NEXT_SHIFT            28
 
-#define SMMU_NUM_ASIDS                         4
 #define SMMU_TLB_FLUSH_VA_SECTION__MASK                0xffc00000
 #define SMMU_TLB_FLUSH_VA_SECTION__SHIFT       12 /* right shift */
 #define SMMU_TLB_FLUSH_VA_GROUP__MASK          0xffffc000
@@ -872,21 +872,38 @@ static int tegra_smmu_resume(struct device *dev)
 static int tegra_smmu_probe(struct platform_device *pdev)
 {
        struct smmu_device *smmu;
-       struct resource *regs, *window;
        struct device *dev = &pdev->dev;
-       int i, err = 0;
+       int i, asids, err = 0;
+       dma_addr_t base;
+       size_t size;
+       const void *prop;
+       struct device_node *mc;
+       struct resource *res;
 
        if (smmu_handle)
                return -EIO;
 
        BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       window = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!regs || !window) {
-               dev_err(dev, "No SMMU resources\n");
+       mc = pdev->dev.parent->of_node;
+       if (!mc)
+               return -ENODEV;
+
+       err = of_get_dma_window(mc, "dma-window", 0, NULL,
+                               &base, &size);
+       if (err)
+               return -ENODEV;
+
+       size >>= SMMU_PAGE_SHIFT;
+       if (!size)
+               return -ENODEV;
+
+       prop = of_get_property(mc, "nvidia,#asids", NULL);
+       if (!prop)
+               return -ENODEV;
+       asids = be32_to_cpup(prop);
+       if (!asids)
                return -ENODEV;
-       }
 
        smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
        if (!smmu) {
@@ -895,17 +912,23 @@ static int tegra_smmu_probe(struct platform_device *pdev)
        }
 
        smmu->dev = dev;
-       smmu->num_as = SMMU_NUM_ASIDS;
-       smmu->iovmm_base = (unsigned long)window->start;
-       smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT;
-       smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs));
+       smmu->num_as = asids;
+       smmu->iovmm_base = base;
+       smmu->page_count = size;
+
+       res = platform_get_resource(to_platform_device(pdev->dev.parent),
+                                   IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       smmu->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!smmu->regs) {
                dev_err(dev, "failed to remap SMMU registers\n");
                err = -ENXIO;
                goto fail;
        }
 
-       smmu->ahb = of_parse_phandle(pdev->dev.of_node, "ahb", 0);
+       smmu->ahb = of_parse_phandle(mc, "ahb", 0);
        if (!smmu->ahb)
                return -ENODEV;
 
@@ -1019,4 +1042,5 @@ module_exit(tegra_smmu_exit);
 
 MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30");
 MODULE_AUTHOR("Hiroshi DOYU <[email protected]>");
+MODULE_ALIAS("platform:tegra-smmu");
 MODULE_LICENSE("GPL v2");
-- 
1.7.5.4

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to