|
@@ -16,13 +16,13 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/ioport.h>
|
|
-#include <linux/clk.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/iommu.h>
|
|
#include <linux/iommu.h>
|
|
#include <linux/omap-iommu.h>
|
|
#include <linux/omap-iommu.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cacheflush.h>
|
|
|
|
|
|
@@ -143,31 +143,44 @@ EXPORT_SYMBOL_GPL(omap_iommu_arch_version);
|
|
static int iommu_enable(struct omap_iommu *obj)
|
|
static int iommu_enable(struct omap_iommu *obj)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
|
|
+ struct platform_device *pdev = to_platform_device(obj->dev);
|
|
|
|
+ struct iommu_platform_data *pdata = pdev->dev.platform_data;
|
|
|
|
|
|
- if (!obj)
|
|
|
|
|
|
+ if (!obj || !pdata)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
if (!arch_iommu)
|
|
if (!arch_iommu)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ if (pdata->deassert_reset) {
|
|
|
|
+ err = pdata->deassert_reset(pdev, pdata->reset_name);
|
|
|
|
+ if (err) {
|
|
|
|
+ dev_err(obj->dev, "deassert_reset failed: %d\n", err);
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pm_runtime_get_sync(obj->dev);
|
|
|
|
|
|
err = arch_iommu->enable(obj);
|
|
err = arch_iommu->enable(obj);
|
|
|
|
|
|
- clk_disable(obj->clk);
|
|
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
static void iommu_disable(struct omap_iommu *obj)
|
|
static void iommu_disable(struct omap_iommu *obj)
|
|
{
|
|
{
|
|
- if (!obj)
|
|
|
|
- return;
|
|
|
|
|
|
+ struct platform_device *pdev = to_platform_device(obj->dev);
|
|
|
|
+ struct iommu_platform_data *pdata = pdev->dev.platform_data;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ if (!obj || !pdata)
|
|
|
|
+ return;
|
|
|
|
|
|
arch_iommu->disable(obj);
|
|
arch_iommu->disable(obj);
|
|
|
|
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
|
|
+
|
|
|
|
+ if (pdata->assert_reset)
|
|
|
|
+ pdata->assert_reset(pdev, pdata->reset_name);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -290,7 +303,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
|
|
if (!obj || !obj->nr_tlb_entries || !e)
|
|
if (!obj || !obj->nr_tlb_entries || !e)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_get_sync(obj->dev);
|
|
|
|
|
|
iotlb_lock_get(obj, &l);
|
|
iotlb_lock_get(obj, &l);
|
|
if (l.base == obj->nr_tlb_entries) {
|
|
if (l.base == obj->nr_tlb_entries) {
|
|
@@ -320,7 +333,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
|
|
|
|
|
|
cr = iotlb_alloc_cr(obj, e);
|
|
cr = iotlb_alloc_cr(obj, e);
|
|
if (IS_ERR(cr)) {
|
|
if (IS_ERR(cr)) {
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
return PTR_ERR(cr);
|
|
return PTR_ERR(cr);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -334,7 +347,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
|
|
l.vict = l.base;
|
|
l.vict = l.base;
|
|
iotlb_lock_set(obj, &l);
|
|
iotlb_lock_set(obj, &l);
|
|
out:
|
|
out:
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -364,7 +377,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
|
|
int i;
|
|
int i;
|
|
struct cr_regs cr;
|
|
struct cr_regs cr;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_get_sync(obj->dev);
|
|
|
|
|
|
for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
|
|
for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
|
|
u32 start;
|
|
u32 start;
|
|
@@ -383,7 +396,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
|
|
iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
|
|
iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
|
|
|
|
if (i == obj->nr_tlb_entries)
|
|
if (i == obj->nr_tlb_entries)
|
|
dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
|
|
dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
|
|
@@ -397,7 +410,7 @@ static void flush_iotlb_all(struct omap_iommu *obj)
|
|
{
|
|
{
|
|
struct iotlb_lock l;
|
|
struct iotlb_lock l;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_get_sync(obj->dev);
|
|
|
|
|
|
l.base = 0;
|
|
l.base = 0;
|
|
l.vict = 0;
|
|
l.vict = 0;
|
|
@@ -405,7 +418,7 @@ static void flush_iotlb_all(struct omap_iommu *obj)
|
|
|
|
|
|
iommu_write_reg(obj, 1, MMU_GFLUSH);
|
|
iommu_write_reg(obj, 1, MMU_GFLUSH);
|
|
|
|
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
|
|
#if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
|
|
@@ -415,11 +428,11 @@ ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes)
|
|
if (!obj || !buf)
|
|
if (!obj || !buf)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_get_sync(obj->dev);
|
|
|
|
|
|
bytes = arch_iommu->dump_ctx(obj, buf, bytes);
|
|
bytes = arch_iommu->dump_ctx(obj, buf, bytes);
|
|
|
|
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
|
|
|
|
return bytes;
|
|
return bytes;
|
|
}
|
|
}
|
|
@@ -433,7 +446,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
|
|
struct cr_regs tmp;
|
|
struct cr_regs tmp;
|
|
struct cr_regs *p = crs;
|
|
struct cr_regs *p = crs;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_get_sync(obj->dev);
|
|
iotlb_lock_get(obj, &saved);
|
|
iotlb_lock_get(obj, &saved);
|
|
|
|
|
|
for_each_iotlb_cr(obj, num, i, tmp) {
|
|
for_each_iotlb_cr(obj, num, i, tmp) {
|
|
@@ -443,7 +456,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
|
|
}
|
|
}
|
|
|
|
|
|
iotlb_lock_set(obj, &saved);
|
|
iotlb_lock_set(obj, &saved);
|
|
- clk_disable(obj->clk);
|
|
|
|
|
|
+ pm_runtime_put_sync(obj->dev);
|
|
|
|
|
|
return p - crs;
|
|
return p - crs;
|
|
}
|
|
}
|
|
@@ -807,9 +820,7 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
|
|
if (!obj->refcount)
|
|
if (!obj->refcount)
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
|
|
|
|
- clk_enable(obj->clk);
|
|
|
|
errs = iommu_report_fault(obj, &da);
|
|
errs = iommu_report_fault(obj, &da);
|
|
- clk_disable(obj->clk);
|
|
|
|
if (errs == 0)
|
|
if (errs == 0)
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
|
|
|
|
@@ -931,17 +942,10 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
|
|
struct resource *res;
|
|
struct resource *res;
|
|
struct iommu_platform_data *pdata = pdev->dev.platform_data;
|
|
struct iommu_platform_data *pdata = pdev->dev.platform_data;
|
|
|
|
|
|
- if (pdev->num_resources != 2)
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
|
|
obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
|
|
if (!obj)
|
|
if (!obj)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- obj->clk = clk_get(&pdev->dev, pdata->clk_name);
|
|
|
|
- if (IS_ERR(obj->clk))
|
|
|
|
- goto err_clk;
|
|
|
|
-
|
|
|
|
obj->nr_tlb_entries = pdata->nr_tlb_entries;
|
|
obj->nr_tlb_entries = pdata->nr_tlb_entries;
|
|
obj->name = pdata->name;
|
|
obj->name = pdata->name;
|
|
obj->dev = &pdev->dev;
|
|
obj->dev = &pdev->dev;
|
|
@@ -984,6 +988,9 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
|
|
goto err_irq;
|
|
goto err_irq;
|
|
platform_set_drvdata(pdev, obj);
|
|
platform_set_drvdata(pdev, obj);
|
|
|
|
|
|
|
|
+ pm_runtime_irq_safe(obj->dev);
|
|
|
|
+ pm_runtime_enable(obj->dev);
|
|
|
|
+
|
|
dev_info(&pdev->dev, "%s registered\n", obj->name);
|
|
dev_info(&pdev->dev, "%s registered\n", obj->name);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
@@ -992,8 +999,6 @@ err_irq:
|
|
err_ioremap:
|
|
err_ioremap:
|
|
release_mem_region(res->start, resource_size(res));
|
|
release_mem_region(res->start, resource_size(res));
|
|
err_mem:
|
|
err_mem:
|
|
- clk_put(obj->clk);
|
|
|
|
-err_clk:
|
|
|
|
kfree(obj);
|
|
kfree(obj);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
@@ -1014,7 +1019,8 @@ static int __devexit omap_iommu_remove(struct platform_device *pdev)
|
|
release_mem_region(res->start, resource_size(res));
|
|
release_mem_region(res->start, resource_size(res));
|
|
iounmap(obj->regbase);
|
|
iounmap(obj->regbase);
|
|
|
|
|
|
- clk_put(obj->clk);
|
|
|
|
|
|
+ pm_runtime_disable(obj->dev);
|
|
|
|
+
|
|
dev_info(&pdev->dev, "%s removed\n", obj->name);
|
|
dev_info(&pdev->dev, "%s removed\n", obj->name);
|
|
kfree(obj);
|
|
kfree(obj);
|
|
return 0;
|
|
return 0;
|