From 2dff7b788dc52c5da3fd2c5863dfad857a7d1710 Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Thu, 16 Jul 2009 16:06:44 +0200 Subject: linux-omap 2.6.29: update support for the ISP resizer --- conf/machine/include/omap3.inc | 2 +- .../linux/linux-omap-2.6.29/beagleboard/defconfig | 58 +- ...base-address-definitions-and-resources-fo.patch | 153 - ...er-Basic-Resizer-refreshed-with-latest-gi.patch | 1890 +++++++++++++ ...OMAP3-Resizer-V4L2-buf-layer-issues-fixed.patch | 729 +++++ .../0025-OMAP3-Resizer-Build-issues-fixed.patch | 36 + ...izer-and-Previewer-driver-added-to-commit.patch | 2915 -------------------- ...Resizer-bug-fixes-on-top-of-1.0.2-release.patch | 730 ----- recipes/linux/linux-omap_2.6.29.bb | 6 +- 9 files changed, 2708 insertions(+), 3811 deletions(-) delete mode 100644 recipes/linux/linux-omap-2.6.29/isp/base/0001-omap3-Add-base-address-definitions-and-resources-fo.patch create mode 100644 recipes/linux/linux-omap-2.6.29/isp/resizer/0023-OMAP-Resizer-Basic-Resizer-refreshed-with-latest-gi.patch create mode 100644 recipes/linux/linux-omap-2.6.29/isp/resizer/0024-OMAP3-Resizer-V4L2-buf-layer-issues-fixed.patch create mode 100644 recipes/linux/linux-omap-2.6.29/isp/resizer/0025-OMAP3-Resizer-Build-issues-fixed.patch delete mode 100644 recipes/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch delete mode 100644 recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch diff --git a/conf/machine/include/omap3.inc b/conf/machine/include/omap3.inc index ea395b441b..9c3c8f59e1 100644 --- a/conf/machine/include/omap3.inc +++ b/conf/machine/include/omap3.inc @@ -1,7 +1,7 @@ require conf/machine/include/tune-cortexa8.inc PREFERRED_PROVIDER_virtual/kernel = "linux-omap" # Increase this everytime you change something in the kernel -MACHINE_KERNEL_PR = "r39" +MACHINE_KERNEL_PR = "r40" KERNEL_IMAGETYPE = "uImage" diff --git a/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig b/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig index 1aa7cf57ac..99be5246a6 100644 --- a/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig +++ b/recipes/linux/linux-omap-2.6.29/beagleboard/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.29-omap1 -# Fri May 29 14:47:52 2009 +# Thu Jul 16 15:21:36 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -32,6 +32,7 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set @@ -189,8 +190,7 @@ CONFIG_ARCH_OMAP3=y # # CONFIG_OMAP_DEBUG_POWERDOMAIN is not set # CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set -CONFIG_OMAP_SMARTREFLEX=y -# CONFIG_OMAP_SMARTREFLEX_TESTING is not set +# CONFIG_OMAP_SMARTREFLEX is not set CONFIG_OMAP_RESET_CLOCKS=y CONFIG_OMAP_BOOT_TAG=y CONFIG_OMAP_BOOT_REASON=y @@ -199,7 +199,7 @@ CONFIG_OMAP_BOOT_REASON=y # CONFIG_OMAP_MUX is not set CONFIG_OMAP_MCBSP=y # CONFIG_OMAP_MBOX_FWK is not set -# CONFIG_OMAP_IOMMU is not set +CONFIG_OMAP_IOMMU=y # CONFIG_OMAP_MPU_TIMER is not set CONFIG_OMAP_32K_TIMER=y CONFIG_OMAP_32K_TIMER_HZ=128 @@ -217,9 +217,9 @@ CONFIG_ARCH_OMAP3430=y # CONFIG_MACH_NOKIA_RX51 is not set # CONFIG_MACH_OMAP_LDP is not set # CONFIG_MACH_OMAP_3430SDP is not set -# CONFIG_MACH_OMAP3EVM is not set +CONFIG_MACH_OMAP3EVM=y CONFIG_MACH_OMAP3_BEAGLE=y -# CONFIG_MACH_OVERO is not set +CONFIG_MACH_OVERO=y # CONFIG_MACH_OMAP3_PANDORA is not set # @@ -268,7 +268,7 @@ CONFIG_VMSPLIT_3G=y # CONFIG_VMSPLIT_2G is not set # CONFIG_VMSPLIT_1G is not set CONFIG_PAGE_OFFSET=0xC0000000 -# CONFIG_PREEMPT is not set +CONFIG_PREEMPT=y CONFIG_HZ=128 CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set @@ -1034,8 +1034,43 @@ CONFIG_MACVLAN=m CONFIG_EQUALIZER=m CONFIG_TUN=m CONFIG_VETH=m -# CONFIG_NET_ETHERNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set @@ -1471,6 +1506,7 @@ CONFIG_MEDIA_TUNER_MXL5005S=m CONFIG_VIDEO_V4L2=m CONFIG_VIDEO_V4L1=m CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m CONFIG_VIDEOBUF_VMALLOC=m CONFIG_VIDEOBUF_DVB=m CONFIG_VIDEO_IR=m @@ -1494,7 +1530,8 @@ CONFIG_VIDEO_VIVI=m # CONFIG_VIDEO_SAA5246A is not set # CONFIG_VIDEO_SAA5249 is not set # CONFIG_VIDEO_AU0828 is not set -# CONFIG_VIDEO_OMAP3 is not set +CONFIG_VIDEO_OMAP3=m +CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=m # CONFIG_SOC_CAMERA is not set CONFIG_V4L_USB_DRIVERS=y CONFIG_USB_VIDEO_CLASS=m @@ -1818,6 +1855,7 @@ CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_SOC=y CONFIG_SND_OMAP_SOC=y CONFIG_SND_OMAP_SOC_MCBSP=y +# CONFIG_SND_OMAP_SOC_OVERO is not set CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set @@ -2514,6 +2552,7 @@ CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_PREEMPT=y # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -2551,6 +2590,7 @@ CONFIG_TRACING=y # # CONFIG_FUNCTION_TRACER is not set # CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_CONTEXT_SWITCH_TRACER is not set # CONFIG_BOOT_TRACER is not set diff --git a/recipes/linux/linux-omap-2.6.29/isp/base/0001-omap3-Add-base-address-definitions-and-resources-fo.patch b/recipes/linux/linux-omap-2.6.29/isp/base/0001-omap3-Add-base-address-definitions-and-resources-fo.patch deleted file mode 100644 index 902f87943d..0000000000 --- a/recipes/linux/linux-omap-2.6.29/isp/base/0001-omap3-Add-base-address-definitions-and-resources-fo.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 742cc1e62f0d04333c51630f3020da000aeb6de1 Mon Sep 17 00:00:00 2001 -From: Sakari Ailus -Date: Mon, 2 Mar 2009 19:36:26 +0200 -Subject: [PATCH] omap3: Add base address definitions and resources for OMAP 3 ISP - -This replaces earlier patch from Sergio Aguirre titled "[REVIEW PATCH 03/14] -OMAP34XX: CAM: Resources fixes". - -Signed-off-by: Sakari Ailus ---- - arch/arm/mach-omap2/devices.c | 66 ++++++++++++++++++++++++--- - arch/arm/plat-omap/include/mach/omap34xx.h | 28 +++++++++++- - 2 files changed, 85 insertions(+), 9 deletions(-) - -diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c -index dad4528..2568b0c 100644 ---- a/arch/arm/mach-omap2/devices.c -+++ b/arch/arm/mach-omap2/devices.c -@@ -56,10 +56,60 @@ static inline void omap_init_camera(void) - - #elif defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE) - --static struct resource cam_resources[] = { -+static struct resource omap3isp_resources[] = { -+ { -+ .start = OMAP3430_ISP_BASE, -+ .end = OMAP3430_ISP_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_CBUFF_BASE, -+ .end = OMAP3430_ISP_CBUFF_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_CCP2_BASE, -+ .end = OMAP3430_ISP_CCP2_END, -+ .flags = IORESOURCE_MEM, -+ }, - { -- .start = OMAP34XX_CAMERA_BASE, -- .end = OMAP34XX_CAMERA_BASE + 0x1B70, -+ .start = OMAP3430_ISP_CCDC_BASE, -+ .end = OMAP3430_ISP_CCDC_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_HIST_BASE, -+ .end = OMAP3430_ISP_HIST_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_H3A_BASE, -+ .end = OMAP3430_ISP_H3A_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_PREV_BASE, -+ .end = OMAP3430_ISP_PREV_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_RESZ_BASE, -+ .end = OMAP3430_ISP_RESZ_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_SBL_BASE, -+ .end = OMAP3430_ISP_SBL_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_CSI2A_BASE, -+ .end = OMAP3430_ISP_CSI2A_END, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = OMAP3430_ISP_CSI2PHY_BASE, -+ .end = OMAP3430_ISP_CSI2PHY_END, - .flags = IORESOURCE_MEM, - }, - { -@@ -68,16 +118,16 @@ static struct resource cam_resources[] = { - } - }; - --static struct platform_device omap_cam_device = { -- .name = "omap34xxcam", -+static struct platform_device omap3isp_device = { -+ .name = "omap3isp", - .id = -1, -- .num_resources = ARRAY_SIZE(cam_resources), -- .resource = cam_resources, -+ .num_resources = ARRAY_SIZE(omap3isp_resources), -+ .resource = omap3isp_resources, - }; - - static inline void omap_init_camera(void) - { -- platform_device_register(&omap_cam_device); -+ platform_device_register(&omap3isp_device); - } - #else - static inline void omap_init_camera(void) -diff --git a/arch/arm/plat-omap/include/mach/omap34xx.h b/arch/arm/plat-omap/include/mach/omap34xx.h -index 27a1e45..3bfbdf7 100644 ---- a/arch/arm/plat-omap/include/mach/omap34xx.h -+++ b/arch/arm/plat-omap/include/mach/omap34xx.h -@@ -49,6 +49,33 @@ - #define OMAP343X_CTRL_BASE OMAP343X_SCM_BASE - - #define OMAP34XX_IC_BASE 0x48200000 -+ -+#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) -+#define OMAP3430_ISP_CBUFF_BASE (OMAP3430_ISP_BASE + 0x0100) -+#define OMAP3430_ISP_CCP2_BASE (OMAP3430_ISP_BASE + 0x0400) -+#define OMAP3430_ISP_CCDC_BASE (OMAP3430_ISP_BASE + 0x0600) -+#define OMAP3430_ISP_HIST_BASE (OMAP3430_ISP_BASE + 0x0A00) -+#define OMAP3430_ISP_H3A_BASE (OMAP3430_ISP_BASE + 0x0C00) -+#define OMAP3430_ISP_PREV_BASE (OMAP3430_ISP_BASE + 0x0E00) -+#define OMAP3430_ISP_RESZ_BASE (OMAP3430_ISP_BASE + 0x1000) -+#define OMAP3430_ISP_SBL_BASE (OMAP3430_ISP_BASE + 0x1200) -+#define OMAP3430_ISP_MMU_BASE (OMAP3430_ISP_BASE + 0x1400) -+#define OMAP3430_ISP_CSI2A_BASE (OMAP3430_ISP_BASE + 0x1800) -+#define OMAP3430_ISP_CSI2PHY_BASE (OMAP3430_ISP_BASE + 0x1970) -+ -+#define OMAP3430_ISP_END (OMAP3430_ISP_BASE + 0x06F) -+#define OMAP3430_ISP_CBUFF_END (OMAP3430_ISP_CBUFF_BASE + 0x077) -+#define OMAP3430_ISP_CCP2_END (OMAP3430_ISP_CCP2_BASE + 0x1EF) -+#define OMAP3430_ISP_CCDC_END (OMAP3430_ISP_CCDC_BASE + 0x0A7) -+#define OMAP3430_ISP_HIST_END (OMAP3430_ISP_HIST_BASE + 0x047) -+#define OMAP3430_ISP_H3A_END (OMAP3430_ISP_H3A_BASE + 0x05F) -+#define OMAP3430_ISP_PREV_END (OMAP3430_ISP_PREV_BASE + 0x09F) -+#define OMAP3430_ISP_RESZ_END (OMAP3430_ISP_RESZ_BASE + 0x0AB) -+#define OMAP3430_ISP_SBL_END (OMAP3430_ISP_SBL_BASE + 0x0FB) -+#define OMAP3430_ISP_MMU_END (OMAP3430_ISP_MMU_BASE + 0x06F) -+#define OMAP3430_ISP_CSI2A_END (OMAP3430_ISP_CSI2A_BASE + 0x16F) -+#define OMAP3430_ISP_CSI2PHY_END (OMAP3430_ISP_CSI2PHY_BASE + 0x007) -+ - #define OMAP34XX_IVA_INTC_BASE 0x40000000 - #define OMAP34XX_HSUSB_OTG_BASE (L4_34XX_BASE + 0xAB000) - #define OMAP34XX_HSUSB_HOST_BASE (L4_34XX_BASE + 0x64000) -@@ -56,7 +83,6 @@ - #define OMAP34XX_SR1_BASE 0x480C9000 - #define OMAP34XX_SR2_BASE 0x480CB000 - --#define OMAP34XX_CAMERA_BASE (L4_34XX_BASE + 0xBC000) - #define OMAP34XX_MAILBOX_BASE (L4_34XX_BASE + 0x94000) - - --- -1.5.6.5 - diff --git a/recipes/linux/linux-omap-2.6.29/isp/resizer/0023-OMAP-Resizer-Basic-Resizer-refreshed-with-latest-gi.patch b/recipes/linux/linux-omap-2.6.29/isp/resizer/0023-OMAP-Resizer-Basic-Resizer-refreshed-with-latest-gi.patch new file mode 100644 index 0000000000..3390599292 --- /dev/null +++ b/recipes/linux/linux-omap-2.6.29/isp/resizer/0023-OMAP-Resizer-Basic-Resizer-refreshed-with-latest-gi.patch @@ -0,0 +1,1890 @@ +From 38f3cd5564a466e5251fc2ff47e0504148922304 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath +Date: Wed, 29 Apr 2009 17:18:56 +0530 +Subject: [PATCH 23/26] OMAP-Resizer: Basic Resizer refreshed with latest gitorious tree + +This is same resizer driver patch posted by Sergio onto +mailing list quite a some time back. This commit refreshes +the same patch on top of latest gitorious.org tree. + +List of New/Modified files: + modified: drivers/media/video/Kconfig + modified: drivers/media/video/isp/Makefile + modified: drivers/media/video/isp/isp.c + modified: drivers/media/video/isp/ispreg.h + new file: drivers/media/video/isp/omap_resizer.c + new file: include/linux/omap_resizer.h + +TODO: + - Resizer driver needs to be independent from camera and ISP + - Custom patches implemented ontop of PSP1.0.2 release + to fix some V4L2-buf layer issues. + - +--- + drivers/media/video/Kconfig | 7 + + drivers/media/video/isp/Makefile | 4 + + drivers/media/video/isp/isp.c | 15 + + drivers/media/video/isp/omap_resizer.c | 1634 ++++++++++++++++++++++++++++++++ + include/linux/omap_resizer.h | 136 +++ + 5 files changed, 1796 insertions(+), 0 deletions(-) + create mode 100644 drivers/media/video/isp/omap_resizer.c + create mode 100644 include/linux/omap_resizer.h + +diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig +index 3cdb5a4..d2b4ae1 100644 +--- a/drivers/media/video/Kconfig ++++ b/drivers/media/video/Kconfig +@@ -720,6 +720,13 @@ config VIDEO_OMAP3 + ---help--- + Driver for an OMAP 3 camera controller. + ++config VIDEO_OMAP34XX_ISP_RESIZER ++ tristate "OMAP ISP Resizer" ++ depends on VIDEO_V4L2 && ARCH_OMAP34XX ++ select VIDEOBUF_GEN ++ select VIDEOBUF_DMA_SG ++ select OMAP_IOMMU ++ + config SOC_CAMERA + tristate "SoC camera support" + depends on VIDEO_V4L2 && HAS_DMA +diff --git a/drivers/media/video/isp/Makefile b/drivers/media/video/isp/Makefile +index f14d617..d171fb9 100644 +--- a/drivers/media/video/isp/Makefile ++++ b/drivers/media/video/isp/Makefile +@@ -7,6 +7,10 @@ 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_RESIZER) += \ ++ omap_resizer.o ++ + endif + + obj-$(CONFIG_VIDEO_OMAP3) += isp-mod.o +diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c +index 54c839b..f1f92b4 100644 +--- a/drivers/media/video/isp/isp.c ++++ b/drivers/media/video/isp/isp.c +@@ -505,6 +505,12 @@ int isp_set_callback(enum isp_callback_type type, isp_callback_t callback, + isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE, + IRQ0ENABLE_PRV_DONE_IRQ); + break; ++ case CBK_RESZ_DONE: ++ isp_reg_writel(IRQ0ENABLE_RSZ_DONE_IRQ, ++ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); ++ isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE, ++ IRQ0ENABLE_RSZ_DONE_IRQ); ++ break; + default: + break; + } +@@ -556,6 +562,10 @@ int isp_unset_callback(enum isp_callback_type type) + isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE, + ~IRQ0ENABLE_PRV_DONE_IRQ); + break; ++ case CBK_RESZ_DONE: ++ isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE, ++ ~IRQ0ENABLE_RSZ_DONE_IRQ); ++ break; + default: + break; + } +@@ -938,6 +948,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/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 ++ * Troy Laramy ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp.h" ++#include "ispmmu.h" ++#include "ispreg.h" ++#include "ispresizer.h" ++#include ++ ++#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_unmap(fh->isp_addr_read); ++ fh->isp_addr_read = 0; ++ } ++ if (fh->isp_addr_write) { ++ ispmmu_unmap(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_unmap(fh->isp_addr_read); ++ ispmmu_unmap(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_map_sg(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 ++ ++/* 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.2.4 + diff --git a/recipes/linux/linux-omap-2.6.29/isp/resizer/0024-OMAP3-Resizer-V4L2-buf-layer-issues-fixed.patch b/recipes/linux/linux-omap-2.6.29/isp/resizer/0024-OMAP3-Resizer-V4L2-buf-layer-issues-fixed.patch new file mode 100644 index 0000000000..2c3023643e --- /dev/null +++ b/recipes/linux/linux-omap-2.6.29/isp/resizer/0024-OMAP3-Resizer-V4L2-buf-layer-issues-fixed.patch @@ -0,0 +1,729 @@ +From ad3bbadb7fc39a946dfd0cdac19e2ec8647b2c2c Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath +Date: Wed, 29 Apr 2009 17:20:27 +0530 +Subject: [PATCH 24/26] OMAP3-Resizer: V4L2-buf layer issues fixed + +V4L2-Buffer layer issues fixed under this commit. +This patch is same as available with PSP1.0.2 release + +The discussion is initiated on this with V4L2 mailing list. + +Please note that this patch is not being tested. +--- + 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 + #include + #include ++#include + #include + #include + +@@ -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_unmap(fh->isp_addr_read); +- fh->isp_addr_read = 0; +- } +- if (fh->isp_addr_write) { +- ispmmu_unmap(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_unmap(fh->config->buf_address[vb->i]); ++ fh->config->buf_address[vb->i] = 0; + +- ispmmu_unmap(fh->isp_addr_read); +- ispmmu_unmap(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_map_sg(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_map_sg(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.2.4 + diff --git a/recipes/linux/linux-omap-2.6.29/isp/resizer/0025-OMAP3-Resizer-Build-issues-fixed.patch b/recipes/linux/linux-omap-2.6.29/isp/resizer/0025-OMAP3-Resizer-Build-issues-fixed.patch new file mode 100644 index 0000000000..143a846e3c --- /dev/null +++ b/recipes/linux/linux-omap-2.6.29/isp/resizer/0025-OMAP3-Resizer-Build-issues-fixed.patch @@ -0,0 +1,36 @@ +From 9fec955e98b4ef7922f629e3a81d2d1af216e028 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath +Date: Wed, 29 Apr 2009 18:12:42 +0530 +Subject: [PATCH 25/26] OMAP3-Resizer: Build issues fixed + +There were some building issues with latest gitorious tree, +fixed them. +--- + drivers/media/video/isp/omap_resizer.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c +index 8059c70..dd90b24 100644 +--- a/drivers/media/video/isp/omap_resizer.c ++++ b/drivers/media/video/isp/omap_resizer.c +@@ -1033,7 +1033,7 @@ static void rsz_vbq_release(struct videobuf_queue *q, + dma = videobuf_to_dma(q->bufs[vb->i]); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); +- ispmmu_unmap(fh->config->buf_address[vb->i]); ++ ispmmu_vunmap(fh->config->buf_address[vb->i]); + fh->config->buf_address[vb->i] = 0; + + spin_lock(&fh->vbq_lock); +@@ -1293,7 +1293,7 @@ static int rsz_vbq_prepare(struct videobuf_queue *q, + goto buf_release; + spin_unlock(&fh->vbq_lock); + } +- isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen); ++ isp_addr = ispmmu_vmap(dma->sglist, dma->sglen); + if (!isp_addr) + err = -EIO; + else { +-- +1.6.2.4 + diff --git a/recipes/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch b/recipes/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch deleted file mode 100644 index f796ce8346..0000000000 --- a/recipes/linux/linux-omap-2.6.29/isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch +++ /dev/null @@ -1,2915 +0,0 @@ -From 3041daa54b49bcb6ab444c7b9e14bc6a1ade6236 Mon Sep 17 00:00:00 2001 -From: Vaibhav Hiremath -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 ---- - 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 -+ * Sergio Aguirre -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 -+ * Sergio Aguirre -+ * -+ * 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 -+ * Troy Laramy -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "isp.h" -+#include "ispmmu.h" -+#include "ispreg.h" -+#include "ispresizer.h" -+#include -+ -+#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 -+ -+/* 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 diff --git a/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch b/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch deleted file mode 100644 index 631b05f417..0000000000 --- a/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch +++ /dev/null @@ -1,730 +0,0 @@ -From 20d79137ecaa6c7dad007d9ea1d7be5550db4839 Mon Sep 17 00:00:00 2001 -From: Vaibhav Hiremath -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 ---- - 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 - #include - #include -+#include - #include - #include - -@@ -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 - diff --git a/recipes/linux/linux-omap_2.6.29.bb b/recipes/linux/linux-omap_2.6.29.bb index 32ad025065..e40daa0ec0 100644 --- a/recipes/linux/linux-omap_2.6.29.bb +++ b/recipes/linux/linux-omap_2.6.29.bb @@ -151,9 +151,9 @@ SRC_URI_append = " \ file://isp/omap3camera/0007-omap3isp-Add-CSI2-interface-support.patch;patch=1 \ file://isp/omap3camera/0008-omap3isp-Add-ISP-tables.patch;patch=1 \ file://isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch;patch=1 \ -# file://isp/base/0001-omap3-Add-base-address-definitions-and-resources-fo.patch;patch=1 \ -# file://isp/standalone/0001-Resizer-and-Previewer-driver-added-to-commit.patch;patch=1 \ -# file://isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch;patch=1 \ + file://isp/resizer/0023-OMAP-Resizer-Basic-Resizer-refreshed-with-latest-gi.patch;patch=1 \ + file://isp/resizer/0024-OMAP3-Resizer-V4L2-buf-layer-issues-fixed.patch;patch=1 \ + file://isp/resizer/0025-OMAP3-Resizer-Build-issues-fixed.patch;patch=1 \ file://0124-leds-gpio-broken-with-current-git.patch;patch=1 \ file://modedb-hd720.patch;patch=1 \ file://0001-implement-TIF_RESTORE_SIGMASK-support-and-enable-the.patch;patch=1 \ -- cgit v1.2.3