summaryrefslogtreecommitdiff
path: root/drivers/iommu/exynos-iommu.c
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2013-08-07 09:27:52 +0200
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:44:05 +0900
commit3ab2bf3e554e22dbf73cc0152ffbaec912bed421 (patch)
tree3aa8bdfa34c8ccf09844a99b83e63e0aca04f9be /drivers/iommu/exynos-iommu.c
parentacd0b1469fd1f714ef8b29c809b757d2081ea9a2 (diff)
downloadlinux-3.10-3ab2bf3e554e22dbf73cc0152ffbaec912bed421.tar.gz
linux-3.10-3ab2bf3e554e22dbf73cc0152ffbaec912bed421.tar.bz2
linux-3.10-3ab2bf3e554e22dbf73cc0152ffbaec912bed421.zip
iommu/exynos: remove support for combined sysmmu controllers
This patch removes support for combined SYSMMU controllers, which can be handled by defining separate device nodes for each controller. This significantly simplifies the code. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
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);