diff options
| author | Adrian Salido-Moreno <adrianm@codeaurora.org> | 2012-08-03 10:23:20 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:12:18 -0700 |
| commit | 16ca2e1fd174c99ea448dde84e52a00f1b644849 (patch) | |
| tree | 87e851296e9fc9123746613c098c88caaf526538 /drivers/video/fbdev | |
| parent | b9cb115cdf99786b5553a70e198fc5c00183cca9 (diff) | |
msm: mdss: display: Enable IOMMU for MDSS driver
Implement all calls to iommu driver from MDSS driver to map all buffers
to virtual address space instead of using physical addresses.
kernel 3.14 upgrade conflicts:
include/linux/msm_mdp.h
Change-Id: Ia194bf53dd881e36c702bbe4c024b652ed34df13
Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -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); |
