aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-01-02 18:06:08 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-25 10:18:42 -0400
commit2a0a5472af5caa0d0df334abb9975dc496f045da (patch)
treee6981f7cc0127340febff0021f398b7300345c47
parent9a8c7fffa2293417d0245fb9f618564d7dee04a6 (diff)
[media] omap3isp: Use the ARM DMA IOMMU-aware operations
Attach an ARM DMA I/O virtual address space to the ISP device. This switches to the IOMMU-aware ARM DMA backend, we can thus remove the explicit calls to the OMAP IOMMU map and unmap functions. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Sakari Ailus <sakari.ailus@iki.fi> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/platform/Kconfig4
-rw-r--r--drivers/media/platform/omap3isp/isp.c102
-rw-r--r--drivers/media/platform/omap3isp/isp.h8
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c34
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.h2
5 files changed, 89 insertions, 61 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
93 93
94config VIDEO_OMAP3 94config VIDEO_OMAP3
95 tristate "OMAP 3 Camera support" 95 tristate "OMAP 3 Camera support"
96 depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 96 depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
97 select ARM_DMA_USE_IOMMU
98 select OMAP_IOMMU
97 ---help--- 99 ---help---
98 Driver for an OMAP 3 camera controller. 100 Driver for an OMAP 3 camera controller.
99 101
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 06a0df434249..5a4801b76282 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -69,6 +69,8 @@
69#include <linux/sched.h> 69#include <linux/sched.h>
70#include <linux/vmalloc.h> 70#include <linux/vmalloc.h>
71 71
72#include <asm/dma-iommu.h>
73
72#include <media/v4l2-common.h> 74#include <media/v4l2-common.h>
73#include <media/v4l2-device.h> 75#include <media/v4l2-device.h>
74 76
@@ -1625,7 +1627,7 @@ struct isp_device *omap3isp_get(struct isp_device *isp)
1625 * Decrement the reference count on the ISP. If the last reference is released, 1627 * Decrement the reference count on the ISP. If the last reference is released,
1626 * power-down all submodules, disable clocks and free temporary buffers. 1628 * power-down all submodules, disable clocks and free temporary buffers.
1627 */ 1629 */
1628void omap3isp_put(struct isp_device *isp) 1630static void __omap3isp_put(struct isp_device *isp, bool save_ctx)
1629{ 1631{
1630 if (isp == NULL) 1632 if (isp == NULL)
1631 return; 1633 return;
@@ -1634,7 +1636,7 @@ void omap3isp_put(struct isp_device *isp)
1634 BUG_ON(isp->ref_count == 0); 1636 BUG_ON(isp->ref_count == 0);
1635 if (--isp->ref_count == 0) { 1637 if (--isp->ref_count == 0) {
1636 isp_disable_interrupts(isp); 1638 isp_disable_interrupts(isp);
1637 if (isp->domain) { 1639 if (save_ctx) {
1638 isp_save_ctx(isp); 1640 isp_save_ctx(isp);
1639 isp->has_context = 1; 1641 isp->has_context = 1;
1640 } 1642 }
@@ -1648,6 +1650,11 @@ void omap3isp_put(struct isp_device *isp)
1648 mutex_unlock(&isp->isp_mutex); 1650 mutex_unlock(&isp->isp_mutex);
1649} 1651}
1650 1652
1653void omap3isp_put(struct isp_device *isp)
1654{
1655 __omap3isp_put(isp, true);
1656}
1657
1651/* -------------------------------------------------------------------------- 1658/* --------------------------------------------------------------------------
1652 * Platform device driver 1659 * Platform device driver
1653 */ 1660 */
@@ -2120,6 +2127,61 @@ error_csiphy:
2120 return ret; 2127 return ret;
2121} 2128}
2122 2129
2130static void isp_detach_iommu(struct isp_device *isp)
2131{
2132 arm_iommu_release_mapping(isp->mapping);
2133 isp->mapping = NULL;
2134 iommu_group_remove_device(isp->dev);
2135}
2136
2137static int isp_attach_iommu(struct isp_device *isp)
2138{
2139 struct dma_iommu_mapping *mapping;
2140 struct iommu_group *group;
2141 int ret;
2142
2143 /* Create a device group and add the device to it. */
2144 group = iommu_group_alloc();
2145 if (IS_ERR(group)) {
2146 dev_err(isp->dev, "failed to allocate IOMMU group\n");
2147 return PTR_ERR(group);
2148 }
2149
2150 ret = iommu_group_add_device(group, isp->dev);
2151 iommu_group_put(group);
2152
2153 if (ret < 0) {
2154 dev_err(isp->dev, "failed to add device to IPMMU group\n");
2155 return ret;
2156 }
2157
2158 /*
2159 * Create the ARM mapping, used by the ARM DMA mapping core to allocate
2160 * VAs. This will allocate a corresponding IOMMU domain.
2161 */
2162 mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G);
2163 if (IS_ERR(mapping)) {
2164 dev_err(isp->dev, "failed to create ARM IOMMU mapping\n");
2165 ret = PTR_ERR(mapping);
2166 goto error;
2167 }
2168
2169 isp->mapping = mapping;
2170
2171 /* Attach the ARM VA mapping to the device. */
2172 ret = arm_iommu_attach_device(isp->dev, mapping);
2173 if (ret < 0) {
2174 dev_err(isp->dev, "failed to attach device to VA mapping\n");
2175 goto error;
2176 }
2177
2178 return 0;
2179
2180error:
2181 isp_detach_iommu(isp);
2182 return ret;
2183}
2184
2123/* 2185/*
2124 * isp_remove - Remove ISP platform device 2186 * isp_remove - Remove ISP platform device
2125 * @pdev: Pointer to ISP platform device 2187 * @pdev: Pointer to ISP platform device
@@ -2135,10 +2197,8 @@ static int isp_remove(struct platform_device *pdev)
2135 isp_xclk_cleanup(isp); 2197 isp_xclk_cleanup(isp);
2136 2198
2137 __omap3isp_get(isp, false); 2199 __omap3isp_get(isp, false);
2138 iommu_detach_device(isp->domain, &pdev->dev); 2200 isp_detach_iommu(isp);
2139 iommu_domain_free(isp->domain); 2201 __omap3isp_put(isp, false);
2140 isp->domain = NULL;
2141 omap3isp_put(isp);
2142 2202
2143 return 0; 2203 return 0;
2144} 2204}
@@ -2265,39 +2325,32 @@ static int isp_probe(struct platform_device *pdev)
2265 } 2325 }
2266 } 2326 }
2267 2327
2268 isp->domain = iommu_domain_alloc(pdev->dev.bus); 2328 /* IOMMU */
2269 if (!isp->domain) { 2329 ret = isp_attach_iommu(isp);
2270 dev_err(isp->dev, "can't alloc iommu domain\n"); 2330 if (ret < 0) {
2271 ret = -ENOMEM; 2331 dev_err(&pdev->dev, "unable to attach to IOMMU\n");
2272 goto error_isp; 2332 goto error_isp;
2273 } 2333 }
2274 2334
2275 ret = iommu_attach_device(isp->domain, &pdev->dev);
2276 if (ret) {
2277 dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
2278 ret = -EPROBE_DEFER;
2279 goto free_domain;
2280 }
2281
2282 /* Interrupt */ 2335 /* Interrupt */
2283 isp->irq_num = platform_get_irq(pdev, 0); 2336 isp->irq_num = platform_get_irq(pdev, 0);
2284 if (isp->irq_num <= 0) { 2337 if (isp->irq_num <= 0) {
2285 dev_err(isp->dev, "No IRQ resource\n"); 2338 dev_err(isp->dev, "No IRQ resource\n");
2286 ret = -ENODEV; 2339 ret = -ENODEV;
2287 goto detach_dev; 2340 goto error_iommu;
2288 } 2341 }
2289 2342
2290 if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED, 2343 if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED,
2291 "OMAP3 ISP", isp)) { 2344 "OMAP3 ISP", isp)) {
2292 dev_err(isp->dev, "Unable to request IRQ\n"); 2345 dev_err(isp->dev, "Unable to request IRQ\n");
2293 ret = -EINVAL; 2346 ret = -EINVAL;
2294 goto detach_dev; 2347 goto error_iommu;
2295 } 2348 }
2296 2349
2297 /* Entities */ 2350 /* Entities */
2298 ret = isp_initialize_modules(isp); 2351 ret = isp_initialize_modules(isp);
2299 if (ret < 0) 2352 if (ret < 0)
2300 goto detach_dev; 2353 goto error_iommu;
2301 2354
2302 ret = isp_register_entities(isp); 2355 ret = isp_register_entities(isp);
2303 if (ret < 0) 2356 if (ret < 0)
@@ -2310,14 +2363,11 @@ static int isp_probe(struct platform_device *pdev)
2310 2363
2311error_modules: 2364error_modules:
2312 isp_cleanup_modules(isp); 2365 isp_cleanup_modules(isp);
2313detach_dev: 2366error_iommu:
2314 iommu_detach_device(isp->domain, &pdev->dev); 2367 isp_detach_iommu(isp);
2315free_domain:
2316 iommu_domain_free(isp->domain);
2317 isp->domain = NULL;
2318error_isp: 2368error_isp:
2319 isp_xclk_cleanup(isp); 2369 isp_xclk_cleanup(isp);
2320 omap3isp_put(isp); 2370 __omap3isp_put(isp, false);
2321error: 2371error:
2322 mutex_destroy(&isp->isp_mutex); 2372 mutex_destroy(&isp->isp_mutex);
2323 2373
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 @@
45#include "ispcsi2.h" 45#include "ispcsi2.h"
46#include "ispccp2.h" 46#include "ispccp2.h"
47 47
48#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
49
50#define ISP_TOK_TERM 0xFFFFFFFF /* 48#define ISP_TOK_TERM 0xFFFFFFFF /*
51 * terminating token for ISP 49 * terminating token for ISP
52 * modules reg list 50 * modules reg list
@@ -152,6 +150,7 @@ struct isp_xclk {
152 * regions. 150 * regions.
153 * @mmio_base_phys: Array with physical L4 bus addresses for ISP register 151 * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
154 * regions. 152 * regions.
153 * @mapping: IOMMU mapping
155 * @stat_lock: Spinlock for handling statistics 154 * @stat_lock: Spinlock for handling statistics
156 * @isp_mutex: Mutex for serializing requests to ISP. 155 * @isp_mutex: Mutex for serializing requests to ISP.
157 * @stop_failure: Indicates that an entity failed to stop. 156 * @stop_failure: Indicates that an entity failed to stop.
@@ -171,7 +170,6 @@ struct isp_xclk {
171 * @isp_res: Pointer to current settings for ISP Resizer. 170 * @isp_res: Pointer to current settings for ISP Resizer.
172 * @isp_prev: Pointer to current settings for ISP Preview. 171 * @isp_prev: Pointer to current settings for ISP Preview.
173 * @isp_ccdc: Pointer to current settings for ISP CCDC. 172 * @isp_ccdc: Pointer to current settings for ISP CCDC.
174 * @iommu: Pointer to requested IOMMU instance for ISP.
175 * @platform_cb: ISP driver callback function pointers for platform code 173 * @platform_cb: ISP driver callback function pointers for platform code
176 * 174 *
177 * This structure is used to store the OMAP ISP Information. 175 * This structure is used to store the OMAP ISP Information.
@@ -189,6 +187,8 @@ struct isp_device {
189 void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; 187 void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
190 unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; 188 unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
191 189
190 struct dma_iommu_mapping *mapping;
191
192 /* ISP Obj */ 192 /* ISP Obj */
193 spinlock_t stat_lock; /* common lock for statistic drivers */ 193 spinlock_t stat_lock; /* common lock for statistic drivers */
194 struct mutex isp_mutex; /* For handling ref_count field */ 194 struct mutex isp_mutex; /* For handling ref_count field */
@@ -219,8 +219,6 @@ struct isp_device {
219 219
220 unsigned int sbl_resources; 220 unsigned int sbl_resources;
221 unsigned int subclk_resources; 221 unsigned int subclk_resources;
222
223 struct iommu_domain *domain;
224}; 222};
225 223
226#define v4l2_dev_to_isp_device(dev) \ 224#define v4l2_dev_to_isp_device(dev) \
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
index cee1b5d29cfa..9c90fb081404 100644
--- a/drivers/media/platform/omap3isp/ispqueue.c
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -26,7 +26,6 @@
26#include <asm/cacheflush.h> 26#include <asm/cacheflush.h>
27#include <linux/dma-mapping.h> 27#include <linux/dma-mapping.h>
28#include <linux/mm.h> 28#include <linux/mm.h>
29#include <linux/omap-iommu.h>
30#include <linux/pagemap.h> 29#include <linux/pagemap.h>
31#include <linux/poll.h> 30#include <linux/poll.h>
32#include <linux/scatterlist.h> 31#include <linux/scatterlist.h>
@@ -159,7 +158,7 @@ static int isp_video_buffer_prepare_kernel(struct isp_video_buffer *buf)
159 struct isp_video *video = vfh->video; 158 struct isp_video *video = vfh->video;
160 159
161 return dma_get_sgtable(video->isp->dev, &buf->sgt, buf->vaddr, 160 return dma_get_sgtable(video->isp->dev, &buf->sgt, buf->vaddr,
162 buf->paddr, PAGE_ALIGN(buf->vbuf.length)); 161 buf->dma, PAGE_ALIGN(buf->vbuf.length));
163} 162}
164 163
165/* 164/*
@@ -170,18 +169,10 @@ static int isp_video_buffer_prepare_kernel(struct isp_video_buffer *buf)
170 */ 169 */
171static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) 170static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
172{ 171{
173 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
174 struct isp_video *video = vfh->video;
175 enum dma_data_direction direction; 172 enum dma_data_direction direction;
176 DEFINE_DMA_ATTRS(attrs); 173 DEFINE_DMA_ATTRS(attrs);
177 unsigned int i; 174 unsigned int i;
178 175
179 if (buf->dma) {
180 omap_iommu_vunmap(video->isp->domain, video->isp->dev,
181 buf->dma);
182 buf->dma = 0;
183 }
184
185 if (buf->vbuf.memory == V4L2_MEMORY_USERPTR) { 176 if (buf->vbuf.memory == V4L2_MEMORY_USERPTR) {
186 if (buf->skip_cache) 177 if (buf->skip_cache)
187 dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); 178 dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
@@ -419,11 +410,8 @@ done:
419 */ 410 */
420static int isp_video_buffer_prepare(struct isp_video_buffer *buf) 411static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
421{ 412{
422 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
423 struct isp_video *video = vfh->video;
424 enum dma_data_direction direction; 413 enum dma_data_direction direction;
425 DEFINE_DMA_ATTRS(attrs); 414 DEFINE_DMA_ATTRS(attrs);
426 unsigned long addr;
427 int ret; 415 int ret;
428 416
429 switch (buf->vbuf.memory) { 417 switch (buf->vbuf.memory) {
@@ -458,23 +446,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
458 goto done; 446 goto done;
459 } 447 }
460 448
449 buf->dma = sg_dma_address(buf->sgt.sgl);
461 break; 450 break;
462 451
463 default: 452 default:
464 return -EINVAL; 453 return -EINVAL;
465 } 454 }
466 455
467 addr = omap_iommu_vmap(video->isp->domain, video->isp->dev, 0, 456 if (!IS_ALIGNED(buf->dma, 32)) {
468 &buf->sgt, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8); 457 dev_dbg(buf->queue->dev,
469 if (IS_ERR_VALUE(addr)) {
470 ret = -EIO;
471 goto done;
472 }
473
474 buf->dma = addr;
475
476 if (!IS_ALIGNED(addr, 32)) {
477 dev_dbg(video->isp->dev,
478 "Buffer address must be aligned to 32 bytes boundary.\n"); 458 "Buffer address must be aligned to 32 bytes boundary.\n");
479 ret = -EINVAL; 459 ret = -EINVAL;
480 goto done; 460 goto done;
@@ -576,7 +556,7 @@ static int isp_video_queue_free(struct isp_video_queue *queue)
576 if (buf->vaddr) { 556 if (buf->vaddr) {
577 dma_free_coherent(queue->dev, 557 dma_free_coherent(queue->dev,
578 PAGE_ALIGN(buf->vbuf.length), 558 PAGE_ALIGN(buf->vbuf.length),
579 buf->vaddr, buf->paddr); 559 buf->vaddr, buf->dma);
580 buf->vaddr = NULL; 560 buf->vaddr = NULL;
581 } 561 }
582 562
@@ -632,7 +612,7 @@ static int isp_video_queue_alloc(struct isp_video_queue *queue,
632 612
633 buf->vbuf.m.offset = i * PAGE_ALIGN(size); 613 buf->vbuf.m.offset = i * PAGE_ALIGN(size);
634 buf->vaddr = mem; 614 buf->vaddr = mem;
635 buf->paddr = dma; 615 buf->dma = dma;
636 } 616 }
637 617
638 buf->vbuf.index = i; 618 buf->vbuf.index = i;
@@ -1079,7 +1059,7 @@ int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
1079 */ 1059 */
1080 vma->vm_pgoff = 0; 1060 vma->vm_pgoff = 0;
1081 1061
1082 ret = dma_mmap_coherent(queue->dev, vma, buf->vaddr, buf->paddr, size); 1062 ret = dma_mmap_coherent(queue->dev, vma, buf->vaddr, buf->dma, size);
1083 if (ret < 0) 1063 if (ret < 0)
1084 goto done; 1064 goto done;
1085 1065
diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h
index d580f581c209..ae4acb9ab5f9 100644
--- a/drivers/media/platform/omap3isp/ispqueue.h
+++ b/drivers/media/platform/omap3isp/ispqueue.h
@@ -68,7 +68,6 @@ enum isp_video_buffer_state {
68 * @prepared: Whether the buffer has been prepared 68 * @prepared: Whether the buffer has been prepared
69 * @skip_cache: Whether to skip cache management operations for this buffer 69 * @skip_cache: Whether to skip cache management operations for this buffer
70 * @vaddr: Memory virtual address (for kernel buffers) 70 * @vaddr: Memory virtual address (for kernel buffers)
71 * @paddr: Memory physicall address (for kernel buffers)
72 * @vm_flags: Buffer VMA flags (for userspace buffers) 71 * @vm_flags: Buffer VMA flags (for userspace buffers)
73 * @npages: Number of pages (for userspace buffers) 72 * @npages: Number of pages (for userspace buffers)
74 * @pages: Pages table (for userspace non-VM_PFNMAP buffers) 73 * @pages: Pages table (for userspace non-VM_PFNMAP buffers)
@@ -87,7 +86,6 @@ struct isp_video_buffer {
87 86
88 /* For kernel buffers. */ 87 /* For kernel buffers. */
89 void *vaddr; 88 void *vaddr;
90 dma_addr_t paddr;
91 89
92 /* For userspace buffers. */ 90 /* For userspace buffers. */
93 vm_flags_t vm_flags; 91 vm_flags_t vm_flags;