diff options
21 files changed, 458 insertions, 1745 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 20f1655e6d75..8108c698b548 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -93,7 +93,9 @@ config VIDEO_M32R_AR_M64278 config VIDEO_OMAP3 tristate "OMAP 3 Camera support" - depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + select ARM_DMA_USE_IOMMU + select OMAP_IOMMU ---help--- Driver for an OMAP 3 camera controller. diff --git a/drivers/media/platform/omap3isp/Makefile b/drivers/media/platform/omap3isp/Makefile index e8847e79e31a..254975a9174e 100644 --- a/drivers/media/platform/omap3isp/Makefile +++ b/drivers/media/platform/omap3isp/Makefile @@ -3,7 +3,7 @@ ccflags-$(CONFIG_VIDEO_OMAP3_DEBUG) += -DDEBUG omap3-isp-objs += \ - isp.o ispqueue.o ispvideo.o \ + isp.o ispvideo.o \ ispcsiphy.o ispccp2.o ispcsi2.o \ ispccdc.o isppreview.o ispresizer.o \ ispstat.o isph3a_aewb.o isph3a_af.o isphist.o diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 06a0df434249..2c7aa6720569 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -69,6 +69,8 @@ #include <linux/sched.h> #include <linux/vmalloc.h> +#include <asm/dma-iommu.h> + #include <media/v4l2-common.h> #include <media/v4l2-device.h> @@ -1397,14 +1399,14 @@ int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, if (isp_pipeline_is_last(me)) { struct isp_video *video = pipe->output; unsigned long flags; - spin_lock_irqsave(&video->queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); atomic_set(stopping, 0); smp_mb(); return 0; } - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); if (!wait_event_timeout(*wait, !atomic_read(stopping), msecs_to_jiffies(1000))) { atomic_set(stopping, 0); @@ -1625,7 +1627,7 @@ struct isp_device *omap3isp_get(struct isp_device *isp) * Decrement the reference count on the ISP. If the last reference is released, * power-down all submodules, disable clocks and free temporary buffers. */ -void omap3isp_put(struct isp_device *isp) +static void __omap3isp_put(struct isp_device *isp, bool save_ctx) { if (isp == NULL) return; @@ -1634,7 +1636,7 @@ void omap3isp_put(struct isp_device *isp) BUG_ON(isp->ref_count == 0); if (--isp->ref_count == 0) { isp_disable_interrupts(isp); - if (isp->domain) { + if (save_ctx) { isp_save_ctx(isp); isp->has_context = 1; } @@ -1648,6 +1650,11 @@ void omap3isp_put(struct isp_device *isp) mutex_unlock(&isp->isp_mutex); } +void omap3isp_put(struct isp_device *isp) +{ + __omap3isp_put(isp, true); +} + /* -------------------------------------------------------------------------- * Platform device driver */ @@ -2120,6 +2127,61 @@ error_csiphy: return ret; } +static void isp_detach_iommu(struct isp_device *isp) +{ + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; + iommu_group_remove_device(isp->dev); +} + +static int isp_attach_iommu(struct isp_device *isp) +{ + struct dma_iommu_mapping *mapping; + struct iommu_group *group; + int ret; + + /* Create a device group and add the device to it. */ + group = iommu_group_alloc(); + if (IS_ERR(group)) { + dev_err(isp->dev, "failed to allocate IOMMU group\n"); + return PTR_ERR(group); + } + + ret = iommu_group_add_device(group, isp->dev); + iommu_group_put(group); + + if (ret < 0) { + dev_err(isp->dev, "failed to add device to IPMMU group\n"); + return ret; + } + + /* + * Create the ARM mapping, used by the ARM DMA mapping core to allocate + * VAs. This will allocate a corresponding IOMMU domain. + */ + mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); + if (IS_ERR(mapping)) { + dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); + ret = PTR_ERR(mapping); + goto error; + } + + isp->mapping = mapping; + + /* Attach the ARM VA mapping to the device. */ + ret = arm_iommu_attach_device(isp->dev, mapping); + if (ret < 0) { + dev_err(isp->dev, "failed to attach device to VA mapping\n"); + goto error; + } + + return 0; + +error: + isp_detach_iommu(isp); + return ret; +} + /* * isp_remove - Remove ISP platform device * @pdev: Pointer to ISP platform device @@ -2135,10 +2197,8 @@ static int isp_remove(struct platform_device *pdev) isp_xclk_cleanup(isp); __omap3isp_get(isp, false); - iommu_detach_device(isp->domain, &pdev->dev); - iommu_domain_free(isp->domain); - isp->domain = NULL; - omap3isp_put(isp); + isp_detach_iommu(isp); + __omap3isp_put(isp, false); return 0; } @@ -2265,39 +2325,32 @@ static int isp_probe(struct platform_device *pdev) } } - isp->domain = iommu_domain_alloc(pdev->dev.bus); - if (!isp->domain) { - dev_err(isp->dev, "can't alloc iommu domain\n"); - ret = -ENOMEM; + /* IOMMU */ + ret = isp_attach_iommu(isp); + if (ret < 0) { + dev_err(&pdev->dev, "unable to attach to IOMMU\n"); goto error_isp; } - ret = iommu_attach_device(isp->domain, &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret); - ret = -EPROBE_DEFER; - goto free_domain; - } - /* Interrupt */ isp->irq_num = platform_get_irq(pdev, 0); if (isp->irq_num <= 0) { dev_err(isp->dev, "No IRQ resource\n"); ret = -ENODEV; - goto detach_dev; + goto error_iommu; } if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) { dev_err(isp->dev, "Unable to request IRQ\n"); ret = -EINVAL; - goto detach_dev; + goto error_iommu; } /* Entities */ ret = isp_initialize_modules(isp); if (ret < 0) - goto detach_dev; + goto error_iommu; ret = isp_register_entities(isp); if (ret < 0) @@ -2310,14 +2363,11 @@ static int isp_probe(struct platform_device *pdev) error_modules: isp_cleanup_modules(isp); -detach_dev: - iommu_detach_device(isp->domain, &pdev->dev); -free_domain: - iommu_domain_free(isp->domain); - isp->domain = NULL; +error_iommu: + isp_detach_iommu(isp); error_isp: isp_xclk_cleanup(isp); - omap3isp_put(isp); + __omap3isp_put(isp, false); error: mutex_destroy(&isp->isp_mutex); diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 6d5e69711907..2c314eea1252 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -45,8 +45,6 @@ #include "ispcsi2.h" #include "ispccp2.h" -#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) - #define ISP_TOK_TERM 0xFFFFFFFF /* * terminating token for ISP * modules reg list @@ -152,6 +150,7 @@ struct isp_xclk { * regions. * @mmio_base_phys: Array with physical L4 bus addresses for ISP register * regions. + * @mapping: IOMMU mapping * @stat_lock: Spinlock for handling statistics * @isp_mutex: Mutex for serializing requests to ISP. * @stop_failure: Indicates that an entity failed to stop. @@ -171,7 +170,6 @@ struct isp_xclk { * @isp_res: Pointer to current settings for ISP Resizer. * @isp_prev: Pointer to current settings for ISP Preview. * @isp_ccdc: Pointer to current settings for ISP CCDC. - * @iommu: Pointer to requested IOMMU instance for ISP. * @platform_cb: ISP driver callback function pointers for platform code * * This structure is used to store the OMAP ISP Information. @@ -189,6 +187,8 @@ struct isp_device { void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; + struct dma_iommu_mapping *mapping; + /* ISP Obj */ spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ @@ -219,8 +219,6 @@ struct isp_device { unsigned int sbl_resources; unsigned int subclk_resources; - - struct iommu_domain *domain; }; #define v4l2_dev_to_isp_device(dev) \ diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 4d920c800ff5..9f727d20f06d 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -30,7 +30,6 @@ #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/mm.h> -#include <linux/omap-iommu.h> #include <linux/sched.h> #include <linux/slab.h> #include <media/v4l2-event.h> @@ -206,7 +205,8 @@ static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc, * ccdc_lsc_program_table - Program Lens Shading Compensation table address. * @ccdc: Pointer to ISP CCDC device. */ -static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr) +static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, + dma_addr_t addr) { isp_reg_writel(to_isp_device(ccdc), addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE); @@ -333,7 +333,7 @@ static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc, return -EBUSY; ccdc_lsc_setup_regs(ccdc, &req->config); - ccdc_lsc_program_table(ccdc, req->table); + ccdc_lsc_program_table(ccdc, req->table.dma); return 0; } @@ -368,11 +368,12 @@ static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc, if (req == NULL) return; - if (req->iovm) - dma_unmap_sg(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); - if (req->table) - omap_iommu_vfree(isp->domain, isp->dev, req->table); + if (req->table.addr) { + sg_free_table(&req->table.sgt); + dma_free_coherent(isp->dev, req->config.size, req->table.addr, + req->table.dma); + } + kfree(req); } @@ -416,7 +417,6 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, struct isp_device *isp = to_isp_device(ccdc); struct ispccdc_lsc_config_req *req; unsigned long flags; - void *table; u16 update; int ret; @@ -444,38 +444,31 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, req->enable = 1; - req->table = omap_iommu_vmalloc(isp->domain, isp->dev, 0, - req->config.size, IOMMU_FLAG); - if (IS_ERR_VALUE(req->table)) { - req->table = 0; - ret = -ENOMEM; - goto done; - } - - req->iovm = omap_find_iovm_area(isp->dev, req->table); - if (req->iovm == NULL) { + req->table.addr = dma_alloc_coherent(isp->dev, req->config.size, + &req->table.dma, + GFP_KERNEL); + if (req->table.addr == NULL) { ret = -ENOMEM; goto done; } - if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE)) { - ret = -ENOMEM; - req->iovm = NULL; + ret = dma_get_sgtable(isp->dev, &req->table.sgt, + req->table.addr, req->table.dma, + req->config.size); + if (ret < 0) goto done; - } - dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); + dma_sync_sg_for_cpu(isp->dev, req->table.sgt.sgl, + req->table.sgt.nents, DMA_TO_DEVICE); - table = omap_da_to_va(isp->dev, req->table); - if (copy_from_user(table, config->lsc, req->config.size)) { + if (copy_from_user(req->table.addr, config->lsc, + req->config.size)) { ret = -EFAULT; goto done; } - dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); + dma_sync_sg_for_device(isp->dev, req->table.sgt.sgl, + req->table.sgt.nents, DMA_TO_DEVICE); } spin_lock_irqsave(&ccdc->lsc.req_lock, flags); @@ -584,7 +577,7 @@ static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc) if (!ccdc->fpc_en) return; - isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC, + isp_reg_writel(isp, ccdc->fpc.dma, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR); /* The FPNUM field must be set before enabling FPC. */ isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT), @@ -724,8 +717,9 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, ccdc->shadow_update = 0; if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) { - u32 table_old = 0; - u32 table_new; + struct omap3isp_ccdc_fpc fpc; + struct ispccdc_fpc fpc_old = { .addr = NULL, }; + struct ispccdc_fpc fpc_new; u32 size; if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED) @@ -734,35 +728,39 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag); if (ccdc->fpc_en) { - if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc, - sizeof(ccdc->fpc))) + if (copy_from_user(&fpc, ccdc_struct->fpc, sizeof(fpc))) return -EFAULT; + size = fpc.fpnum * 4; + /* - * table_new must be 64-bytes aligned, but it's - * already done by omap_iommu_vmalloc(). + * The table address must be 64-bytes aligned, which is + * guaranteed by dma_alloc_coherent(). */ - size = ccdc->fpc.fpnum * 4; - table_new = omap_iommu_vmalloc(isp->domain, isp->dev, - 0, size, IOMMU_FLAG); - if (IS_ERR_VALUE(table_new)) + fpc_new.fpnum = fpc.fpnum; + fpc_new.addr = dma_alloc_coherent(isp->dev, size, + &fpc_new.dma, + GFP_KERNEL); + if (fpc_new.addr == NULL) return -ENOMEM; - if (copy_from_user(omap_da_to_va(isp->dev, table_new), - (__force void __user *) - ccdc->fpc.fpcaddr, size)) { - omap_iommu_vfree(isp->domain, isp->dev, - table_new); + if (copy_from_user(fpc_new.addr, + (__force void __user *)fpc.fpcaddr, + size)) { + dma_free_coherent(isp->dev, size, fpc_new.addr, + fpc_new.dma); return -EFAULT; } - table_old = ccdc->fpc.fpcaddr; - ccdc->fpc.fpcaddr = table_new; + fpc_old = ccdc->fpc; + ccdc->fpc = fpc_new; } ccdc_configure_fpc(ccdc); - if (table_old != 0) - omap_iommu_vfree(isp->domain, isp->dev, table_old); + + if (fpc_old.addr != NULL) + dma_free_coherent(isp->dev, fpc_old.fpnum * 4, + fpc_old.addr, fpc_old.dma); } return ccdc_lsc_config(ccdc, ccdc_struct); @@ -1523,7 +1521,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) { - ccdc_set_outaddr(ccdc, buffer->isp_addr); + ccdc_set_outaddr(ccdc, buffer->dma); restart = 1; } @@ -1662,7 +1660,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) if (!(ccdc->output & CCDC_OUTPUT_MEMORY)) return -ENODEV; - ccdc_set_outaddr(ccdc, buffer->isp_addr); + ccdc_set_outaddr(ccdc, buffer->dma); /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when @@ -2580,8 +2578,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) cancel_work_sync(&ccdc->lsc.table_work); ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); - if (ccdc->fpc.fpcaddr != 0) - omap_iommu_vfree(isp->domain, isp->dev, ccdc->fpc.fpcaddr); + if (ccdc->fpc.addr != NULL) + dma_free_coherent(isp->dev, ccdc->fpc.fpnum * 4, ccdc->fpc.addr, + ccdc->fpc.dma); mutex_destroy(&ccdc->ioctl_lock); } diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index 9d24e4107864..f65061602c71 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -46,6 +46,12 @@ enum ccdc_input_entity { #define OMAP3ISP_CCDC_NEVENTS 16 +struct ispccdc_fpc { + void *addr; + dma_addr_t dma; + unsigned int fpnum; +}; + enum ispccdc_lsc_state { LSC_STATE_STOPPED = 0, LSC_STATE_STOPPING = 1, @@ -57,8 +63,12 @@ struct ispccdc_lsc_config_req { struct list_head list; struct omap3isp_ccdc_lsc_config config; unsigned char enable; - u32 table; - struct iovm_struct *iovm; + + struct { + void *addr; + dma_addr_t dma; + struct sg_table sgt; + } table; }; /* @@ -136,7 +146,7 @@ struct isp_ccdc_device { fpc_en:1; struct omap3isp_ccdc_blcomp blcomp; struct omap3isp_ccdc_bclamp clamp; - struct omap3isp_ccdc_fpc fpc; + struct ispccdc_fpc fpc; struct ispccdc_lsc lsc; unsigned int update; unsigned int shadow_update; diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index b30b67d22a58..f3801db9095c 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -549,7 +549,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) buffer = omap3isp_video_buffer_next(&ccp2->video_in); if (buffer != NULL) - ccp2_set_inaddr(ccp2, buffer->isp_addr); + ccp2_set_inaddr(ccp2, buffer->dma); pipe->state |= ISP_PIPELINE_IDLE_INPUT; @@ -940,7 +940,7 @@ static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer) { struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2; - ccp2_set_inaddr(ccp2, buffer->isp_addr); + ccp2_set_inaddr(ccp2, buffer->dma); return 0; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 620560828a48..5a2e47e58b84 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -695,7 +695,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2) if (buffer == NULL) return; - csi2_set_outaddr(csi2, buffer->isp_addr); + csi2_set_outaddr(csi2, buffer->dma); csi2_ctx_enable(isp, csi2, 0, 1); } @@ -812,7 +812,7 @@ static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer) struct isp_device *isp = video->isp; struct isp_csi2_device *csi2 = &isp->isp_csi2a; - csi2_set_outaddr(csi2, buffer->isp_addr); + csi2_set_outaddr(csi2, buffer->dma); /* * If streaming was enabled before there was a buffer queued diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index 75fd82b152ba..d6811ce263eb 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -47,7 +47,7 @@ static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv) if (aewb->state == ISPSTAT_DISABLED) return; - isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr, + isp_reg_writel(aewb->isp, aewb->active_buf->dma_addr, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST); if (!aewb->update) diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index a0bf5af32438..6fc960cd30f5 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -51,7 +51,7 @@ static void h3a_af_setup_regs(struct ispstat *af, void *priv) if (af->state == ISPSTAT_DISABLED) return; - isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A, + isp_reg_writel(af->isp, af->active_buf->dma_addr, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST); if (!af->update) diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 395b2b068c75..720809b07e75 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -1499,14 +1499,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev) if (prev->input == PREVIEW_INPUT_MEMORY) { buffer = omap3isp_video_buffer_next(&prev->video_in); if (buffer != NULL) - preview_set_inaddr(prev, buffer->isp_addr); + preview_set_inaddr(prev, buffer->dma); pipe->state |= ISP_PIPELINE_IDLE_INPUT; } if (prev->output & PREVIEW_OUTPUT_MEMORY) { buffer = omap3isp_video_buffer_next(&prev->video_out); if (buffer != NULL) { - preview_set_outaddr(prev, buffer->isp_addr); + preview_set_outaddr(prev, buffer->dma); restart = 1; } pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; @@ -1577,10 +1577,10 @@ static int preview_video_queue(struct isp_video *video, struct isp_prev_device *prev = &video->isp->isp_prev; if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - preview_set_inaddr(prev, buffer->isp_addr); + preview_set_inaddr(prev, buffer->dma); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - preview_set_outaddr(prev, buffer->isp_addr); + preview_set_outaddr(prev, buffer->dma); return 0; } diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c deleted file mode 100644 index a5e65858e799..000000000000 --- a/drivers/media/platform/omap3isp/ispqueue.c +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * ispqueue.c - * - * TI OMAP3 ISP - Video buffers queue handling - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> - * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include <asm/cacheflush.h> -#include <linux/dma-mapping.h> -#include <linux/mm.h> -#include <linux/pagemap.h> -#include <linux/poll.h> -#include <linux/scatterlist.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include "ispqueue.h" - -/* ----------------------------------------------------------------------------- - * Video buffers management - */ - -/* - * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP - * - * The typical operation required here is Cache Invalidation across - * the (user space) buffer address range. And this _must_ be done - * at QBUF stage (and *only* at QBUF). - * - * We try to use optimal cache invalidation function: - * - dmac_map_area: - * - used when the number of pages are _low_. - * - it becomes quite slow as the number of pages increase. - * - for 648x492 viewfinder (150 pages) it takes 1.3 ms. - * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms. - * - * - flush_cache_all: - * - used when the number of pages are _high_. - * - time taken in the range of 500-900 us. - * - has a higher penalty but, as whole dcache + icache is invalidated - */ -/* - * FIXME: dmac_inv_range crashes randomly on the user space buffer - * address. Fall back to flush_cache_all for now. - */ -#define ISP_CACHE_FLUSH_PAGES_MAX 0 - -static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf) -{ - if (buf->skip_cache) - return; - - if (buf->vbuf.m.userptr == 0 || buf->npages == 0 || - buf->npages > ISP_CACHE_FLUSH_PAGES_MAX) - flush_cache_all(); - else { - dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length, - DMA_FROM_DEVICE); - outer_inv_range(buf->vbuf.m.userptr, - buf->vbuf.m.userptr + buf->vbuf.length); - } -} - -/* - * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped - * - * Lock the VMAs underlying the given buffer into memory. This avoids the - * userspace buffer mapping from being swapped out, making VIPT cache handling - * easier. - * - * Note that the pages will not be freed as the buffers have been locked to - * memory using by a call to get_user_pages(), but the userspace mapping could - * still disappear if the VMAs are not locked. This is caused by the memory - * management code trying to be as lock-less as possible, which results in the - * userspace mapping manager not finding out that the pages are locked under - * some conditions. - */ -static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock) -{ - struct vm_area_struct *vma; - unsigned long start; - unsigned long end; - int ret = 0; - - if (buf->vbuf.memory == V4L2_MEMORY_MMAP) - return 0; - - /* We can be called from workqueue context if the current task dies to - * unlock the VMAs. In that case there's no current memory management - * context so unlocking can't be performed, but the VMAs have been or - * are getting destroyed anyway so it doesn't really matter. - */ - if (!current || !current->mm) - return lock ? -EINVAL : 0; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - down_write(¤t->mm->mmap_sem); - spin_lock(¤t->mm->page_table_lock); - - do { - vma = find_vma(current->mm, start); - if (vma == NULL) { - ret = -EFAULT; - goto out; - } - - if (lock) - vma->vm_flags |= VM_LOCKED; - else - vma->vm_flags &= ~VM_LOCKED; - - start = vma->vm_end + 1; - } while (vma->vm_end < end); - - if (lock) - buf->vm_flags |= VM_LOCKED; - else - buf->vm_flags &= ~VM_LOCKED; - -out: - spin_unlock(¤t->mm->page_table_lock); - up_write(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer - * - * Iterate over the vmalloc'ed area and create a scatter list entry for every - * page. - */ -static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int npages; - unsigned int i; - void *addr; - - addr = buf->vaddr; - npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT; - - sglist = vmalloc(npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, npages); - - for (i = 0; i < npages; ++i, addr += PAGE_SIZE) { - struct page *page = vmalloc_to_page(addr); - - if (page == NULL || PageHighMem(page)) { - vfree(sglist); - return -EINVAL; - } - - sg_set_page(&sglist[i], page, PAGE_SIZE, 0); - } - - buf->sglen = npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer - * - * Walk the buffer pages list and create a 1:1 mapping to a scatter list. - */ -static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int offset = buf->offset; - unsigned int i; - - sglist = vmalloc(buf->npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, buf->npages); - - for (i = 0; i < buf->npages; ++i) { - if (PageHighMem(buf->pages[i])) { - vfree(sglist); - return -EINVAL; - } - - sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset, - offset); - offset = 0; - } - - buf->sglen = buf->npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer - * - * Create a scatter list of physically contiguous pages starting at the buffer - * memory physical address. - */ -static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int offset = buf->offset; |