diff options
| -rw-r--r-- | drivers/video/fbdev/msm/mdss.h | 22 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_host.c | 34 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_panel.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 19 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.c | 123 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 33 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_util.c | 20 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_wb.c | 26 |
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); |
