[COMMON] iommu/exynos: add probe function
authorJanghyuck Kim <janghyuck.kim@samsung.com>
Fri, 22 Apr 2016 12:03:30 +0000 (21:03 +0900)
committerSangwook Ju <sw.ju@samsung.com>
Mon, 14 May 2018 10:45:18 +0000 (19:45 +0900)
resources like SFR and IRQ are registered and main structure for sysmmu
is created in probe function.

Change-Id: I3266acf9b97bea4395804a5bf1f814c7b0f4815f
Signed-off-by: Janghyuck Kim <janghyuck.kim@samsung.com>
drivers/iommu/exynos-iommu.c
drivers/iommu/exynos-iommu.h

index e4f7127dd71a7fc2b0325052218ac6af9949ec40..f8dca04ce26f2ccff52a1542ef1080c70db0ca87 100644 (file)
@@ -29,6 +29,8 @@
 
 static struct kmem_cache *lv2table_kmem_cache;
 
+static struct sysmmu_drvdata *sysmmu_drvdata_list;
+
 struct exynos_client {
        struct list_head list;
        struct device_node *master_np;
@@ -72,9 +74,103 @@ void exynos_iommu_unmap_userptr(struct iommu_domain *dom,
        return;
 }
 
+static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+static int get_hw_version(struct device *dev, void __iomem *sfrbase)
+{
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               dev_err(dev, "Failed to runtime pm get(%d)\n", ret);
+               return ret;
+       }
+       ret = MMU_RAW_VER(__raw_readl(sfrbase + REG_MMU_VERSION));
+       pm_runtime_put(dev);
+
+       return ret;
+}
+
+static struct iommu_ops exynos_iommu_ops;
 static int __init exynos_sysmmu_probe(struct platform_device *pdev)
 {
-       /* Dummy */
+       int irq, ret;
+       struct device *dev = &pdev->dev;
+       struct sysmmu_drvdata *data;
+       struct resource *res;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "Failed to get resource info\n");
+               return -ENOENT;
+       }
+
+       data->sfrbase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->sfrbase))
+               return PTR_ERR(data->sfrbase);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(dev, "Unable to find IRQ resource\n");
+               return irq;
+       }
+
+       ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0,
+                               dev_name(dev), data);
+       if (ret) {
+               dev_err(dev, "Unabled to register handler of irq %d\n", irq);
+               return ret;
+       }
+
+       data->clk = devm_clk_get(dev, "aclk");
+       if (IS_ERR(data->clk)) {
+               dev_err(dev, "Failed to get clock!\n");
+               return PTR_ERR(data->clk);
+       } else  {
+               ret = clk_prepare(data->clk);
+               if (ret) {
+                       dev_err(dev, "Failed to prepare clk\n");
+                       return ret;
+               }
+       }
+
+       data->sysmmu = dev;
+       spin_lock_init(&data->lock);
+       if (!sysmmu_drvdata_list) {
+               sysmmu_drvdata_list = data;
+       } else {
+               data->next = sysmmu_drvdata_list->next;
+               sysmmu_drvdata_list->next = data;
+       }
+
+       platform_set_drvdata(pdev, data);
+
+       pm_runtime_enable(dev);
+
+       data->version = get_hw_version(dev, data->sfrbase);
+
+       /* TODO: Parsing Device Tree for properties */
+
+       iommu_device_set_ops(&data->iommu, &exynos_iommu_ops);
+       iommu_device_set_fwnode(&data->iommu, &dev->of_node->fwnode);
+
+       ret = iommu_device_register(&data->iommu);
+       if (ret) {
+               dev_err(dev, "Failed to register device\n");
+               return ret;
+       }
+
+       dev_info(data->sysmmu, "is probed. Version %d.%d.%d\n",
+                       MMU_MAJ_VER(data->version),
+                       MMU_MIN_VER(data->version),
+                       MMU_REV_VER(data->version));
 
        return 0;
 }
index 30b61a63fdf3e35d5ad90965c30b10dfbe0cec59..81b305338db532f0a0e859af9a43c69a1ac530b2 100644 (file)
@@ -42,6 +42,18 @@ typedef u32 sysmmu_pte_t;
 #define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE)
 #define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t))
 
+#define REG_MMU_CTRL           0x000
+#define REG_MMU_CFG            0x004
+#define REG_MMU_STATUS         0x008
+#define REG_MMU_VERSION                0x034
+
+#define MMU_MAJ_VER(val)       ((val) >> 11)
+#define MMU_MIN_VER(val)       ((val >> 4) & 0x7F)
+#define MMU_REV_VER(val)       ((val) & 0xF)
+#define MMU_RAW_VER(reg)       (((reg) >> 17) & 0x7FFF) /* upper 15 bits */
+
+#define MAKE_MMU_VER(maj, min) ((((maj) & 0xF) << 11) | \
+                                       (((min) & 0x7F) << 4))
 /*
  * This structure exynos specific generalization of struct iommu_domain.
  * It contains list of all master devices represented by owner, which has
@@ -84,11 +96,12 @@ struct sysmmu_drvdata {
        struct device *sysmmu;          /* SYSMMU controller device */
        void __iomem *sfrbase;          /* our registers */
        struct clk *clk;                /* SYSMMU's clock */
+       struct iommu_device iommu;      /* IOMMU core handle */
        int activations;                /* number of calls to sysmmu_enable */
        int runtime_active;     /* Runtime PM activated count from master */
        spinlock_t lock;                /* lock for modyfying state */
        phys_addr_t pgtable;            /* assigned page table structure */
-       unsigned int version;           /* our version */
+       int version;                    /* our version */
 };
 
 struct exynos_vm_region {