From: Janghyuck Kim Date: Fri, 22 Apr 2016 12:03:30 +0000 (+0900) Subject: [COMMON] iommu/exynos: add probe function X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=3a5306f6ef16a271eea8b7691f81d11a92e03014;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [COMMON] iommu/exynos: add probe function 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 --- diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index e4f7127dd71a..f8dca04ce26f 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -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; } diff --git a/drivers/iommu/exynos-iommu.h b/drivers/iommu/exynos-iommu.h index 30b61a63fdf3..81b305338db5 100644 --- a/drivers/iommu/exynos-iommu.h +++ b/drivers/iommu/exynos-iommu.h @@ -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 {