diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch | 2915 |
1 files changed, 2915 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch new file mode 100644 index 0000000000..f796ce8346 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch @@ -0,0 +1,2915 @@ +From 3041daa54b49bcb6ab444c7b9e14bc6a1ade6236 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Fri, 13 Feb 2009 14:44:20 +0530 +Subject: [PATCH 1/2] Resizer and Previewer driver added to commit + +The Resizer and Previewer driver added to the commit +from the patch submitted by Sergio on 12 Dec 2008. + +The new WTBU code base and Nokia fixes package doesn't contain +standalone resizer driver support. + +Following major changes done - + + - Added stand-alone resizer driver support + in isp.c file. + - Seperate Kconfig file created + - hardware access of resizer module fixed as per new + isp.c + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + drivers/media/video/Kconfig | 5 +- + drivers/media/video/isp/Kconfig | 16 + + drivers/media/video/isp/Makefile | 7 + + drivers/media/video/isp/isp.c | 12 + + drivers/media/video/isp/ispmmu.c | 1 + + drivers/media/video/isp/omap_previewer.c | 825 +++++++++++++++ + drivers/media/video/isp/omap_previewer.h | 162 +++ + drivers/media/video/isp/omap_resizer.c | 1634 ++++++++++++++++++++++++++++++ + include/linux/omap_resizer.h | 136 +++ + 9 files changed, 2794 insertions(+), 4 deletions(-) + create mode 100644 drivers/media/video/isp/Kconfig + create mode 100644 drivers/media/video/isp/omap_previewer.c + create mode 100644 drivers/media/video/isp/omap_previewer.h + create mode 100644 drivers/media/video/isp/omap_resizer.c + create mode 100644 include/linux/omap_resizer.h + +diff --git a/drivers/media/video/isp/Kconfig b/drivers/media/video/isp/Kconfig +new file mode 100644 +index 0000000..acda63b +--- /dev/null ++++ b/drivers/media/video/isp/Kconfig +@@ -0,0 +1,16 @@ ++# Kconfig for OMAP3 ISP driver ++ ++config VIDEO_OMAP3_ISP ++ tristate ++ select VIDEOBUF_GEN ++ select VIDEOBUF_DMA_SG ++ ++config VIDEO_OMAP34XX_ISP_PREVIEWER ++ tristate "OMAP ISP Previewer" ++ depends on !ARCH_OMAP3410 ++ select VIDEO_OMAP3_ISP ++ ++config VIDEO_OMAP34XX_ISP_RESIZER ++ tristate "OMAP ISP Resizer" ++ depends on !ARCH_OMAP3410 ++ select VIDEO_OMAP3_ISP +diff --git a/drivers/media/video/isp/Makefile b/drivers/media/video/isp/Makefile +index 0f9301c..ed10a51 100644 +--- a/drivers/media/video/isp/Makefile ++++ b/drivers/media/video/isp/Makefile +@@ -7,6 +7,13 @@ else + isp-mod-objs += \ + isp.o ispccdc.o ispmmu.o \ + isppreview.o ispresizer.o isph3a.o isphist.o isp_af.o ispcsi2.o ++ ++obj-$(CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER) += \ ++ omap_previewer.o ++ ++obj-$(CONFIG_VIDEO_OMAP34XX_ISP_RESIZER) += \ ++ omap_resizer.o ++ + endif + + obj-$(CONFIG_VIDEO_OMAP3_ISP) += isp-mod.o +diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c +index 6034a56..09a1792 100644 +--- a/drivers/media/video/isp/isp.c ++++ b/drivers/media/video/isp/isp.c +@@ -521,6 +521,13 @@ int isp_set_callback(enum isp_callback_type type, isp_callback_t callback, + OMAP3_ISP_IOMEM_MAIN, + ISP_IRQ0ENABLE); + break; ++ case CBK_RESZ_DONE: ++ isp_reg_writel(IRQ0ENABLE_RSZ_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN, ++ ISP_IRQ0STATUS); ++ isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE) | ++ IRQ0ENABLE_RSZ_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN, ++ ISP_IRQ0ENABLE); ++ break; + default: + break; + } +@@ -996,6 +1003,11 @@ static irqreturn_t omap34xx_isp_isr(int irq, void *_isp) + if (!ispresizer_busy()) + ispresizer_config_shadow_registers(); + isp_buf_process(bufs); ++ } else { ++ if (irqdis->isp_callbk[CBK_RESZ_DONE]) ++ irqdis->isp_callbk[CBK_RESZ_DONE](RESZ_DONE, ++ irqdis->isp_callbk_arg1[CBK_RESZ_DONE], ++ irqdis->isp_callbk_arg2[CBK_RESZ_DONE]); + } + } + +diff --git a/drivers/media/video/isp/ispmmu.c b/drivers/media/video/isp/ispmmu.c +index 076aea1..b943d5b 100644 +--- a/drivers/media/video/isp/ispmmu.c ++++ b/drivers/media/video/isp/ispmmu.c +@@ -289,6 +289,7 @@ int ispmmu_get_mapeable_space(void) + return (L2P_TABLE_NR - no_of_l2p_alloted) * ISPMMU_TTB_ENTRIES_NR * + ISPMMU_L2D_ENTRIES_NR; + } ++EXPORT_SYMBOL_GPL(ispmmu_get_mapeable_space); + + /** + * ispmmu_map - Map a physically contiguous buffer to ISP space. +diff --git a/drivers/media/video/isp/omap_previewer.c b/drivers/media/video/isp/omap_previewer.c +new file mode 100644 +index 0000000..634a056 +--- /dev/null ++++ b/drivers/media/video/isp/omap_previewer.c +@@ -0,0 +1,825 @@ ++/* ++ * drivers/media/video/isp/omap_previewer.c ++ * ++ * Wrapper for Preview module in TI's OMAP3430 ISP ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * ++ * Contributors: ++ * Leonides Martinez <leonides.martinez@ti.com> ++ * Sergio Aguirre <saaguirre@ti.com> ++ * ++ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++#include <linux/mutex.h> ++#include <linux/cdev.h> ++#include <linux/device.h> ++#include <linux/delay.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <linux/io.h> ++#include <media/v4l2-dev.h> ++#include <asm/cacheflush.h> ++ ++#include "isp.h" ++#include "ispmmu.h" ++#include "ispreg.h" ++#include "omap_previewer.h" ++ ++#define OMAP_PREV_NAME "omap-previewer" ++ ++static int prev_major = -1; ++static struct device *prev_dev; ++static struct class *prev_class; ++static struct prev_device *prevdevice; ++static struct platform_driver omap_previewer_driver; ++ ++static u32 prev_bufsize; ++ ++/** ++ * prev_calculate_crop - Calculate crop size according to device parameters ++ * @device: Structure containing ISP preview wrapper global information ++ * @crop: Structure containing crop size ++ * ++ * This function is used to calculate frame size reduction depending on ++ * the features enabled by the application. ++ **/ ++static void prev_calculate_crop(struct prev_device *device, ++ struct prev_cropsize *crop) ++{ ++ dev_dbg(prev_dev, "prev_calculate_crop E\n"); ++ ++ if (!device || !crop) { ++ dev_err(prev_dev, "\nErron in argument"); ++ return; ++ } ++ ++ isppreview_try_size(device->params->size_params.hsize, ++ device->params->size_params.vsize, ++ &crop->hcrop, &crop->vcrop); ++ crop->hcrop &= PREV_16PIX_ALIGN_MASK; ++ dev_dbg(prev_dev, "prev_calculate_crop L\n"); ++} ++ ++/** ++ * prev_get_status - Get status of ISP preview module ++ * @status: Structure containing the busy state. ++ * ++ * Checks if the ISP preview module is busy. ++ * ++ * Returns 0 if successful, or -EINVAL if the status parameter is invalid. ++ **/ ++static int prev_get_status(struct prev_status *status) ++{ ++ if (!status) { ++ dev_err(prev_dev, "get_status: invalid parameter\n"); ++ return -EINVAL; ++ } ++ status->hw_busy = (char)isppreview_busy(); ++ return 0; ++} ++ ++/** ++ * prev_hw_setup - Stores the desired configuration in the proper HW registers ++ * @config: Structure containing the desired configuration for ISP preview ++ * module. ++ * ++ * Reads the structure sent, and modifies the desired registers. ++ * ++ * Always returns 0. ++ **/ ++static int prev_hw_setup(struct prev_params *config) ++{ ++ dev_dbg(prev_dev, "prev_hw_setup E\n"); ++ ++ if (config->features & PREV_AVERAGER) ++ isppreview_config_averager(config->average); ++ else ++ isppreview_config_averager(0); ++ ++ if (config->features & PREV_INVERSE_ALAW) ++ isppreview_enable_invalaw(1); ++ else ++ isppreview_enable_invalaw(0); ++ ++ if (config->features & PREV_HORZ_MEDIAN_FILTER) { ++ isppreview_config_hmed(config->hmf_params); ++ isppreview_enable_hmed(1); ++ } else ++ isppreview_enable_hmed(0); ++ ++ if (config->features & PREV_DARK_FRAME_SUBTRACT) { ++ isppreview_set_darkaddr(config->drkf_params.addr); ++ isppreview_config_darklineoffset(config->drkf_params.offset); ++ isppreview_enable_drkframe(1); ++ } else ++ isppreview_enable_drkframe(0); ++ ++ if (config->features & PREV_LENS_SHADING) { ++ isppreview_config_drkf_shadcomp(config->lens_shading_shift); ++ isppreview_enable_shadcomp(1); ++ } else ++ isppreview_enable_shadcomp(0); ++ ++ dev_dbg(prev_dev, "prev_hw_setup L\n"); ++ return 0; ++} ++ ++/** ++ * prev_validate_params - Validate configuration parameters for Preview Wrapper ++ * @params: Structure containing configuration parameters ++ * ++ * Validate configuration parameters for Preview Wrapper ++ * ++ * Returns 0 if successful, or -EINVAL if a parameter value is invalid. ++ **/ ++static int prev_validate_params(struct prev_params *params) ++{ ++ if (!params) { ++ dev_err(prev_dev, "validate_params: error in argument"); ++ goto err_einval; ++ } ++ ++ if ((params->features & PREV_AVERAGER) == PREV_AVERAGER) { ++ if ((params->average != NO_AVE) ++ && (params->average != AVE_2_PIX) ++ && (params->average != AVE_4_PIX) ++ && (params->average != AVE_8_PIX)) { ++ dev_err(prev_dev, "validate_params: wrong pix " ++ "average\n"); ++ goto err_einval; ++ } else if (((params->average == AVE_2_PIX) ++ && (params->size_params.hsize % 2)) ++ || ((params->average == AVE_4_PIX) ++ && (params->size_params.hsize % 4)) ++ || ((params->average == AVE_8_PIX) ++ && (params->size_params.hsize % 8))) { ++ dev_err(prev_dev, "validate_params: " ++ "wrong pix average for input size\n"); ++ goto err_einval; ++ } ++ } ++ ++ if ((params->size_params.pixsize != PREV_INWIDTH_8BIT) ++ && (params->size_params.pixsize ++ != PREV_INWIDTH_10BIT)) { ++ dev_err(prev_dev, "validate_params: wrong pixsize\n"); ++ goto err_einval; ++ } ++ ++ if (params->size_params.hsize > MAX_IMAGE_WIDTH ++ || params->size_params.hsize < 0) { ++ dev_err(prev_dev, "validate_params: wrong hsize\n"); ++ goto err_einval; ++ } ++ ++ if ((params->pix_fmt != YCPOS_YCrYCb) ++ && (YCPOS_YCbYCr != params->pix_fmt) ++ && (YCPOS_CbYCrY != params->pix_fmt) ++ && (YCPOS_CrYCbY != params->pix_fmt)) { ++ dev_err(prev_dev, "validate_params: wrong pix_fmt"); ++ goto err_einval; ++ } ++ ++ if ((params->features & PREV_DARK_FRAME_SUBTRACT) ++ && (params->features ++ & PREV_DARK_FRAME_CAPTURE)) { ++ dev_err(prev_dev, "validate_params: DARK FRAME CAPTURE and " ++ "SUBSTRACT cannot be enabled " ++ "at same time\n"); ++ goto err_einval; ++ } ++ ++ if (params->features & PREV_DARK_FRAME_SUBTRACT) ++ if (!params->drkf_params.addr ++ || (params->drkf_params.offset % 32)) { ++ dev_err(prev_dev, "validate_params: dark frame " ++ "address\n"); ++ goto err_einval; ++ } ++ ++ if (params->features & PREV_LENS_SHADING) ++ if ((params->lens_shading_shift > 7) ++ || !params->drkf_params.addr ++ || (params->drkf_params.offset % 32)) { ++ dev_err(prev_dev, "validate_params: lens shading " ++ "shift\n"); ++ goto err_einval; ++ } ++ ++ if ((params->size_params.in_pitch <= 0) ++ || (params->size_params.in_pitch % 32)) { ++ params->size_params.in_pitch = ++ (params->size_params.hsize * 2) & 0xFFE0; ++ dev_err(prev_dev, "\nError in in_pitch; new value = %d", ++ params->size_params.in_pitch); ++ } ++ ++ return 0; ++err_einval: ++ return -EINVAL; ++} ++ ++/** ++ * preview_isr - Callback from ISP driver for ISP Preview Interrupt ++ * @status: ISP IRQ0STATUS register value ++ * @arg1: Structure containing ISP preview wrapper global information ++ * @arg2: Currently not used ++ **/ ++static void preview_isr(unsigned long status, isp_vbq_callback_ptr arg1, ++ void *arg2) ++{ ++ struct prev_device *device = (struct prev_device *)arg1; ++ ++ if ((status & PREV_DONE) != PREV_DONE) ++ return; ++ ++ if (device) ++ complete(&device->wfc); ++} ++ ++/** ++ * prev_do_preview - Performs the Preview process ++ * @device: Structure containing ISP preview wrapper global information ++ * @arg: Currently not used ++ * ++ * Returns 0 if successful, or -EINVAL if the sent parameters are invalid. ++ **/ ++static int prev_do_preview(struct prev_device *device, int *arg) ++{ ++ int bpp, size; ++ int ret = 0; ++ u32 out_hsize, out_vsize, out_line_offset; ++ ++ dev_dbg(prev_dev, "prev_do_preview E\n"); ++ ++ if (!device) { ++ dev_err(prev_dev, "preview: invalid parameters\n"); ++ return -EINVAL; ++ } ++ ++ if (device->params->size_params.pixsize == PREV_INWIDTH_8BIT) ++ bpp = 1; ++ else ++ bpp = 2; ++ ++ size = device->params->size_params.hsize * ++ device->params->size_params.vsize * bpp; ++ ++ ret = isppreview_set_inaddr(device->isp_addr_read); ++ if (ret) ++ goto out; ++ ++ ret = isppreview_set_outaddr(device->isp_addr_read); ++ if (ret) ++ goto out; ++ ++ isppreview_try_size(device->params->size_params.hsize, ++ device->params->size_params.vsize, ++ &out_hsize, &out_vsize); ++ ++ ret = isppreview_config_inlineoffset(device->params->size_params.hsize ++ * bpp); ++ if (ret) ++ goto out; ++ ++ out_line_offset = (out_hsize * bpp) & PREV_32BYTES_ALIGN_MASK; ++ ++ ret = isppreview_config_outlineoffset(out_line_offset); ++ if (ret) ++ goto out; ++ ++ ret = isppreview_config_size(device->params->size_params.hsize, ++ device->params->size_params.vsize, ++ out_hsize, out_vsize); ++ if (ret) ++ goto out; ++ ++ isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM); ++ ++ ret = isp_set_callback(CBK_PREV_DONE, preview_isr, (void *)device, ++ (void *)NULL); ++ if (ret) { ++ dev_err(prev_dev, "ERROR while setting Previewer callback!\n"); ++ goto out; ++ } ++ isppreview_enable(1); ++ ++ wait_for_completion_interruptible(&device->wfc); ++ ++ if (device->isp_addr_read) { ++ ispmmu_vunmap(device->isp_addr_read); ++ device->isp_addr_read = 0; ++ } ++ ++ ret = isp_unset_callback(CBK_PREV_DONE); ++ ++ dev_dbg(prev_dev, "prev_do_preview L\n"); ++out: ++ return ret; ++} ++ ++/** ++ * previewer_vbq_release - Videobuffer queue release ++ * @q: Structure containing the videobuffer queue. ++ * @vb: Structure containing the videobuffer used for previewer processing. ++ **/ ++static void previewer_vbq_release(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct prev_fh *fh = q->priv_data; ++ struct prev_device *device = fh->device; ++ ++ ispmmu_vunmap(device->isp_addr_read); ++ device->isp_addr_read = 0; ++ spin_lock(&device->vbq_lock); ++ vb->state = VIDEOBUF_NEEDS_INIT; ++ spin_unlock(&device->vbq_lock); ++ dev_dbg(prev_dev, "previewer_vbq_release\n"); ++} ++ ++/** ++ * previewer_vbq_setup - Sets up the videobuffer size and validates count. ++ * @q: Structure containing the videobuffer queue. ++ * @cnt: Number of buffers requested ++ * @size: Size in bytes of the buffer used for previewing ++ * ++ * Always returns 0. ++ **/ ++static int previewer_vbq_setup(struct videobuf_queue *q, ++ unsigned int *cnt, ++ unsigned int *size) ++{ ++ struct prev_fh *fh = q->priv_data; ++ struct prev_device *device = fh->device; ++ u32 bpp = 1; ++ ++ spin_lock(&device->vbq_lock); ++ if (*cnt <= 0) ++ *cnt = VIDEO_MAX_FRAME; ++ ++ if (*cnt > VIDEO_MAX_FRAME) ++ *cnt = VIDEO_MAX_FRAME; ++ ++ if (!device->params->size_params.hsize || ++ !device->params->size_params.vsize) { ++ dev_err(prev_dev, "Can't setup buffer size\n"); ++ spin_unlock(&device->vbq_lock); ++ return -EINVAL; ++ } ++ ++ if (device->params->size_params.pixsize == PREV_INWIDTH_10BIT) ++ bpp = 2; ++ *size = prev_bufsize = bpp * device->params->size_params.hsize ++ * device->params->size_params.vsize; ++ spin_unlock(&device->vbq_lock); ++ dev_dbg(prev_dev, "previewer_vbq_setup\n"); ++ return 0; ++} ++ ++/** ++ * previewer_vbq_prepare - Videobuffer is prepared and mmapped. ++ * @q: Structure containing the videobuffer queue. ++ * @vb: Structure containing the videobuffer used for previewer processing. ++ * @field: Type of field to set in videobuffer device. ++ * ++ * Returns 0 if successful, or -EINVAL if buffer couldn't get allocated, or ++ * -EIO if the ISP MMU mapping fails ++ **/ ++static int previewer_vbq_prepare(struct videobuf_queue *q, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ struct prev_fh *fh = q->priv_data; ++ struct prev_device *device = fh->device; ++ int err = -EINVAL; ++ unsigned int isp_addr; ++ struct videobuf_dmabuf *dma = videobuf_to_dma(vb); ++ ++ dev_dbg(prev_dev, "previewer_vbq_prepare E\n"); ++ spin_lock(&device->vbq_lock); ++ if (vb->baddr) { ++ vb->size = prev_bufsize; ++ vb->bsize = prev_bufsize; ++ } else { ++ spin_unlock(&device->vbq_lock); ++ dev_err(prev_dev, "No user buffer allocated\n"); ++ goto out; ++ } ++ ++ vb->width = device->params->size_params.hsize; ++ vb->height = device->params->size_params.vsize; ++ vb->field = field; ++ spin_unlock(&device->vbq_lock); ++ ++ 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 ++ device->isp_addr_read = isp_addr; ++ } ++ } ++ ++ if (!err) { ++ vb->state = VIDEOBUF_PREPARED; ++ flush_cache_user_range(NULL, vb->baddr, ++ (vb->baddr + vb->bsize)); ++ } else ++ previewer_vbq_release(q, vb); ++ ++ dev_dbg(prev_dev, "previewer_vbq_prepare L\n"); ++out: ++ return err; ++} ++ ++static void previewer_vbq_queue(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ return; ++} ++ ++/** ++ * previewer_open - Initializes and opens the Preview Wrapper ++ * @inode: Inode structure associated with the Preview Wrapper ++ * @filp: File structure associated with the Preview Wrapper ++ * ++ * Returns 0 if successful, -EACCES if its unable to initialize default config, ++ * -EBUSY if its already opened or the ISP module is not available, or -ENOMEM ++ * if its unable to allocate the device in kernel space memory. ++ **/ ++static int previewer_open(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ struct prev_device *device = prevdevice; ++ struct prev_params *config = isppreview_get_config(); ++ struct prev_fh *fh; ++ ++ if (config == NULL) { ++ dev_err(prev_dev, "Unable to initialize default config " ++ "from isppreviewer\n\n"); ++ return -EACCES; ++ } ++ ++ if (device->opened || (filp->f_flags & O_NONBLOCK)) { ++ dev_err(prev_dev, "previewer_open: device is already " ++ "opened\n"); ++ return -EBUSY; ++ } ++ ++ fh = kzalloc(sizeof(struct prev_fh), GFP_KERNEL); ++ if (NULL == fh) ++ return -ENOMEM; ++ ++ isp_get(); ++ ret = isppreview_request(); ++ if (ret) { ++ isp_put(); ++ dev_err(prev_dev, "Can't acquire isppreview\n"); ++ return ret; ++ } ++ ++ device->params = config; ++ device->opened = 1; ++ ++ filp->private_data = fh; ++ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ fh->device = device; ++ ++ videobuf_queue_sg_init(&fh->vbq, &device->vbq_ops, NULL, ++ &device->vbq_lock, fh->type, ++ V4L2_FIELD_NONE, ++ sizeof(struct videobuf_buffer), fh); ++ ++ init_completion(&device->wfc); ++ device->wfc.done = 0; ++ mutex_init(&device->prevwrap_mutex); ++ ++ return 0; ++} ++ ++/** ++ * previewer_release - Releases Preview Wrapper and frees up allocated memory ++ * @inode: Inode structure associated with the Preview Wrapper ++ * @filp: File structure associated with the Preview Wrapper ++ * ++ * Always returns 0. ++ **/ ++static int previewer_release(struct inode *inode, struct file *filp) ++{ ++ struct prev_fh *fh = filp->private_data; ++ struct prev_device *device = fh->device; ++ struct videobuf_queue *q = &fh->vbq; ++ ++ device->opened = 0; ++ device->params = NULL; ++ isppreview_free(); ++ videobuf_mmap_free(q); ++ isp_put(); ++ prev_bufsize = 0; ++ filp->private_data = NULL; ++ kfree(fh); ++ ++ dev_dbg(prev_dev, "previewer_release\n"); ++ return 0; ++} ++ ++/** ++ * previewer_mmap - Memory maps the Preview Wrapper module. ++ * @file: File structure associated with the Preview Wrapper ++ * @vma: Virtual memory area structure. ++ * ++ * Returns 0 if successful, or returned value by the videobuf_mmap_mapper() ++ * function. ++ **/ ++static int previewer_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct prev_fh *fh = file->private_data; ++ dev_dbg(prev_dev, "previewer_mmap\n"); ++ ++ return videobuf_mmap_mapper(&fh->vbq, vma); ++} ++ ++/** ++ * previewer_ioctl - I/O control function for Preview Wrapper ++ * @inode: Inode structure associated with the Preview Wrapper. ++ * @file: File structure associated with the Preview Wrapper. ++ * @cmd: Type of command to execute. ++ * @arg: Argument to send to requested command. ++ * ++ * Returns 0 if successful, -1 if bad command passed or access is denied, ++ * -EFAULT if copy_from_user() or copy_to_user() fails, -EINVAL if parameter ++ * validation fails or parameter structure is not present ++ **/ ++static int previewer_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ struct prev_params params; ++ struct prev_fh *fh = file->private_data; ++ struct prev_device *device = fh->device; ++ ++ dev_dbg(prev_dev, "Entering previewer_ioctl()\n"); ++ ++ if ((_IOC_TYPE(cmd) != PREV_IOC_BASE) ++ || (_IOC_NR(cmd) > PREV_IOC_MAXNR)) { ++ dev_err(prev_dev, "Bad command Value \n"); ++ goto err_minusone; ++ } ++ ++ if (_IOC_DIR(cmd) & _IOC_READ) ++ ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); ++ else if (_IOC_DIR(cmd) & _IOC_WRITE) ++ ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); ++ if (ret) { ++ dev_err(prev_dev, "access denied\n"); ++ goto err_minusone; ++ } ++ ++ switch (cmd) { ++ case PREV_REQBUF: ++ if (mutex_lock_interruptible(&device->prevwrap_mutex)) ++ goto err_eintr; ++ ret = videobuf_reqbufs(&fh->vbq, (void *)arg); ++ mutex_unlock(&device->prevwrap_mutex); ++ break; ++ ++ case PREV_QUERYBUF: ++ if (mutex_lock_interruptible(&device->prevwrap_mutex)) ++ goto err_eintr; ++ ret = videobuf_querybuf(&fh->vbq, (void *)arg); ++ mutex_unlock(&device->prevwrap_mutex); ++ break; ++ ++ case PREV_QUEUEBUF: ++ if (mutex_lock_interruptible(&device->prevwrap_mutex)) ++ goto err_eintr; ++ ret = videobuf_qbuf(&fh->vbq, (void *)arg); ++ mutex_unlock(&device->prevwrap_mutex); ++ break; ++ ++ case PREV_SET_PARAM: ++ if (mutex_lock_interruptible(&device->prevwrap_mutex)) ++ goto err_eintr; ++ if (copy_from_user(¶ms, (struct prev_params *)arg, ++ sizeof(struct prev_params))) { ++ mutex_unlock(&device->prevwrap_mutex); ++ return -EFAULT; ++ } ++ ret = prev_validate_params(¶ms); ++ if (ret < 0) { ++ dev_err(prev_dev, "Error validating parameters!\n"); ++ mutex_unlock(&device->prevwrap_mutex); ++ goto out; ++ } ++ if (device->params) ++ memcpy(device->params, ¶ms, ++ sizeof(struct prev_params)); ++ else { ++ mutex_unlock(&device->prevwrap_mutex); ++ return -EINVAL; ++ } ++ ++ ret = prev_hw_setup(device->params); ++ mutex_unlock(&device->prevwrap_mutex); ++ break; ++ ++ case PREV_GET_PARAM: ++ if (copy_to_user((struct prev_params *)arg, device->params, ++ sizeof(struct prev_params))) ++ ret = -EFAULT; ++ break; ++ ++ case PREV_GET_STATUS: ++ ret = prev_get_status((struct prev_status *)arg); ++ break; ++ ++ case PREV_PREVIEW: ++ if (mutex_lock_interruptible(&device->prevwrap_mutex)) ++ goto err_eintr; ++ ret = prev_do_preview(device, (int *)arg); ++ mutex_unlock(&device->prevwrap_mutex); ++ break; ++ ++ case PREV_GET_CROPSIZE: ++ { ++ struct prev_cropsize outputsize; ++ prev_calculate_crop(device, &outputsize); ++ if (copy_to_user((struct prev_cropsize *)arg, &outputsize, ++ sizeof(struct prev_cropsize))) ++ ret = -EFAULT; ++ } ++ break; ++ ++ default: ++ dev_err(prev_dev, "previewer_ioctl: Invalid Command Value\n"); ++ ret = -EINVAL; ++ } ++out: ++ return ret; ++err_minusone: ++ return -1; ++err_eintr: ++ return -EINTR; ++} ++ ++/** ++ * previewer_platform_release - Acts when Reference count is zero ++ * @device: Structure containing ISP preview wrapper global information ++ * ++ * This is called when the reference count goes to zero ++ **/ ++static void previewer_platform_release(struct device *device) ++{ ++ dev_dbg(prev_dev, "previewer_platform_release()\n"); ++} ++ ++static struct file_operations prev_fops = { ++ .owner = THIS_MODULE, ++ .open = previewer_open, ++ .release = previewer_release, ++ .mmap = previewer_mmap, ++ .ioctl = previewer_ioctl, ++}; ++ ++static struct platform_device omap_previewer_device = { ++ .name = OMAP_PREV_NAME, ++ .id = -1, ++ .dev = { ++ .release = previewer_platform_release, ++ } ++}; ++ ++/** ++ * previewer_probe - Checks for device presence ++ * @pdev: Structure containing details of the current device. ++ * ++ * Always returns 0 ++ **/ ++static int __init previewer_probe(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++/** ++ * previewer_remove - Handles the removal of the driver ++ * @pdev: Structure containing details of the current device. ++ * ++ * Always returns 0. ++ **/ ++static int previewer_remove(struct platform_device *pdev) ++{ ++ dev_dbg(prev_dev, "previewer_remove()\n"); ++ ++ platform_device_unregister(&omap_previewer_device); ++ platform_driver_unregister(&omap_previewer_driver); ++ unregister_chrdev(prev_major, OMAP_PREV_NAME); ++ return 0; ++} ++ ++static struct platform_driver omap_previewer_driver = { ++ .probe = previewer_probe, ++ .remove = previewer_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = OMAP_PREV_NAME, ++ }, ++}; ++ ++/** ++ * omap_previewer_init - Initialization of Preview Wrapper ++ * ++ * Returns 0 if successful, -ENOMEM if could not allocate memory, -ENODEV if ++ * could not register the wrapper as a character device, or other errors if the ++ * device or driver can't register. ++ **/ ++static int __init omap_previewer_init(void) ++{ ++ int ret; ++ struct prev_device *device; ++ ++ device = kzalloc(sizeof(struct prev_device), GFP_KERNEL); ++ if (!device) { ++ dev_err(prev_dev, OMAP_PREV_NAME ": could not allocate" ++ " memory\n"); ++ return -ENOMEM; ++ } ++ prev_major = register_chrdev(0, OMAP_PREV_NAME, &prev_fops); ++ ++ if (prev_major < 0) { ++ dev_err(prev_dev, OMAP_PREV_NAME ": initialization " ++ "failed. could not register character " ++ "device\n"); ++ return -ENODEV; ++ } ++ ++ ret = platform_driver_register(&omap_previewer_driver); ++ if (ret) { ++ dev_err(prev_dev, OMAP_PREV_NAME ++ ": failed to register platform driver!\n"); ++ goto fail2; ++ } ++ ret = platform_device_register(&omap_previewer_device); ++ if (ret) { ++ dev_err(prev_dev, OMAP_PREV_NAME ++ ": failed to register platform device!\n"); ++ goto fail3; ++ } ++ ++ prev_class = class_create(THIS_MODULE, OMAP_PREV_NAME); ++ if (!prev_class) ++ goto fail4; ++ ++ prev_dev = device_create(prev_class, prev_dev, ++ (MKDEV(prev_major, 0)), NULL, ++ OMAP_PREV_NAME); ++ dev_dbg(prev_dev, OMAP_PREV_NAME ": Registered Previewer Wrapper\n"); ++ device->opened = 0; ++ ++ device->vbq_ops.buf_setup = previewer_vbq_setup; ++ device->vbq_ops.buf_prepare = previewer_vbq_prepare; ++ device->vbq_ops.buf_release = previewer_vbq_release; ++ device->vbq_ops.buf_queue = previewer_vbq_queue; ++ spin_lock_init(&device->vbq_lock); ++ ++ prevdevice = device; ++ return 0; ++ ++fail4: ++ platform_device_unregister(&omap_previewer_device); ++fail3: ++ platform_driver_unregister(&omap_previewer_driver); ++fail2: ++ unregister_chrdev(prev_major, OMAP_PREV_NAME); ++ ++ return ret; ++} ++ ++/** ++ * omap_previewer_exit - Close of Preview Wrapper ++ **/ ++static void __exit omap_previewer_exit(void) ++{ ++ previewer_remove(&omap_previewer_device); ++ kfree(prevdevice); ++ prev_major = -1; ++} ++ ++module_init(omap_previewer_init); ++module_exit(omap_previewer_exit); ++ ++MODULE_AUTHOR("Texas Instruments"); ++MODULE_DESCRIPTION("OMAP ISP Previewer"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/video/isp/omap_previewer.h b/drivers/media/video/isp/omap_previewer.h +new file mode 100644 +index 0000000..0bb31cd +--- /dev/null ++++ b/drivers/media/video/isp/omap_previewer.h +@@ -0,0 +1,162 @@ ++/* ++ * drivers/media/video/isp/omap_previewer.h ++ * ++ * Header file for Preview module wrapper in TI's OMAP3430 ISP ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * ++ * Contributors: ++ * Leonides Martinez <leonides.martinez@ti.com> ++ * Sergio Aguirre <saaguirre@ti.com> ++ * ++ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++#include "isppreview.h" ++ ++#ifndef OMAP_ISP_PREVIEW_WRAP_H ++#define OMAP_ISP_PREVIEW_WRAP_H ++ ++#define PREV_IOC_BASE 'P' ++#define PREV_REQBUF _IOWR(PREV_IOC_BASE, 1,\ ++ struct v4l2_requestbuffers) ++#define PREV_QUERYBUF _IOWR(PREV_IOC_BASE, 2,\ ++ struct v4l2_buffer) ++#define PREV_SET_PARAM _IOW(PREV_IOC_BASE, 3,\ ++ struct prev_params) ++#define PREV_GET_PARAM _IOWR(PREV_IOC_BASE, 4,\ ++ struct prev_params) ++#define PREV_PREVIEW _IOR(PREV_IOC_BASE, 5, int) ++#define PREV_GET_STATUS _IOR(PREV_IOC_BASE, 6, char) ++#define PREV_GET_CROPSIZE _IOR(PREV_IOC_BASE, 7,\ ++ struct prev_cropsize) ++#define PREV_QUEUEBUF _IOWR(PREV_IOC_BASE, 8,\ ++ struct v4l2_buffer) ++#define PREV_IOC_MAXNR 8 ++ ++#define LUMA_TABLE_SIZE 128 ++#define GAMMA_TABLE_SIZE 1024 ++#define CFA_COEFF_TABLE_SIZE 576 ++#define NOISE_FILTER_TABLE_SIZE 256 ++ ++#define MAX_IMAGE_WIDTH 3300 ++ ++#define PREV_INWIDTH_8BIT 0 /* pixel width of 8 bits */ ++#define PREV_INWIDTH_10BIT 1 /* pixel width of 10 bits */ ++ ++#define PREV_32BYTES_ALIGN_MASK 0xFFFFFFE0 ++#define PREV_16PIX_ALIGN_MASK 0xFFFFFFF0 ++ ++/** ++ * struct prev_rgbblending - Structure for RGB2RGB blending parameters ++ * @blending: Color correlation 3x3 matrix. ++ * @offset: Color correlation offsets. ++ */ ++struct prev_rgbblending { ++ short blending[RGB_MAX][RGB_MAX]; /* color correlation 3x3 ++ * matrix. ++ */ ++ short offset[RGB_MAX]; /* color correlation offsets */ ++}; ++ ++/** ++ * struct prev_cfa_coeffs - Structure for CFA coefficients ++ * @hthreshold: Horizontal threshold. ++ * @vthreshold: Vertical threshold. ++ * @coeffs: CFA coefficients ++ */ ++struct prev_cfa_coeffs { ++ char hthreshold, vthreshold; ++ int coeffs[CFA_COEFF_TABLE_SIZE]; ++}; ++ ++/** ++ * struct prev_gamma_coeffs - Structure for Gamma Coefficients ++ * @red: Table of gamma correction values for red color. ++ * @green: Table of gamma correction values for green color. ++ * @blue: Table of gamma correction values for blue color. ++ */ ++struct prev_gamma_coeffs { ++ unsigned char red[GAMMA_TABLE_SIZE]; ++ unsigned char green[GAMMA_TABLE_SIZE]; ++ unsigned char blue[GAMMA_TABLE_SIZE]; ++}; ++ ++/** ++ * struct prev_noiseflt_coeffs - Structure for Noise Filter Coefficients. ++ * @noise: Noise filter table. ++ * @strength: Used to find out weighted average. ++ */ ++struct prev_noiseflt_coeffs { ++ unsigned char noise[NOISE_FILTER_TABLE_SIZE]; ++ unsigned char strength; ++}; ++ ++/** ++ * struct prev_chroma_spr - Structure for Chroma Suppression. ++ * @hpfy: High passed version of Y or normal Y. ++ * @threshold: Threshold for chroma suppress. ++ * @gain: Chroma suppression gain ++ */ ++struct prev_chroma_spr { ++ unsigned char hpfy; ++ char threshold; ++ unsigned char gain; ++}; ++ ++/** ++ * struct prev_status - Structure to know status of the hardware ++ * @hw_busy: Flag to indicate if Hardware is Busy. ++ */ ++struct prev_status { ++ char hw_busy; ++}; ++ ++/** ++ * struct prev_cropsize - Structure to know crop size. ++ * @hcrop: Horizontal size of crop window. ++ * @vcrop: Vertical size of crop window. ++ */ ++struct prev_cropsize { ++ int hcrop; ++ int vcrop; ++}; ++ ++/** ++ * struct prev_device - Global device information structure. ++ * @params: Pointer to structure containing preview parameters. ++ * @opened: State of the device. ++ * @wfc: Wait for completion. Used for locking operations. ++ * @prevwrap_mutex: Mutex for preview wrapper use. ++ * @vbq_lock: Spinlock for videobuf queues. ++ * @vbq_ops: Videobuf queue operations ++ * @isp_addr_read: Input/Output address ++ */ ++struct prev_device { ++ struct prev_params *params; ++ unsigned char opened; ++ struct completion wfc; ++ struct mutex prevwrap_mutex; /* For generic internal use */ ++ spinlock_t vbq_lock; /* For videobuffer queue handling */ ++ struct videobuf_queue_ops vbq_ops; ++ dma_addr_t isp_addr_read; ++}; ++ ++/** ++ * struct prev_fh - Per-filehandle data structure ++ * @type: Used buffer type. ++ * @vbq: Videobuffer queue. ++ * @device: Pointer to device information structure. ++ */ ++struct prev_fh { ++ enum v4l2_buf_type type; ++ struct videobuf_queue vbq; ++ struct prev_device *device; ++}; ++#endif +diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c +new file mode 100644 +index 0000000..54bc425 +--- /dev/null ++++ b/drivers/media/video/isp/omap_resizer.c +@@ -0,0 +1,1634 @@ ++/* ++ * drivers/media/video/isp/omap_resizer.c ++ * ++ * Wrapper for Resizer module in TI's OMAP3430 ISP ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * ++ * Contributors: ++ * Sergio Aguirre <saaguirre@ti.com> ++ * Troy Laramy <t-laramy@ti.com> ++ * ++ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++#include <linux/mutex.h> ++#include <linux/cdev.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/uaccess.h> ++#include <media/v4l2-dev.h> ++#include <asm/cacheflush.h> ++ ++#include "isp.h" ++#include "ispmmu.h" ++#include "ispreg.h" ++#include "ispresizer.h" ++#include <linux/omap_resizer.h> ++ ++#define OMAP_REZR_NAME "omap-resizer" ++ ++/* Defines and Constants*/ ++#define MAX_CHANNELS 16 ++#define MAX_IMAGE_WIDTH 2047 ++#define MAX_IMAGE_WIDTH_HIGH 2047 ++#define ALIGNMENT 16 ++#define CHANNEL_BUSY 1 ++#define CHANNEL_FREE 0 ++#define PIXEL_EVEN 2 ++#define RATIO_MULTIPLIER 256 ++/* Bit position Macro */ ++/* macro for bit set and clear */ ++#define BITSET(variable, bit) ((variable) | (1 << bit)) ++#define BITRESET(variable, bit) ((variable) & ~(0x00000001 << (bit))) ++#define SET_BIT_INPUTRAM 28 ++#define SET_BIT_CBLIN 29 ++#define SET_BIT_INPTYP 27 ++#define SET_BIT_YCPOS 26 ++#define INPUT_RAM 1 ++#define UP_RSZ_RATIO 64 ++#define DOWN_RSZ_RATIO 512 ++#define UP_RSZ_RATIO1 513 ++#define DOWN_RSZ_RATIO1 1024 ++#define RSZ_IN_SIZE_VERT_SHIFT 16 ++#define MAX_HORZ_PIXEL_8BIT 31 ++#define MAX_HORZ_PIXEL_16BIT 15 ++#define NUM_PHASES 8 ++#define NUM_TAPS 4 ++#define NUM_D2PH 4 /* for downsampling * 2+x ~ 4x, ++ * number of phases ++ */ ++#define NUM_D2TAPS 7 /* for downsampling * 2+x ~ 4x, ++ * number of taps ++ */ ++#define ALIGN32 32 ++#define MAX_COEF_COUNTER 16 ++#define COEFF_ADDRESS_OFFSET 0x04 ++ ++/* Global structure which contains information about number of channels ++ and protection variables */ ++struct device_params { ++ ++ unsigned char opened; /* state of the device */ ++ struct completion compl_isr; /* Completion for interrupt */ ++ struct mutex reszwrap_mutex; /* Semaphore for array */ ++ ++ struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */ ++}; ++ ++/* Register mapped structure which contains the every register ++ information */ ++struct resizer_config { ++ u32 rsz_pcr; /* pcr register mapping ++ * variable. ++ */ ++ u32 rsz_in_start; /* in_start register mapping ++ * variable. ++ */ ++ u32 rsz_in_size; /* in_size register mapping ++ * variable. ++ */ ++ u32 rsz_out_size; /* out_size register mapping ++ * variable. ++ */ ++ u32 rsz_cnt; /* rsz_cnt register mapping ++ * variable. ++ */ ++ u32 rsz_sdr_inadd; /* sdr_inadd register mapping ++ * variable. ++ */ ++ u32 rsz_sdr_inoff; /* sdr_inoff register mapping ++ * variable. ++ */ ++ u32 rsz_sdr_outadd; /* sdr_outadd register mapping ++ * variable. ++ */ ++ u32 rsz_sdr_outoff; /* sdr_outbuff register ++ * mapping variable. ++ */ ++ u32 rsz_coeff_horz[16]; /* horizontal coefficients ++ * mapping array. ++ */ ++ u32 rsz_coeff_vert[16]; /* vertical coefficients ++ * mapping array. ++ */ ++ u32 rsz_yehn; /* yehn(luma)register mapping ++ * variable. ++ */ ++}; ++ ++struct rsz_mult { ++ int in_hsize; /* input frame horizontal ++ * size. ++ */ ++ int in_vsize; /* input frame vertical size. ++ */ ++ int out_hsize; /* output frame horizontal ++ * size. ++ */ ++ int out_vsize; /* output frame vertical ++ * size. ++ */ ++ int in_pitch; /* offset between two rows of ++ * input frame. ++ */ ++ int out_pitch; /* offset between two rows of ++ * output frame. ++ */ ++ int end_hsize; ++ int end_vsize; ++ int num_htap; /* 0 = 7tap; 1 = 4tap */ ++ int num_vtap; /* 0 = 7tap; 1 = 4tap */ ++ int active; ++ int inptyp; ++ int vrsz; ++ int hrsz; ++ int hstph; /* for specifying horizontal ++ * starting phase. ++ */ ++ int vstph; ++ int pix_fmt; /* # defined, UYVY or YUYV. */ ++ int cbilin; /* # defined, filter with luma ++ * or bi-linear. ++ */ ++ u16 tap4filt_coeffs[32]; /* horizontal filter ++ * coefficients. ++ */ ++ u16 tap7filt_coeffs[32]; /* vertical filter ++ * coefficients. ++ */ ++}; ++/* Channel specific structure contains information regarding ++ the every channel */ ++struct channel_config { ++ struct resizer_config register_config; /* Instance of register set ++ * mapping structure ++ */ ++ int status; /* Specifies whether the ++ * channel is busy or not ++ */ ++ struct mutex chanprotection_mutex; ++ enum config_done config_state; ++ u8 input_buf_index; ++ u8 output_buf_index; ++ ++}; ++ ++/* per-filehandle data structure */ ++struct rsz_fh { ++ struct rsz_params *params; ++ struct channel_config *config; ++ struct rsz_mult *multipass; /* Multipass to support ++ * resizing ration outside ++ * of 0.25x to 4x ++ */ ++ spinlock_t vbq_lock; /* spinlock for videobuf ++ * queues. ++ */ ++ enum v4l2_buf_type type; ++ 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 ++ */ ++}; ++ ++static struct device_params *device_config; ++static struct device *rsz_device; ++static int rsz_major = -1; ++/* functions declaration */ ++static void rsz_hardware_setup(struct channel_config *rsz_conf_chan); ++static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *, ++ struct channel_config *); ++static int rsz_get_params(struct rsz_params *, struct channel_config *); ++static void rsz_copy_data(struct rsz_mult *multipass, ++ struct rsz_params *params); ++static void rsz_isr(unsigned long status, isp_vbq_callback_ptr arg1, ++ void *arg2); ++static void rsz_calculate_crop(struct channel_config *rsz_conf_chan, ++ struct rsz_cropsize *cropsize); ++static int rsz_set_multipass(struct rsz_mult *multipass, ++ struct channel_config *rsz_conf_chan); ++static int rsz_set_ratio(struct rsz_mult *multipass, ++ struct channel_config *rsz_conf_chan); ++static void rsz_config_ratio(struct rsz_mult *multipass, ++ struct channel_config *rsz_conf_chan); ++ ++/** ++ * rsz_hardware_setup - Sets hardware configuration registers ++ * @rsz_conf_chan: Structure containing channel configuration ++ * ++ * Set hardware configuration registers ++ **/ ++static void rsz_hardware_setup(struct channel_config *rsz_conf_chan) ++{ ++ int coeffcounter; ++ int coeffoffset = 0; ++ ++ omap_writel(rsz_conf_chan->register_config.rsz_cnt, ++ OMAP3ISP_RESZ_REG(ISPRSZ_CNT)); ++ ++ omap_writel(rsz_conf_chan->register_config.rsz_in_start, ++ OMAP3ISP_RESZ_REG(ISPRSZ_IN_START)); ++ omap_writel(rsz_conf_chan->register_config.rsz_in_size, ++ OMAP3ISP_RESZ_REG(ISPRSZ_IN_SIZE)); ++ ++ omap_writel(rsz_conf_chan->register_config.rsz_out_size, ++ OMAP3ISP_RESZ_REG(ISPRSZ_OUT_SIZE)); ++ omap_writel(rsz_conf_chan->register_config.rsz_sdr_inadd, ++ OMAP3ISP_RESZ_REG(ISPRSZ_SDR_INADD)); ++ omap_writel(rsz_conf_chan->register_config.rsz_sdr_inoff, ++ OMAP3ISP_RESZ_REG(ISPRSZ_SDR_INOFF)); ++ omap_writel(rsz_conf_chan->register_config.rsz_sdr_outadd, ++ OMAP3ISP_RESZ_REG(ISPRSZ_SDR_OUTADD)); ++ omap_writel(rsz_conf_chan->register_config.rsz_sdr_outoff, ++ OMAP3ISP_RESZ_REG(ISPRSZ_SDR_OUTOFF)); ++ omap_writel(rsz_conf_chan->register_config.rsz_yehn, OMAP3ISP_RESZ_REG(ISPRSZ_YENH)); ++ ++ for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER; ++ coeffcounter++) { ++ omap_writel(rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter], ++ OMAP3ISP_RESZ_REG(ISPRSZ_HFILT10 ++ + coeffoffset)); ++ ++ omap_writel(rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter], ++ OMAP3ISP_RESZ_REG(ISPRSZ_VFILT10 ++ + coeffoffset)); ++ coeffoffset = coeffoffset + COEFF_ADDRESS_OFFSET; ++ } ++} ++ ++/** ++ * rsz_start - Enables Resizer Wrapper ++ * @arg: Currently not used. ++ * @device: Structure containing ISP resizer wrapper global information ++ * ++ * 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 ++ * on the value of the blocking argument in the rsz_resize structure. If it is ++ * blocking, the status of the task can be checked by calling ioctl ++ * RSZ_G_STATUS. Only one task can be outstanding for each logical channel. ++ * ++ * Returns 0 if successful, or -EINVAL if could not set callback for RSZR IRQ ++ * event or the state of the channel is not configured. ++ **/ ++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; ++ int ret; ++ ++ if (rsz_conf_chan->config_state) { ++ dev_err(rsz_device, "State not configured \n"); ++ goto err_einval; ++ } ++ ++ rsz_conf_chan->status = CHANNEL_BUSY; ++ ++ rsz_hardware_setup(rsz_conf_chan); ++ ++ if (isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL, ++ (void *)NULL)) { ++ dev_err(rsz_device, "No callback for RSZR\n"); ++ goto err_einval; ++ } ++mult: ++ device_config->compl_isr.done = 0; ++ ++ ispresizer_enable(1); ++ ++ ret = wait_for_completion_interruptible(&device_config->compl_isr); ++ if (ret != 0) { ++ dev_dbg(rsz_device, "Unexpected exit from " ++ "wait_for_completion_interruptible\n"); ++ wait_for_completion(&device_config->compl_isr); ++ } ++ ++ if (multipass->active) { ++ rsz_set_multipass(multipass, rsz_conf_chan); ++ 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); ++ ++ return 0; ++err_einval: ++ return -EINVAL; ++} ++ ++/** ++ * rsz_set_multipass - Set resizer multipass ++ * @rsz_conf_chan: Structure containing channel configuration ++ * ++ * Returns always 0 ++ **/ ++static int rsz_set_multipass(struct rsz_mult *multipass, ++ struct channel_config *rsz_conf_chan) ++{ ++ multipass->in_hsize = multipass->out_hsize; ++ multipass->in_vsize = multipass->out_vsize; ++ multipass->out_hsize = multipass->end_hsize; ++ multipass->out_vsize = multipass->end_vsize; ++ ++ multipass->out_pitch = (multipass->inptyp ? multipass->out_hsize ++ : (multipass->out_hsize * 2)); ++ multipass->in_pitch = (multipass->inptyp ? multipass->in_hsize ++ : (multipass->in_hsize * 2)); ++ ++ rsz_set_ratio(multipass, rsz_conf_chan); ++ rsz_config_ratio(multipass, rsz_conf_chan); ++ rsz_hardware_setup(rsz_conf_chan); ++ return 0; ++} ++ ++/** ++ * rsz_copy_data - Copy data ++ * @params: Structure containing the Resizer Wrapper parameters ++ * ++ * Copy data ++ **/ ++static void rsz_copy_data(struct rsz_mult *multipass, struct rsz_params *params) ++{ ++ int i; ++ multipass->in_hsize = params->in_hsize; ++ multipass->in_vsize = params->in_vsize; ++ multipass->out_hsize = params->out_hsize; ++ multipass->out_vsize = params->out_vsize; ++ multipass->end_hsize = params->out_hsize; ++ multipass->end_vsize = params->out_vsize; ++ multipass->in_pitch = params->in_pitch; ++ multipass->out_pitch = params->out_pitch; ++ multipass->hstph = params->hstph; ++ multipass->vstph = params->vstph; ++ multipass->inptyp = params->inptyp; ++ multipass->pix_fmt = params->pix_fmt; ++ multipass->cbilin = params->cbilin; ++ ++ for (i = 0; i < 32; i++) { ++ multipass->tap4filt_coeffs[i] = params->tap4filt_coeffs[i]; ++ multipass->tap7filt_coeffs[i] = params->tap7filt_coeffs[i]; ++ } ++} ++ ++/** ++ * rsz_set_params - Set parameters for resizer wrapper ++ * @params: Structure containing the Resizer Wrapper parameters ++ * @rsz_conf_chan: Structure containing channel configuration ++ * ++ * Used to set the parameters of the Resizer hardware, including input and ++ * output image size, horizontal and vertical poly-phase filter coefficients, ++ * luma enchancement filter coefficients, etc. ++ **/ ++static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *params, ++ struct channel_config *rsz_conf_chan) ++{ ++ int mul = 1; ++ if ((params->yenh_params.type < 0) || (params->yenh_params.type > 2)) { ++ dev_err(rsz_device, "rsz_set_params: Wrong yenh type\n"); ++ return -EINVAL; ++ } ++ if ((params->in_vsize <= 0) || (params->in_hsize <= 0) || ++ (params->out_vsize <= 0) || (params->out_hsize <= 0) || ++ (params->in_pitch <= 0) || (params->out_pitch <= 0)) { ++ dev_err(rsz_device, "rsz_set_params: Invalid size params\n"); ++ return -EINVAL; ++ } ++ if ((params->inptyp != RSZ_INTYPE_YCBCR422_16BIT) && ++ (params->inptyp != RSZ_INTYPE_PLANAR_8BIT)) { ++ dev_err(rsz_device, "rsz_set_params: Invalid input type\n"); ++ return -EINVAL; ++ } ++ if ((params->pix_fmt != RSZ_PIX_FMT_UYVY) && ++ (params->pix_fmt != RSZ_PIX_FMT_YUYV)) { ++ dev_err(rsz_device, "rsz_set_params: Invalid pixel format\n"); ++ return -EINVAL; ++ } ++ if (params->inptyp == RSZ_INTYPE_YCBCR422_16BIT) ++ mul = 2; ++ else ++ mul = 1; ++ if (params->in_pitch < (params->in_hsize * mul)) { ++ dev_err(rsz_device, "rsz_set_params: Pitch is incorrect\n"); ++ return -EINVAL; ++ } ++ if (params->out_pitch < (params->out_hsize * mul)) { ++ dev_err(rsz_device, "rsz_set_params: Out pitch cannot be less" ++ " than out hsize\n"); ++ return -EINVAL; ++ } ++ /* Output H size should be even */ ++ if ((params->out_hsize % PIXEL_EVEN) != 0) { ++ dev_err(rsz_device, "rsz_set_params: Output H size should" ++ " be even\n"); ++ return -EINVAL; ++ } ++ if (params->horz_starting_pixel < 0) { ++ dev_err(rsz_device, "rsz_set_params: Horz start pixel cannot" ++ " be less than zero\n"); ++ return -EINVAL; ++ } ++ ++ rsz_copy_data(multipass, params); ++ if (0 != rsz_set_ratio(multipass, rsz_conf_chan)) ++ goto err_einval; ++ ++ if (params->yenh_params.type) { ++ if ((multipass->num_htap && multipass->out_hsize > ++ 1280) || ++ (!multipass->num_htap && multipass->out_hsize > ++ 640)) ++ goto err_einval; ++ } ++ ++ if (INPUT_RAM) ++ params->vert_starting_pixel = 0; ++ ++ rsz_conf_chan->register_config.rsz_in_start = ++ (params->vert_starting_pixel ++ << ISPRSZ_IN_SIZE_VERT_SHIFT) ++ & ISPRSZ_IN_SIZE_VERT_MASK; ++ ++ if (params->inptyp == RSZ_INTYPE_PLANAR_8BIT) { ++ if (params->horz_starting_pixel > MAX_HORZ_PIXEL_8BIT) ++ goto err_einval; ++ } ++ if (params->inptyp == RSZ_INTYPE_YCBCR422_16BIT) { ++ if (params->horz_starting_pixel > MAX_HORZ_PIXEL_16BIT) ++ goto err_einval; ++ } ++ ++ rsz_conf_chan->register_config.rsz_in_start |= ++ params->horz_starting_pixel ++ & ISPRSZ_IN_START_HORZ_ST_MASK; ++ ++ rsz_conf_chan->register_config.rsz_yehn = ++ (params->yenh_params.type ++ << ISPRSZ_YENH_ALGO_SHIFT) ++ & ISPRSZ_YENH_ALGO_MASK; ++ ++ if (params->yenh_params.type) { ++ rsz_conf_chan->register_config.rsz_yehn |= ++ params->yenh_params.core ++ & ISPRSZ_YENH_CORE_MASK; ++ ++ rsz_conf_chan->register_config.rsz_yehn |= ++ (params->yenh_params.gain ++ << ISPRSZ_YENH_GAIN_SHIFT) ++ & ISPRSZ_YENH_GAIN_MASK; ++ ++ rsz_conf_chan->register_config.rsz_yehn |= ++ (params->yenh_params.slop ++ << ISPRSZ_YENH_SLOP_SHIFT) ++ & ISPRSZ_YENH_SLOP_MASK; ++ } ++ ++ rsz_config_ratio(multipass, rsz_conf_chan); ++ ++ rsz_conf_chan->config_state = STATE_CONFIGURED; ++ ++ return 0; ++err_einval: ++ return -EINVAL; ++} ++ ++/** ++ * rsz_set_ratio - Set ratio ++ * @rsz_conf_chan: Structure containing channel configuration ++ * ++ * Returns 0 if successful, -EINVAL if invalid output size, upscaling ratio is ++ * being requested, or other ratio configuration value is out of bounds ++ **/ ++static int rsz_set_ratio(struct rsz_mult *multipass, ++ struct channel_config *rsz_conf_chan) ++{ ++ int alignment = 0; ++ ++ rsz_conf_chan->register_config.rsz_cnt = 0; ++ ++ if ((multipass->out_hsize > MAX_IMAGE_WIDTH) || ++ (multipass->out_vsize > MAX_IMAGE_WIDTH)) { ++ dev_err(rsz_device, "Invalid output size!"); ++ goto err_einval; ++ } ++ if (multipass->cbilin) { ++ rsz_conf_chan->register_config.rsz_cnt = ++ BITSET(rsz_conf_chan->register_config.rsz_cnt, ++ SET_BIT_CBLIN); ++ } ++ if (INPUT_RAM) { ++ rsz_conf_chan->register_config.rsz_cnt = ++ BITSET(rsz_conf_chan->register_config.rsz_cnt, ++ SET_BIT_INPUTRAM); ++ } ++ if (multipass->inptyp == RSZ_INTYPE_PLANAR_8BIT) { ++ rsz_conf_chan->register_config.rsz_cnt = ++ BITSET(rsz_conf_chan->register_config.rsz_cnt, ++ SET_BIT_INPTYP); ++ } else { ++ rsz_conf_chan->register_config.rsz_cnt = ++ BITRESET(rsz_conf_chan->register_config. ++ rsz_cnt, SET_BIT_INPTYP); ++ ++ if (multipass->pix_fmt == RSZ_PIX_FMT_UYVY) { ++ rsz_conf_chan->register_config.rsz_cnt = ++ BITRESET(rsz_conf_chan->register_config. ++ rsz_cnt, SET_BIT_YCPOS); ++ } else if (multipass->pix_fmt == RSZ_PIX_FMT_YUYV) { ++ rsz_conf_chan->register_config.rsz_cnt = ++ BITSET(rsz_conf_chan->register_config. ++ rsz_cnt, SET_BIT_YCPOS); ++ } ++ ++ } ++ multipass->vrsz = ++ (multipass->in_vsize * RATIO_MULTIPLIER) / multipass->out_vsize; ++ multipass->hrsz = ++ (multipass->in_hsize * RATIO_MULTIPLIER) / multipass->out_hsize; ++ if (UP_RSZ_RATIO > multipass->vrsz || UP_RSZ_RATIO > multipass->hrsz) { ++ dev_err(rsz_device, "Upscaling ratio not supported!"); ++ goto err_einval; ++ } ++ multipass->vrsz = (multipass->in_vsize - NUM_D2TAPS) * RATIO_MULTIPLIER ++ / (multipass->out_vsize - 1); ++ multipass->hrsz = ((multipass->in_hsize - NUM_D2TAPS) ++ * RATIO_MULTIPLIER) / ++ (multipass->out_hsize - 1); ++ ++ if (multipass->hrsz <= 512) { ++ multipass->hrsz = (multipass->in_hsize - NUM_TAPS) ++ * RATIO_MULTIPLIER ++ / (multipass->out_hsize - 1); ++ if (multipass->hrsz < 64) ++ multipass->hrsz = 64; ++ if (multipass->hrsz > 512) ++ multipass->hrsz = 512; ++ if (multipass->hstph > NUM_PHASES) ++ goto err_einval; ++ multipass->num_htap = 1; ++ } else if (multipass->hrsz >= 513 && multipass->hrsz <= 1024) { ++ if (multipass->hstph > NUM_D2PH) ++ goto err_einval; ++ multipass->num_htap = 0; ++ } ++ ++ if (multipass->vrsz <= 512) { ++ multipass->vrsz = (multipass->in_vsize - NUM_TAPS) ++ * RATIO_MULTIPLIER ++ / (multipass->out_vsize - 1); ++ if (multipass->vrsz < 64) ++ multipass->vrsz = 64; ++ if (multipass->vrsz > 512) ++ multipass->vrsz = 512; ++ if (multipass->vstph > NUM_PHASES) ++ goto err_einval; ++ multipass->num_vtap = 1; ++ } else if (multipass->vrsz >= 513 && multipass->vrsz <= 1024) { ++ if (multipass->vstph > NUM_D2PH) ++ goto err_einval; ++ multipass->num_vtap = 0; ++ } ++ ++ if ((multipass->in_pitch) % ALIGN32) { ++ dev_err(rsz_device, "Invalid input pitch: %d \n", ++ multipass->in_pitch); ++ goto err_einval; ++ } ++ if ((multipass->out_pitch) % ALIGN32) { ++ dev_err(rsz_device, "Invalid output pitch %d \n", ++ multipass->out_pitch); ++ goto err_einval; ++ } ++ ++ if (multipass->vrsz < 256 && ++ (multipass->in_vsize < multipass->out_vsize)) { ++ if (multipass->inptyp == RSZ_INTYPE_PLANAR_8BIT) ++ alignment = ALIGNMENT; ++ else if (multipass->inptyp == RSZ_INTYPE_YCBCR422_16BIT) ++ alignment = (ALIGNMENT / 2); ++ else ++ dev_err(rsz_device, "Invalid input type\n"); ++ ++ if (!(((multipass->out_hsize % PIXEL_EVEN) == 0) ++ && (multipass->out_hsize % alignment) == 0)) { ++ dev_err(rsz_device, "wrong hsize\n"); ++ goto err_einval; ++ } ++ } ++ if (multipass->hrsz >= 64 && multipass->hrsz <= 1024) { ++ if (multipass->out_hsize > MAX_IMAGE_WIDTH) { ++ dev_err(rsz_device, "wrong width\n"); ++ goto err_einval; ++ } ++ multipass->active = 0; ++ ++ } else if (multipass->hrsz > 1024) { ++ if (multipass->out_hsize > MAX_IMAGE_WIDTH) { ++ dev_err(rsz_device, "wrong width\n"); ++ goto err_einval; ++ } ++ if (multipass->hstph > NUM_D2PH) ++ goto err_einval; ++ multipass->num_htap = 0; ++ multipass->out_hsize = multipass->in_hsize * 256 / 1024; ++ if (multipass->out_hsize % ALIGN32) { ++ multipass->out_hsize += ++ abs((multipass->out_hsize % ALIGN32) - ALIGN32); ++ } ++ multipass->out_pitch = ((multipass->inptyp) ? ++ multipass->out_hsize : ++ (multipass->out_hsize * 2)); ++ multipass->hrsz = ((multipass->in_hsize - NUM_D2TAPS) ++ * RATIO_MULTIPLIER) ++ / (multipass->out_hsize - 1); ++ multipass->active = 1; ++ ++ } ++ ++ if (multipass->vrsz > 1024) { ++ if (multipass->out_vsize > MAX_IMAGE_WIDTH_HIGH) { ++ dev_err(rsz_device, "wrong width\n"); ++ goto err_einval; ++ } ++ ++ multipass->out_vsize = multipass->in_vsize * 256 / 1024; ++ multipass->vrsz = ((multipass->in_vsize - NUM_D2TAPS) ++ * RATIO_MULTIPLIER) ++ / (multipass->out_vsize - 1); ++ multipass->active = 1; ++ multipass->num_vtap = 0; ++ ++ } ++ rsz_conf_chan->register_config.rsz_out_size = ++ multipass->out_hsize ++ & ISPRSZ_OUT_SIZE_HORZ_MASK; ++ ++ rsz_conf_chan->register_config.rsz_out_size |= ++ (multipass->out_vsize ++ << ISPRSZ_OUT_SIZE_VERT_SHIFT) ++ & ISPRSZ_OUT_SIZE_VERT_MASK; ++ ++ rsz_conf_chan->register_config.rsz_sdr_inoff = ++ multipass->in_pitch ++ & ISPRSZ_SDR_INOFF_OFFSET_MASK; ++ ++ rsz_conf_chan->register_config.rsz_sdr_outoff = ++ multipass->out_pitch ++ & ISPRSZ_SDR_OUTOFF_OFFSET_MASK; ++ ++ if (multipass->hrsz >= 64 && multipass->hrsz <= 512) { ++ if (multipass->hstph > NUM_PHASES) ++ goto err_einval; ++ } else if (multipass->hrsz >= 64 && multipass->hrsz <= 512) { ++ if (multipass->hstph > NUM_D2PH) ++ goto err_einval; ++ } ++ ++ rsz_conf_chan->register_config.rsz_cnt |= ++ (multipass->hstph ++ << ISPRSZ_CNT_HSTPH_SHIFT) ++ & ISPRSZ_CNT_HSTPH_MASK; ++ ++ if (multipass->vrsz >= 64 && multipass->hrsz <= 512) { ++ if (multipass->vstph > NUM_PHASES) ++ goto err_einval; ++ } else if (multipass->vrsz >= 64 && multipass->vrsz <= 512) { ++ if (multipass->vstph > NUM_D2PH) ++ goto err_einval; ++ } ++ ++ rsz_conf_chan->register_config.rsz_cnt |= ++ (multipass->vstph ++ << ISPRSZ_CNT_VSTPH_SHIFT) ++ & ISPRSZ_CNT_VSTPH_MASK; ++ ++ rsz_conf_chan->register_config.rsz_cnt |= ++ (multipass->hrsz - 1) ++ & ISPRSZ_CNT_HRSZ_MASK; ++ ++ rsz_conf_chan->register_config.rsz_cnt |= ++ ((multipass->vrsz - 1) ++ << ISPRSZ_CNT_VRSZ_SHIFT) ++ & ISPRSZ_CNT_VRSZ_MASK; ++ ++ return 0; ++err_einval: ++ return -EINVAL; ++} ++ ++/** ++ * rsz_config_ratio - Configure ratio ++ * @rsz_conf_chan: Structure containing channel configuration ++ * ++ * Configure ratio ++ **/ ++static void rsz_config_ratio(struct rsz_mult *multipass, ++ struct channel_config *rsz_conf_chan) ++{ ++ int hsize; ++ int vsize; ++ int coeffcounter; ++ ++ if (multipass->hrsz <= 512) { ++ hsize = ((32 * multipass->hstph + (multipass->out_hsize - 1) ++ * multipass->hrsz + 16) >> 8) + 7; ++ } else { ++ hsize = ((64 * multipass->hstph + (multipass->out_hsize - 1) ++ * multipass->hrsz + 32) >> 8) + 7; ++ } ++ if (multipass->vrsz <= 512) { ++ vsize = ((32 * multipass->vstph + (multipass->out_vsize - 1) ++ * multipass->vrsz + 16) >> 8) + 4; ++ } else { ++ vsize = ((64 * multipass->vstph + (multipass->out_vsize - 1) ++ * multipass->vrsz + 32) >> 8) + 7; ++ } ++ rsz_conf_chan->register_config.rsz_in_size = hsize; ++ ++ rsz_conf_chan->register_config.rsz_in_size |= ++ ((vsize << ISPRSZ_IN_SIZE_VERT_SHIFT) ++ & ISPRSZ_IN_SIZE_VERT_MASK); ++ ++ for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER; ++ coeffcounter++) { ++ if (multipass->num_htap) { ++ rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter] = ++ (multipass->tap4filt_coeffs[2 ++ * coeffcounter] ++ & ISPRSZ_HFILT10_COEF0_MASK); ++ rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter] |= ++ ((multipass->tap4filt_coeffs[2 ++ * coeffcounter + 1] ++ << ISPRSZ_HFILT10_COEF1_SHIFT) ++ & ISPRSZ_HFILT10_COEF1_MASK); ++ } else { ++ rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter] = ++ (multipass->tap7filt_coeffs[2 ++ * coeffcounter] ++ & ISPRSZ_HFILT10_COEF0_MASK); ++ ++ rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter] |= ++ ((multipass->tap7filt_coeffs[2 ++ * coeffcounter + 1] ++ << ISPRSZ_HFILT10_COEF1_SHIFT) ++ & ISPRSZ_HFILT10_COEF1_MASK); ++ } ++ ++ if (multipass->num_vtap) { ++ rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter] = ++ (multipass->tap4filt_coeffs[2 ++ * coeffcounter] ++ & ISPRSZ_VFILT10_COEF0_MASK); ++ ++ rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter] |= ++ ((multipass->tap4filt_coeffs[2 ++ * coeffcounter + 1] ++ << ISPRSZ_VFILT10_COEF1_SHIFT) & ++ ISPRSZ_VFILT10_COEF1_MASK); ++ } else { ++ rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter] = ++ (multipass->tap7filt_coeffs[2 ++ * coeffcounter] ++ & ISPRSZ_VFILT10_COEF0_MASK); ++ rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter] |= ++ ((multipass->tap7filt_coeffs[2 ++ * coeffcounter + 1] ++ << ISPRSZ_VFILT10_COEF1_SHIFT) ++ & ISPRSZ_VFILT10_COEF1_MASK); ++ } ++ } ++} ++ ++/** ++ * rsz_get_params - Gets the parameter values ++ * @params: Structure containing the Resizer Wrapper parameters ++ * @rsz_conf_chan: Structure containing channel configuration ++ * ++ * Used to get the Resizer hardware settings associated with the ++ * current logical channel represented by fd. ++ **/ ++static int rsz_get_params(struct rsz_params *params, ++ struct channel_config *rsz_conf_chan) ++{ ++ int coeffcounter; ++ ++ if (rsz_conf_chan->config_state) { ++ dev_err(rsz_device, "state not configured\n"); ++ return -EINVAL; ++ } ++ ++ params->in_hsize = rsz_conf_chan->register_config.rsz_in_size ++ & ISPRSZ_IN_SIZE_HORZ_MASK; ++ params->in_vsize = (rsz_conf_chan->register_config.rsz_in_size ++ & ISPRSZ_IN_SIZE_VERT_MASK) ++ >> ISPRSZ_IN_SIZE_VERT_SHIFT; ++ ++ params->in_pitch = rsz_conf_chan->register_config.rsz_sdr_inoff ++ & ISPRSZ_SDR_INOFF_OFFSET_MASK; ++ ++ params->out_hsize = rsz_conf_chan->register_config.rsz_out_size ++ & ISPRSZ_OUT_SIZE_HORZ_MASK; ++ ++ params->out_vsize = (rsz_conf_chan->register_config.rsz_out_size ++ & ISPRSZ_OUT_SIZE_VERT_MASK) ++ >> ISPRSZ_OUT_SIZE_VERT_SHIFT; ++ ++ params->out_pitch = rsz_conf_chan->register_config.rsz_sdr_outoff ++ & ISPRSZ_SDR_OUTOFF_OFFSET_MASK; ++ ++ params->cbilin = (rsz_conf_chan->register_config.rsz_cnt ++ & SET_BIT_CBLIN) >> SET_BIT_CBLIN; ++ ++ params->inptyp = (rsz_conf_chan->register_config.rsz_cnt ++ & ISPRSZ_CNT_INPTYP_MASK) ++ >> SET_BIT_INPTYP; ++ params->horz_starting_pixel = ((rsz_conf_chan->register_config. ++ rsz_in_start ++ & ISPRSZ_IN_START_HORZ_ST_MASK)); ++ params->vert_starting_pixel = ((rsz_conf_chan->register_config. ++ rsz_in_start ++ & ISPRSZ_IN_START_VERT_ST_MASK) ++ >> ISPRSZ_IN_START_VERT_ST_SHIFT); ++ ++ params->hstph = ((rsz_conf_chan->register_config.rsz_cnt ++ & ISPRSZ_CNT_HSTPH_MASK ++ >> ISPRSZ_CNT_HSTPH_SHIFT)); ++ params->vstph = ((rsz_conf_chan->register_config.rsz_cnt ++ & ISPRSZ_CNT_VSTPH_MASK ++ >> ISPRSZ_CNT_VSTPH_SHIFT)); ++ ++ for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER; ++ coeffcounter++) { ++ params->tap4filt_coeffs[2 * coeffcounter] = ++ rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter] ++ & ISPRSZ_HFILT10_COEF0_MASK; ++ ++ params->tap4filt_coeffs[2 * coeffcounter + 1] = ++ (rsz_conf_chan->register_config. ++ rsz_coeff_horz[coeffcounter] ++ & ISPRSZ_HFILT10_COEF1_MASK) ++ >> ISPRSZ_HFILT10_COEF1_SHIFT; ++ ++ params->tap7filt_coeffs[2 * coeffcounter] = ++ rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter] ++ & ISPRSZ_VFILT10_COEF0_MASK; ++ ++ params->tap7filt_coeffs[2 * coeffcounter + 1] = ++ (rsz_conf_chan->register_config. ++ rsz_coeff_vert[coeffcounter] ++ & ISPRSZ_VFILT10_COEF1_MASK) ++ >> ISPRSZ_VFILT10_COEF1_SHIFT; ++ ++ } ++ ++ params->yenh_params.type = (rsz_conf_chan->register_config.rsz_yehn ++ & ISPRSZ_YENH_ALGO_MASK) ++ >> ISPRSZ_YENH_ALGO_SHIFT; ++ ++ params->yenh_params.core = rsz_conf_chan->register_config.rsz_yehn ++ & ISPRSZ_YENH_CORE_MASK; ++ ++ params->yenh_params.gain = (rsz_conf_chan->register_config.rsz_yehn ++ & ISPRSZ_YENH_GAIN_MASK) ++ >> ISPRSZ_YENH_GAIN_SHIFT; ++ ++ params->yenh_params.slop = (rsz_conf_chan->register_config.rsz_yehn ++ & ISPRSZ_YENH_SLOP_MASK) ++ >> ISPRSZ_YENH_SLOP_SHIFT; ++ ++ params->pix_fmt = ((rsz_conf_chan->register_config.rsz_cnt ++ & ISPRSZ_CNT_PIXFMT_MASK) ++ >> SET_BIT_YCPOS); ++ ++ if (params->pix_fmt) ++ params->pix_fmt = RSZ_PIX_FMT_UYVY; ++ else ++ params->pix_fmt = RSZ_PIX_FMT_YUYV; ++ ++ return 0; ++} ++ ++/** ++ * rsz_calculate_crop - Calculate Crop values ++ * @rsz_conf_chan: Structure containing channel configuration ++ * @cropsize: Structure containing crop parameters ++ * ++ * Calculate Crop values ++ **/ ++static void rsz_calculate_crop(struct channel_config *rsz_conf_chan, ++ struct rsz_cropsize *cropsize) ++{ ++ int luma_enable; ++ ++ cropsize->hcrop = 0; ++ cropsize->vcrop = 0; ++ ++ luma_enable = (rsz_conf_chan->register_config.rsz_yehn ++ & ISPRSZ_YENH_ALGO_MASK) ++ >> ISPRSZ_YENH_ALGO_SHIFT; ++ ++ if (luma_enable) ++ cropsize->hcrop += 2; ++} ++ ++/** ++ * rsz_vbq_release - Videobuffer queue release ++ * @q: Structure containing the videobuffer queue file handle, and device ++ * structure which contains the actual configuration. ++ * @vb: Structure containing the videobuffer used for resizer processing. ++ **/ ++static void rsz_vbq_release(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ int i; ++ struct rsz_fh *fh = q->priv_data; ++ ++ 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); ++ } ++ ++ 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); ++ ++} ++ ++/** ++ * rsz_vbq_setup - Sets up the videobuffer size and validates count. ++ * @q: Structure containing the videobuffer queue file handle, and device ++ * structure which contains the actual configuration. ++ * @cnt: Number of buffers requested ++ * @size: Size in bytes of the buffer used for previewing ++ * ++ * Always returns 0. ++ **/ ++static int rsz_vbq_setup(struct videobuf_queue *q, unsigned int *cnt, ++ unsigned int *size) ++{ ++ struct rsz_fh *fh = q->priv_data; ++ struct rsz_mult *multipass = fh->multipass; ++ u32 insize, outsize; ++ ++ spin_lock(&fh->vbq_lock); ++ if (*cnt <= 0) ++ *cnt = VIDEO_MAX_FRAME; ++ ++ if (*cnt > VIDEO_MAX_FRAME) ++ *cnt = VIDEO_MAX_FRAME; ++ ++ outsize = multipass->out_pitch * multipass->out_vsize; ++ insize = multipass->in_pitch * multipass->in_vsize; ++ if (*cnt == 1 && (outsize > insize)) { ++ dev_err(rsz_device, "2 buffers are required for Upscaling " ++ "mode\n"); ++ goto err_einval; ++ } ++ if (!fh->params->in_hsize || !fh->params->in_vsize) { ++ dev_err(rsz_device, "Can't setup buffer size\n"); ++ goto err_einval; ++ } else { ++ if (outsize > insize) ++ *size = outsize; ++ else ++ *size = insize; ++ ++ fh->rsz_bufsize = *size; ++ } ++ spin_unlock(&fh->vbq_lock); ++ ++ return 0; ++err_einval: ++ spin_unlock(&fh->vbq_lock); ++ return -EINVAL; ++} ++ ++/** ++ * rsz_vbq_prepare - Videobuffer is prepared and mmapped. ++ * @q: Structure containing the videobuffer queue file handle, and device ++ * structure which contains the actual configuration. ++ * @vb: Structure containing the videobuffer used for resizer processing. ++ * @field: Type of field to set in videobuffer device. ++ * ++ * Returns 0 if successful, or -EINVAL if buffer couldn't get allocated, or ++ * -EIO if the ISP MMU mapping fails ++ **/ ++static int rsz_vbq_prepare(struct videobuf_queue *q, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ 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); ++ ++ spin_lock(&fh->vbq_lock); ++ if (vb->baddr) { ++ 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; ++ } ++ if (vb->i) { ++ vb->width = fh->params->out_hsize; ++ vb->height = fh->params->out_vsize; ++ } else { ++ vb->width = fh->params->in_hsize; ++ vb->height = fh->params->in_vsize; ++ } ++ ++ vb->field = field; ++ spin_unlock(&fh->vbq_lock); ++ ++ 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 { ++ 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; ++ } ++ } ++ } ++ ++ } ++ ++ 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; ++} ++ ++static void rsz_vbq_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) ++{ ++ return; ++} ++ ++/** ++ * rsz_open - Initializes and opens the Resizer Wrapper ++ * @inode: Inode structure associated with the Resizer Wrapper ++ * @filp: File structure associated with the Resizer Wrapper ++ * ++ * Returns 0 if successful, -EBUSY if its already opened or the ISP module is ++ * not available, or -ENOMEM if its unable to allocate the device in kernel ++ * space memory. ++ **/ ++static int rsz_open(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ struct channel_config *rsz_conf_chan; ++ struct rsz_fh *fh; ++ struct device_params *device = device_config; ++ struct rsz_params *params; ++ struct rsz_mult *multipass; ++ ++ if ((filp->f_flags & O_NONBLOCK) == O_NONBLOCK) { ++ printk(KERN_DEBUG "omap-resizer: Device is opened in " ++ "non blocking mode\n"); ++ } else { ++ printk(KERN_DEBUG "omap-resizer: Device is opened in blocking " ++ "mode\n"); ++ } ++ fh = kzalloc(sizeof(struct rsz_fh), GFP_KERNEL); ++ if (NULL == fh) ++ return -ENOMEM; ++ ++ isp_get(); ++ ++ rsz_conf_chan = kzalloc(sizeof(struct channel_config), GFP_KERNEL); ++ if (rsz_conf_chan == NULL) { ++ dev_err(rsz_device, "\n cannot allocate memory to config"); ++ ret = -ENOMEM; ++ goto err_enomem0; ++ } ++ params = kzalloc(sizeof(struct rsz_params), GFP_KERNEL); ++ if (params == NULL) { ++ dev_err(rsz_device, "\n cannot allocate memory to params"); ++ ret = -ENOMEM; ++ goto err_enomem1; ++ } ++ multipass = kzalloc(sizeof(struct rsz_mult), GFP_KERNEL); ++ if (multipass == NULL) { ++ dev_err(rsz_device, "\n cannot allocate memory to multipass"); ++ ret = -ENOMEM; ++ goto err_enomem2; ++ } ++ ++ fh->multipass = multipass; ++ fh->params = params; ++ fh->config = rsz_conf_chan; ++ ++ if (mutex_lock_interruptible(&device->reszwrap_mutex)) { ++ ret = -EINTR; ++ goto err_enomem2; ++ } ++ device->opened++; ++ mutex_unlock(&device->reszwrap_mutex); ++ ++ rsz_conf_chan->config_state = STATE_NOT_CONFIGURED; ++ rsz_conf_chan->status = CHANNEL_FREE; ++ ++ filp->private_data = fh; ++ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ fh->device = device; ++ ++ videobuf_queue_sg_init(&fh->vbq, &device->vbq_ops, NULL, ++ &fh->vbq_lock, fh->type, ++ V4L2_FIELD_NONE, ++ sizeof(struct videobuf_buffer), fh); ++ ++ spin_lock_init(&fh->vbq_lock); ++ mutex_init(&rsz_conf_chan->chanprotection_mutex); ++ ++ return 0; ++err_enomem2: ++ kfree(params); ++err_enomem1: ++ kfree(rsz_conf_chan); ++err_enomem0: ++ kfree(fh); ++ return ret; ++} ++ ++/** ++ * rsz_release - Releases Resizer Wrapper and frees up allocated memory ++ * @inode: Inode structure associated with the Resizer Wrapper ++ * @filp: File structure associated with the Resizer Wrapper ++ * ++ * Returns 0 if successful, or -EBUSY if channel is being used. ++ **/ ++static int rsz_release(struct inode *inode, struct file *filp) ++{ ++ u32 timeout = 0; ++ struct rsz_fh *fh = filp->private_data; ++ struct channel_config *rsz_conf_chan = fh->config; ++ struct rsz_params *params = fh->params; ++ struct rsz_mult *multipass = fh->multipass; ++ struct videobuf_queue *q = &fh->vbq; ++ ++ while ((rsz_conf_chan->status != CHANNEL_FREE) && (timeout < 20)) { ++ 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; ++ ++ fh->rsz_bufsize = 0; ++ filp->private_data = NULL; ++ ++ kfree(rsz_conf_chan); ++ kfree(params); ++ kfree(multipass); ++ kfree(fh); ++ ++ isp_put(); ++ ++ return 0; ++} ++ ++/** ++ * rsz_mmap - Memory maps the Resizer Wrapper module. ++ * @file: File structure associated with the Resizer Wrapper ++ * @vma: Virtual memory area structure. ++ * ++ * Returns 0 if successful, or returned value by the videobuf_mmap_mapper() ++ * function. ++ **/ ++static int rsz_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct rsz_fh *fh = file->private_data; ++ ++ return videobuf_mmap_mapper(&fh->vbq, vma); ++} ++ ++/** ++ * rsz_ioctl - I/O control function for Resizer Wrapper ++ * @inode: Inode structure associated with the Resizer Wrapper. ++ * @file: File structure associated with the Resizer Wrapper. ++ * @cmd: Type of command to execute. ++ * @arg: Argument to send to requested command. ++ * ++ * Returns 0 if successful, -EBUSY if channel is being used, -1 if bad command ++ * passed or access is denied, -EFAULT if copy_from_user() or copy_to_user() ++ * fails, -EINVAL if parameter validation fails or parameter structure is not ++ * present. ++ **/ ++static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret = 0; ++ struct rsz_fh *fh = file->private_data; ++ struct device_params *device = fh->device; ++ struct channel_config *rsz_conf_chan = fh->config; ++ ++ if ((_IOC_TYPE(cmd) != RSZ_IOC_BASE) ++ || (_IOC_NR(cmd) > RSZ_IOC_MAXNR)) { ++ dev_err(rsz_device, "Bad command value \n"); ++ return -1; ++ } ++ ++ if (_IOC_DIR(cmd) & _IOC_READ) ++ ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); ++ else if (_IOC_DIR(cmd) & _IOC_WRITE) ++ ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); ++ ++ if (ret) { ++ dev_err(rsz_device, "Access denied\n"); ++ return -1; ++ } ++ ++ switch (cmd) { ++ case RSZ_REQBUF: ++ { ++ struct v4l2_requestbuffers req_buf; ++ if (copy_from_user(&req_buf, (struct v4l2_requestbuffers *)arg, ++ sizeof(struct v4l2_requestbuffers))) { ++ return -EFAULT; ++ } ++ if (mutex_lock_interruptible(&rsz_conf_chan-> ++ chanprotection_mutex)) ++ return -EINTR; ++ ret = videobuf_reqbufs(&fh->vbq, (void *)&req_buf); ++ mutex_unlock(&rsz_conf_chan->chanprotection_mutex); ++ break; ++ } ++ case RSZ_QUERYBUF: ++ { ++ struct v4l2_buffer buf; ++ if (copy_from_user(&buf, (struct v4l2_buffer *)arg, ++ sizeof(struct v4l2_buffer))) { ++ return -EFAULT; ++ } ++ if (mutex_lock_interruptible(&rsz_conf_chan-> ++ chanprotection_mutex)) ++ return -EINTR; ++ ret = videobuf_querybuf(&fh->vbq, (void *)&buf); ++ mutex_unlock(&rsz_conf_chan->chanprotection_mutex); ++ if (copy_to_user((struct v4l2_buffer *)arg, &buf, ++ sizeof(struct v4l2_buffer))) ++ return -EFAULT; ++ break; ++ } ++ case RSZ_QUEUEBUF: ++ { ++ struct v4l2_buffer buf; ++ if (copy_from_user(&buf, (struct v4l2_buffer *)arg, ++ sizeof(struct v4l2_buffer))) { ++ return -EFAULT; ++ } ++ if (mutex_lock_interruptible(&rsz_conf_chan-> ++ chanprotection_mutex)) ++ return -EINTR; ++ ret = videobuf_qbuf(&fh->vbq, (void *)&buf); ++ mutex_unlock(&rsz_conf_chan->chanprotection_mutex); ++ break; ++ } ++ case RSZ_S_PARAM: ++ { ++ struct rsz_params *params = fh->params; ++ if (copy_from_user(params, (struct rsz_params *)arg, ++ 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); ++ break; ++ } ++ case RSZ_G_PARAM: ++ ret = rsz_get_params((struct rsz_params *)arg, rsz_conf_chan); ++ break; ++ ++ case RSZ_G_STATUS: ++ { ++ struct rsz_status *status; ++ status = (struct rsz_status *)arg; ++ status->chan_busy = rsz_conf_chan->status; ++ status->hw_busy = ispresizer_busy(); ++ status->src = INPUT_RAM; ++ break; ++ } ++ case RSZ_RESIZE: ++ if (file->f_flags & O_NONBLOCK) { ++ if (ispresizer_busy()) ++ return -EBUSY; ++ else { ++ if (!mutex_trylock(&device->reszwrap_mutex)) ++ return -EBUSY; ++ } ++ } else { ++ if (mutex_lock_interruptible(&device->reszwrap_mutex)) ++ return -EINTR; ++ } ++ ret = rsz_start((int *)arg, fh); ++ mutex_unlock(&device->reszwrap_mutex); ++ break; ++ case RSZ_GET_CROPSIZE: ++ rsz_calculate_crop(rsz_conf_chan, (struct rsz_cropsize *)arg); ++ break; ++ ++ default: ++ dev_err(rsz_device, "resizer_ioctl: Invalid Command Value"); ++ return -EINVAL; ++ } ++ ++ return (long)ret; ++} ++ ++static struct file_operations rsz_fops = { ++ .owner = THIS_MODULE, ++ .open = rsz_open, ++ .release = rsz_release, ++ .mmap = rsz_mmap, ++ .unlocked_ioctl = rsz_unlocked_ioctl, ++}; ++ ++/** ++ * rsz_isr - Interrupt Service Routine for Resizer wrapper ++ * @status: ISP IRQ0STATUS register value ++ * @arg1: Currently not used ++ * @arg2: Currently not used ++ * ++ * Interrupt Service Routine for Resizer wrapper ++ **/ ++static void rsz_isr(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2) ++{ ++ ++ if ((status & RESZ_DONE) != RESZ_DONE) ++ return; ++ ++ complete(&(device_config->compl_isr)); ++ ++} ++ ++/** ++ * resizer_platform_release - Acts when Reference count is zero ++ * @device: Structure containing ISP resizer wrapper global information ++ * ++ * This is called when the reference count goes to zero. ++ **/ ++static void resizer_platform_release(struct device *device) ++{ ++} ++ ++/** ++ * resizer_probe - Checks for device presence ++ * @device: Structure containing details of the current device. ++ * ++ * Always returns 0. ++ **/ ++static int __init resizer_probe(struct platform_device *device) ++{ ++ return 0; ++} ++ ++/** ++ * resizer_remove - Handles the removal of the driver ++ * @omap_resizer_device: Structure containing details of the current device. ++ * ++ * Always returns 0. ++ **/ ++static int resizer_remove(struct platform_device *omap_resizer_device) ++{ ++ return 0; ++} ++ ++static struct class *rsz_class; ++static struct cdev c_dev; ++static dev_t dev; ++static struct platform_device omap_resizer_device = { ++ .name = OMAP_REZR_NAME, ++ .id = 2, ++ .dev = { ++ .release = resizer_platform_release,} ++}; ++ ++static struct platform_driver omap_resizer_driver = { ++ .probe = resizer_probe, ++ .remove = resizer_remove, ++ .driver = { ++ .bus = &platform_bus_type, ++ .name = OMAP_REZR_NAME, ++ }, ++}; ++ ++/** ++ * omap_rsz_init - Initialization of Resizer Wrapper ++ * ++ * Returns 0 if successful, -ENOMEM if could not allocate memory, -ENODEV if ++ * could not register the wrapper as a character device, or other errors if the ++ * device or driver can't register. ++ **/ ++static int __init omap_rsz_init(void) ++{ ++ int ret = 0; ++ struct device_params *device; ++ device = kzalloc(sizeof(struct device_params), GFP_KERNEL); ++ if (!device) { ++ dev_err(rsz_device, OMAP_REZR_NAME ": could not allocate " ++ "memory\n"); ++ 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; ++ } ++ ++ /* Register the driver in the kernel */ ++ /* Initialize of character device */ ++ cdev_init(&c_dev, &rsz_fops); ++ c_dev.owner = THIS_MODULE; ++ c_dev.ops = &rsz_fops; ++ ++ /* Addding character device */ ++ ret = cdev_add(&c_dev, dev, 1); ++ if (ret) { ++ dev_err(rsz_device, OMAP_REZR_NAME ": Error adding " ++ "device - %d\n", ret); ++ goto fail2; ++ } ++ rsz_major = MAJOR(dev); ++ ++ /* register driver as a platform driver */ ++ ret = platform_driver_register(&omap_resizer_driver); ++ if (ret) { ++ dev_err(rsz_device, OMAP_REZR_NAME ++ ": Failed to register platform driver!\n"); ++ goto fail3; ++ } ++ ++ /* Register the drive as a platform device */ ++ ret = platform_device_register(&omap_resizer_device); ++ if (ret) { ++ dev_err(rsz_device, OMAP_REZR_NAME ++ ": Failed to register platform device!\n"); ++ goto fail4; ++ } ++ ++ rsz_class = class_create(THIS_MODULE, OMAP_REZR_NAME); ++ if (!rsz_class) { ++ dev_err(rsz_device, OMAP_REZR_NAME ++ ": Failed to create class!\n"); ++ goto fail5; ++ } ++ ++ /* make entry in the devfs */ ++ rsz_device = device_create(rsz_class, rsz_device, ++ MKDEV(rsz_major, 0), NULL, ++ OMAP_REZR_NAME); ++ dev_dbg(rsz_device, OMAP_REZR_NAME ": Registered Resizer Wrapper\n"); ++ device->opened = 0; ++ ++ device->vbq_ops.buf_setup = rsz_vbq_setup; ++ device->vbq_ops.buf_prepare = rsz_vbq_prepare; ++ device->vbq_ops.buf_release = rsz_vbq_release; ++ device->vbq_ops.buf_queue = rsz_vbq_queue; ++ init_completion(&device->compl_isr); ++ mutex_init(&device->reszwrap_mutex); ++ ++ device_config = device; ++ return 0; ++ ++fail5: ++ platform_device_unregister(&omap_resizer_device); ++fail4: ++ platform_driver_unregister(&omap_resizer_driver); ++fail3: ++ cdev_del(&c_dev); ++fail2: ++ unregister_chrdev_region(dev, 1); ++ kfree(device); ++ return ret; ++} ++ ++/** ++ * omap_rsz_exit - Close of Resizer Wrapper ++ **/ ++void __exit omap_rsz_exit(void) ++{ ++ device_destroy(rsz_class, dev); ++ class_destroy(rsz_class); ++ platform_device_unregister(&omap_resizer_device); ++ platform_driver_unregister(&omap_resizer_driver); ++ cdev_del(&c_dev); ++ unregister_chrdev_region(dev, 1); ++ kfree(device_config); ++} ++ ++module_init(omap_rsz_init) ++module_exit(omap_rsz_exit) ++ ++MODULE_AUTHOR("Texas Instruments"); ++MODULE_DESCRIPTION("OMAP ISP Resizer"); ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h +new file mode 100644 +index 0000000..5ac0c88 +--- /dev/null ++++ b/include/linux/omap_resizer.h +@@ -0,0 +1,136 @@ ++/* ++ * drivers/media/video/isp/omap_resizer.h ++ * ++ * Include file for Resizer module wrapper in TI's OMAP3430 ISP ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * ++ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++#ifndef OMAP_RESIZER_H ++#define OMAP_RESIZER_H ++ ++#include <linux/types.h> ++ ++/* ioctls definition */ ++#define RSZ_IOC_BASE 'R' ++#define RSZ_IOC_MAXNR 8 ++ ++/*Ioctl options which are to be passed while calling the ioctl*/ ++#define RSZ_REQBUF _IOWR(RSZ_IOC_BASE, 1,\ ++ struct v4l2_requestbuffers) ++#define RSZ_QUERYBUF _IOWR(RSZ_IOC_BASE, 2, struct v4l2_buffer) ++#define RSZ_S_PARAM _IOWR(RSZ_IOC_BASE, 3, struct rsz_params) ++#define RSZ_G_PARAM _IOWR(RSZ_IOC_BASE, 4, struct rsz_params) ++#define RSZ_RESIZE _IOWR(RSZ_IOC_BASE, 5, __s32) ++#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_INTYPE_YCBCR422_16BIT 0 ++#define RSZ_INTYPE_PLANAR_8BIT 1 ++#define RSZ_PIX_FMT_UYVY 1 /* cb:y:cr:y */ ++#define RSZ_PIX_FMT_YUYV 0 /* y:cb:y:cr */ ++ ++enum config_done { ++ STATE_CONFIGURED, /* Resizer driver configured ++ * by application. ++ */ ++ STATE_NOT_CONFIGURED /* Resizer driver not ++ * configured by application. ++ */ ++}; ++ ++/* Structure Definitions */ ++ ++/* used to luma enhancement options */ ++ ++struct rsz_yenh { ++ __s32 type; /* represents luma enable or ++ * disable. ++ */ ++ __u8 gain; /* represents gain. */ ++ __u8 slop; /* represents slop. */ ++ __u8 core; /* Represents core value. */ ++}; ++ ++/* Conatins all the parameters for resizing. This structure ++ * is used to configure resiser parameters ++ */ ++struct rsz_params { ++ __s32 in_hsize; /* input frame horizontal ++ * size. ++ */ ++ __s32 in_vsize; /* input frame vertical size */ ++ __s32 in_pitch; /* offset between two rows of ++ * input frame. ++ */ ++ __s32 inptyp; /* for determining 16 bit or ++ * 8 bit data. ++ */ ++ __s32 vert_starting_pixel; /* for specifying vertical ++ * starting pixel in input. ++ */ ++ __s32 horz_starting_pixel; /* for specyfing horizontal ++ * starting pixel in input. ++ */ ++ __s32 cbilin; /* # defined, filter with luma ++ * or bi-linear interpolation. ++ */ ++ __s32 pix_fmt; /* # defined, UYVY or YUYV */ ++ __s32 out_hsize; /* output frame horizontal ++ * size. ++ */ ++ __s32 out_vsize; /* output frame vertical ++ * size. ++ */ ++ __s32 out_pitch; /* offset between two rows of ++ * output frame. ++ */ ++ __s32 hstph; /* for specifying horizontal ++ * starting phase. ++ */ ++ __s32 vstph; /* for specifying vertical ++ * starting phase. ++ */ ++ __u16 tap4filt_coeffs[32]; /* horizontal filter ++ * coefficients. ++ */ ++ __u16 tap7filt_coeffs[32]; /* vertical filter ++ * coefficients. ++ */ ++ struct rsz_yenh yenh_params; ++}; ++ ++/* Contains the status of hardware and channel */ ++struct rsz_status { ++ __s32 chan_busy; /* 1: channel is busy, ++ * 0: channel is not busy ++ */ ++ __s32 hw_busy; /* 1: hardware is busy, ++ * 0: hardware is not busy ++ */ ++ __s32 src; /* # defined, can be either ++ * SD-RAM or CCDC/PREVIEWER ++ */ ++}; ++ ++/* Passed by application for getting crop size */ ++struct rsz_cropsize { ++ __u32 hcrop; /* Number of pixels per line ++ * cropped in output image. ++ */ ++ ++ __u32 vcrop; /* Number of lines cropped ++ * in output image. ++ */ ++}; ++ ++#endif +-- +1.6.0.3 + +--- /tmp/Kconfig 2009-04-06 10:56:27.000000000 +0200 ++++ git/drivers/media/video/Kconfig 2009-04-06 10:57:25.000000000 +0200 +@@ -711,6 +711,9 @@ + CMOS camera controller. This is the controller found on first- + generation OLPC systems. + ++ ++source "drivers/media/video/isp/Kconfig" ++ + config VIDEO_OMAP3 + tristate "OMAP 3 Camera support" + select VIDEOBUF_GEN |