diff options
Diffstat (limited to 'drivers/iommu/omap-iommu.c')
-rw-r--r-- | drivers/iommu/omap-iommu.c | 107 |
1 files changed, 74 insertions, 33 deletions
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index d0b1234581b..18108c1405e 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c | |||
@@ -16,17 +16,20 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/ioport.h> | 18 | #include <linux/ioport.h> |
19 | #include <linux/clk.h> | ||
20 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
21 | #include <linux/iommu.h> | 20 | #include <linux/iommu.h> |
21 | #include <linux/omap-iommu.h> | ||
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/io.h> | ||
25 | #include <linux/pm_runtime.h> | ||
24 | 26 | ||
25 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
26 | 28 | ||
27 | #include <plat/iommu.h> | 29 | #include <linux/platform_data/iommu-omap.h> |
28 | 30 | ||
29 | #include <plat/iopgtable.h> | 31 | #include "omap-iopgtable.h" |
32 | #include "omap-iommu.h" | ||
30 | 33 | ||
31 | #define for_each_iotlb_cr(obj, n, __i, cr) \ | 34 | #define for_each_iotlb_cr(obj, n, __i, cr) \ |
32 | for (__i = 0; \ | 35 | for (__i = 0; \ |
@@ -51,6 +54,21 @@ struct omap_iommu_domain { | |||
51 | spinlock_t lock; | 54 | spinlock_t lock; |
52 | }; | 55 | }; |
53 | 56 | ||
57 | #define MMU_LOCK_BASE_SHIFT 10 | ||
58 | #define MMU_LOCK_BASE_MASK (0x1f << MMU_LOCK_BASE_SHIFT) | ||
59 | #define MMU_LOCK_BASE(x) \ | ||
60 | ((x & MMU_LOCK_BASE_MASK) >> MMU_LOCK_BASE_SHIFT) | ||
61 | |||
62 | #define MMU_LOCK_VICT_SHIFT 4 | ||
63 | #define MMU_LOCK_VICT_MASK (0x1f << MMU_LOCK_VICT_SHIFT) | ||
64 | #define MMU_LOCK_VICT(x) \ | ||
65 | ((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT) | ||
66 | |||
67 | struct iotlb_lock { | ||
68 | short base; | ||
69 | short vict; | ||
70 | }; | ||
71 | |||
54 | /* accommodate the difference between omap1 and omap2/3 */ | 72 | /* accommodate the difference between omap1 and omap2/3 */ |
55 | static const struct iommu_functions *arch_iommu; | 73 | static const struct iommu_functions *arch_iommu; |
56 | 74 | ||
@@ -125,31 +143,44 @@ EXPORT_SYMBOL_GPL(omap_iommu_arch_version); | |||
125 | static int iommu_enable(struct omap_iommu *obj) | 143 | static int iommu_enable(struct omap_iommu *obj) |
126 | { | 144 | { |
127 | int err; | 145 | int err; |
146 | struct platform_device *pdev = to_platform_device(obj->dev); | ||
147 | struct iommu_platform_data *pdata = pdev->dev.platform_data; | ||
128 | 148 | ||
129 | if (!obj) | 149 | if (!obj || !pdata) |
130 | return -EINVAL; | 150 | return -EINVAL; |
131 | 151 | ||
132 | if (!arch_iommu) | 152 | if (!arch_iommu) |
133 | return -ENODEV; | 153 | return -ENODEV; |
134 | 154 | ||
135 | clk_enable(obj->clk); | 155 | if (pdata->deassert_reset) { |
156 | err = pdata->deassert_reset(pdev, pdata->reset_name); | ||
157 | if (err) { | ||
158 | dev_err(obj->dev, "deassert_reset failed: %d\n", err); | ||
159 | return err; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | pm_runtime_get_sync(obj->dev); | ||
136 | 164 | ||
137 | err = arch_iommu->enable(obj); | 165 | err = arch_iommu->enable(obj); |
138 | 166 | ||
139 | clk_disable(obj->clk); | ||
140 | return err; | 167 | return err; |
141 | } | 168 | } |
142 | 169 | ||
143 | static void iommu_disable(struct omap_iommu *obj) | 170 | static void iommu_disable(struct omap_iommu *obj) |
144 | { | 171 | { |
145 | if (!obj) | 172 | struct platform_device *pdev = to_platform_device(obj->dev); |
146 | return; | 173 | struct iommu_platform_data *pdata = pdev->dev.platform_data; |
147 | 174 | ||
148 | clk_enable(obj->clk); | 175 | if (!obj || !pdata) |
176 | return; | ||
149 | 177 | ||
150 | arch_iommu->disable(obj); | 178 | arch_iommu->disable(obj); |
151 | 179 | ||
152 | clk_disable(obj->clk); | 180 | pm_runtime_put_sync(obj->dev); |
181 | |||
182 | if (pdata->assert_reset) | ||
183 | pdata->assert_reset(pdev, pdata->reset_name); | ||
153 | } | 184 | } |
154 | 185 | ||
155 | /* | 186 | /* |
@@ -272,7 +303,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) | |||
272 | if (!obj || !obj->nr_tlb_entries || !e) | 303 | if (!obj || !obj->nr_tlb_entries || !e) |
273 | return -EINVAL; | 304 | return -EINVAL; |
274 | 305 | ||
275 | clk_enable(obj->clk); | 306 | pm_runtime_get_sync(obj->dev); |
276 | 307 | ||
277 | iotlb_lock_get(obj, &l); | 308 | iotlb_lock_get(obj, &l); |
278 | if (l.base == obj->nr_tlb_entries) { | 309 | if (l.base == obj->nr_tlb_entries) { |
@@ -302,7 +333,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) | |||
302 | 333 | ||
303 | cr = iotlb_alloc_cr(obj, e); | 334 | cr = iotlb_alloc_cr(obj, e); |
304 | if (IS_ERR(cr)) { | 335 | if (IS_ERR(cr)) { |
305 | clk_disable(obj->clk); | 336 | pm_runtime_put_sync(obj->dev); |
306 | return PTR_ERR(cr); | 337 | return PTR_ERR(cr); |
307 | } | 338 | } |
308 | 339 | ||
@@ -316,7 +347,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) | |||
316 | l.vict = l.base; | 347 | l.vict = l.base; |
317 | iotlb_lock_set(obj, &l); | 348 | iotlb_lock_set(obj, &l); |
318 | out: | 349 | out: |
319 | clk_disable(obj->clk); | 350 | pm_runtime_put_sync(obj->dev); |
320 | return err; | 351 | return err; |
321 | } | 352 | } |
322 | 353 | ||
@@ -346,7 +377,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da) | |||
346 | int i; | 377 | int i; |
347 | struct cr_regs cr; | 378 | struct cr_regs cr; |
348 | 379 | ||
349 | clk_enable(obj->clk); | 380 | pm_runtime_get_sync(obj->dev); |
350 | 381 | ||
351 | for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) { | 382 | for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) { |
352 | u32 start; | 383 | u32 start; |
@@ -365,7 +396,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da) | |||
365 | iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); | 396 | iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); |
366 | } | 397 | } |
367 | } | 398 | } |
368 | clk_disable(obj->clk); | 399 | pm_runtime_put_sync(obj->dev); |
369 | 400 | ||
370 | if (i == obj->nr_tlb_entries) | 401 | if (i == obj->nr_tlb_entries) |
371 | dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da); | 402 | dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da); |
@@ -379,7 +410,7 @@ static void flush_iotlb_all(struct omap_iommu *obj) | |||
379 | { | 410 | { |
380 | struct iotlb_lock l; | 411 | struct iotlb_lock l; |
381 | 412 | ||
382 | clk_enable(obj->clk); | 413 | pm_runtime_get_sync(obj->dev); |
383 | 414 | ||
384 | l.base = 0; | 415 | l.base = 0; |
385 | l.vict = 0; | 416 | l.vict = 0; |
@@ -387,7 +418,7 @@ static void flush_iotlb_all(struct omap_iommu *obj) | |||
387 | 418 | ||
388 | iommu_write_reg(obj, 1, MMU_GFLUSH); | 419 | iommu_write_reg(obj, 1, MMU_GFLUSH); |
389 | 420 | ||
390 | clk_disable(obj->clk); | 421 | pm_runtime_put_sync(obj->dev); |
391 | } | 422 | } |
392 | 423 | ||
393 | #if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) | 424 | #if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) |
@@ -397,11 +428,11 @@ ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes) | |||
397 | if (!obj || !buf) | 428 | if (!obj || !buf) |
398 | return -EINVAL; | 429 | return -EINVAL; |
399 | 430 | ||
400 | clk_enable(obj->clk); | 431 | pm_runtime_get_sync(obj->dev); |
401 | 432 | ||
402 | bytes = arch_iommu->dump_ctx(obj, buf, bytes); | 433 | bytes = arch_iommu->dump_ctx(obj, buf, bytes); |
403 | 434 | ||
404 | clk_disable(obj->clk); | 435 | pm_runtime_put_sync(obj->dev); |
405 | 436 | ||
406 | return bytes; | 437 | return bytes; |
407 | } | 438 | } |
@@ -415,7 +446,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) | |||
415 | struct cr_regs tmp; | 446 | struct cr_regs tmp; |
416 | struct cr_regs *p = crs; | 447 | struct cr_regs *p = crs; |
417 | 448 | ||
418 | clk_enable(obj->clk); | 449 | pm_runtime_get_sync(obj->dev); |
419 | iotlb_lock_get(obj, &saved); | 450 | iotlb_lock_get(obj, &saved); |
420 | 451 | ||
421 | for_each_iotlb_cr(obj, num, i, tmp) { | 452 | for_each_iotlb_cr(obj, num, i, tmp) { |
@@ -425,7 +456,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) | |||
425 | } | 456 | } |
426 | 457 | ||
427 | iotlb_lock_set(obj, &saved); | 458 | iotlb_lock_set(obj, &saved); |
428 | clk_disable(obj->clk); | 459 | pm_runtime_put_sync(obj->dev); |
429 | 460 | ||
430 | return p - crs; | 461 | return p - crs; |
431 | } | 462 | } |
@@ -789,9 +820,7 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) | |||
789 | if (!obj->refcount) | 820 | if (!obj->refcount) |
790 | return IRQ_NONE; | 821 | return IRQ_NONE; |
791 | 822 | ||
792 | clk_enable(obj->clk); | ||
793 | errs = iommu_report_fault(obj, &da); | 823 | errs = iommu_report_fault(obj, &da); |
794 | clk_disable(obj->clk); | ||
795 | if (errs == 0) | 824 | if (errs == 0) |
796 | return IRQ_HANDLED; | 825 | return IRQ_HANDLED; |
797 | 826 | ||
@@ -913,17 +942,10 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) | |||
913 | struct resource *res; | 942 | struct resource *res; |
914 | struct iommu_platform_data *pdata = pdev->dev.platform_data; | 943 | struct iommu_platform_data *pdata = pdev->dev.platform_data; |
915 | 944 | ||
916 | if (pdev->num_resources != 2) | ||
917 | return -EINVAL; | ||
918 | |||
919 | obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL); | 945 | obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL); |
920 | if (!obj) | 946 | if (!obj) |
921 | return -ENOMEM; | 947 | return -ENOMEM; |
922 | 948 | ||
923 | obj->clk = clk_get(&pdev->dev, pdata->clk_name); | ||
924 | if (IS_ERR(obj->clk)) | ||
925 | goto err_clk; | ||
926 | |||
927 | obj->nr_tlb_entries = pdata->nr_tlb_entries; | 949 | obj->nr_tlb_entries = pdata->nr_tlb_entries; |
928 | obj->name = pdata->name; | 950 | obj->name = pdata->name; |
929 | obj->dev = &pdev->dev; | 951 | obj->dev = &pdev->dev; |
@@ -966,6 +988,9 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) | |||
966 | goto err_irq; | 988 | goto err_irq; |
967 | platform_set_drvdata(pdev, obj); | 989 | platform_set_drvdata(pdev, obj); |
968 | 990 | ||
991 | pm_runtime_irq_safe(obj->dev); | ||
992 | pm_runtime_enable(obj->dev); | ||
993 | |||
969 | dev_info(&pdev->dev, "%s registered\n", obj->name); | 994 | dev_info(&pdev->dev, "%s registered\n", obj->name); |
970 | return 0; | 995 | return 0; |
971 | 996 | ||
@@ -974,8 +999,6 @@ err_irq: | |||
974 | err_ioremap: | 999 | err_ioremap: |
975 | release_mem_region(res->start, resource_size(res)); | 1000 | release_mem_region(res->start, resource_size(res)); |
976 | err_mem: | 1001 | err_mem: |
977 | clk_put(obj->clk); | ||
978 | err_clk: | ||
979 | kfree(obj); | 1002 | kfree(obj); |
980 | return err; | 1003 | return err; |
981 | } | 1004 | } |
@@ -996,7 +1019,8 @@ static int __devexit omap_iommu_remove(struct platform_device *pdev) | |||
996 | release_mem_region(res->start, resource_size(res)); | 1019 | release_mem_region(res->start, resource_size(res)); |
997 | iounmap(obj->regbase); | 1020 | iounmap(obj->regbase); |
998 | 1021 | ||
999 | clk_put(obj->clk); | 1022 | pm_runtime_disable(obj->dev); |
1023 | |||
1000 | dev_info(&pdev->dev, "%s removed\n", obj->name); | 1024 | dev_info(&pdev->dev, "%s removed\n", obj->name); |
1001 | kfree(obj); | 1025 | kfree(obj); |
1002 | return 0; | 1026 | return 0; |
@@ -1015,6 +1039,23 @@ static void iopte_cachep_ctor(void *iopte) | |||
1015 | clean_dcache_area(iopte, IOPTE_TABLE_SIZE); | 1039 | clean_dcache_area(iopte, IOPTE_TABLE_SIZE); |
1016 | } | 1040 | } |
1017 | 1041 | ||
1042 | static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, | ||
1043 | u32 flags) | ||
1044 | { | ||
1045 | memset(e, 0, sizeof(*e)); | ||
1046 | |||
1047 | e->da = da; | ||
1048 | e->pa = pa; | ||
1049 | e->valid = 1; | ||
1050 | /* FIXME: add OMAP1 support */ | ||
1051 | e->pgsz = flags & MMU_CAM_PGSZ_MASK; | ||
1052 | e->endian = flags & MMU_RAM_ENDIAN_MASK; | ||
1053 | e->elsz = flags & MMU_RAM_ELSZ_MASK; | ||
1054 | e->mixed = flags & MMU_RAM_MIXED_MASK; | ||
1055 | |||
1056 | return iopgsz_to_bytes(e->pgsz); | ||
1057 | } | ||
1058 | |||
1018 | static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, | 1059 | static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, |
1019 | phys_addr_t pa, size_t bytes, int prot) | 1060 | phys_addr_t pa, size_t bytes, int prot) |
1020 | { | 1061 | { |