add the hardware functionality for enablling the dm365 auto exposure and white balance unit. The module supports hardware setup, isr management, and parameter validation. Signed-off-by: Manjunath Hadli <manjunath.hadli@xxxxxx> --- drivers/media/video/davinci/dm365_a3_hw.c | 387 ++++++++++++++++++++ drivers/media/video/davinci/dm365_a3_hw.h | 253 +++++++++++++ drivers/media/video/davinci/dm365_aew.c | 544 +++++++++++++++++++++++++++++ drivers/media/video/davinci/dm365_aew.h | 55 +++ include/linux/dm365_aew.h | 153 ++++++++ 5 files changed, 1392 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/dm365_a3_hw.c create mode 100644 drivers/media/video/davinci/dm365_a3_hw.h create mode 100644 drivers/media/video/davinci/dm365_aew.c create mode 100644 drivers/media/video/davinci/dm365_aew.h create mode 100644 include/linux/dm365_aew.h diff --git a/drivers/media/video/davinci/dm365_a3_hw.c b/drivers/media/video/davinci/dm365_a3_hw.c new file mode 100644 index 0000000..b929c22 --- /dev/null +++ b/drivers/media/video/davinci/dm365_a3_hw.c @@ -0,0 +1,387 @@ +/* +* Copyright (C) 2011 Texas Instruments Inc +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "dm365_af.h" +#include "dm365_aew.h" +#include "dm365_a3_hw.h" + +/* 3A hardware module configuration */ +struct a3_config { + /* lock for write protection */ + struct mutex lock; + /* base address */ + void __iomem *base; +}; + +/* H3A module configuration */ +static struct a3_config a3_cfg; + +/* register access routines */ +static inline u32 regr(unsigned int offset) +{ + return __raw_readl(a3_cfg.base + offset); +} + +static inline u32 regw(u32 val, unsigned int offset) +{ + __raw_writel(val, (a3_cfg.base + offset)); + + return val; +} + +/* Function to set register */ +int af_register_setup(struct device *dev, struct af_device *af_dev) +{ + unsigned int address; + unsigned int utemp; + int index; + + /* Lock resource since this register is written by + * both the AF and AEW drivers + */ + mutex_lock(&a3_cfg.lock); + /* Configure Hardware Registers */ + /* Set PCR Register */ + utemp = regr(AFPCR); /* Read PCR Register */ + + /*Set Accumulator Mode */ + utemp &= ~FVMODE; + if (af_dev->config->mode == ACCUMULATOR_PEAK) + utemp |= FVMODE; + /* Set A-law */ + utemp &= ~AF_ALAW_EN; + if (af_dev->config->alaw_enable == H3A_AF_ENABLE) + utemp |= AF_ALAW_EN; + + /* Set HFV only or HFV and VFV */ + utemp &= ~AF_VF_EN; + if (af_dev->config->fv_sel == AF_HFV_AND_VFV) + utemp |= AF_VF_EN; + /* Set RGB Position */ + utemp &= ~RGBPOS; + utemp |= (af_dev->config->rgb_pos) << AF_RGBPOS_SHIFT; + + utemp &= ~AF_MED_EN; + /*HMF Configurations */ + if (af_dev->config->hmf_config.enable == H3A_AF_ENABLE) { + /* Enable HMF */ + utemp |= AF_MED_EN; + /* Set Median Threshold */ + utemp &= ~MED_TH; + utemp |= (af_dev->config->hmf_config.threshold << + AF_MED_TH_SHIFT) & MED_TH; + } + /* Set PCR Register */ + regw(utemp , AFPCR); + mutex_unlock(&a3_cfg.lock); + + /* Configure AFPAX1 */ + /*Paxel parameter configuration */ + /*Set Width in AFPAX1 Register */ + utemp = SET_VAL(af_dev->config->paxel_config.width) << AF_PAXW_SHIFT; + + /* Set height in AFPAX1 */ + utemp &= ~PAXH; + utemp |= SET_VAL(af_dev->config->paxel_config.height); + regw(utemp , AFPAX1); + /* Configure AFPAX2 Register */ + /* Set Column Increment in AFPAX2 Register */ + utemp = 0; + utemp &= ~AFINCH; + utemp |= SET_VAL(af_dev->config->paxel_config.column_incr) << + AF_COLUMN_INCR_SHIFT; + + /* Set Line Increment in AFPAX2 Register */ + utemp &= ~AFINCV; + utemp |= SET_VAL(af_dev->config->paxel_config.line_incr) << + AF_LINE_INCR_SHIFT; + + /* Set Vertical Count */ + utemp &= ~PAXVC; + utemp |= (af_dev->config->paxel_config.vt_cnt - 1) << AF_VT_COUNT_SHIFT; + /* Set Horizontal Count */ + utemp &= ~PAXHC; + utemp |= af_dev->config->paxel_config.hz_cnt - 1; + regw(utemp, AFPAX2); + + /* Configure PAXSTART Register */ + /*Configure Horizontal Start */ + utemp = 0; + utemp &= ~PAXSH; + utemp |= af_dev->config->paxel_config.hz_start << AF_HZ_START_SHIFT; + /* Configure Vertical Start */ + utemp &= ~PAXSV; + utemp |= af_dev->config->paxel_config.vt_start; + regw(utemp , AFPAXSTART); + + /*SetIIRSH Register */ + regw(af_dev->config->iir_config.hz_start_pos, AFIIRSH); + + /* Set IIR Filter0 Coefficients */ + address = AFCOEF010; + for (index = 0; index < AF_NUMBER_OF_HFV_COEF; index += 2) { + utemp = af_dev->config->iir_config.coeff_set0[index] & + COEF_MASK0; + if (index < AF_NUMBER_OF_HFV_COEF - 1) { + utemp |= (af_dev->config->iir_config. + coeff_set0[index + 1] << AF_COEF_SHIFT) & COEF_MASK1; + } + regw(utemp, address); + dev_dbg(dev, "COEF0 %x\n", regr(address)); + address = address + AF_OFFSET; + } + + /* Set IIR Filter1 Coefficients */ + address = AFCOEF110; + for (index = 0; index < AF_NUMBER_OF_HFV_COEF; index += 2) { + utemp = af_dev->config->iir_config.coeff_set1[index] & + COEF_MASK0; + if (index < AF_NUMBER_OF_HFV_COEF-1) { + utemp |= (af_dev->config->iir_config. + coeff_set1[index + 1] << AF_COEF_SHIFT) & COEF_MASK1; + } + regw(utemp, address); + dev_dbg(dev, "COEF0 %x\n", regr(address)); + address = address + AF_OFFSET; + } + + /* HFV thresholds for FIR 1 & 2 */ + utemp = af_dev->config->fir_config.hfv_thr1 & HFV_THR0_MASK; + utemp |= (af_dev->config->fir_config.hfv_thr2 << HFV_THR2_SHIFT) & + HFV_THR2_MASK; + regw(utemp, AF_HFV_THR); + + /* VFV coefficients and thresholds */ + utemp = af_dev->config->fir_config.coeff_1[0] & VFV_COEF_MASK0; + utemp |= (af_dev->config->fir_config.coeff_1[1] << 8) & VFV_COEF_MASK1; + utemp |= (af_dev->config->fir_config.coeff_1[2] << 16) & VFV_COEF_MASK2; + utemp |= (af_dev->config->fir_config.coeff_1[3] << 24) & VFV_COEF_MASK3; + regw(utemp, AF_VFV_CFG1); + + utemp = af_dev->config->fir_config.coeff_1[4] & VFV_COEF_MASK0; + utemp |= (af_dev->config->fir_config.vfv_thr1 << VFV_THR_SHIFT) & + VFV_THR_MASK; + regw(utemp, AF_VFV_CFG2); + + /* VFV coefficients and thresholds */ + utemp = af_dev->config->fir_config.coeff_2[0] & VFV_COEF_MASK0; + utemp |= (af_dev->config->fir_config.coeff_2[1] << 8) & VFV_COEF_MASK1; + utemp |= (af_dev->config->fir_config.coeff_2[2] << 16) & VFV_COEF_MASK2; + utemp |= (af_dev->config->fir_config.coeff_2[3] << 24) & VFV_COEF_MASK3; + regw(utemp, AF_VFV_CFG3); + + utemp = af_dev->config->fir_config.coeff_2[4] & VFV_COEF_MASK0; + utemp |= (af_dev->config->fir_config.vfv_thr2 << VFV_THR_SHIFT) & + VFV_THR_MASK; + regw(utemp, AF_VFV_CFG4); + /* Set AFBUFST to Current buffer Physical Address */ + regw((unsigned int)(virt_to_phys(af_dev->buff_curr)), AFBUFST); + + return 0; +} +EXPORT_SYMBOL(af_register_setup); + +inline u32 af_get_hw_state(void) +{ + return (regr(AFPCR) & AF_BUSYAF) >> AF_BUSYAF_SHIFT; +} +EXPORT_SYMBOL(af_get_hw_state); + +inline u32 aew_get_hw_state(void) +{ + return (regr(AEWPCR) & AEW_BUSYAEWB) >> AEW_BUSYAEW_SHIFT; +} +EXPORT_SYMBOL(aew_get_hw_state); + +inline u32 af_get_enable(void) +{ + return regr(AFPCR) & AF_EN; +} +EXPORT_SYMBOL(af_get_enable); + +inline u32 aew_get_enable(void) +{ + return (regr(AEWPCR) & AEW_EN) >> AEW_EN_SHIFT; +} +EXPORT_SYMBOL(aew_get_enable); + +/* Function to Enable/Disable AF Engine */ +inline void af_engine_setup(struct device *dev, int enable) +{ + unsigned int pcr; + + mutex_lock(&a3_cfg.lock); + pcr = regr(AFPCR); + dev_dbg(dev, "Engine Setup value before PCR : %x\n", pcr); + + /* Set AF_EN bit in PCR Register */ + if (enable) + pcr |= AF_EN; + else + pcr &= ~AF_EN; + + regw(pcr, AFPCR); + mutex_unlock(&a3_cfg.lock); + + dev_dbg(dev, "Engine Setup value after PCR : %x\n", pcr); +} +EXPORT_SYMBOL(af_engine_setup); + +/* Function to set address */ +inline void af_set_address(struct device *dev, unsigned long address) +{ + regw((address & ~0x3F), AFBUFST); +} +EXPORT_SYMBOL(af_set_address); + +/* Function to set hardware configuration registers */ +int aew_register_setup(struct device *dev, struct aew_device *aew_dev) +{ + unsigned utemp; + + mutex_lock(&a3_cfg.lock); + /* Set up the registers */ + utemp = regr(AEWPCR); + + /* Enable A Law */ + if (aew_dev->config->alaw_enable == H3A_AEW_ENABLE) + utemp |= AEW_ALAW_EN; + else + utemp &= ~AEW_ALAW_EN; + + utemp &= ~AEW_MED_EN; + /*HMF Configurations */ + if (aew_dev->config->hmf_config.enable == H3A_AEW_ENABLE) { + /* Enable HMF */ + utemp |= AEW_MED_EN; + /* Set Median Threshold */ + utemp &= ~MED_TH; + utemp |= (aew_dev->config->hmf_config.threshold << + AF_MED_TH_SHIFT) & MED_TH; + } + + /*Configure Saturation limit */ + utemp &= ~AVE2LMT; + utemp |= aew_dev->config->saturation_limit << AEW_AVE2LMT_SHIFT; + regw(utemp, AEWPCR); + mutex_unlock(&a3_cfg.lock); + + /*Window parameter configuration */ + /* Configure Window Width in AEWWIN1 register */ + utemp = SET_VAL(aew_dev->config->window_config.height) << + AEW_WINH_SHIFT; + + /* Configure Window height in AEWWIN1 register */ + utemp |= SET_VAL(aew_dev->config->window_config.width) << + AEW_WINW_SHIFT; + + /* Configure Window vertical count in AEWWIN2 register */ + utemp |= (aew_dev->config->window_config.vt_cnt - 1) << + AEW_VT_COUNT_SHIFT; + + /* Configure Window horizontal count in AEWWIN1 register */ + utemp |= (aew_dev->config->window_config).hz_cnt - 1; + + /* Configure Window vertical start in AEWWIN1 register */ + regw(utemp, AEWWIN1); + + /*Window Start parameter configuration */ + utemp = aew_dev->config->window_config.vt_start << AEW_VT_START_SHIFT; + + /* Configure Window horizontal start in AEWWIN2 register */ + utemp &= ~WINSH; + utemp |= (aew_dev->config->window_config).hz_start; + regw(utemp, AEWINSTART); + + /*Window Line Increment configuration */ + /*Configure vertical line increment in AEWSUBWIN */ + utemp = SET_VAL(aew_dev->config->window_config. + vt_line_incr) << AEW_LINE_INCR_SHIFT; + + /* Configuring Horizontal Line increment in AEWSUBWIN */ + utemp &= ~AEWINCH; + utemp |= SET_VAL(aew_dev->config->window_config.hz_line_incr); + + regw(utemp, AEWSUBWIN); + + /* Black Window Configuration */ + /* Configure vertical start and height in AEWWINBLK */ + utemp = (aew_dev->config->blackwindow_config).vt_start << + AEW_BLKWIN_VT_START_SHIFT; + + /* Configure height in Black window */ + utemp &= ~BLKWINH; + utemp |= SET_VAL(aew_dev->config->blackwindow_config.height); + regw(utemp, AEWINBLK); + + /* AE/AWB engine configuration */ + utemp = aew_dev->config->sum_shift & AEW_SUMSHFT_MASK; + utemp |= (aew_dev->config->out_format << AEFMT_SHFT) & AEFMT_MASK; + regw(utemp, AEW_CFG); + + /* Set AFBUFST to Current buffer Physical Address */ + regw((unsigned int)(virt_to_phys(aew_dev->buff_curr)), AEWBUFST); + + return 0; +} +EXPORT_SYMBOL(aew_register_setup); + +/* Function to enable/ disable AEW Engine */ +inline void aew_engine_setup(struct device *dev, int value) +{ + unsigned int pcr; + + dev_dbg(dev, "AEW_REG(PCR) Before Setting %x\n", regr(AEWPCR)); + mutex_lock(&a3_cfg.lock); + /* Read Pcr Register */ + pcr = regr(AEWPCR); + pcr &= ~AEW_EN; + pcr |= value << AEW_EN_SHIFT; + /*Set AF_EN bit in PCR Register */ + regw(pcr, AEWPCR); + mutex_unlock(&a3_cfg.lock); + dev_dbg(dev, "After Setting %d : PCR VALUE %x\n", value, regr(AEWPCR)); + +} +EXPORT_SYMBOL(aew_engine_setup); + +/* Function used to set adddress */ +inline void aew_set_address(struct device *dev, unsigned long address) +{ + regw((address & ~0x3F), AEWBUFST); +} +EXPORT_SYMBOL(aew_set_address); + +static int dm365_afew_hw_init(void) +{ + mutex_init(&a3_cfg.lock); + a3_cfg.base = ioremap(DM365_A3_HW_ADDR, DM365_A3_HW_ADDR_SIZE); + if (!a3_cfg.base) { + printk(KERN_ERR "Unable to ioremap 3A registers\n"); + return -EINVAL; + } + regw(0, LINE_START); + + return 0; +} + +static void dm365_afew_hw_exit(void) +{ + iounmap(a3_cfg.base); +} +subsys_initcall(dm365_afew_hw_init); +module_exit(dm365_afew_hw_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/dm365_a3_hw.h b/drivers/media/video/davinci/dm365_a3_hw.h new file mode 100644 index 0000000..eb5a1d4 --- /dev/null +++ b/drivers/media/video/davinci/dm365_a3_hw.h @@ -0,0 +1,253 @@ +/* +* Copyright (C) 2011 Texas Instruments Inc +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DM365_A3_HW_H +#define DM365_A3_HW_H + +#include <linux/io.h> +#include <linux/device.h> +#include <mach/hardware.h> +#include "dm365_aew.h" +#include "dm365_af.h" + +/* AF/AE/AWB Base address and range */ +#define DM365_A3_HW_ADDR 0x1c71400 +#define DM365_A3_HW_ADDR_SIZE 128 +/* AF Register Offsets */ + +/* Peripheral Revision and Class Information */ +#define AFPID 0x0 +/* Peripheral Control Register */ +#define AFPCR 0x4 +/* Setup for the Paxel Configuration */ +#define AFPAX1 0x8 +/* Setup for the Paxel Configuration */ +#define AFPAX2 0xc +/* Start Position for AF Engine Paxels */ +#define AFPAXSTART 0x10 +/* Start Position for IIRSH */ +#define AFIIRSH 0x14 +/* SDRAM/DDRAM Start address */ +#define AFBUFST 0x18 +/* IIR filter coefficient data for SET 0 */ +#define AFCOEF010 0x1c +/* IIR filter coefficient data for SET 0 */ +#define AFCOEF032 0x20 +/* IIR filter coefficient data for SET 0 */ +#define AFCOEF054 0x24 +/* IIR filter coefficient data for SET 0 */ +#define AFCOEF076 0x28 +/* IIR filter coefficient data for SET 0 */ +#define AFCOEF098 0x2c +/* IIR filter coefficient data for SET 0 */ +#define AFCOEF0010 0x30 +/* IIR filter coefficient data for SET 1 */ +#define AFCOEF110 0x34 +/* IIR filter coefficient data for SET 1 */ +#define AFCOEF132 0x38 +/* IIR filter coefficient data for SET 1 */ +#define AFCOEF154 0x3c +/* IIR filter coefficient data for SET 1 */ +#define AFCOEF176 0x40 +/* IIR filter coefficient data for SET 1 */ +#define AFCOEF198 0x44 +/* IIR filter coefficient data for SET 1 */ +#define AFCOEF1010 0x48 + +/* Vertical Focus vlaue configuration 1 */ +#define AF_VFV_CFG1 0x68 +/* Vertical Focus vlaue configuration 2 */ +#define AF_VFV_CFG2 0x6c +/* Vertical Focus vlaue configuration 3 */ +#define AF_VFV_CFG3 0x70 +/* Vertical Focus vlaue configuration 4 */ +#define AF_VFV_CFG4 0x74 +/* Horizontal Focus vlaue Threshold */ +#define AF_HFV_THR 0x78 +/* COEFFICIENT BASE ADDRESS */ + +#define AF_OFFSET 0x00000004 + +/* AEW Register offsets */ +#define AEWPID AFPID +/* Peripheral Control Register */ +#define AEWPCR AFPCR +/* Configuration for AE/AWB Windows */ +#define AEWWIN1 0x4c +/* Start position for AE/AWB Windows */ +#define AEWINSTART 0x50 +/* Start position and height for black linr of AE/AWB Windows */ +#define AEWINBLK 0x54 +/* Configuration for subsampled data in AE/AWB windows */ +#define AEWSUBWIN 0x58 +/* SDRAM/DDRAM Start address for AEW Engine */ +#define AEWBUFST 0x5c +/* Line start */ +#define LINE_START 0x64 + +/* AEW Engine configuration */ +#define AEW_CFG 0x60 + +/* PID fields */ +#define PID_MINOR (0x3f << 0) +#define PID_MAJOR (7 << 8) +#define PID_RTL (0x1f << 11) +#define PID_FUNC (0xfff << 16) +#define PID_SCHEME (3 << 30) + +/* PCR FIELDS */ + +/*Saturation Limit */ +#define AVE2LMT (0x3ff << 22) +#define AF_VF_EN (1 << 20) +#define AEW_MED_EN (1 << 19) +/* Busy bit for AEW */ +#define AEW_BUSYAEWB (1 << 18) +/* Alaw Enable/Disable Bit */ +#define AEW_ALAW_EN (1 << 17) +/* AEW Engine Enable/Disable bit */ +#define AEW_EN (1 << 16) +/* Busy Bit for AF */ +#define AF_BUSYAF (1 << 15) +#define FVMODE (1 << 14) +#define RGBPOS (7 << 11) +#define MED_TH (0xff << 3) +#define AF_MED_EN (1 << 2) +#define AF_ALAW_EN (1 << 1) +#define AF_EN (1 << 0) + +/* + * AFPAX1 fields + */ +#define PAXW (0xff << 16) +#define PAXH 0xff + +/* + * AFPAX2 fields + */ +#define AFINCH (0xf << 17) +#define AFINCV (0xf << 13) +#define PAXVC (0x7f << 6) +#define PAXHC 0x3f + +/* + * AFPAXSTART fields + */ +#define PAXSH (0xfff << 16) +#define PAXSV 0xfff + +/* + * IIR COEFFICIENT MASKS + */ +#define COEF_MASK0 0xfff +#define COEF_MASK1 (0xfff << 16) + +/* + * VFV_CFGX COEFFICIENT MASKS + */ +#define VFV_COEF_MASK0 0xff +#define VFV_COEF_MASK1 (0xff << 8) +#define VFV_COEF_MASK2 (0xff << 16) +#define VFV_COEF_MASK3 (0xff << 24) + +/* HFV THR MASKS */ +#define HFV_THR0_MASK 0xffff +#define HFV_THR2_SHIFT 16 +#define HFV_THR2_MASK (0xffff << HFV_THR2_SHIFT) + +/* VFV THR MASKS */ +#define VFV_THR_SHIFT 16 +#define VFV_THR_MASK (0xffff << VFV_THR_SHIFT) + +/* BIT SHIFTS */ +#define AF_BUSYAF_SHIFT 15 +#define AEW_EN_SHIFT 16 +#define AEW_BUSYAEW_SHIFT 18 +#define AF_RGBPOS_SHIFT 11 +#define AF_MED_TH_SHIFT 3 +#define AF_PAXW_SHIFT 16 +#define AF_LINE_INCR_SHIFT 13 +#define AF_COLUMN_INCR_SHIFT 17 +#define AF_VT_COUNT_SHIFT 6 +#define AF_HZ_START_SHIFT 16 +#define AF_COEF_SHIFT 16 + +/* AEWWIN1 fields */ +/* Window Height */ +#define WINH (0x7f << 24) +/* Window Width */ +#define WINW (0x7f << 13) +/* Window vertical Count */ +#define WINVC (0x7f << 6) +/* Window Horizontal Count */ +#define WINHC 0x3f + +/* AEWWINSTART fields */ +/* Window Vertical Start */ +#define WINSV (0xfff << 16) +/* Window Horizontal start */ +#define WINSH 0xfff + +/* AEWWINBLK fields + * Black Window Vertical Start + */ +#define BLKWINSV (0xfff << 16) +/* Black Window height */ +#define BLKWINH 0x7f + +/* AEWSUBWIN fields + * Vertical Lime Increment + */ +#define AEWINCV (0xf << 8) +/* Horizontal Line Increment */ +#define AEWINCH 0xf + +/* BIT POSITIONS */ +#define AEW_AVE2LMT_SHIFT 22 +#define AEW_WINH_SHIFT 24 +#define AEW_WINW_SHIFT 13 +#define AEW_VT_COUNT_SHIFT 6 +#define AEW_VT_START_SHIFT 16 +#define AEW_LINE_INCR_SHIFT 8 + +#define AEW_EN_SHIFT 16 +#define AEW_BUSYAEWB_SHIFT 18 +#define AEW_BLKWIN_VT_START_SHIFT 16 + +#define AEFMT_SHFT 8 +#define AEFMT_MASK (3 << AEFMT_SHFT) +#define AEW_SUMSHFT_MASK 0xf + +#define SET_VAL(x) (((x) / 2) - 1) +#define NOT_EVEN 1 +#define CHECK_EVEN(x) ((x) % 2) + +/* Function declaration for af */ +int af_register_setup(struct device *, struct af_device *); +void af_set_address(struct device *, unsigned long); +void af_engine_setup(struct device *, int); +u32 af_get_hw_state(void); +u32 af_get_enable(void); + +/* Function Declaration for aew */ +int aew_register_setup(struct device *, struct aew_device *); +void aew_set_address(struct device *, unsigned long); +void aew_engine_setup(struct device *, int); +u32 aew_get_hw_state(void); +u32 aew_get_enable(void); + +#endif /*end of #ifdef __DAVINCI_A3_HW_H */ diff --git a/drivers/media/video/davinci/dm365_aew.c b/drivers/media/video/davinci/dm365_aew.c new file mode 100644 index 0000000..8c193c8 --- /dev/null +++ b/drivers/media/video/davinci/dm365_aew.c @@ -0,0 +1,544 @@ +/* +* Copyright (C) 2011 Texas Instruments Inc +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <media/v4l2-device.h> +#include "dm365_a3_hw.h" +#include "vpss.h" +#include "vpfe_aew.h" + +#define DRIVERNAME "DM365AEW" + +/* Global structure */ +static struct aew_device *aew_dev_configptr; +static struct device *aewdev; + +int aew_validate_parameters(void) +{ + + /* Check horizontal Count */ + if (aew_dev_configptr->config->window_config.hz_cnt < + AEW_WINDOW_HORIZONTAL_COUNT_MIN || + aew_dev_configptr->config->window_config.hz_cnt > + AEW_WINDOW_HORIZONTAL_COUNT_MAX) { + dev_err(aewdev, "Horizontal Count is incorrect\n"); + return -EINVAL; + } + /* Check Vertical Count */ + if (aew_dev_configptr->config->window_config.vt_cnt < + AEW_WINDOW_VERTICAL_COUNT_MIN || + aew_dev_configptr->config->window_config.vt_cnt > + AEW_WINDOW_VERTICAL_COUNT_MAX) { + dev_err(aewdev, "Vertical Count is incorrect\n"); + return -EINVAL; + } + /* Check line increment */ + if (NOT_EVEN == CHECK_EVEN(aew_dev_configptr->config->window_config. + hz_line_incr) || aew_dev_configptr->config->window_config. + hz_line_incr < AEW_HZ_LINEINCR_MIN || + aew_dev_configptr->config->window_config.hz_line_incr > + AEW_HZ_LINEINCR_MAX) { + dev_err(aewdev, "Invalid Parameters\n"); + dev_err(aewdev, "Horizontal Line Increment is incorrect\n"); + return -EINVAL; + } + /* Check line increment */ + if (NOT_EVEN == CHECK_EVEN(aew_dev_configptr->config->window_config. + vt_line_incr) || aew_dev_configptr->config->window_config. + vt_line_incr < AEW_VT_LINEINCR_MIN || + aew_dev_configptr->config->window_config.vt_line_incr > + AEW_VT_LINEINCR_MAX) { + dev_err(aewdev, "Invalid Parameters\n"); + dev_err(aewdev, "Vertical Line Increment is incorrect\n"); + return -EINVAL; + } + /* Check width */ + if (NOT_EVEN == CHECK_EVEN(aew_dev_configptr->config->window_config. + width) || aew_dev_configptr->config->window_config.width < + AEW_WIDTH_MIN || + aew_dev_configptr->config->window_config.width > + AEW_WIDTH_MAX) { + dev_err(aewdev, "Width is incorrect\n"); + return -EINVAL; + } + /* Check Height */ + if (NOT_EVEN == CHECK_EVEN(aew_dev_configptr->config->window_config. + height) || aew_dev_configptr->config->window_config.height < + AEW_HEIGHT_MIN || + aew_dev_configptr->config->window_config.height > + AEW_HEIGHT_MAX) { + dev_err(aewdev, "height incorrect\n"); + return -EINVAL; + } + /* Check Horizontal Start */ + if (aew_dev_configptr->config->window_config.hz_start < + AEW_HZSTART_MIN || + aew_dev_configptr->config->window_config.hz_start > + AEW_HZSTART_MAX) { + dev_err(aewdev, "horizontal start is incorrect\n"); + return -EINVAL; + } + if (aew_dev_configptr->config->window_config.vt_start > + AEW_VTSTART_MAX) { + dev_err(aewdev, "Vertical start is incorrect\n"); + return -EINVAL; + } + if (aew_dev_configptr->config->alaw_enable > H3A_AEW_ENABLE || + aew_dev_configptr->config->alaw_enable < H3A_AEW_DISABLE) { + dev_err(aewdev, "A Law setting is incorrect\n"); + return -EINVAL; + } + if (aew_dev_configptr->config->saturation_limit > AEW_AVELMT_MAX) { + dev_err(aewdev, "Saturation Limit is incorrect\n"); + return -EINVAL; + } + /* Check Black Window Height */ + if (NOT_EVEN == CHECK_EVEN(aew_dev_configptr->config-> + blackwindow_config.height) || + aew_dev_configptr->config->blackwindow_config.height < + AEW_BLKWINHEIGHT_MIN || + aew_dev_configptr->config->blackwindow_config.height > + AEW_BLKWINHEIGHT_MAX) { + dev_err(aewdev, "Black Window height incorrect\n"); + return -EINVAL; + } + /* Check Black Window Height */ + if (NOT_EVEN == CHECK_EVEN(aew_dev_configptr->config-> + blackwindow_config.height) || + aew_dev_configptr->config->blackwindow_config.vt_start < + AEW_BLKWINVTSTART_MIN || + aew_dev_configptr->config->blackwindow_config.vt_start > + AEW_BLKWINVTSTART_MAX) { + dev_err(aewdev, "Black Window vertical Start is incorrect\n"); + return -EINVAL; + } + + if (aew_dev_configptr->config->out_format < AEW_OUT_SUM_OF_SQUARES || + aew_dev_configptr->config->out_format > AEW_OUT_SUM_ONLY) { + dev_err(aewdev, "Invalid out_format\n"); + return -EINVAL; + } + + if (aew_dev_configptr->config->sum_shift > AEW_SUMSHIFT_MAX) { + dev_err(aewdev, "sum_shift param is invalid, max = %d\n", + AEW_SUMSHIFT_MAX); + return -EINVAL; + } + + return 0; +} + +/* inline function to free reserver pages */ +inline void aew_free_pages(unsigned long addr, unsigned long bufsize) +{ + unsigned long tempaddr; + unsigned long size; + + tempaddr = addr; + if (!addr) + return; + + size = PAGE_SIZE << (get_order(bufsize)); + while (size > 0) { + ClearPageReserved(virt_to_page(addr)); + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + free_pages(tempaddr, get_order(bufsize)); +} + +/* Function to perform hardware Configuration */ +int aew_hardware_setup(void) +{ + unsigned int busyaew; + unsigned long size; + unsigned long adr; + /* Size for buffer in bytes */ + int buff_size; + int result; + + /* Get the value of PCR register */ + busyaew = aew_get_hw_state(); + + /* If H3A Engine is busy then return */ + if (busyaew == 1) { + dev_err(aewdev, "Error : AEW Engine is busy\n"); + return -EBUSY; + } + + result = aew_validate_parameters(); + dev_dbg(aewdev, "Result = %d\n", result); + if (result < 0) { + dev_err(aewdev, "Error : Parameters are incorrect\n"); + return result; + } + + /* Deallocate the previously allocated buffers */ + if (aew_dev_configptr->buff_old) + aew_free_pages((unsigned long)aew_dev_configptr->buff_old, + aew_dev_configptr->size_window); + + if (aew_dev_configptr->buff_curr) + aew_free_pages((unsigned long)aew_dev_configptr-> + buff_curr, aew_dev_configptr->size_window); + + if (aew_dev_configptr->buff_app) + aew_free_pages((unsigned long)aew_dev_configptr-> + buff_app, aew_dev_configptr->size_window); + + /* + * Allocat the buffers as per the new buffer size + * Allocate memory for old buffer + */ + if (aew_dev_configptr->config->out_format == AEW_OUT_SUM_ONLY) + buff_size = (aew_dev_configptr->config->window_config.hz_cnt) * + (aew_dev_configptr->config->window_config.vt_cnt) * + AEW_WINDOW_SIZE_SUM_ONLY; + else + buff_size = (aew_dev_configptr->config->window_config.hz_cnt) * + (aew_dev_configptr->config->window_config.vt_cnt) * + AEW_WINDOW_SIZE; + + aew_dev_configptr->buff_old = (void *)__get_free_pages(GFP_KERNEL | + GFP_DMA, get_order(buff_size)); + + if (aew_dev_configptr->buff_old == NULL) + return -ENOMEM; + + /* Make pges reserved so that they will be swapped out */ + adr = (unsigned long)aew_dev_configptr->buff_old; + size = PAGE_SIZE << (get_order(buff_size)); + while (size > 0) { + /* + * make sure the frame buffers + * are never swapped out of memory + */ + SetPageReserved(virt_to_page(adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + /* Allocate memory for current buffer */ + aew_dev_configptr->buff_curr = (void *)__get_free_pages(GFP_KERNEL | + GFP_DMA, get_order(buff_size)); + + if (aew_dev_configptr->buff_curr == NULL) { + /*Free all buffer that are allocated */ + if (aew_dev_configptr->buff_old) + aew_free_pages((unsigned long)aew_dev_configptr-> + buff_old, buff_size); + return -ENOMEM; + } + + /* Make pges reserved so that they will be swapped out */ + adr = (unsigned long)aew_dev_configptr->buff_curr; + size = PAGE_SIZE << (get_order(buff_size)); + while (size > 0) { + /* + * make sure the frame buffers + * are never swapped out of memory + */ + SetPageReserved(virt_to_page(adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + /* Allocate memory for application buffer */ + aew_dev_configptr->buff_app = (void *)__get_free_pages(GFP_KERNEL | + GFP_DMA, get_order(buff_size)); + + if (aew_dev_configptr->buff_app == NULL) { + /* Free all buffer that were allocated previously */ + if (aew_dev_configptr->buff_old) + aew_free_pages((unsigned long)aew_dev_configptr-> + buff_old, buff_size); + if (aew_dev_configptr->buff_curr) + aew_free_pages((unsigned long)aew_dev_configptr-> + buff_curr, buff_size); + return -ENOMEM; + } + + /* Make pages reserved so that they will be swapped out */ + adr = (unsigned long)aew_dev_configptr->buff_app; + size = PAGE_SIZE << (get_order(buff_size)); + while (size > 0) { + /* + * make sure the frame buffers + * are never swapped out of memory + */ + SetPageReserved(virt_to_page(adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + /* Set the registers */ + aew_register_setup(aewdev, aew_dev_configptr); + aew_dev_configptr->size_window = buff_size; + aew_dev_configptr->aew_config = H3A_AEW_CONFIG; + + return 0; +} + +int aew_open(void) +{ + /* Return if Device is in use (Single Channel Support is provided) */ + if (aew_dev_configptr->in_use == AEW_IN_USE) + return -EBUSY; + + /* Set the aew_dev_configptr structure */ + aew_dev_configptr->config = NULL; + + /* Allocate memory for configuration structure of this channel */ + aew_dev_configptr->config = (struct aew_configuration *) + kmalloc(sizeof(struct aew_configuration), GFP_KERNEL); + + if (aew_dev_configptr->config == NULL) { + dev_err(aewdev, "Error : Kmalloc fail\n"); + return -ENOMEM; + } + + /* Device is in use */ + aew_dev_configptr->in_use = AEW_IN_USE; + /* No Hardware Set up done */ + aew_dev_configptr->aew_config = H3A_AEW_CONFIG_NOT_DONE; + /* No statistics are available */ + aew_dev_configptr->buffer_filled = 0; + /* Set Window Size to 0 */ + aew_dev_configptr->size_window = 0; + + return 0; +} + +int aew_release(void) +{ + aew_engine_setup(aewdev, 0); + /* The Application has closed device so device is not in use */ + aew_dev_configptr->in_use = AEW_NOT_IN_USE; + + /* Release memory for configuration structure of this channel */ + kfree(aew_dev_configptr->config); + + /* Free Old Buffer */ + if (aew_dev_configptr->buff_old) + aew_free_pages((unsigned long)aew_dev_configptr->buff_old, + aew_dev_configptr->size_window); + + /* Free Current Buffer */ + if (aew_dev_configptr->buff_curr) + aew_free_pages((unsigned long)aew_dev_configptr-> + buff_curr, aew_dev_configptr->size_window); + + /* Free Application Buffer */ + if (aew_dev_configptr->buff_app) + aew_free_pages((unsigned long)aew_dev_configptr->buff_app, + aew_dev_configptr->size_window); + + aew_dev_configptr->buff_old = NULL; + aew_dev_configptr->buff_curr = NULL; + aew_dev_configptr->config = NULL; + aew_dev_configptr->buff_app = NULL; + + return 0; +} + +/* + * This function will process IOCTL commands sent by the application and + * control the devices IO operations. + */ +int aew_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + /* Stores Previous Configurations */ + struct aew_configuration aewconfig = *(aew_dev_configptr->config); + struct aew_statdata *stat_data = (struct aew_statdata *)arg; + void *buffer_temp; + int result; + + /* Switch according to IOCTL command */ + switch (cmd) { + /* + * This ioctl is used to perform hardware set up + * and will set all the registers for AF engine + */ + case AEW_S_PARAM: + /* Copy config structure passed by user */ + memcpy(aew_dev_configptr->config, + (struct aew_configuration *)arg, + sizeof(struct aew_configuration)); + + /* Call aew_hardware_setup to perform register configuration */ + result = aew_hardware_setup(); + if (!result) { + /* + * Hardware Set up is successful + * Return the no of bytes required for buffer + */ + result = aew_dev_configptr->size_window; + } else { + /* Change Configuration Structure to original */ + *(aew_dev_configptr->config) = aewconfig; + dev_err(aewdev, "Error : AEW_S_PARAM failed\n"); + } + break; + + /* This ioctl is used to return parameters in user space */ + case AEW_G_PARAM: + if (aew_dev_configptr->aew_config == H3A_AEW_CONFIG) { + memcpy((struct aew_configuration *)arg, + aew_dev_configptr->config, + sizeof(struct aew_configuration)); + result = aew_dev_configptr->size_window; + } else { + dev_err(aewdev, + "Error : AEW Hardware is not configured.\n"); + result = -EINVAL; + } + break; + case AEW_GET_STAT: + /* Implement the read functionality */ + if (aew_dev_configptr->buffer_filled != 1) + return -EINVAL; + + if (stat_data->buf_length < aew_dev_configptr->size_window) + return -EINVAL; + + /* Disable the interrupts and then swap the buffers */ + disable_irq(6); + + /* New Statistics are availaible */ + aew_dev_configptr->buffer_filled = 0; + + /* Swap application buffer and old buffer */ + buffer_temp = aew_dev_configptr->buff_old; + aew_dev_configptr->buff_old = aew_dev_configptr->buff_app; + aew_dev_configptr->buff_app = buffer_temp; + + /* Interrupts are enabled */ + enable_irq(6); + + /* + * Copy the entire statistics located in application + * buffer to user space + */ + memcpy(stat_data->buffer, aew_dev_configptr->buff_app, + aew_dev_configptr->size_window); + + result = aew_dev_configptr->size_window; + break; + default: + dev_err(aewdev, "Error: It should not come here!!\n"); + result = -ENOTTY; + break; + } + return result; +} + +/* This function will handle interrupt generated by H3A Engine. */ +static irqreturn_t aew_isr(int irq, void *dev_id) +{ + struct v4l2_subdev *sd = dev_id; + /* EN AF Bit */ + unsigned int enaew; + /* Temporary Buffer for Swapping */ + void *buffer_temp; + + /* Get the value of PCR register */ + enaew = aew_get_enable(); + + /* If AEW engine is not enabled, interrupt is not for AEW */ + if (!enaew || !aew_dev_configptr) + return IRQ_RETVAL(IRQ_NONE); + + /* + * Interrupt is generated by AEW, so Service the Interrupt + * Swap current buffer and old buffer + */ + buffer_temp = aew_dev_configptr->buff_curr; + aew_dev_configptr->buff_curr = aew_dev_configptr->buff_old; + aew_dev_configptr->buff_old = buffer_temp; + + /* Set the AEWBUFSTAT REgister to current buffer Address */ + aew_set_address(aewdev, + (unsigned long)(virt_to_phys(aew_dev_configptr->buff_curr))); + /* + * Set buffer filled flag to indicate statistics are available + */ + aew_dev_configptr->buffer_filled = 1; + /* queue the event with v4l2 */ + aew_queue_event(sd); + + return IRQ_RETVAL(IRQ_HANDLED); +} + +int aew_set_stream(struct v4l2_subdev *sd, int enable) +{ + int result; + + if (!enable) { + /* stop capture */ + free_irq(6, sd); + /* Disable AEW Engine */ + aew_engine_setup(aewdev, 0); + return 0; + } + /* start capture */ + /* Enable AEW Engine if Hardware set up is done */ + if (aew_dev_configptr->aew_config == H3A_AEW_CONFIG_NOT_DONE) { + dev_err(aewdev, "Error : AEW Hardware is not configured.\n"); + return -EINVAL; + } + result = request_irq(6, aew_isr, IRQF_SHARED, "dm365_h3a_aew", + (void *)sd); + if (result != 0) + return result; + /* Enable AF Engine */ + aew_engine_setup(aewdev, 1); + + return 0; +} + +int aew_init(struct platform_device *pdev) +{ + aew_dev_configptr = kmalloc(sizeof(struct aew_device), GFP_KERNEL); + if (!aew_dev_configptr) { + printk(KERN_ERR "aew_init: Error : kmalloc fail\n"); + return -ENOMEM; + } + /* Initialize device structure */ + memset(aew_dev_configptr, 0, sizeof(struct aew_device)); + aew_dev_configptr->in_use = AEW_NOT_IN_USE; + aew_dev_configptr->buffer_filled = 0; + aewdev = &pdev->dev; + + return 0; +} + +void aew_cleanup(void) +{ + /* in use */ + if (aew_dev_configptr->in_use == AEW_IN_USE) { + printk(KERN_ERR "aew_cleanup: Error : dm365_aew in use"); + return; + } + /* Free device structure */ + kfree(aew_dev_configptr); + aew_dev_configptr = NULL; +} diff --git a/drivers/media/video/davinci/dm365_aew.h b/drivers/media/video/davinci/dm365_aew.h new file mode 100644 index 0000000..47bfda5 --- /dev/null +++ b/drivers/media/video/davinci/dm365_aew.h @@ -0,0 +1,55 @@ +/* +* Copyright (C) 2011 Texas Instruments Inc +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef DM365_AEW_DRIVER_H +#define DM365_AEW_DRIVER_H + +#include <linux/ioctl.h> +#include <linux/wait.h> +#include <linux/mutex.h> +#include <linux/io.h> +#include <linux/dm365_aew.h> + +/* Contains information about device structure of AEW*/ +struct aew_device { + /* Driver usage flag */ + enum aew_in_use_flag in_use; + /* Device configuration */ + struct aew_configuration *config; + /* Contains latest statistics */ + void *buff_old; + /* Buffer in which HW will fill the statistics or HW is already + * filling + */ + void *buff_curr; + /* statistics Buffer which will be passed */ + void *buff_app; + /* to user on read call. Flag indicates statistics are available */ + int buffer_filled; + /* Window size in bytes */ + unsigned int size_window; + /* Wait queue for the driver */ + wait_queue_head_t aew_wait_queue; + /* Mutex for driver */ + struct mutex read_blocked; + /* Flag indicates Engine is configured */ + enum aew_config_flag aew_config; +}; + +int aew_validate_parameters(void); +int aew_hardware_setup(void); + +#endif /*End of DM365_AEW_H */ diff --git a/include/linux/dm365_aew.h b/include/linux/dm365_aew.h new file mode 100644 index 0000000..3882d79 --- /dev/null +++ b/include/linux/dm365_aew.h @@ -0,0 +1,153 @@ +/* +* Copyright (C) 2011 Texas Instruments Inc +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _DM365_AEW_INCLUDE_H +#define _DM365_AEW_INCLUDE_H + +/* Driver Range Constants */ +#define AEW_WINDOW_VERTICAL_COUNT_MIN 1 +#define AEW_WINDOW_VERTICAL_COUNT_MAX 128 +#define AEW_WINDOW_HORIZONTAL_COUNT_MIN 2 +#define AEW_WINDOW_HORIZONTAL_COUNT_MAX 36 + +#define AEW_WIDTH_MIN 8 +#define AEW_WIDTH_MAX 256 + +#define AEW_AVELMT_MAX 1023 + +#define AEW_HZ_LINEINCR_MIN 2 +#define AEW_HZ_LINEINCR_MAX 32 + +#define AEW_VT_LINEINCR_MIN 2 +#define AEW_VT_LINEINCR_MAX 32 + +#define AEW_HEIGHT_MIN 2 +#define AEW_HEIGHT_MAX 256 + +#define AEW_HZSTART_MIN 0 +#define AEW_HZSTART_MAX 4095 + +#define AEW_VTSTART_MIN 0 +#define AEW_VTSTART_MAX 4095 + +#define AEW_BLKWINHEIGHT_MIN 2 +#define AEW_BLKWINHEIGHT_MAX 256 +#define AEW_BLKWINVTSTART_MIN 0 +#define AEW_BLKWINVTSTART_MAX 4095 + +#define AEW_SUMSHIFT_MAX 15 + +/* Statistics data size per window */ +#define AEW_WINDOW_SIZE 32 +#define AEW_WINDOW_SIZE_SUM_ONLY 16 + +/* List of ioctls */ +#define AEW_MAGIC_NO 'e' +#define AEW_S_PARAM _IOWR(AEW_MAGIC_NO, 1, struct aew_configuration) +#define AEW_G_PARAM _IOWR(AEW_MAGIC_NO, 2, struct aew_configuration) +#define AEW_GET_STAT _IOWR(AEW_MAGIC_NO, 5, struct aew_statdata) + +/* Enum for device usage */ +enum aew_in_use_flag { + /* Device is not in use */ + AEW_NOT_IN_USE, + /* Device in use */ + AEW_IN_USE +}; + +/* Enum for Enable/Disable specific feature */ +enum aew_enable_flag { + H3A_AEW_DISABLE, + H3A_AEW_ENABLE +}; + +enum aew_config_flag { + H3A_AEW_CONFIG_NOT_DONE, + H3A_AEW_CONFIG +}; + + +/* Contains the information regarding Window Structure in AEW Engine */ +struct aew_window { + /* Width of the window */ + unsigned int width; + /* Height of the window */ + unsigned int height; + /* Horizontal Start of the window */ + unsigned int hz_start; + /* Vertical Start of the window */ + unsigned int vt_start; + /* Horizontal Count */ + unsigned int hz_cnt; + /* Vertical Count */ + unsigned int vt_cnt; + /* Horizontal Line Increment */ + unsigned int hz_line_incr; + /* Vertical Line Increment */ + unsigned int vt_line_incr; +}; + +/* Contains the information regarding the AEW Black Window Structure */ +struct aew_black_window { + /* Height of the Black Window */ + unsigned int height; + /* Vertical Start of the black Window */ + unsigned int vt_start; +}; + +/* Contains the information regarding the Horizontal Median Filter */ +struct aew_hmf { + /* Status of Horizontal Median Filter */ + enum aew_enable_flag enable; + /* Threshhold Value for Horizontal Median Filter. Make sure + * to keep this same as AF threshold since we have a common + * threshold for both + */ + unsigned int threshold; +}; + +/* AE/AWB output format */ +enum aew_output_format { + AEW_OUT_SUM_OF_SQUARES, + AEW_OUT_MIN_MAX, + AEW_OUT_SUM_ONLY +}; + +/* Contains configuration required for setup of AEW engine */ +struct aew_configuration { + /* A-law status */ + enum aew_enable_flag alaw_enable; + /* AE/AWB output format */ + enum aew_output_format out_format; + /* AW/AWB right shift value for sum of pixels */ + char sum_shift; + /* Saturation Limit */ + int saturation_limit; + /* HMF configurations */ + struct aew_hmf hmf_config; + /* Window for AEW Engine */ + struct aew_window window_config; + /* Black Window */ + struct aew_black_window blackwindow_config; +}; + +struct aew_statdata { + void *buffer; + int buf_length; +}; + +#endif -- 1.6.2.4 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html