aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-msm/iommu.c93
1 files changed, 82 insertions, 11 deletions
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 67e8f531b7af..a468ee309d65 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -33,6 +33,16 @@
33#include <mach/iommu_hw-8xxx.h> 33#include <mach/iommu_hw-8xxx.h>
34#include <mach/iommu.h> 34#include <mach/iommu.h>
35 35
36#define MRC(reg, processor, op1, crn, crm, op2) \
37__asm__ __volatile__ ( \
38" mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \
39: "=r" (reg))
40
41#define RCP15_PRRR(reg) MRC(reg, p15, 0, c10, c2, 0)
42#define RCP15_NMRR(reg) MRC(reg, p15, 0, c10, c2, 1)
43
44static int msm_iommu_tex_class[4];
45
36DEFINE_SPINLOCK(msm_iommu_lock); 46DEFINE_SPINLOCK(msm_iommu_lock);
37 47
38struct msm_priv { 48struct msm_priv {
@@ -98,6 +108,7 @@ static void __reset_context(void __iomem *base, int ctx)
98 108
99static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable) 109static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
100{ 110{
111 unsigned int prrr, nmrr;
101 __reset_context(base, ctx); 112 __reset_context(base, ctx);
102 113
103 /* Set up HTW mode */ 114 /* Set up HTW mode */
@@ -130,11 +141,11 @@ static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
130 /* Turn on TEX Remap */ 141 /* Turn on TEX Remap */
131 SET_TRE(base, ctx, 1); 142 SET_TRE(base, ctx, 1);
132 143
133 /* Do not configure PRRR / NMRR on the IOMMU for now. We will assume 144 /* Set TEX remap attributes */
134 * TEX class 0 for everything until attributes are properly worked out 145 RCP15_PRRR(prrr);
135 */ 146 RCP15_NMRR(nmrr);
136 SET_PRRR(base, ctx, 0); 147 SET_PRRR(base, ctx, prrr);
137 SET_NMRR(base, ctx, 0); 148 SET_NMRR(base, ctx, nmrr);
138 149
139 /* Turn on BFB prefetch */ 150 /* Turn on BFB prefetch */
140 SET_BFBDFE(base, ctx, 1); 151 SET_BFBDFE(base, ctx, 1);
@@ -304,12 +315,21 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
304 unsigned long *sl_table; 315 unsigned long *sl_table;
305 unsigned long *sl_pte; 316 unsigned long *sl_pte;
306 unsigned long sl_offset; 317 unsigned long sl_offset;
318 unsigned int pgprot;
307 size_t len = 0x1000UL << order; 319 size_t len = 0x1000UL << order;
308 int ret = 0; 320 int ret = 0, tex, sh;
309 321
310 spin_lock_irqsave(&msm_iommu_lock, flags); 322 spin_lock_irqsave(&msm_iommu_lock, flags);
311 priv = domain->priv;
312 323
324 sh = (prot & MSM_IOMMU_ATTR_SH) ? 1 : 0;
325 tex = msm_iommu_tex_class[prot & MSM_IOMMU_CP_MASK];
326
327 if (tex < 0 || tex > NUM_TEX_CLASS - 1) {
328 ret = -EINVAL;
329 goto fail;
330 }
331
332 priv = domain->priv;
313 if (!priv) { 333 if (!priv) {
314 ret = -EINVAL; 334 ret = -EINVAL;
315 goto fail; 335 goto fail;
@@ -330,6 +350,18 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
330 goto fail; 350 goto fail;
331 } 351 }
332 352
353 if (len == SZ_16M || len == SZ_1M) {
354 pgprot = sh ? FL_SHARED : 0;
355 pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0;
356 pgprot |= tex & 0x02 ? FL_CACHEABLE : 0;
357 pgprot |= tex & 0x04 ? FL_TEX0 : 0;
358 } else {
359 pgprot = sh ? SL_SHARED : 0;
360 pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0;
361 pgprot |= tex & 0x02 ? SL_CACHEABLE : 0;
362 pgprot |= tex & 0x04 ? SL_TEX0 : 0;
363 }
364
333 fl_offset = FL_OFFSET(va); /* Upper 12 bits */ 365 fl_offset = FL_OFFSET(va); /* Upper 12 bits */
334 fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */ 366 fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
335 367
@@ -338,12 +370,12 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
338 for (i = 0; i < 16; i++) 370 for (i = 0; i < 16; i++)
339 *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION | 371 *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
340 FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT | 372 FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
341 FL_SHARED; 373 FL_SHARED | pgprot;
342 } 374 }
343 375
344 if (len == SZ_1M) 376 if (len == SZ_1M)
345 *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE | 377 *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
346 FL_TYPE_SECT | FL_SHARED; 378 FL_TYPE_SECT | FL_SHARED | pgprot;
347 379
348 /* Need a 2nd level table */ 380 /* Need a 2nd level table */
349 if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) { 381 if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) {
@@ -368,14 +400,14 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
368 400
369 if (len == SZ_4K) 401 if (len == SZ_4K)
370 *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 | 402 *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
371 SL_SHARED | SL_TYPE_SMALL; 403 SL_SHARED | SL_TYPE_SMALL | pgprot;
372 404
373 if (len == SZ_64K) { 405 if (len == SZ_64K) {
374 int i; 406 int i;
375 407
376 for (i = 0; i < 16; i++) 408 for (i = 0; i < 16; i++)
377 *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 | 409 *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
378 SL_AP1 | SL_SHARED | SL_TYPE_LARGE; 410 SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
379 } 411 }
380 412
381 __flush_iotlb(domain); 413 __flush_iotlb(domain);
@@ -593,8 +625,47 @@ static struct iommu_ops msm_iommu_ops = {
593 .domain_has_cap = msm_iommu_domain_has_cap 625 .domain_has_cap = msm_iommu_domain_has_cap
594}; 626};
595 627
628static int __init get_tex_class(int icp, int ocp, int mt, int nos)
629{
630 int i = 0;
631 unsigned int prrr = 0;
632 unsigned int nmrr = 0;
633 int c_icp, c_ocp, c_mt, c_nos;
634
635 RCP15_PRRR(prrr);
636 RCP15_NMRR(nmrr);
637
638 for (i = 0; i < NUM_TEX_CLASS; i++) {
639 c_nos = PRRR_NOS(prrr, i);
640 c_mt = PRRR_MT(prrr, i);
641 c_icp = NMRR_ICP(nmrr, i);
642 c_ocp = NMRR_OCP(nmrr, i);
643
644 if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos)
645 return i;
646 }
647
648 return -ENODEV;
649}
650
651static void __init setup_iommu_tex_classes(void)
652{
653 msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] =
654 get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1);
655
656 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] =
657 get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1);
658
659 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] =
660 get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1);
661
662 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] =
663 get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1);
664}
665
596static int __init msm_iommu_init(void) 666static int __init msm_iommu_init(void)
597{ 667{
668 setup_iommu_tex_classes();
598 register_iommu(&msm_iommu_ops); 669 register_iommu(&msm_iommu_ops);
599 return 0; 670 return 0;
600} 671}