731 lines
22 KiB
Diff
731 lines
22 KiB
Diff
From 20d79137ecaa6c7dad007d9ea1d7be5550db4839 Mon Sep 17 00:00:00 2001
|
|
From: Vaibhav Hiremath <hvaibhav@ti.com>
|
|
Date: Fri, 13 Feb 2009 15:40:25 +0530
|
|
Subject: [PATCH 2/2] Resizer bug fixes on top of 1.0.2 release
|
|
|
|
This commit contains resizer bug fixes on top of
|
|
PSP1.0.2 release -
|
|
- 4096 aligned address constraint
|
|
- workaround for extra page allocation for page aligned
|
|
size buffers
|
|
|
|
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
|
|
---
|
|
drivers/media/video/isp/omap_resizer.c | 417 ++++++++++++++++++++++++--------
|
|
include/linux/omap_resizer.h | 3 +-
|
|
2 files changed, 321 insertions(+), 99 deletions(-)
|
|
|
|
diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c
|
|
index 54bc425..8059c70 100644
|
|
--- a/drivers/media/video/isp/omap_resizer.c
|
|
+++ b/drivers/media/video/isp/omap_resizer.c
|
|
@@ -28,6 +28,7 @@
|
|
#include <linux/platform_device.h>
|
|
#include <linux/io.h>
|
|
#include <linux/uaccess.h>
|
|
+#include <linux/pci.h>
|
|
#include <media/v4l2-dev.h>
|
|
#include <asm/cacheflush.h>
|
|
|
|
@@ -76,6 +77,10 @@
|
|
#define MAX_COEF_COUNTER 16
|
|
#define COEFF_ADDRESS_OFFSET 0x04
|
|
|
|
+#define RSZ_DEF_REQ_EXP 0xE /* Default read operation expand
|
|
+ * for the Resizer driver; value
|
|
+ * taken from Davinci.
|
|
+ */
|
|
/* Global structure which contains information about number of channels
|
|
and protection variables */
|
|
struct device_params {
|
|
@@ -85,6 +90,7 @@ struct device_params {
|
|
struct mutex reszwrap_mutex; /* Semaphore for array */
|
|
|
|
struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
|
|
+ unsigned long extra_page_addr;
|
|
};
|
|
|
|
/* Register mapped structure which contains the every register
|
|
@@ -126,6 +132,9 @@ struct resizer_config {
|
|
u32 rsz_yehn; /* yehn(luma)register mapping
|
|
* variable.
|
|
*/
|
|
+ u32 sdr_req_exp; /* Configuration for Non
|
|
+ * real time read expand
|
|
+ */
|
|
};
|
|
|
|
struct rsz_mult {
|
|
@@ -179,6 +188,7 @@ struct channel_config {
|
|
* channel is busy or not
|
|
*/
|
|
struct mutex chanprotection_mutex;
|
|
+ int buf_address[VIDEO_MAX_FRAME];
|
|
enum config_done config_state;
|
|
u8 input_buf_index;
|
|
u8 output_buf_index;
|
|
@@ -200,8 +210,6 @@ struct rsz_fh {
|
|
struct videobuf_queue vbq;
|
|
struct device_params *device;
|
|
|
|
- dma_addr_t isp_addr_read; /* Input/Output address */
|
|
- dma_addr_t isp_addr_write; /* Input/Output address */
|
|
u32 rsz_bufsize; /* channel specific buffersize
|
|
*/
|
|
};
|
|
@@ -227,6 +235,10 @@ static int rsz_set_ratio(struct rsz_mult *multipass,
|
|
static void rsz_config_ratio(struct rsz_mult *multipass,
|
|
struct channel_config *rsz_conf_chan);
|
|
|
|
+static void inline rsz_set_exp(unsigned int exp)
|
|
+{
|
|
+ omap_writel(((exp & 0x3FF) << 10), OMAP3ISP_SBL_REG(0xF8));
|
|
+}
|
|
/**
|
|
* rsz_hardware_setup - Sets hardware configuration registers
|
|
* @rsz_conf_chan: Structure containing channel configuration
|
|
@@ -271,12 +283,15 @@ static void rsz_hardware_setup(struct channel_config *rsz_conf_chan)
|
|
+ coeffoffset));
|
|
coeffoffset = coeffoffset + COEFF_ADDRESS_OFFSET;
|
|
}
|
|
+ /* Configure the read expand register */
|
|
+ rsz_set_exp(rsz_conf_chan->register_config.sdr_req_exp);
|
|
}
|
|
|
|
/**
|
|
* rsz_start - Enables Resizer Wrapper
|
|
* @arg: Currently not used.
|
|
- * @device: Structure containing ISP resizer wrapper global information
|
|
+ * @fh: File structure containing ISP resizer information specific to
|
|
+ * channel opened.
|
|
*
|
|
* Submits a resizing task specified by the rsz_resize structure. The call can
|
|
* either be blocked until the task is completed or returned immediately based
|
|
@@ -292,12 +307,18 @@ int rsz_start(int *arg, struct rsz_fh *fh)
|
|
struct channel_config *rsz_conf_chan = fh->config;
|
|
struct rsz_mult *multipass = fh->multipass;
|
|
struct videobuf_queue *q = &fh->vbq;
|
|
+ struct videobuf_buffer *buf;
|
|
int ret;
|
|
|
|
if (rsz_conf_chan->config_state) {
|
|
dev_err(rsz_device, "State not configured \n");
|
|
goto err_einval;
|
|
}
|
|
+ if (!rsz_conf_chan->register_config.rsz_sdr_inadd ||
|
|
+ !rsz_conf_chan->register_config.rsz_sdr_outadd) {
|
|
+ dev_err(rsz_device, "address is null\n");
|
|
+ goto err_einval;
|
|
+ }
|
|
|
|
rsz_conf_chan->status = CHANNEL_BUSY;
|
|
|
|
@@ -325,33 +346,22 @@ mult:
|
|
goto mult;
|
|
}
|
|
|
|
- if (fh->isp_addr_read) {
|
|
- ispmmu_vunmap(fh->isp_addr_read);
|
|
- fh->isp_addr_read = 0;
|
|
- }
|
|
- if (fh->isp_addr_write) {
|
|
- ispmmu_vunmap(fh->isp_addr_write);
|
|
- fh->isp_addr_write = 0;
|
|
- }
|
|
-
|
|
rsz_conf_chan->status = CHANNEL_FREE;
|
|
- q->bufs[rsz_conf_chan->input_buf_index]->state = VIDEOBUF_NEEDS_INIT;
|
|
- q->bufs[rsz_conf_chan->output_buf_index]->state = VIDEOBUF_NEEDS_INIT;
|
|
rsz_conf_chan->register_config.rsz_sdr_outadd = 0;
|
|
rsz_conf_chan->register_config.rsz_sdr_inadd = 0;
|
|
|
|
- /* Unmap and free the DMA memory allocated for buffers */
|
|
- videobuf_dma_unmap(q, videobuf_to_dma(
|
|
- q->bufs[rsz_conf_chan->input_buf_index]));
|
|
- videobuf_dma_unmap(q, videobuf_to_dma(
|
|
- q->bufs[rsz_conf_chan->output_buf_index]));
|
|
- videobuf_dma_free(videobuf_to_dma(
|
|
- q->bufs[rsz_conf_chan->input_buf_index]));
|
|
- videobuf_dma_free(videobuf_to_dma(
|
|
- q->bufs[rsz_conf_chan->output_buf_index]));
|
|
-
|
|
isp_unset_callback(CBK_RESZ_DONE);
|
|
|
|
+ /* Empty the Videobuf queue which was filled during the qbuf */
|
|
+ buf = q->bufs[rsz_conf_chan->input_buf_index];
|
|
+ buf->state = VIDEOBUF_IDLE;
|
|
+ list_del(&buf->stream);
|
|
+ if (rsz_conf_chan->input_buf_index != rsz_conf_chan->output_buf_index) {
|
|
+ buf = q->bufs[rsz_conf_chan->output_buf_index];
|
|
+ buf->state = VIDEOBUF_IDLE;
|
|
+ list_del(&buf->stream);
|
|
+ }
|
|
+
|
|
return 0;
|
|
err_einval:
|
|
return -EINVAL;
|
|
@@ -359,6 +369,8 @@ err_einval:
|
|
|
|
/**
|
|
* rsz_set_multipass - Set resizer multipass
|
|
+ * @multipass: Structure containing channel configuration
|
|
+ for multipass support
|
|
* @rsz_conf_chan: Structure containing channel configuration
|
|
*
|
|
* Returns always 0
|
|
@@ -384,6 +396,8 @@ static int rsz_set_multipass(struct rsz_mult *multipass,
|
|
|
|
/**
|
|
* rsz_copy_data - Copy data
|
|
+ * @multipass: Structure containing channel configuration
|
|
+ for multipass support
|
|
* @params: Structure containing the Resizer Wrapper parameters
|
|
*
|
|
* Copy data
|
|
@@ -413,6 +427,8 @@ static void rsz_copy_data(struct rsz_mult *multipass, struct rsz_params *params)
|
|
|
|
/**
|
|
* rsz_set_params - Set parameters for resizer wrapper
|
|
+ * @multipass: Structure containing channel configuration
|
|
+ for multipass support
|
|
* @params: Structure containing the Resizer Wrapper parameters
|
|
* @rsz_conf_chan: Structure containing channel configuration
|
|
*
|
|
@@ -524,6 +540,8 @@ static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *params,
|
|
}
|
|
|
|
rsz_config_ratio(multipass, rsz_conf_chan);
|
|
+ /* Default value for read expand:Taken from Davinci */
|
|
+ rsz_conf_chan->register_config.sdr_req_exp = RSZ_DEF_REQ_EXP;
|
|
|
|
rsz_conf_chan->config_state = STATE_CONFIGURED;
|
|
|
|
@@ -534,6 +552,8 @@ err_einval:
|
|
|
|
/**
|
|
* rsz_set_ratio - Set ratio
|
|
+ * @multipass: Structure containing channel configuration
|
|
+ for multipass support
|
|
* @rsz_conf_chan: Structure containing channel configuration
|
|
*
|
|
* Returns 0 if successful, -EINVAL if invalid output size, upscaling ratio is
|
|
@@ -548,7 +568,8 @@ static int rsz_set_ratio(struct rsz_mult *multipass,
|
|
|
|
if ((multipass->out_hsize > MAX_IMAGE_WIDTH) ||
|
|
(multipass->out_vsize > MAX_IMAGE_WIDTH)) {
|
|
- dev_err(rsz_device, "Invalid output size!");
|
|
+ dev_err(rsz_device, "Invalid output size! - %d", \
|
|
+ multipass->out_hsize);
|
|
goto err_einval;
|
|
}
|
|
if (multipass->cbilin) {
|
|
@@ -758,6 +779,8 @@ err_einval:
|
|
|
|
/**
|
|
* rsz_config_ratio - Configure ratio
|
|
+ * @multipass: Structure containing channel configuration
|
|
+ for multipass support
|
|
* @rsz_conf_chan: Structure containing channel configuration
|
|
*
|
|
* Configure ratio
|
|
@@ -789,6 +812,20 @@ static void rsz_config_ratio(struct rsz_mult *multipass,
|
|
((vsize << ISPRSZ_IN_SIZE_VERT_SHIFT)
|
|
& ISPRSZ_IN_SIZE_VERT_MASK);
|
|
|
|
+ /* This is another workaround for the ISP-MMU translation fault.
|
|
+ For the parameters whose image size comes exactly to PAGE_SIZE
|
|
+ generates ISP-MMU translation fault. The root-cause is the equation
|
|
+ input width = (32*sph + (ow - 1)*hrsz + 16) >> 8 + 7
|
|
+ = (64*sph + (ow - 1)*hrsz + 32) >> 8 + 7
|
|
+ input height = (32*spv + (oh - 1)*vrsz + 16) >> 8 + 4
|
|
+ = (64*spv + (oh - 1)*vrsz + 32) >> 8 + 7
|
|
+
|
|
+ we are adjusting the input width to suit for Resizer module,
|
|
+ application should use this configuration henceforth.
|
|
+ */
|
|
+ multipass->in_hsize = hsize;
|
|
+ multipass->in_vsize = vsize;
|
|
+
|
|
for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
|
|
coeffcounter++) {
|
|
if (multipass->num_htap) {
|
|
@@ -990,24 +1027,15 @@ static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
|
|
static void rsz_vbq_release(struct videobuf_queue *q,
|
|
struct videobuf_buffer *vb)
|
|
{
|
|
- int i;
|
|
struct rsz_fh *fh = q->priv_data;
|
|
+ struct videobuf_dmabuf *dma = NULL;
|
|
|
|
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
|
|
- struct videobuf_dmabuf *dma = NULL;
|
|
- if (!q->bufs[i])
|
|
- continue;
|
|
- if (q->bufs[i]->memory != V4L2_MEMORY_MMAP)
|
|
- continue;
|
|
- dma = videobuf_to_dma(q->bufs[i]);
|
|
- videobuf_dma_unmap(q, dma);
|
|
- videobuf_dma_free(dma);
|
|
- }
|
|
+ dma = videobuf_to_dma(q->bufs[vb->i]);
|
|
+ videobuf_dma_unmap(q, dma);
|
|
+ videobuf_dma_free(dma);
|
|
+ ispmmu_vunmap(fh->config->buf_address[vb->i]);
|
|
+ fh->config->buf_address[vb->i] = 0;
|
|
|
|
- ispmmu_vunmap(fh->isp_addr_read);
|
|
- ispmmu_vunmap(fh->isp_addr_write);
|
|
- fh->isp_addr_read = 0;
|
|
- fh->isp_addr_write = 0;
|
|
spin_lock(&fh->vbq_lock);
|
|
vb->state = VIDEOBUF_NEEDS_INIT;
|
|
spin_unlock(&fh->vbq_lock);
|
|
@@ -1062,7 +1090,105 @@ err_einval:
|
|
spin_unlock(&fh->vbq_lock);
|
|
return -EINVAL;
|
|
}
|
|
+/*
|
|
+ * This function is work around for the videobuf_iolock API,
|
|
+ * for User memory allocated with ioremap (VM_IO flag) the API
|
|
+ * get_user_pages fails.
|
|
+ *
|
|
+ * To fulfill this requirement, we have completely ignored VM layer of
|
|
+ * Linux, and configuring the ISP MMU with physical address.
|
|
+ */
|
|
+static int omap_videobuf_dma_init_user(struct videobuf_buffer *vb,
|
|
+ unsigned long physp, unsigned long asize)
|
|
+{
|
|
+ struct videobuf_dmabuf *dma;
|
|
+ struct scatterlist *sglist;
|
|
+ unsigned long data, first, last;
|
|
+ int len, i = 0;
|
|
+
|
|
+ dma = videobuf_to_dma(vb);
|
|
+ data = vb->baddr;
|
|
+
|
|
+ first = (data & PAGE_MASK) >> PAGE_SHIFT;
|
|
+ last = ((data+asize-1) & PAGE_MASK) >> PAGE_SHIFT;
|
|
+ dma->offset = data & ~PAGE_MASK;
|
|
+ dma->nr_pages = last-first+1;
|
|
+
|
|
+ dma->direction = PCI_DMA_FROMDEVICE;
|
|
+ /*
|
|
+ * Allocate array of sglen + 1, to add entry of extra page
|
|
+ * for input buffer. Driver always uses 0th buffer as input buffer.
|
|
+ */
|
|
+ len = dma->nr_pages + (vb->i ? 0 : 1);
|
|
+ sglist = kcalloc(len, sizeof(*sglist), GFP_KERNEL);
|
|
+ if (NULL == sglist)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ sglist[0].offset = 0;
|
|
+ sglist[0].length = PAGE_SIZE - dma->offset;
|
|
+ sglist[0].dma_address = (dma_addr_t)physp;
|
|
+ physp += sglist[0].length;
|
|
+ /*
|
|
+ * Iterate in a loop for the number of pages
|
|
+ */
|
|
+ for (i = 1; i < (len - (vb->i ? 0 : 1)); i++) {
|
|
+ sglist[i].offset = 0;
|
|
+ sglist[i].length = PAGE_SIZE;
|
|
+ sglist[i].dma_address = (dma_addr_t)physp;
|
|
+ physp += PAGE_SIZE;
|
|
+ }
|
|
+ if (0 == vb->i) {
|
|
+ sglist[i].offset = 0;
|
|
+ sglist[i].length = PAGE_SIZE;
|
|
+ sglist[i].dma_address =
|
|
+ (dma_addr_t)device_config->extra_page_addr;
|
|
+ }
|
|
+ dma->sglist = sglist;
|
|
+ dma->sglen = len;
|
|
+ return 0;
|
|
+
|
|
+ }
|
|
+/*
|
|
+ * This function is workaround for the issue, where ISP-MMU generated
|
|
+ * translation fault for specific params whose size is aligned to PAGE_SIZE.
|
|
+
|
|
+ * As a workaround we are padding one extra page for input buffer. This page
|
|
+ * we are allocating during init time and will not be released through-out
|
|
+ * life time of resizer driver. Please note that Resizer module only reads
|
|
+ * from this extra page.
|
|
+ */
|
|
+int omap_create_sg(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
|
|
+{
|
|
+ struct scatterlist *sglist;
|
|
+ int sglen;
|
|
|
|
+ sglen = dma->sglen;
|
|
+ sglist = kcalloc(sglen + 1, sizeof(*sglist), GFP_KERNEL);
|
|
+ if (NULL == sglist)
|
|
+ return -ENOMEM;
|
|
+ /*
|
|
+ * Copy the sglist locally
|
|
+ */
|
|
+ memcpy(sglist, dma->sglist, sglen * sizeof(*sglist));
|
|
+ /*
|
|
+ * Release the old sglist, since we already copied it locally
|
|
+ */
|
|
+ videobuf_dma_unmap(q, dma);
|
|
+ /*
|
|
+ * Add extra entry to sglist to work with specific params, whose
|
|
+ * buffer address alined to PAGE_SIZE.
|
|
+ */
|
|
+ sglist[sglen].offset = 0;
|
|
+ sglist[sglen].length = PAGE_SIZE;
|
|
+ sglist[sglen].dma_address = (dma_addr_t)device_config->extra_page_addr;
|
|
+ sglen++;
|
|
+ /*
|
|
+ * Save the sglist for mapping to ISP-MMU space
|
|
+ */
|
|
+ dma->sglist = sglist;
|
|
+ dma->sglen = sglen;
|
|
+ return 0;
|
|
+}
|
|
/**
|
|
* rsz_vbq_prepare - Videobuffer is prepared and mmapped.
|
|
* @q: Structure containing the videobuffer queue file handle, and device
|
|
@@ -1079,19 +1205,24 @@ static int rsz_vbq_prepare(struct videobuf_queue *q,
|
|
{
|
|
struct rsz_fh *fh = q->priv_data;
|
|
struct channel_config *rsz_conf_chan = fh->config;
|
|
- struct rsz_mult *multipass = fh->multipass;
|
|
int err = 0;
|
|
unsigned int isp_addr, insize, outsize;
|
|
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
|
|
-
|
|
+ struct rsz_mult *multipass = fh->multipass;
|
|
spin_lock(&fh->vbq_lock);
|
|
if (vb->baddr) {
|
|
+ /* Check for 32 byte alignement */
|
|
+ if (vb->baddr != (vb->baddr & ~0x1F)) {
|
|
+ spin_unlock(&fh->vbq_lock);
|
|
+ dev_err(rsz_device, "Buffer address should be aligned \
|
|
+ to 32 byte\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
vb->size = fh->rsz_bufsize;
|
|
vb->bsize = fh->rsz_bufsize;
|
|
} else {
|
|
spin_unlock(&fh->vbq_lock);
|
|
dev_err(rsz_device, "No user buffer allocated\n");
|
|
- goto out;
|
|
+ return -EINVAL;
|
|
}
|
|
if (vb->i) {
|
|
vb->width = fh->params->out_hsize;
|
|
@@ -1103,55 +1234,128 @@ static int rsz_vbq_prepare(struct videobuf_queue *q,
|
|
|
|
vb->field = field;
|
|
spin_unlock(&fh->vbq_lock);
|
|
+ /*
|
|
+ * Calculate input and output sizes, will be used while mapping
|
|
+ * user pages
|
|
+ */
|
|
+ outsize = multipass->out_pitch * multipass->out_vsize;
|
|
+ insize = multipass->in_pitch * multipass->in_vsize;
|
|
|
|
if (vb->state == VIDEOBUF_NEEDS_INIT) {
|
|
- err = videobuf_iolock(q, vb, NULL);
|
|
- if (!err) {
|
|
- isp_addr = ispmmu_vmap(dma->sglist, dma->sglen);
|
|
- if (!isp_addr)
|
|
- err = -EIO;
|
|
- else {
|
|
- if (vb->i) {
|
|
- rsz_conf_chan->register_config.
|
|
- rsz_sdr_outadd
|
|
- = isp_addr;
|
|
- fh->isp_addr_write = isp_addr;
|
|
- rsz_conf_chan->output_buf_index = vb->i;
|
|
- } else {
|
|
+ struct videobuf_dmabuf *dma;
|
|
+ struct vm_area_struct *vma;
|
|
+ spin_lock(&fh->vbq_lock);
|
|
+ dma = videobuf_to_dma(vb);
|
|
+ vma = find_vma(current->mm, vb->baddr);
|
|
+ if ((vma) && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
|
|
+ /* This will catch ioremaped buffers to the kernel.
|
|
+ * It gives two possible scenarios -
|
|
+ * - Driver allocates buffer using either
|
|
+ * dma_alloc_coherent or get_free_pages,
|
|
+ * and maps to user space using
|
|
+ * io_remap_pfn_range/remap_pfn_range
|
|
+ * - Drivers maps memory outside from Linux using
|
|
+ * io_remap
|
|
+ */
|
|
+ unsigned long physp = 0, asize;
|
|
+ asize = vb->i ? outsize : insize;
|
|
+ if ((vb->baddr + asize) > vma->vm_end) {
|
|
+ spin_unlock(&fh->vbq_lock);
|
|
+ dev_err(rsz_device, "User Buffer Allocation:" \
|
|
+ "err=%lu[%lu]\n",\
|
|
+ (vma->vm_end - vb->baddr), asize);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ physp = (vma->vm_pgoff << PAGE_SHIFT) +
|
|
+ (vb->baddr - vma->vm_start);
|
|
+ err = omap_videobuf_dma_init_user(vb, physp, asize);
|
|
+ spin_unlock(&fh->vbq_lock);
|
|
+ if (0 != err)
|
|
+ return err;
|
|
+ } else {
|
|
+ err = videobuf_iolock(q, vb, NULL);
|
|
+ /*
|
|
+ * In case of user pointer mode, the get_user_pages
|
|
+ * will fail if user has allocated less memory than
|
|
+ * vb->size. But it is not error from resizer driver
|
|
+ * point of view. so handled seperately
|
|
+ */
|
|
+ if ((err < 0) && (dma->nr_pages > 0))
|
|
+ err = videobuf_dma_map(q, dma);
|
|
+ if (err)
|
|
+ goto buf_release;
|
|
+ /*
|
|
+ * Add one extra page for input buffer
|
|
+ */
|
|
+ if (0 == vb->i)
|
|
+ err = omap_create_sg(q, dma);
|
|
+ if (err)
|
|
+ goto buf_release;
|
|
+ spin_unlock(&fh->vbq_lock);
|
|
+ }
|
|
+ isp_addr = ispmmu_vmap(dma->sglist, dma->sglen);
|
|
+ if (!isp_addr)
|
|
+ err = -EIO;
|
|
+ else {
|
|
+ if (vb->i) {
|
|
+ rsz_conf_chan->buf_address[vb->i] = isp_addr;
|
|
+ rsz_conf_chan->register_config.
|
|
+ rsz_sdr_outadd
|
|
+ = isp_addr;
|
|
+ rsz_conf_chan->output_buf_index = vb->i;
|
|
+ } else {
|
|
+ rsz_conf_chan->buf_address[vb->i] = isp_addr;
|
|
+ rsz_conf_chan->register_config.
|
|
+ rsz_sdr_inadd
|
|
+ = isp_addr;
|
|
+ rsz_conf_chan->input_buf_index = vb->i;
|
|
+ if (outsize < insize && rsz_conf_chan->
|
|
+ register_config.
|
|
+ rsz_sdr_outadd == 0) {
|
|
rsz_conf_chan->register_config.
|
|
- rsz_sdr_inadd
|
|
- = isp_addr;
|
|
- rsz_conf_chan->input_buf_index = vb->i;
|
|
- outsize = multipass->out_pitch *
|
|
- multipass->out_vsize;
|
|
- insize = multipass->in_pitch *
|
|
- multipass->in_vsize;
|
|
- if (outsize < insize) {
|
|
- rsz_conf_chan->register_config.
|
|
- rsz_sdr_outadd
|
|
- = isp_addr;
|
|
- rsz_conf_chan->
|
|
- output_buf_index =
|
|
- vb->i;
|
|
- }
|
|
-
|
|
- fh->isp_addr_read = isp_addr;
|
|
+ rsz_sdr_outadd
|
|
+ = isp_addr;
|
|
+ rsz_conf_chan->
|
|
+ output_buf_index =
|
|
+ vb->i;
|
|
}
|
|
}
|
|
}
|
|
|
|
- }
|
|
+ } else {
|
|
+ if(vb->i) {
|
|
+ rsz_conf_chan->register_config.
|
|
+ rsz_sdr_outadd =
|
|
+ rsz_conf_chan->buf_address[vb->i];
|
|
+ rsz_conf_chan->output_buf_index = vb->i;
|
|
+ } else {
|
|
+ rsz_conf_chan->register_config.
|
|
+ rsz_sdr_inadd =
|
|
+ rsz_conf_chan->buf_address[vb->i];
|
|
+ rsz_conf_chan->input_buf_index = vb->i;
|
|
+ if(outsize < insize && rsz_conf_chan->
|
|
+ register_config.
|
|
+ rsz_sdr_outadd == 0) {
|
|
+ rsz_conf_chan->register_config.
|
|
+ rsz_sdr_outadd
|
|
+ = rsz_conf_chan->buf_address[vb->i];
|
|
+ rsz_conf_chan->output_buf_index = vb->i;
|
|
+ }
|
|
+
|
|
+ }
|
|
|
|
+ }
|
|
if (!err) {
|
|
spin_lock(&fh->vbq_lock);
|
|
vb->state = VIDEOBUF_PREPARED;
|
|
spin_unlock(&fh->vbq_lock);
|
|
- flush_cache_user_range(NULL, vb->baddr, (vb->baddr
|
|
- + vb->bsize));
|
|
} else
|
|
rsz_vbq_release(q, vb);
|
|
|
|
-out:
|
|
+ return err;
|
|
+buf_release:
|
|
+ spin_unlock(&fh->vbq_lock);
|
|
+ rsz_vbq_release(q, vb);
|
|
return err;
|
|
}
|
|
|
|
@@ -1255,7 +1459,8 @@ err_enomem0:
|
|
**/
|
|
static int rsz_release(struct inode *inode, struct file *filp)
|
|
{
|
|
- u32 timeout = 0;
|
|
+ int i;
|
|
+ unsigned int timeout = 0;
|
|
struct rsz_fh *fh = filp->private_data;
|
|
struct channel_config *rsz_conf_chan = fh->config;
|
|
struct rsz_params *params = fh->params;
|
|
@@ -1266,17 +1471,17 @@ static int rsz_release(struct inode *inode, struct file *filp)
|
|
timeout++;
|
|
schedule();
|
|
}
|
|
- if (mutex_lock_interruptible(&device_config->reszwrap_mutex))
|
|
- return -EINTR;
|
|
- device_config->opened--;
|
|
- mutex_unlock(&device_config->reszwrap_mutex);
|
|
- /* This will Free memory allocated to the buffers,
|
|
- * and flushes the queue
|
|
- */
|
|
- videobuf_queue_cancel(q);
|
|
- fh->params = NULL;
|
|
- fh->config = NULL;
|
|
+ /* Free memory allocated to the buffers */
|
|
+ for (i = 0 ; i < VIDEO_MAX_FRAME ; i++) {
|
|
+ struct videobuf_dmabuf *dma = NULL;
|
|
+ if (!q->bufs[i])
|
|
+ continue;
|
|
+ dma = videobuf_to_dma(q->bufs[i]);
|
|
+ videobuf_dma_unmap(q, dma);
|
|
+ videobuf_dma_free(dma);
|
|
+ }
|
|
|
|
+ videobuf_mmap_free(q);
|
|
fh->rsz_bufsize = 0;
|
|
filp->private_data = NULL;
|
|
|
|
@@ -1286,7 +1491,8 @@ static int rsz_release(struct inode *inode, struct file *filp)
|
|
kfree(fh);
|
|
|
|
isp_put();
|
|
-
|
|
+ fh->params = NULL;
|
|
+ fh->config = NULL;
|
|
return 0;
|
|
}
|
|
|
|
@@ -1353,6 +1559,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
|
|
chanprotection_mutex))
|
|
return -EINTR;
|
|
ret = videobuf_reqbufs(&fh->vbq, (void *)&req_buf);
|
|
+ if (ret >= 0) {
|
|
+ if (copy_to_user((struct v4l2_requestbuffers *)arg,
|
|
+ &req_buf, sizeof(struct
|
|
+ v4l2_requestbuffers)))
|
|
+ return -EFAULT;
|
|
+ }
|
|
mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
|
|
break;
|
|
}
|
|
@@ -1394,11 +1606,7 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
|
|
sizeof(struct rsz_params))) {
|
|
return -EFAULT;
|
|
}
|
|
- if (mutex_lock_interruptible(&rsz_conf_chan->
|
|
- chanprotection_mutex))
|
|
- return -EINTR;
|
|
- ret = rsz_set_params(fh->multipass, params, rsz_conf_chan);
|
|
- mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
|
|
+ ret = rsz_set_params(fh->multipass, fh->params, rsz_conf_chan);
|
|
break;
|
|
}
|
|
case RSZ_G_PARAM:
|
|
@@ -1433,6 +1641,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
|
|
rsz_calculate_crop(rsz_conf_chan, (struct rsz_cropsize *)arg);
|
|
break;
|
|
|
|
+ case RSZ_S_EXP:
|
|
+ if (mutex_lock_interruptible(&rsz_conf_chan->chanprotection_mutex))
|
|
+ return -EINTR;
|
|
+ rsz_conf_chan->register_config.sdr_req_exp = *((unsigned int *)arg);
|
|
+ mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
|
|
+ break;
|
|
default:
|
|
dev_err(rsz_device, "resizer_ioctl: Invalid Command Value");
|
|
return -EINVAL;
|
|
@@ -1535,14 +1749,18 @@ static int __init omap_rsz_init(void)
|
|
"memory\n");
|
|
return -ENOMEM;
|
|
}
|
|
-
|
|
+ device->extra_page_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
|
|
+ if (!device->extra_page_addr) {
|
|
+ dev_err(rsz_device, OMAP_REZR_NAME ":Allocation failed. ");
|
|
+ kfree(device);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME);
|
|
if (ret < 0) {
|
|
dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. "
|
|
"Could not allocate region "
|
|
"for character device\n");
|
|
- kfree(device);
|
|
- return -ENODEV;
|
|
+ goto fail1;
|
|
}
|
|
|
|
/* Register the driver in the kernel */
|
|
@@ -1608,6 +1826,8 @@ fail3:
|
|
cdev_del(&c_dev);
|
|
fail2:
|
|
unregister_chrdev_region(dev, 1);
|
|
+fail1:
|
|
+ free_pages((unsigned long)device->extra_page_addr, 0);
|
|
kfree(device);
|
|
return ret;
|
|
}
|
|
@@ -1623,6 +1843,7 @@ void __exit omap_rsz_exit(void)
|
|
platform_driver_unregister(&omap_resizer_driver);
|
|
cdev_del(&c_dev);
|
|
unregister_chrdev_region(dev, 1);
|
|
+ free_pages((unsigned long)device_config->extra_page_addr, 0);
|
|
kfree(device_config);
|
|
}
|
|
|
|
diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h
|
|
index 5ac0c88..47b8dd8 100644
|
|
--- a/include/linux/omap_resizer.h
|
|
+++ b/include/linux/omap_resizer.h
|
|
@@ -21,7 +21,7 @@
|
|
|
|
/* ioctls definition */
|
|
#define RSZ_IOC_BASE 'R'
|
|
-#define RSZ_IOC_MAXNR 8
|
|
+#define RSZ_IOC_MAXNR 9
|
|
|
|
/*Ioctl options which are to be passed while calling the ioctl*/
|
|
#define RSZ_REQBUF _IOWR(RSZ_IOC_BASE, 1,\
|
|
@@ -33,6 +33,7 @@
|
|
#define RSZ_G_STATUS _IOWR(RSZ_IOC_BASE, 6, struct rsz_status)
|
|
#define RSZ_QUEUEBUF _IOWR(RSZ_IOC_BASE, 7, struct v4l2_buffer)
|
|
#define RSZ_GET_CROPSIZE _IOWR(RSZ_IOC_BASE, 8, struct rsz_cropsize)
|
|
+#define RSZ_S_EXP _IOWR(RSZ_IOC_BASE, 9, __s32)
|
|
|
|
#define RSZ_INTYPE_YCBCR422_16BIT 0
|
|
#define RSZ_INTYPE_PLANAR_8BIT 1
|
|
--
|
|
1.6.0.3
|
|
|