Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142
Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
new file mode 100644
index 0000000..eb4582e
--- /dev/null
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -0,0 +1,273 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/msm_subsystem_map.h>
+#include <linux/memory_alloc.h>
+#include <linux/iommu.h>
+#include <asm/sizes.h>
+#include <asm/page.h>
+#include <linux/init.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+struct msm_iommu_domain {
+ int domain_idx;
+ int iova_pool_idx;
+};
+
+enum {
+ GLOBAL_DOMAIN,
+ VIDEO_DOMAIN,
+ EMPTY_DOMAIN,
+ MAX_DOMAINS
+};
+
+enum {
+ GLOBAL_MEMORY_POOL,
+ VIDEO_FIRMWARE_POOL,
+ VIDEO_ALLOC_POOL,
+};
+
+struct {
+ char *name;
+ int domain;
+} msm_iommu_ctx_names[] = {
+ /* Camera */
+ {
+ .name = "vpe_src",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "vpe_dst",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "vfe_imgwr",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "vfe_misc",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "ijpeg_src",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "ijpeg_dst",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "jpegd_src",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "jpegd_dst",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_vg1",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_vg2",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_rgb1",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_rgb2",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Rotator */
+ {
+ .name = "rot_src",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Rotator */
+ {
+ .name = "rot_dst",
+ .domain = GLOBAL_DOMAIN,
+ },
+ /* Video */
+ {
+ .name = "vcodec_a_mm1",
+ .domain = VIDEO_DOMAIN,
+ },
+ /* Video */
+ {
+ .name = "vcodec_b_mm2",
+ .domain = VIDEO_DOMAIN,
+ },
+ /* Video */
+ {
+ .name = "vcodec_a_stream",
+ .domain = VIDEO_DOMAIN,
+ },
+};
+
+static struct iommu_domain *msm_iommu_domains[MAX_DOMAINS];
+
+static struct mem_pool msm_iommu_iova_pools[] = {
+ [GLOBAL_MEMORY_POOL] = {
+ .paddr = SZ_4K,
+ .size = SZ_2G - SZ_4K,
+ },
+ /*
+ * The video hardware has several constraints:
+ * 1) The start address for firmware must be 128K aligned
+ * 2) The video firmware must exist at a lower address than
+ * all other video allocations
+ * 3) Video allocations cannot be more than 256MB away from the
+ * firmware
+ *
+ * Splitting the video pools makes sure that firmware will
+ * always be lower than regular allocations and the maximum
+ * size of 256MB will be enforced.
+ */
+ [VIDEO_FIRMWARE_POOL] = {
+ .paddr = SZ_128K,
+ .size = SZ_16M - SZ_128K,
+ },
+ [VIDEO_ALLOC_POOL] = {
+ .paddr = SZ_16M,
+ .size = SZ_256M - SZ_16M - SZ_128K,
+ }
+};
+
+static struct msm_iommu_domain msm_iommu_subsystems[] = {
+ [JPEGD_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [VPE_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [MDP0_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [MDP1_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [ROT_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [IJPEG_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [VFE_SUBSYS_ID] = {
+ .domain_idx = GLOBAL_DOMAIN,
+ .iova_pool_idx = GLOBAL_MEMORY_POOL,
+ },
+ [VCODEC_A_SUBSYS_ID] = {
+ .domain_idx = VIDEO_DOMAIN,
+ .iova_pool_idx = VIDEO_ALLOC_POOL,
+ },
+ [VCODEC_B_SUBSYS_ID] = {
+ .domain_idx = VIDEO_DOMAIN,
+ .iova_pool_idx = VIDEO_ALLOC_POOL,
+ },
+ [VIDEO_FWARE_ID] = {
+ .domain_idx = VIDEO_DOMAIN,
+ .iova_pool_idx = VIDEO_FIRMWARE_POOL,
+ }
+};
+
+struct iommu_domain *msm_subsystem_get_domain(int subsys_id)
+{
+ int id = msm_iommu_subsystems[subsys_id].domain_idx;
+
+ return msm_iommu_domains[id];
+}
+
+struct mem_pool *msm_subsystem_get_pool(int subsys_id)
+{
+ int id = msm_iommu_subsystems[subsys_id].iova_pool_idx;
+
+ return &msm_iommu_iova_pools[id];
+}
+
+static int __init msm_subsystem_iommu_init(void)
+{
+ int i;
+
+ for (i = 0; i < (ARRAY_SIZE(msm_iommu_domains) - 1); i++)
+ msm_iommu_domains[i] = iommu_domain_alloc();
+
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_iova_pools); i++) {
+ mutex_init(&msm_iommu_iova_pools[i].pool_mutex);
+ msm_iommu_iova_pools[i].gpool = gen_pool_create(PAGE_SHIFT, -1);
+
+ if (!msm_iommu_iova_pools[i].gpool) {
+ pr_err("%s: could not allocate iova pool. iommu"
+ " programming will not work with iova space"
+ " %d\n", __func__, i);
+ continue;
+ }
+
+ if (gen_pool_add(msm_iommu_iova_pools[i].gpool,
+ msm_iommu_iova_pools[i].paddr,
+ msm_iommu_iova_pools[i].size,
+ -1)) {
+ pr_err("%s: could not add memory to iova pool. iommu"
+ " programming will not work with iova space"
+ " %d\n", __func__, i);
+ gen_pool_destroy(msm_iommu_iova_pools[i].gpool);
+ msm_iommu_iova_pools[i].gpool = NULL;
+ continue;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+ int domain_idx;
+ struct device *ctx = msm_iommu_get_ctx(
+ msm_iommu_ctx_names[i].name);
+
+ if (!ctx)
+ continue;
+
+ domain_idx = msm_iommu_ctx_names[i].domain;
+
+ if (!msm_iommu_domains[domain_idx])
+ continue;
+
+ if (iommu_attach_device(msm_iommu_domains[domain_idx], ctx)) {
+ pr_err("%s: could not attach domain %d to context %s."
+ " iommu programming will not occur.\n",
+ __func__, domain_idx,
+ msm_iommu_ctx_names[i].name);
+ msm_iommu_subsystems[i].domain_idx = EMPTY_DOMAIN;
+ continue;
+ }
+ }
+
+ return 0;
+}
+device_initcall(msm_subsystem_iommu_init);