summaryrefslogtreecommitdiff
path: root/drivers/iommu/exynos-iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/exynos-iommu.c')
-rw-r--r--drivers/iommu/exynos-iommu.c193
1 files changed, 74 insertions, 119 deletions
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 6eed6d6828d..b46c3fe2f30 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -183,7 +183,6 @@ struct sysmmu_drvdata {
struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu; /* System MMU's device descriptor */
struct device *master; /* Owner of system MMU */
- int nsfrs;
struct clk *clk;
struct clk *clk_master;
int activations;
@@ -191,7 +190,7 @@ struct sysmmu_drvdata {
struct iommu_domain *domain;
bool runtime_active;
unsigned long pgtable;
- void __iomem *sfrbases[0];
+ void __iomem *sfrbase;
};
static bool set_sysmmu_active(struct sysmmu_drvdata *data)
@@ -214,11 +213,11 @@ static bool is_sysmmu_active(struct sysmmu_drvdata *data)
}
static unsigned int __sysmmu_version(struct sysmmu_drvdata *data,
- int idx, unsigned int *minor)
+ unsigned int *minor)
{
unsigned long major;
- major = readl(data->sfrbases[idx] + REG_MMU_VERSION);
+ major = readl(data->sfrbase + REG_MMU_VERSION);
if (minor)
*minor = MMU_MIN_VER(major);
@@ -282,7 +281,6 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
{
struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
unsigned long flags;
- int i;
BUG_ON((base0 + size0) <= base0);
BUG_ON((size1 > 0) && ((base1 + size1) <= base1));
@@ -292,31 +290,31 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
goto finish;
clk_enable(data->clk_master);
- for (i = 0; i < data->nsfrs; i++) {
- if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
- if (!sysmmu_block(data->sfrbases[i]))
- continue;
-
- if (size1 == 0) {
- if (size0 <= SZ_128K) {
- base1 = base0;
- size1 = size0;
- } else {
- size1 = size0 -
- ALIGN(size0 / 2, SZ_64K);
- size0 = size0 - size1;
- base1 = base0 + size0;
- }
+
+ if ((readl(data->sfrbase + REG_MMU_VERSION) >> 28) == 3) {
+ if (!sysmmu_block(data->sfrbase))
+ goto skip;
+
+ if (size1 == 0) {
+ if (size0 <= SZ_128K) {
+ base1 = base0;
+ size1 = size0;
+ } else {
+ size1 = size0 -
+ ALIGN(size0 / 2, SZ_64K);
+ size0 = size0 - size1;
+ base1 = base0 + size0;
}
+ }
- __sysmmu_set_prefbuf(
- data->sfrbases[i], base0, size0, 0);
- __sysmmu_set_prefbuf(
- data->sfrbases[i], base1, size1, 1);
+ __sysmmu_set_prefbuf(
+ data->sfrbase, base0, size0, 0);
+ __sysmmu_set_prefbuf(
+ data->sfrbase, base1, size1, 1);
- sysmmu_unblock(data->sfrbases[i]);
- }
+ sysmmu_unblock(data->sfrbase);
}
+skip:
clk_disable(data->clk_master);
finish:
spin_unlock_irqrestore(&data->lock, flags);
@@ -354,53 +352,41 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
struct exynos_iommu_client *client = NULL;
enum exynos_sysmmu_inttype itype;
unsigned long addr = -1;
- int i, ret = -ENOSYS;
+ int ret = -ENOSYS;
if (data->master)
client = data->master->archdata.iommu;
WARN_ON(!is_sysmmu_active(data));
- for (i = 0; i < data->nsfrs; i++) {
- struct resource *irqres;
- irqres = platform_get_resource(to_platform_device(data->sysmmu),
- IORESOURCE_IRQ, i);
- if (irqres && ((int)irqres->start == irq))
- break;
- }
-
if (client)
spin_lock(&client->lock);
spin_lock(&data->lock);
- if (i == data->nsfrs) {
+ itype = (enum exynos_sysmmu_inttype)
+ __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS));
+ if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
itype = SYSMMU_FAULT_UNKNOWN;
- } else {
- itype = (enum exynos_sysmmu_inttype)
- __ffs(__raw_readl(data->sfrbases[i] + REG_INT_STATUS));
- if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
- itype = SYSMMU_FAULT_UNKNOWN;
- else
- addr = __raw_readl(
- data->sfrbases[i] + fault_reg_offset[itype]);
- }
+ else
+ addr = __raw_readl(
+ data->sfrbase + fault_reg_offset[itype]);
if (data->domain)
ret = report_iommu_fault(data->domain, data->master,
addr, itype);
if (!ret && (itype != SYSMMU_FAULT_UNKNOWN))
- __raw_writel(1 << itype, data->sfrbases[i] + REG_INT_CLEAR);
+ __raw_writel(1 << itype, data->sfrbase + REG_INT_CLEAR);
else {
unsigned long ba = data->pgtable;
if (itype != SYSMMU_FAULT_UNKNOWN)
- ba = __raw_readl(data->sfrbases[i] + REG_PT_BASE_ADDR);
+ ba = __raw_readl(data->sfrbase + REG_PT_BASE_ADDR);
show_fault_information(dev_name(data->sysmmu),
itype, ba, addr);
}
if (itype != SYSMMU_FAULT_UNKNOWN)
- sysmmu_unblock(data->sfrbases[i]);
+ sysmmu_unblock(data->sfrbase);
spin_unlock(&data->lock);
if (client)
@@ -411,14 +397,10 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
{
- int i;
-
clk_enable(data->clk_master);
- for (i = 0; i < data->nsfrs; i++) {
- __raw_writel(CTRL_DISABLE,
- data->sfrbases[i] + REG_MMU_CTRL);
- __raw_writel(0, data->sfrbases[i] + REG_MMU_CFG);
- }
+
+ __raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);
+ __raw_writel(0, data->sfrbase + REG_MMU_CFG);
clk_disable(data->clk);
clk_disable(data->clk_master);
@@ -452,12 +434,12 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
}
-static void __sysmmu_init_config(struct sysmmu_drvdata *data, int idx)
+static void __sysmmu_init_config(struct sysmmu_drvdata *data)
{
unsigned long cfg = CFG_LRU | CFG_QOS(15);
int maj, min = 0;
- maj = __sysmmu_version(data, idx, &min);
+ maj = __sysmmu_version(data, &min);
if (maj == 3) {
if (min > 1) {
cfg |= CFG_FLPDCACHE;
@@ -465,25 +447,22 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data, int idx)
}
}
- __raw_writel(cfg, data->sfrbases[idx] + REG_MMU_CFG);
+ __raw_writel(cfg, data->sfrbase + REG_MMU_CFG);
}
static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
{
- int i;
-
clk_enable(data->clk_master);
clk_enable(data->clk);
- for (i = 0; i < data->nsfrs; i++) {
- __raw_writel(CTRL_BLOCK, data->sfrbases[i] + REG_MMU_CTRL);
+ __raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);
- __sysmmu_init_config(data, i);
+ __sysmmu_init_config(data);
- __sysmmu_set_ptbase(data->sfrbases[i], data->pgtable);
+ __sysmmu_set_ptbase(data->sfrbase, data->pgtable);
+
+ __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);
- __raw_writel(CTRL_ENABLE, data->sfrbases[i] + REG_MMU_CTRL);
- }
clk_disable(data->clk_master);
}
@@ -604,11 +583,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)
spin_lock_irqsave(&data->lock, flags);
if (is_sysmmu_active(data) && data->runtime_active) {
- int i;
clk_enable(data->clk_master);
- for (i = 0; i < data->nsfrs; i++)
- __sysmmu_tlb_invalidate_entry(
- data->sfrbases[i], iova);
+ __sysmmu_tlb_invalidate_entry(data->sfrbase, iova);
clk_disable(data->clk_master);
} else {
dev_dbg(dev,
@@ -633,16 +609,12 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
spin_lock_irqsave(&data->lock, flags);
if (is_sysmmu_active(data) &&
data->runtime_active) {
- int i;
- for (i = 0; i < data->nsfrs; i++) {
- clk_enable(data->clk_master);
- if (sysmmu_block(data->sfrbases[i])) {
- __sysmmu_tlb_invalidate(
- data->sfrbases[i]);
- sysmmu_unblock(data->sfrbases[i]);
- }
- clk_disable(data->clk_master);
+ clk_enable(data->clk_master);
+ if (sysmmu_block(data->sfrbase)) {
+ __sysmmu_tlb_invalidate(data->sfrbase);
+ sysmmu_unblock(data->sfrbase);
}
+ clk_disable(data->clk_master);
} else {
dev_dbg(dev, "disabled. Skipping TLB invalidation\n");
}
@@ -652,58 +624,41 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
static int __init exynos_sysmmu_probe(struct platform_device *pdev)
{
- int i, ret;
+ int ret;
struct device *dev = &pdev->dev;
struct sysmmu_drvdata *data;
+ struct resource *res;
+ int irq;
- if (pdev->num_resources == 0) {
- dev_err(dev, "No System MMU resource defined\n");
- return -ENODEV;
- }
-
- data = devm_kzalloc(dev,
- sizeof(*data) +
- sizeof(*data->sfrbases) * (pdev->num_resources / 2),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(dev, "Not enough memory for initialization\n");
return -ENOMEM;
}
- data->nsfrs = pdev->num_resources / 2;
-
- for (i = 0; i < data->nsfrs; i++) {
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- dev_err(dev, "Unable to find IOMEM region\n");
- return -ENOENT;
- }
-
- data->sfrbases[i] = devm_request_and_ioremap(dev, res);
- if (!data->sfrbases[i]) {
- dev_err(dev, "Unable to map IOMEM @ %#x\n", res->start);
- return -EBUSY;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "Unable to find IOMEM region\n");
+ return -ENOENT;
}
- for (i = 0; i < data->nsfrs; i++) {
- int irq;
+ data->sfrbase = devm_request_and_ioremap(dev, res);
+ if (!data->sfrbase) {
+ dev_err(dev, "Unable to map IOMEM @ %#x\n", res->start);
+ return -EBUSY;
+ }
- irq = platform_get_irq(pdev, i);
- if (irq <= 0) {
- dev_err(dev, "Unable to find IRQ resource\n");
- return -ENOENT;
- }
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "Unable to find IRQ resource\n");
+ return -ENOENT;
+ }
- ret = devm_request_irq(dev, irq, exynos_sysmmu_irq,
- 0, dev_name(dev), data);
- if (ret) {
- dev_err(dev, "Unable to register handler to irq %d\n",
- irq);
- return ret;
- }
+ ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0, dev_name(dev),
+ data);
+ if (ret) {
+ dev_err(dev, "Unable to register handler to irq %d\n", irq);
+ return ret;
}
pm_runtime_enable(dev);