forked from Minki/linux
25e73b425c
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>
100 lines
2.6 KiB
C
100 lines
2.6 KiB
C
/*
|
|
* drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
|
|
*
|
|
* Samsung MFC (Multi Function Codec - FIMV) driver
|
|
* This file contains hw related functions.
|
|
*
|
|
* Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com/
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "s5p_mfc_debug.h"
|
|
#include "s5p_mfc_opr.h"
|
|
#include "s5p_mfc_opr_v5.h"
|
|
#include "s5p_mfc_opr_v6.h"
|
|
|
|
static struct s5p_mfc_hw_ops *s5p_mfc_ops;
|
|
|
|
void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev)
|
|
{
|
|
if (IS_MFCV6_PLUS(dev)) {
|
|
s5p_mfc_ops = s5p_mfc_init_hw_ops_v6();
|
|
dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6;
|
|
} else {
|
|
s5p_mfc_ops = s5p_mfc_init_hw_ops_v5();
|
|
dev->warn_start = S5P_FIMV_ERR_WARNINGS_START;
|
|
}
|
|
dev->mfc_ops = s5p_mfc_ops;
|
|
}
|
|
|
|
void s5p_mfc_init_regs(struct s5p_mfc_dev *dev)
|
|
{
|
|
if (IS_MFCV6_PLUS(dev))
|
|
dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev);
|
|
}
|
|
|
|
int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx,
|
|
struct s5p_mfc_priv_buf *b)
|
|
{
|
|
unsigned int bits = dev->mem_size >> PAGE_SHIFT;
|
|
unsigned int count = b->size >> PAGE_SHIFT;
|
|
unsigned int align = (SZ_64K >> PAGE_SHIFT) - 1;
|
|
unsigned int start, offset;
|
|
|
|
mfc_debug(3, "Allocating priv: %zu\n", b->size);
|
|
|
|
if (dev->mem_virt) {
|
|
start = bitmap_find_next_zero_area(dev->mem_bitmap, bits, 0, count, align);
|
|
if (start > bits)
|
|
goto no_mem;
|
|
|
|
bitmap_set(dev->mem_bitmap, start, count);
|
|
offset = start << PAGE_SHIFT;
|
|
b->virt = dev->mem_virt + offset;
|
|
b->dma = dev->mem_base + offset;
|
|
} else {
|
|
struct device *mem_dev = dev->mem_dev[mem_ctx];
|
|
dma_addr_t base = dev->dma_base[mem_ctx];
|
|
|
|
b->ctx = mem_ctx;
|
|
b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL);
|
|
if (!b->virt)
|
|
goto no_mem;
|
|
if (b->dma < base) {
|
|
mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n",
|
|
&b->dma, &base);
|
|
dma_free_coherent(mem_dev, b->size, b->virt, b->dma);
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma);
|
|
return 0;
|
|
no_mem:
|
|
mfc_err("Allocating private buffer of size %zu failed\n", b->size);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev,
|
|
struct s5p_mfc_priv_buf *b)
|
|
{
|
|
if (dev->mem_virt) {
|
|
unsigned int start = (b->dma - dev->mem_base) >> PAGE_SHIFT;
|
|
unsigned int count = b->size >> PAGE_SHIFT;
|
|
|
|
bitmap_clear(dev->mem_bitmap, start, count);
|
|
} else {
|
|
struct device *mem_dev = dev->mem_dev[b->ctx];
|
|
|
|
dma_free_coherent(mem_dev, b->size, b->virt, b->dma);
|
|
}
|
|
b->virt = NULL;
|
|
b->dma = 0;
|
|
b->size = 0;
|
|
}
|
|
|