summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss.h22
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c34
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c19
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c123
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_wb.c26
9 files changed, 267 insertions, 18 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index a1ec1c677a41..7f77da065613 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -15,6 +15,7 @@
#define MDSS_H
#include <linux/ion.h>
+#include <linux/msm_mdp.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/workqueue.h>
@@ -72,6 +73,8 @@ struct mdss_data_type {
u32 *mixer_type_map;
struct ion_client *iclient;
+ int iommu_domain;
+ int iommu_attached;
};
extern struct mdss_data_type *mdss_res;
@@ -93,10 +96,29 @@ struct mdss_hw {
void mdss_enable_irq(struct mdss_hw *hw);
void mdss_disable_irq(struct mdss_hw *hw);
void mdss_disable_irq_nosync(struct mdss_hw *hw);
+
static inline struct ion_client *mdss_get_ionclient(void)
{
if (!mdss_res)
return NULL;
return mdss_res->iclient;
}
+
+static inline int is_mdss_iommu_attached(void)
+{
+ if (!mdss_res)
+ return false;
+ return mdss_res->iommu_attached;
+}
+
+static inline int mdss_get_iommu_domain(void)
+{
+ if (!mdss_res)
+ return -ENODEV;
+
+ return mdss_res->iommu_domain;
+}
+
+int mdss_iommu_attach(void);
+int mdss_iommu_dettach(void);
#endif /* MDSS_H */
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 8922bb6245b3..2ac27e3bb545 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -21,6 +21,8 @@
#include <linux/slab.h>
#include <linux/iopoll.h>
+#include <mach/iommu_domains.h>
+
#include "mdss.h"
#include "mdss_dsi.h"
@@ -1093,6 +1095,7 @@ int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
int len;
int i;
char *bp;
+ unsigned long size, addr;
bp = tp->data;
@@ -1102,17 +1105,30 @@ int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
pr_debug("\n");
- len = tp->len;
- len += 3;
- len &= ~0x03; /* multipled by 4 */
+ len = ALIGN(tp->len, 4);
+ size = ALIGN(tp->len, SZ_4K);
- tp->dmap = dma_map_single(&dsi_dev, tp->data, len, DMA_TO_DEVICE);
- if (dma_mapping_error(&dsi_dev, tp->dmap))
+ tp->dmap = dma_map_single(&dsi_dev, tp->data, size, DMA_TO_DEVICE);
+ if (dma_mapping_error(&dsi_dev, tp->dmap)) {
pr_err("%s: dmap mapp failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (is_mdss_iommu_attached()) {
+ int ret = msm_iommu_map_contig_buffer(tp->dmap,
+ mdss_get_iommu_domain(), 0,
+ size, SZ_4K, 0, &(addr));
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("unable to map dma memory to iommu(%d)\n", ret);
+ return -ENOMEM;
+ }
+ } else {
+ addr = tp->dmap;
+ }
INIT_COMPLETION(dsi_dma_comp);
- MIPI_OUTP((pdata->dsi_base) + 0x048, tp->dmap);
+ MIPI_OUTP((pdata->dsi_base) + 0x048, addr);
MIPI_OUTP((pdata->dsi_base) + 0x04c, len);
wmb();
@@ -1121,7 +1137,11 @@ int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
wait_for_completion(&dsi_dma_comp);
- dma_unmap_single(&dsi_dev, tp->dmap, len, DMA_TO_DEVICE);
+ if (is_mdss_iommu_attached())
+ msm_iommu_unmap_contig_buffer(addr, mdss_get_iommu_domain(),
+ 0, size);
+
+ dma_unmap_single(&dsi_dev, tp->dmap, size, DMA_TO_DEVICE);
tp->dmap = 0;
return tp->len;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index cc19518d421b..2c3567cfc698 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -528,8 +528,8 @@ static struct platform_driver this_driver = {
static int __init mdss_dsi_panel_init(void)
{
- mdss_dsi_buf_alloc(&dsi_panel_tx_buf, DSI_BUF_SIZE);
- mdss_dsi_buf_alloc(&dsi_panel_rx_buf, DSI_BUF_SIZE);
+ mdss_dsi_buf_alloc(&dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
+ mdss_dsi_buf_alloc(&dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
return platform_driver_register(&this_driver);
}
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 05d29c05f26a..126d9338ead4 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -611,6 +611,14 @@ static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
virt = ion_map_kernel(iclient, mfd->ihdl, 0);
ion_phys(iclient, mfd->ihdl, &phys, &size);
+
+ if (is_mdss_iommu_attached()) {
+ ion_map_iommu(iclient, mfd->ihdl,
+ mdss_get_iommu_domain(),
+ 0, SZ_4K, 0, &mfd->iova,
+ (unsigned long *) &size,
+ 0, 0);
+ }
} else {
virt = dma_alloc_coherent(NULL, size,
(dma_addr_t *) &phys, GFP_KERNEL);
@@ -1227,6 +1235,7 @@ EXPORT_SYMBOL(mdss_register_panel);
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
{
struct fb_info *info;
+ struct msm_fb_data_type *mfd;
if (fb_num > MAX_FBI_LIST)
return -EINVAL;
@@ -1235,8 +1244,16 @@ int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
if (!info)
return -ENOENT;
- *start = info->fix.smem_start;
+ mfd = (struct msm_fb_data_type *)info->par;
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->iova)
+ *start = mfd->iova;
+ else
+ *start = info->fix.smem_start;
*len = info->fix.smem_len;
+
return 0;
}
EXPORT_SYMBOL(mdss_fb_get_phys_info);
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 6d2374091827..30b53262c953 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -76,8 +76,10 @@ struct msm_fb_data_type {
struct mdp_histogram *hist);
struct ion_handle *ihdl;
+ unsigned long iova;
void *cursor_buf;
- void *cursor_buf_phys;
+ unsigned long cursor_buf_phys;
+ unsigned long cursor_buf_iova;
u32 bl_level;
struct mutex lock;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index cb01eaa3d416..acc0b8f9db19 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
@@ -42,6 +43,8 @@
#include <mach/hardware.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
#include "mdss.h"
#include "mdss_fb.h"
@@ -92,6 +95,30 @@ static struct msm_bus_scale_pdata mdp_bus_scale_table = {
.name = "mdss_mdp",
};
+struct msm_iova_partition mdp_iommu_partitions[] = {
+ {
+ .start = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ },
+};
+struct msm_iova_layout mdp_iommu_layout = {
+ .client_name = "mdss_mdp",
+ .partitions = mdp_iommu_partitions,
+ .npartitions = ARRAY_SIZE(mdp_iommu_partitions),
+};
+
+struct {
+ char *name;
+ struct device *ctx;
+} mdp_iommu_ctx[] = {
+ {
+ .name = "mdp_0",
+ },
+ {
+ .name = "mdp_1",
+ }
+};
+
struct mdss_hw mdss_mdp_hw = {
.hw_ndx = MDSS_HW_MDP,
.ptr = NULL,
@@ -584,6 +611,96 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
return 0;
}
+static int mdss_iommu_fault_handler(struct iommu_domain *domain,
+ struct device *dev, unsigned long iova, int flags)
+{
+ pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
+ return 0;
+}
+
+int mdss_iommu_attach(void)
+{
+ struct iommu_domain *domain;
+ int i, domain_idx;
+
+ if (mdss_res->iommu_attached) {
+ pr_warn("mdp iommu already attached\n");
+ return 0;
+ }
+
+ domain_idx = mdss_get_iommu_domain();
+ domain = msm_get_iommu_domain(domain_idx);
+ if (!domain) {
+ pr_err("unable to get iommu domain(%d)\n", domain_idx);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++) {
+ if (iommu_attach_device(domain, mdp_iommu_ctx[i].ctx)) {
+ WARN(1, "could not attach iommu domain %d to ctx %s\n",
+ domain_idx, mdp_iommu_ctx[i].name);
+ return -EINVAL;
+ }
+ }
+ mdss_res->iommu_attached = true;
+
+ return 0;
+}
+
+int mdss_iommu_dettach(void)
+{
+ struct iommu_domain *domain;
+ int i, domain_idx;
+
+ if (!mdss_res->iommu_attached) {
+ pr_warn("mdp iommu already dettached\n");
+ return 0;
+ }
+
+ domain_idx = mdss_get_iommu_domain();
+ domain = msm_get_iommu_domain(domain_idx);
+ if (!domain) {
+ pr_err("unable to get iommu domain(%d)\n", domain_idx);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++)
+ iommu_detach_device(domain, mdp_iommu_ctx[i].ctx);
+ mdss_res->iommu_attached = false;
+
+ return 0;
+}
+
+int mdss_iommu_init(void)
+{
+ struct iommu_domain *domain;
+ int domain_idx, i;
+
+ domain_idx = msm_register_domain(&mdp_iommu_layout);
+ if (IS_ERR_VALUE(domain_idx))
+ return -EINVAL;
+
+ domain = msm_get_iommu_domain(domain_idx);
+ if (!domain) {
+ pr_err("unable to get iommu domain(%d)\n", domain_idx);
+ return -EINVAL;
+ }
+
+ iommu_set_fault_handler(domain, mdss_iommu_fault_handler);
+
+ for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++) {
+ mdp_iommu_ctx[i].ctx = msm_iommu_get_ctx(mdp_iommu_ctx[i].name);
+ if (!mdp_iommu_ctx[i].ctx) {
+ pr_warn("unable to get iommu ctx(%s)\n",
+ mdp_iommu_ctx[i].name);
+ return -EINVAL;
+ }
+ }
+ mdss_res->iommu_domain = domain_idx;
+
+ return 0;
+}
+
static int mdss_hw_init(struct mdss_data_type *mdata)
{
char *base = mdata->vbif_base;
@@ -646,6 +763,10 @@ static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
mdata->iclient = NULL;
}
+ rc = mdss_iommu_init();
+ if (!IS_ERR_VALUE(rc))
+ mdss_iommu_attach();
+
rc = mdss_hw_init(mdata);
return rc;
@@ -748,9 +869,11 @@ void mdss_mdp_footswitch_ctrl(int on)
ret = regulator_enable(mdss_res->fs);
if (ret)
pr_err("Footswitch failed to enable\n");
+ mdss_iommu_attach();
mdss_res->fs_ena = true;
} else if (!on && mdss_res->fs_ena) {
pr_debug("Disable MDP FS\n");
+ mdss_iommu_dettach();
regulator_disable(mdss_res->fs);
mdss_res->fs_ena = false;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 810c14768ad6..6f3a56c08130 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -20,6 +20,8 @@
#include <linux/module.h>
#include <linux/uaccess.h>
+#include <mach/iommu_domains.h>
+
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
@@ -699,7 +701,12 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
return;
}
- data.p[0].addr = fbi->fix.smem_start + offset;
+ if (is_mdss_iommu_attached())
+ data.p[0].addr = mfd->iova;
+ else
+ data.p[0].addr = fbi->fix.smem_start;
+
+ data.p[0].addr += offset;
data.p[0].len = fbi->fix.smem_len - offset;
data.num_planes = 1;
@@ -788,7 +795,7 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
u32 blendcfg;
int off, ret = 0;
- if (!mfd->cursor_buf) {
+ if (!mfd->cursor_buf && (cursor->set & FB_CUR_SETIMAGE)) {
mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
(dma_addr_t *) &mfd->cursor_buf_phys,
GFP_KERNEL);
@@ -796,6 +803,19 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
pr_err("can't allocate cursor buffer\n");
return -ENOMEM;
}
+
+ ret = msm_iommu_map_contig_buffer(mfd->cursor_buf_phys,
+ mdss_get_iommu_domain(), 0,
+ MDSS_MDP_CURSOR_SIZE, SZ_4K,
+ 0, &(mfd->cursor_buf_iova));
+ if (IS_ERR_VALUE(ret)) {
+ dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+ mfd->cursor_buf,
+ (dma_addr_t) mfd->cursor_buf_phys);
+ pr_err("unable to map cursor buffer to iommu(%d)\n",
+ ret);
+ return -ENOMEM;
+ }
}
mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
@@ -817,12 +837,17 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
(img->dy << 16) | img->dx);
if (cursor->set & FB_CUR_SETIMAGE) {
- int calpha_en, transp_en, alpha, size;
+ int calpha_en, transp_en, alpha, size, cursor_addr;
ret = copy_from_user(mfd->cursor_buf, img->data,
img->width * img->height * 4);
if (ret)
return ret;
+ if (is_mdss_iommu_attached())
+ cursor_addr = mfd->cursor_buf_iova;
+ else
+ cursor_addr = mfd->cursor_buf_phys;
+
if (img->bg_color == 0xffffffff)
transp_en = 0;
else
@@ -841,7 +866,7 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
img->width * 4);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
- mfd->cursor_buf_phys);
+ cursor_addr);
wmb();
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index a54e480f96fd..1a4c7cd2dbda 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -17,11 +17,14 @@
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/ion.h>
+#include <linux/iommu.h>
#include <linux/msm_kgsl.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/major.h>
+#include <mach/iommu_domains.h>
+
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_formats.h"
@@ -296,6 +299,11 @@ int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
data->srcp_file = NULL;
} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
pr_debug("ion hdl=%p buf=0x%x\n", data->srcp_ihdl, data->addr);
+
+ if (is_mdss_iommu_attached())
+ ion_unmap_iommu(iclient, data->srcp_ihdl,
+ mdss_get_iommu_domain(), 0);
+
ion_free(iclient, data->srcp_ihdl);
data->srcp_ihdl = NULL;
} else {
@@ -348,7 +356,17 @@ int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data)
data->srcp_ihdl = NULL;
return ret;
}
- ret = ion_phys(iclient, data->srcp_ihdl, start, (size_t *) len);
+
+ if (is_mdss_iommu_attached()) {
+ ret = ion_map_iommu(iclient, data->srcp_ihdl,
+ mdss_get_iommu_domain(),
+ 0, SZ_4K, 0, start, len, 0,
+ ION_IOMMU_UNMAP_DELAYED);
+ } else {
+ ret = ion_phys(iclient, data->srcp_ihdl, start,
+ (size_t *) len);
+ }
+
if (IS_ERR_VALUE(ret)) {
ion_free(iclient, data->srcp_ihdl);
pr_err("failed to map ion handle (%d)\n", ret);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_wb.c b/drivers/video/fbdev/msm/mdss_mdp_wb.c
index f8ed5837668c..c5c632d7729e 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_wb.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_wb.c
@@ -18,6 +18,10 @@
#include <linux/major.h>
#include <linux/module.h>
#include <linux/uaccess.h>
+#include <linux/iommu.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
#include "mdss_mdp.h"
#include "mdss_fb.h"
@@ -68,6 +72,7 @@ struct mdss_mdp_data *mdss_mdp_wb_debug_buffer(struct msm_fb_data_type *mfd)
static void *videomemory;
static ion_phys_addr_t mdss_wb_mem;
static struct mdss_mdp_data mdss_wb_buffer = { .num_planes = 1, };
+ int rc;
if (IS_ERR_OR_NULL(ihdl)) {
struct fb_info *fbi;
@@ -79,6 +84,7 @@ struct mdss_mdp_data *mdss_mdp_wb_debug_buffer(struct msm_fb_data_type *mfd)
img_size = fbi->var.xres * fbi->var.yres *
fbi->var.bits_per_pixel / 8;
+
ihdl = ion_alloc(iclient, img_size, SZ_4K,
ION_HEAP(ION_SF_HEAP_ID));
if (IS_ERR_OR_NULL(ihdl)) {
@@ -89,8 +95,18 @@ struct mdss_mdp_data *mdss_mdp_wb_debug_buffer(struct msm_fb_data_type *mfd)
videomemory = ion_map_kernel(iclient, ihdl, 0);
ion_phys(iclient, ihdl, &mdss_wb_mem, &img_size);
- img->addr = mdss_wb_mem;
- img->len = img_size;
+ if (is_mdss_iommu_attached()) {
+ rc = ion_map_iommu(iclient, ihdl,
+ mdss_get_iommu_domain(),
+ 0, SZ_4K, 0,
+ (unsigned long *) &img->addr,
+ (unsigned long *) &img->len,
+ 0, 0);
+ } else {
+ img->addr = mdss_wb_mem;
+ img->len = img_size;
+ }
+
pr_debug("ihdl=%p virt=%p phys=0x%lx iova=0x%x size=%u\n",
ihdl, videomemory, mdss_wb_mem, img->addr, img_size);
}
@@ -550,3 +566,9 @@ int msm_fb_writeback_terminate(struct fb_info *info)
return mdss_mdp_wb_terminate(mfd);
}
EXPORT_SYMBOL(msm_fb_writeback_terminate);
+
+int msm_fb_get_iommu_domain(void)
+{
+ return mdss_get_iommu_domain();
+}
+EXPORT_SYMBOL(msm_fb_get_iommu_domain);