summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/s5p-mfc/s5p_mfc.c
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2017-02-13 08:57:11 -0200
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-04-05 16:01:24 -0300
commit25e73b425c34e32d220fc2b06ba4bf9354850400 (patch)
treecfddce54831b29563d356a9f41f16972c9ed1cf4 /drivers/media/platform/s5p-mfc/s5p_mfc.c
parent9ce4780380207fa071430da92e9d93f769002231 (diff)
downloadlinux-25e73b425c34e32d220fc2b06ba4bf9354850400.tar.bz2
[media] s5p-mfc: Add support for probe-time preallocated block based allocator
Current MFC driver depends on the fact that when IOMMU is available, the DMA-mapping framework and its IOMMU glue will use first-fit allocator. This was true for ARM architecture, but its not for ARM64 arch. However, in case of MFC v6+ hardware and latest firmware, it turned out that there is no strict requirement for ALL buffers to be allocated on higher addresses than the firmware base. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Such relaxed requirements for the memory buffers can be easily fulfilled by allocating firmware, device and per-context buffers from the probe-time preallocated larger buffer. This patch adds support for it. This way the driver finally works fine on ARM64 architecture. The size of the preallocated buffer is 8 MiB, what is enough for three instances H264 decoders or encoders (other codecs have smaller memory requirements). If one needs more for particular use case, one can use "mem" module parameter to force larger (or smaller) buffer (for example by adding "s5p_mfc.mem=16M" to kernel command line). [mchehab@s-opensource.com: fix two checkpatch warnings: don't initialize static to NULL; don't use S_foo permisions] Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com> Tested-by: Javier Martinez Canillas <javier@osg.samsung.com> Acked-by: Andrzej Hajda <a.hajda@samsung.com> Tested-by: Smitha T Murthy <smitha.t@samsung.com> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/s5p-mfc/s5p_mfc.c')
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index ff3bb8af2423..e3d760516c4c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -43,6 +43,10 @@ int mfc_debug_level;
module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
+static char *mfc_mem_size;
+module_param_named(mem, mfc_mem_size, charp, 0644);
+MODULE_PARM_DESC(mem, "Preallocated memory size for the firmware and context buffers");
+
/* Helper functions for interrupt processing */
/* Remove from hw execution round robin */
@@ -1173,6 +1177,8 @@ static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev)
static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev)
{
struct device *dev = &mfc_dev->plat_dev->dev;
+ unsigned long mem_size = SZ_8M;
+ unsigned int bitmap_size;
/*
* When IOMMU is available, we cannot use the default configuration,
* because of MFC firmware requirements: address space limited to
@@ -1186,17 +1192,39 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev)
if (ret)
return ret;
- mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev;
- ret = s5p_mfc_alloc_firmware(mfc_dev);
- if (ret) {
+ if (mfc_mem_size)
+ mem_size = memparse(mfc_mem_size, NULL);
+
+ bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long);
+
+ mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mfc_dev->mem_bitmap) {
exynos_unconfigure_iommu(dev);
- return ret;
+ return -ENOMEM;
}
- mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma;
- mfc_dev->dma_base[BANK2_CTX] = mfc_dev->fw_buf.dma;
+ mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size,
+ &mfc_dev->mem_base, GFP_KERNEL);
+ if (!mfc_dev->mem_virt) {
+ kfree(mfc_dev->mem_bitmap);
+ dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n",
+ (mem_size / SZ_1M));
+ exynos_unconfigure_iommu(dev);
+ return -ENOMEM;
+ }
+ mfc_dev->mem_size = mem_size;
+ mfc_dev->dma_base[BANK1_CTX] = mfc_dev->mem_base;
+ mfc_dev->dma_base[BANK2_CTX] = mfc_dev->mem_base;
+
+ /* Firmware allocation cannot fail in this case */
+ s5p_mfc_alloc_firmware(mfc_dev);
+
+ mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev;
vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
+ dev_info(dev, "preallocated %ld MiB buffer for the firmware and context buffers\n",
+ (mem_size / SZ_1M));
+
return 0;
}
@@ -1205,6 +1233,9 @@ static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev)
struct device *dev = &mfc_dev->plat_dev->dev;
exynos_unconfigure_iommu(dev);
+ dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt,
+ mfc_dev->mem_base);
+ kfree(mfc_dev->mem_bitmap);
vb2_dma_contig_clear_max_seg_size(dev);
}