2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2011-02-12 18:05:06 -03:00
/*
* isppreview . c
*
* TI OMAP3 ISP driver - Preview module
*
* Copyright ( C ) 2010 Nokia Corporation
* Copyright ( C ) 2009 Texas Instruments , Inc .
*
* Contacts : Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
* Sakari Ailus < sakari . ailus @ iki . fi >
*/
# include <linux/device.h>
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/uaccess.h>
# include "isp.h"
# include "ispreg.h"
# include "isppreview.h"
2011-03-30 22:57:33 -03:00
/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
2017-08-25 08:06:37 -04:00
static const struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
2011-02-12 18:05:06 -03:00
{ /* RGB-RGB Matrix */
{ 0x01E2 , 0x0F30 , 0x0FEE } ,
{ 0x0F9B , 0x01AC , 0x0FB9 } ,
{ 0x0FE0 , 0x0EC0 , 0x0260 }
} , /* RGB Offset */
{ 0x0000 , 0x0000 , 0x0000 }
} ;
2011-03-30 22:57:33 -03:00
/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
2017-08-25 08:06:37 -04:00
static const struct omap3isp_prev_csc flr_prev_csc = {
2011-02-12 18:05:06 -03:00
{ /* CSC Coef Matrix */
{ 66 , 129 , 25 } ,
{ - 38 , - 75 , 112 } ,
{ 112 , - 94 , - 18 }
} , /* CSC Offset */
{ 0x0 , 0x0 , 0x0 }
} ;
2011-03-30 22:57:33 -03:00
/* Default values in Office Fluorescent Light for CFA Gradient*/
2011-02-12 18:05:06 -03:00
# define FLR_CFA_GRADTHRS_HORZ 0x28
# define FLR_CFA_GRADTHRS_VERT 0x28
2011-03-30 22:57:33 -03:00
/* Default values in Office Fluorescent Light for Chroma Suppression*/
2011-02-12 18:05:06 -03:00
# define FLR_CSUP_GAIN 0x0D
# define FLR_CSUP_THRES 0xEB
2011-03-30 22:57:33 -03:00
/* Default values in Office Fluorescent Light for Noise Filter*/
2011-02-12 18:05:06 -03:00
# define FLR_NF_STRGTH 0x03
/* Default values for White Balance */
# define FLR_WBAL_DGAIN 0x100
# define FLR_WBAL_COEF 0x20
2011-03-30 22:57:33 -03:00
/* Default values in Office Fluorescent Light for Black Adjustment*/
2011-02-12 18:05:06 -03:00
# define FLR_BLKADJ_BLUE 0x0
# define FLR_BLKADJ_GREEN 0x0
# define FLR_BLKADJ_RED 0x0
# define DEF_DETECT_CORRECT_VAL 0xe
2011-09-21 20:05:45 -03:00
/*
* Margins and image size limits .
*
* The preview engine crops several rows and columns internally depending on
* which filters are enabled . To avoid format changes when the filters are
* enabled or disabled ( which would prevent them from being turned on or off
2012-12-07 07:48:55 -03:00
* during streaming ) , the driver assumes all filters that can be configured
* during streaming are enabled when computing sink crop and source format
* limits .
2011-09-21 20:05:45 -03:00
*
* If a filter is disabled , additional cropping is automatically added at the
* preview engine input by the driver to avoid overflow at line and frame end .
* This is completely transparent for applications .
*
* Median filter 4 pixels
* Noise filter ,
* Faulty pixels correction 4 pixels , 4 lines
* Color suppression 2 pixels
* or luma enhancement
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2012-12-07 07:48:55 -03:00
* Maximum total 10 pixels , 4 lines
2011-09-21 20:05:45 -03:00
*
* The color suppression and luma enhancement filters are applied after bayer to
* YUV conversion . They thus can crop one pixel on the left and one pixel on the
* right side of the image without changing the color pattern . When both those
* filters are disabled , the driver must crop the two pixels on the same side of
* the image to avoid changing the bayer pattern . The left margin is thus set to
2012-12-07 07:48:55 -03:00
* 6 pixels and the right margin to 4 pixels .
2011-09-21 20:05:45 -03:00
*/
2012-12-07 07:48:55 -03:00
# define PREV_MARGIN_LEFT 6
# define PREV_MARGIN_RIGHT 4
# define PREV_MARGIN_TOP 2
# define PREV_MARGIN_BOTTOM 2
2011-09-21 20:05:45 -03:00
2011-10-03 07:56:15 -03:00
# define PREV_MIN_IN_WIDTH 64
# define PREV_MIN_IN_HEIGHT 8
# define PREV_MAX_IN_HEIGHT 16384
2011-10-03 07:56:15 -03:00
# define PREV_MIN_OUT_WIDTH 0
# define PREV_MIN_OUT_HEIGHT 0
# define PREV_MAX_OUT_WIDTH_REV_1 1280
# define PREV_MAX_OUT_WIDTH_REV_2 3300
# define PREV_MAX_OUT_WIDTH_REV_15 4096
2011-02-12 18:05:06 -03:00
/*
2014-02-21 09:07:21 -03:00
* Coefficient Tables for the submodules in Preview .
2011-02-12 18:05:06 -03:00
* Array is initialised with the values from . the tables text file .
*/
/*
* CFA Filter Coefficient Table
*
*/
2012-06-18 11:24:48 -03:00
static u32 cfa_coef_table [ 4 ] [ OMAP3ISP_PREV_CFA_BLK_SIZE ] = {
2011-02-12 18:05:06 -03:00
# include "cfa_coef_table.h"
} ;
/*
* Default Gamma Correction Table - All components
*/
static u32 gamma_table [ ] = {
# include "gamma_table.h"
} ;
/*
* Noise Filter Threshold table
*/
static u32 noise_filter_table [ ] = {
# include "noise_filter_table.h"
} ;
/*
* Luminance Enhancement Table
*/
static u32 luma_enhance_table [ ] = {
# include "luma_enhance_table.h"
} ;
/*
2012-07-06 09:07:33 -03:00
* preview_config_luma_enhancement - Configure the Luminance Enhancement table
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 09:07:33 -03:00
preview_config_luma_enhancement ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 09:07:33 -03:00
const struct omap3isp_prev_luma * yt = & params - > luma ;
unsigned int i ;
2011-02-12 18:05:06 -03:00
2012-07-06 09:07:33 -03:00
isp_reg_writel ( isp , ISPPRV_YENH_TABLE_ADDR ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_ADDR ) ;
for ( i = 0 ; i < OMAP3ISP_PREV_YENH_TBL_SIZE ; i + + ) {
isp_reg_writel ( isp , yt - > table [ i ] ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_DATA ) ;
}
2011-02-12 18:05:06 -03:00
}
/*
2012-07-06 09:07:33 -03:00
* preview_enable_luma_enhancement - Enable / disable Luminance Enhancement
2011-02-12 18:05:06 -03:00
*/
2012-07-06 09:07:33 -03:00
static void
preview_enable_luma_enhancement ( struct isp_prev_device * prev , bool enable )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
2012-07-06 09:07:33 -03:00
ISPPRV_PCR_YNENHEN ) ;
2011-02-12 18:05:06 -03:00
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
2012-07-06 09:07:33 -03:00
ISPPRV_PCR_YNENHEN ) ;
2011-02-12 18:05:06 -03:00
}
/*
2012-07-06 09:07:33 -03:00
* preview_enable_invalaw - Enable / disable Inverse A - Law decompression
2011-02-12 18:05:06 -03:00
*/
2012-07-06 09:07:33 -03:00
static void preview_enable_invalaw ( struct isp_prev_device * prev , bool enable )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
2012-10-23 08:11:55 -03:00
ISPPRV_PCR_INVALAW ) ;
2011-02-12 18:05:06 -03:00
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
2012-10-23 08:11:55 -03:00
ISPPRV_PCR_INVALAW ) ;
2011-02-12 18:05:06 -03:00
}
/*
2012-07-06 08:43:27 -03:00
* preview_config_hmed - Configure the Horizontal Median Filter
2011-02-12 18:05:06 -03:00
*/
2012-07-06 08:43:27 -03:00
static void preview_config_hmed ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_hmed * hmed = & params - > hmed ;
2011-02-12 18:05:06 -03:00
isp_reg_writel ( isp , ( hmed - > odddist = = 1 ? 0 : ISPPRV_HMED_ODDDIST ) |
( hmed - > evendist = = 1 ? 0 : ISPPRV_HMED_EVENDIST ) |
( hmed - > thres < < ISPPRV_HMED_THRESHOLD_SHIFT ) ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_HMED ) ;
}
/*
2012-07-06 09:07:33 -03:00
* preview_enable_hmed - Enable / disable the Horizontal Median Filter
2011-02-12 18:05:06 -03:00
*/
2012-07-06 09:07:33 -03:00
static void preview_enable_hmed ( struct isp_prev_device * prev , bool enable )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 09:07:33 -03:00
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_HMEDEN ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_HMEDEN ) ;
2011-02-12 18:05:06 -03:00
}
/*
2012-06-18 11:24:48 -03:00
* preview_config_cfa - Configure CFA Interpolation for Bayer formats
*
* The CFA table is organised in four blocks , one per Bayer component . The
* hardware expects blocks to follow the Bayer order of the input data , while
* the driver stores the table in GRBG order in memory . The blocks need to be
* reordered to support non - GRBG Bayer patterns .
2011-02-12 18:05:06 -03:00
*/
2012-06-18 11:24:48 -03:00
static void preview_config_cfa ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
2012-06-18 11:24:48 -03:00
static const unsigned int cfa_coef_order [ 4 ] [ 4 ] = {
{ 0 , 1 , 2 , 3 } , /* GRBG */
{ 1 , 0 , 3 , 2 } , /* RGGB */
{ 2 , 3 , 0 , 1 } , /* BGGR */
{ 3 , 2 , 1 , 0 } , /* GBRG */
} ;
const unsigned int * order = cfa_coef_order [ prev - > params . cfa_order ] ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_cfa * cfa = & params - > cfa ;
2012-06-18 11:24:48 -03:00
struct isp_device * isp = to_isp_device ( prev ) ;
2011-02-12 18:05:06 -03:00
unsigned int i ;
2012-06-18 11:24:48 -03:00
unsigned int j ;
2011-02-12 18:05:06 -03:00
isp_reg_writel ( isp ,
( cfa - > gradthrs_vert < < ISPPRV_CFA_GRADTH_VER_SHIFT ) |
( cfa - > gradthrs_horz < < ISPPRV_CFA_GRADTH_HOR_SHIFT ) ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_CFA ) ;
isp_reg_writel ( isp , ISPPRV_CFA_TABLE_ADDR ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_ADDR ) ;
2012-06-18 11:24:48 -03:00
for ( i = 0 ; i < 4 ; + + i ) {
const __u32 * block = cfa - > table [ order [ i ] ] ;
for ( j = 0 ; j < OMAP3ISP_PREV_CFA_BLK_SIZE ; + + j )
isp_reg_writel ( isp , block [ j ] , OMAP3_ISP_IOMEM_PREV ,
ISPPRV_SET_TBL_DATA ) ;
2011-02-12 18:05:06 -03:00
}
}
/*
2012-07-06 08:43:27 -03:00
* preview_config_chroma_suppression - Configure Chroma Suppression
2011-02-12 18:05:06 -03:00
*/
static void
preview_config_chroma_suppression ( struct isp_prev_device * prev ,
2012-07-06 08:43:27 -03:00
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_csup * cs = & params - > csup ;
2011-02-12 18:05:06 -03:00
isp_reg_writel ( isp ,
cs - > gain | ( cs - > thres < < ISPPRV_CSUP_THRES_SHIFT ) |
( cs - > hypf_en < < ISPPRV_CSUP_HPYF_SHIFT ) ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_CSUP ) ;
}
/*
2012-07-06 08:43:27 -03:00
* preview_enable_chroma_suppression - Enable / disable Chrominance Suppression
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 08:43:27 -03:00
preview_enable_chroma_suppression ( struct isp_prev_device * prev , bool enable )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_SUPEN ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_SUPEN ) ;
}
/*
2012-07-06 08:43:27 -03:00
* preview_config_whitebalance - Configure White Balance parameters
2011-02-12 18:05:06 -03:00
*
* Coefficient matrix always with default values .
*/
static void
2012-07-06 08:43:27 -03:00
preview_config_whitebalance ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_wbal * wbal = & params - > wbal ;
2011-02-12 18:05:06 -03:00
u32 val ;
isp_reg_writel ( isp , wbal - > dgain , OMAP3_ISP_IOMEM_PREV , ISPPRV_WB_DGAIN ) ;
val = wbal - > coef0 < < ISPPRV_WBGAIN_COEF0_SHIFT ;
val | = wbal - > coef1 < < ISPPRV_WBGAIN_COEF1_SHIFT ;
val | = wbal - > coef2 < < ISPPRV_WBGAIN_COEF2_SHIFT ;
val | = wbal - > coef3 < < ISPPRV_WBGAIN_COEF3_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_WBGAIN ) ;
isp_reg_writel ( isp ,
ISPPRV_WBSEL_COEF0 < < ISPPRV_WBSEL_N0_0_SHIFT |
ISPPRV_WBSEL_COEF1 < < ISPPRV_WBSEL_N0_1_SHIFT |
ISPPRV_WBSEL_COEF0 < < ISPPRV_WBSEL_N0_2_SHIFT |
ISPPRV_WBSEL_COEF1 < < ISPPRV_WBSEL_N0_3_SHIFT |
ISPPRV_WBSEL_COEF2 < < ISPPRV_WBSEL_N1_0_SHIFT |
ISPPRV_WBSEL_COEF3 < < ISPPRV_WBSEL_N1_1_SHIFT |
ISPPRV_WBSEL_COEF2 < < ISPPRV_WBSEL_N1_2_SHIFT |
ISPPRV_WBSEL_COEF3 < < ISPPRV_WBSEL_N1_3_SHIFT |
ISPPRV_WBSEL_COEF0 < < ISPPRV_WBSEL_N2_0_SHIFT |
ISPPRV_WBSEL_COEF1 < < ISPPRV_WBSEL_N2_1_SHIFT |
ISPPRV_WBSEL_COEF0 < < ISPPRV_WBSEL_N2_2_SHIFT |
ISPPRV_WBSEL_COEF1 < < ISPPRV_WBSEL_N2_3_SHIFT |
ISPPRV_WBSEL_COEF2 < < ISPPRV_WBSEL_N3_0_SHIFT |
ISPPRV_WBSEL_COEF3 < < ISPPRV_WBSEL_N3_1_SHIFT |
ISPPRV_WBSEL_COEF2 < < ISPPRV_WBSEL_N3_2_SHIFT |
ISPPRV_WBSEL_COEF3 < < ISPPRV_WBSEL_N3_3_SHIFT ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_WBSEL ) ;
}
/*
2012-07-06 08:43:27 -03:00
* preview_config_blkadj - Configure Black Adjustment
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 08:43:27 -03:00
preview_config_blkadj ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_blkadj * blkadj = & params - > blkadj ;
2011-02-12 18:05:06 -03:00
isp_reg_writel ( isp , ( blkadj - > blue < < ISPPRV_BLKADJOFF_B_SHIFT ) |
( blkadj - > green < < ISPPRV_BLKADJOFF_G_SHIFT ) |
( blkadj - > red < < ISPPRV_BLKADJOFF_R_SHIFT ) ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_BLKADJOFF ) ;
}
/*
2012-07-06 08:43:27 -03:00
* preview_config_rgb_blending - Configure RGB - RGB Blending
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 08:43:27 -03:00
preview_config_rgb_blending ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_rgbtorgb * rgbrgb = & params - > rgb2rgb ;
2011-02-12 18:05:06 -03:00
u32 val ;
val = ( rgbrgb - > matrix [ 0 ] [ 0 ] & 0xfff ) < < ISPPRV_RGB_MAT1_MTX_RR_SHIFT ;
val | = ( rgbrgb - > matrix [ 0 ] [ 1 ] & 0xfff ) < < ISPPRV_RGB_MAT1_MTX_GR_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_MAT1 ) ;
val = ( rgbrgb - > matrix [ 0 ] [ 2 ] & 0xfff ) < < ISPPRV_RGB_MAT2_MTX_BR_SHIFT ;
val | = ( rgbrgb - > matrix [ 1 ] [ 0 ] & 0xfff ) < < ISPPRV_RGB_MAT2_MTX_RG_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_MAT2 ) ;
val = ( rgbrgb - > matrix [ 1 ] [ 1 ] & 0xfff ) < < ISPPRV_RGB_MAT3_MTX_GG_SHIFT ;
val | = ( rgbrgb - > matrix [ 1 ] [ 2 ] & 0xfff ) < < ISPPRV_RGB_MAT3_MTX_BG_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_MAT3 ) ;
val = ( rgbrgb - > matrix [ 2 ] [ 0 ] & 0xfff ) < < ISPPRV_RGB_MAT4_MTX_RB_SHIFT ;
val | = ( rgbrgb - > matrix [ 2 ] [ 1 ] & 0xfff ) < < ISPPRV_RGB_MAT4_MTX_GB_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_MAT4 ) ;
val = ( rgbrgb - > matrix [ 2 ] [ 2 ] & 0xfff ) < < ISPPRV_RGB_MAT5_MTX_BB_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_MAT5 ) ;
val = ( rgbrgb - > offset [ 0 ] & 0x3ff ) < < ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT ;
val | = ( rgbrgb - > offset [ 1 ] & 0x3ff ) < < ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_OFF1 ) ;
val = ( rgbrgb - > offset [ 2 ] & 0x3ff ) < < ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_RGB_OFF2 ) ;
}
/*
2012-07-06 08:43:27 -03:00
* preview_config_csc - Configure Color Space Conversion ( RGB to YCbYCr )
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 08:43:27 -03:00
preview_config_csc ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-07-06 08:43:27 -03:00
const struct omap3isp_prev_csc * csc = & params - > csc ;
2011-02-12 18:05:06 -03:00
u32 val ;
val = ( csc - > matrix [ 0 ] [ 0 ] & 0x3ff ) < < ISPPRV_CSC0_RY_SHIFT ;
val | = ( csc - > matrix [ 0 ] [ 1 ] & 0x3ff ) < < ISPPRV_CSC0_GY_SHIFT ;
val | = ( csc - > matrix [ 0 ] [ 2 ] & 0x3ff ) < < ISPPRV_CSC0_BY_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_CSC0 ) ;
val = ( csc - > matrix [ 1 ] [ 0 ] & 0x3ff ) < < ISPPRV_CSC1_RCB_SHIFT ;
val | = ( csc - > matrix [ 1 ] [ 1 ] & 0x3ff ) < < ISPPRV_CSC1_GCB_SHIFT ;
val | = ( csc - > matrix [ 1 ] [ 2 ] & 0x3ff ) < < ISPPRV_CSC1_BCB_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_CSC1 ) ;
val = ( csc - > matrix [ 2 ] [ 0 ] & 0x3ff ) < < ISPPRV_CSC2_RCR_SHIFT ;
val | = ( csc - > matrix [ 2 ] [ 1 ] & 0x3ff ) < < ISPPRV_CSC2_GCR_SHIFT ;
val | = ( csc - > matrix [ 2 ] [ 2 ] & 0x3ff ) < < ISPPRV_CSC2_BCR_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_CSC2 ) ;
val = ( csc - > offset [ 0 ] & 0xff ) < < ISPPRV_CSC_OFFSET_Y_SHIFT ;
val | = ( csc - > offset [ 1 ] & 0xff ) < < ISPPRV_CSC_OFFSET_CB_SHIFT ;
val | = ( csc - > offset [ 2 ] & 0xff ) < < ISPPRV_CSC_OFFSET_CR_SHIFT ;
isp_reg_writel ( isp , val , OMAP3_ISP_IOMEM_PREV , ISPPRV_CSC_OFFSET ) ;
}
/*
2012-07-06 09:07:33 -03:00
* preview_config_yc_range - Configure the max and min Y and C values
*/
static void
preview_config_yc_range ( struct isp_prev_device * prev ,
const struct prev_params * params )
{
struct isp_device * isp = to_isp_device ( prev ) ;
const struct omap3isp_prev_yclimit * yc = & params - > yclimit ;
isp_reg_writel ( isp ,
yc - > maxC < < ISPPRV_SETUP_YC_MAXC_SHIFT |
yc - > maxY < < ISPPRV_SETUP_YC_MAXY_SHIFT |
yc - > minC < < ISPPRV_SETUP_YC_MINC_SHIFT |
yc - > minY < < ISPPRV_SETUP_YC_MINY_SHIFT ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SETUP_YC ) ;
}
/*
* preview_config_dcor - Configure Couplet Defect Correction
*/
static void
preview_config_dcor ( struct isp_prev_device * prev ,
const struct prev_params * params )
{
struct isp_device * isp = to_isp_device ( prev ) ;
const struct omap3isp_prev_dcor * dcor = & params - > dcor ;
isp_reg_writel ( isp , dcor - > detect_correct [ 0 ] ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_CDC_THR0 ) ;
isp_reg_writel ( isp , dcor - > detect_correct [ 1 ] ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_CDC_THR1 ) ;
isp_reg_writel ( isp , dcor - > detect_correct [ 2 ] ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_CDC_THR2 ) ;
isp_reg_writel ( isp , dcor - > detect_correct [ 3 ] ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_CDC_THR3 ) ;
isp_reg_clr_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DCCOUP ,
dcor - > couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0 ) ;
}
/*
* preview_enable_dcor - Enable / disable Couplet Defect Correction
*/
static void preview_enable_dcor ( struct isp_prev_device * prev , bool enable )
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DCOREN ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DCOREN ) ;
}
/*
* preview_enable_drkframe_capture - Enable / disable Dark Frame Capture
*/
static void
preview_enable_drkframe_capture ( struct isp_prev_device * prev , bool enable )
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DRKFCAP ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DRKFCAP ) ;
}
/*
* preview_enable_drkframe - Enable / disable Dark Frame Subtraction
*/
static void preview_enable_drkframe ( struct isp_prev_device * prev , bool enable )
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DRKFEN ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_DRKFEN ) ;
}
/*
* preview_config_noisefilter - Configure the Noise Filter
*/
static void
preview_config_noisefilter ( struct isp_prev_device * prev ,
const struct prev_params * params )
{
struct isp_device * isp = to_isp_device ( prev ) ;
const struct omap3isp_prev_nf * nf = & params - > nf ;
unsigned int i ;
isp_reg_writel ( isp , nf - > spread , OMAP3_ISP_IOMEM_PREV , ISPPRV_NF ) ;
isp_reg_writel ( isp , ISPPRV_NF_TABLE_ADDR ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_ADDR ) ;
for ( i = 0 ; i < OMAP3ISP_PREV_NF_TBL_SIZE ; i + + ) {
isp_reg_writel ( isp , nf - > table [ i ] ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_DATA ) ;
2011-02-12 18:05:06 -03:00
}
2012-07-06 09:07:33 -03:00
}
/*
* preview_enable_noisefilter - Enable / disable the Noise Filter
*/
static void
preview_enable_noisefilter ( struct isp_prev_device * prev , bool enable )
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_NFEN ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_NFEN ) ;
}
/*
* preview_config_gammacorrn - Configure the Gamma Correction tables
*/
static void
preview_config_gammacorrn ( struct isp_prev_device * prev ,
const struct prev_params * params )
{
struct isp_device * isp = to_isp_device ( prev ) ;
const struct omap3isp_prev_gtables * gt = & params - > gamma ;
unsigned int i ;
isp_reg_writel ( isp , ISPPRV_REDGAMMA_TABLE_ADDR ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_ADDR ) ;
for ( i = 0 ; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE ; i + + )
isp_reg_writel ( isp , gt - > red [ i ] , OMAP3_ISP_IOMEM_PREV ,
ISPPRV_SET_TBL_DATA ) ;
isp_reg_writel ( isp , ISPPRV_GREENGAMMA_TABLE_ADDR ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_ADDR ) ;
for ( i = 0 ; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE ; i + + )
isp_reg_writel ( isp , gt - > green [ i ] , OMAP3_ISP_IOMEM_PREV ,
ISPPRV_SET_TBL_DATA ) ;
isp_reg_writel ( isp , ISPPRV_BLUEGAMMA_TABLE_ADDR ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_SET_TBL_ADDR ) ;
for ( i = 0 ; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE ; i + + )
isp_reg_writel ( isp , gt - > blue [ i ] , OMAP3_ISP_IOMEM_PREV ,
ISPPRV_SET_TBL_DATA ) ;
2011-02-12 18:05:06 -03:00
}
2012-07-06 09:12:44 -03:00
/*
* preview_enable_gammacorrn - Enable / disable Gamma Correction
*
* When gamma correction is disabled , the module is bypassed and its output is
* the 8 MSB of the 10 - bit input .
*/
static void
preview_enable_gammacorrn ( struct isp_prev_device * prev , bool enable )
{
struct isp_device * isp = to_isp_device ( prev ) ;
if ( enable )
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_GAMMA_BYPASS ) ;
else
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_GAMMA_BYPASS ) ;
}
2011-02-12 18:05:06 -03:00
/*
2012-07-06 08:43:27 -03:00
* preview_config_contrast - Configure the Contrast
2011-02-12 18:05:06 -03:00
*
* Value should be programmed before enabling the module .
*/
static void
2012-07-06 08:43:27 -03:00
preview_config_contrast ( struct isp_prev_device * prev ,
const struct prev_params * params )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
isp_reg_clr_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_CNT_BRT ,
0xff < < ISPPRV_CNT_BRT_CNT_SHIFT ,
2012-07-06 08:43:27 -03:00
params - > contrast < < ISPPRV_CNT_BRT_CNT_SHIFT ) ;
2011-02-12 18:05:06 -03:00
}
/*
2012-07-06 09:07:33 -03:00
* preview_config_brightness - Configure the Brightness
*/
static void
preview_config_brightness ( struct isp_prev_device * prev ,
const struct prev_params * params )
{
struct isp_device * isp = to_isp_device ( prev ) ;
isp_reg_clr_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_CNT_BRT ,
0xff < < ISPPRV_CNT_BRT_BRT_SHIFT ,
params - > brightness < < ISPPRV_CNT_BRT_BRT_SHIFT ) ;
}
/*
* preview_update_contrast - Updates the contrast .
* @ contrast : Pointer to hold the current programmed contrast value .
2011-02-12 18:05:06 -03:00
*
2012-07-06 09:07:33 -03:00
* Value should be programmed before enabling the module .
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 09:07:33 -03:00
preview_update_contrast ( struct isp_prev_device * prev , u8 contrast )
2011-02-12 18:05:06 -03:00
{
2012-03-26 10:24:50 -03:00
struct prev_params * params ;
unsigned long flags ;
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
2012-07-06 09:07:33 -03:00
params = ( prev - > params . active & OMAP3ISP_PREV_CONTRAST )
2012-03-26 10:24:50 -03:00
? & prev - > params . params [ 0 ] : & prev - > params . params [ 1 ] ;
2011-02-12 18:05:06 -03:00
2012-07-06 09:07:33 -03:00
if ( params - > contrast ! = ( contrast * ISPPRV_CONTRAST_UNITS ) ) {
params - > contrast = contrast * ISPPRV_CONTRAST_UNITS ;
params - > update | = OMAP3ISP_PREV_CONTRAST ;
2011-02-12 18:05:06 -03:00
}
2012-03-26 10:24:50 -03:00
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
}
/*
2012-07-06 09:07:33 -03:00
* preview_update_brightness - Updates the brightness in preview module .
* @ brightness : Pointer to hold the current programmed brightness value .
*
2011-02-12 18:05:06 -03:00
*/
static void
2012-07-06 09:07:33 -03:00
preview_update_brightness ( struct isp_prev_device * prev , u8 brightness )
2011-02-12 18:05:06 -03:00
{
2012-07-06 09:07:33 -03:00
struct prev_params * params ;
unsigned long flags ;
2011-02-12 18:05:06 -03:00
2012-07-06 09:07:33 -03:00
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
params = ( prev - > params . active & OMAP3ISP_PREV_BRIGHTNESS )
? & prev - > params . params [ 0 ] : & prev - > params . params [ 1 ] ;
2011-02-12 18:05:06 -03:00
2012-07-06 09:07:33 -03:00
if ( params - > brightness ! = ( brightness * ISPPRV_BRIGHT_UNITS ) ) {
params - > brightness = brightness * ISPPRV_BRIGHT_UNITS ;
params - > update | = OMAP3ISP_PREV_BRIGHTNESS ;
}
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
}
2012-03-26 10:24:50 -03:00
static u32
preview_params_lock ( struct isp_prev_device * prev , u32 update , bool shadow )
{
u32 active = prev - > params . active ;
if ( shadow ) {
/* Mark all shadow parameters we are going to touch as busy. */
prev - > params . params [ 0 ] . busy | = ~ active & update ;
prev - > params . params [ 1 ] . busy | = active & update ;
} else {
/* Mark all active parameters we are going to touch as busy. */
update = ( prev - > params . params [ 0 ] . update & active )
| ( prev - > params . params [ 1 ] . update & ~ active ) ;
prev - > params . params [ 0 ] . busy | = active & update ;
prev - > params . params [ 1 ] . busy | = ~ active & update ;
}
return update ;
}
static void
preview_params_unlock ( struct isp_prev_device * prev , u32 update , bool shadow )
{
u32 active = prev - > params . active ;
if ( shadow ) {
/* Set the update flag for shadow parameters that have been
* updated and clear the busy flag for all shadow parameters .
*/
prev - > params . params [ 0 ] . update | = ( ~ active & update ) ;
prev - > params . params [ 1 ] . update | = ( active & update ) ;
prev - > params . params [ 0 ] . busy & = active ;
prev - > params . params [ 1 ] . busy & = ~ active ;
} else {
/* Clear the update flag for active parameters that have been
* applied and the busy flag for all active parameters .
*/
prev - > params . params [ 0 ] . update & = ~ ( active & update ) ;
prev - > params . params [ 1 ] . update & = ~ ( ~ active & update ) ;
prev - > params . params [ 0 ] . busy & = ~ active ;
prev - > params . params [ 1 ] . busy & = active ;
}
}
static void preview_params_switch ( struct isp_prev_device * prev )
{
u32 to_switch ;
/* Switch active parameters with updated shadow parameters when the
* shadow parameter has been updated and neither the active not the
* shadow parameter is busy .
*/
to_switch = ( prev - > params . params [ 0 ] . update & ~ prev - > params . active )
| ( prev - > params . params [ 1 ] . update & prev - > params . active ) ;
to_switch & = ~ ( prev - > params . params [ 0 ] . busy |
prev - > params . params [ 1 ] . busy ) ;
if ( to_switch = = 0 )
return ;
prev - > params . active ^ = to_switch ;
/* Remove the update flag for the shadow copy of parameters we have
* switched .
*/
prev - > params . params [ 0 ] . update & = ~ ( ~ prev - > params . active & to_switch ) ;
prev - > params . params [ 1 ] . update & = ~ ( prev - > params . active & to_switch ) ;
}
2011-02-12 18:05:06 -03:00
/* preview parameters update structure */
struct preview_update {
2012-07-06 08:43:27 -03:00
void ( * config ) ( struct isp_prev_device * , const struct prev_params * ) ;
void ( * enable ) ( struct isp_prev_device * , bool ) ;
2012-04-09 09:25:34 -03:00
unsigned int param_offset ;
unsigned int param_size ;
unsigned int config_offset ;
2012-04-05 12:38:23 -03:00
bool skip ;
2011-02-12 18:05:06 -03:00
} ;
2012-04-05 13:51:17 -03:00
/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
2012-04-09 09:25:34 -03:00
static const struct preview_update update_attrs [ ] = {
2012-04-05 13:51:17 -03:00
/* OMAP3ISP_PREV_LUMAENH */ {
2011-02-12 18:05:06 -03:00
preview_config_luma_enhancement ,
2012-04-05 13:51:17 -03:00
preview_enable_luma_enhancement ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , luma ) ,
FIELD_SIZEOF ( struct prev_params , luma ) ,
offsetof ( struct omap3isp_prev_update_config , luma ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_INVALAW */ {
2011-02-12 18:05:06 -03:00
NULL ,
2012-04-05 13:51:17 -03:00
preview_enable_invalaw ,
} , /* OMAP3ISP_PREV_HRZ_MED */ {
2011-02-12 18:05:06 -03:00
preview_config_hmed ,
2012-04-05 13:51:17 -03:00
preview_enable_hmed ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , hmed ) ,
FIELD_SIZEOF ( struct prev_params , hmed ) ,
offsetof ( struct omap3isp_prev_update_config , hmed ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_CFA */ {
2011-02-12 18:05:06 -03:00
preview_config_cfa ,
2012-04-19 13:38:29 -03:00
NULL ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , cfa ) ,
FIELD_SIZEOF ( struct prev_params , cfa ) ,
offsetof ( struct omap3isp_prev_update_config , cfa ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_CHROMA_SUPP */ {
2011-02-12 18:05:06 -03:00
preview_config_chroma_suppression ,
2012-04-05 13:51:17 -03:00
preview_enable_chroma_suppression ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , csup ) ,
FIELD_SIZEOF ( struct prev_params , csup ) ,
offsetof ( struct omap3isp_prev_update_config , csup ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_WB */ {
2011-02-12 18:05:06 -03:00
preview_config_whitebalance ,
2012-04-05 13:51:17 -03:00
NULL ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , wbal ) ,
FIELD_SIZEOF ( struct prev_params , wbal ) ,
offsetof ( struct omap3isp_prev_update_config , wbal ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_BLKADJ */ {
2011-02-12 18:05:06 -03:00
preview_config_blkadj ,
2012-04-05 13:51:17 -03:00
NULL ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , blkadj ) ,
FIELD_SIZEOF ( struct prev_params , blkadj ) ,
offsetof ( struct omap3isp_prev_update_config , blkadj ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_RGB2RGB */ {
2011-02-12 18:05:06 -03:00
preview_config_rgb_blending ,
2012-04-05 13:51:17 -03:00
NULL ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , rgb2rgb ) ,
FIELD_SIZEOF ( struct prev_params , rgb2rgb ) ,
offsetof ( struct omap3isp_prev_update_config , rgb2rgb ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_COLOR_CONV */ {
2012-04-17 13:05:12 -03:00
preview_config_csc ,
2012-04-05 13:51:17 -03:00
NULL ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , csc ) ,
FIELD_SIZEOF ( struct prev_params , csc ) ,
offsetof ( struct omap3isp_prev_update_config , csc ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_YC_LIMIT */ {
2011-02-12 18:05:06 -03:00
preview_config_yc_range ,
2012-04-05 13:51:17 -03:00
NULL ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , yclimit ) ,
FIELD_SIZEOF ( struct prev_params , yclimit ) ,
offsetof ( struct omap3isp_prev_update_config , yclimit ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_DEFECT_COR */ {
2011-02-12 18:05:06 -03:00
preview_config_dcor ,
2012-04-05 13:51:17 -03:00
preview_enable_dcor ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , dcor ) ,
FIELD_SIZEOF ( struct prev_params , dcor ) ,
offsetof ( struct omap3isp_prev_update_config , dcor ) ,
2012-07-06 09:12:44 -03:00
} , /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
NULL ,
2011-02-12 18:05:06 -03:00
NULL ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
2011-02-12 18:05:06 -03:00
NULL ,
2012-04-05 13:51:17 -03:00
preview_enable_drkframe_capture ,
} , /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
2011-02-12 18:05:06 -03:00
NULL ,
2012-04-05 13:51:17 -03:00
preview_enable_drkframe ,
} , /* OMAP3ISP_PREV_LENS_SHADING */ {
2012-07-06 08:26:57 -03:00
NULL ,
2012-04-05 13:51:17 -03:00
preview_enable_drkframe ,
} , /* OMAP3ISP_PREV_NF */ {
2011-02-12 18:05:06 -03:00
preview_config_noisefilter ,
2012-04-05 13:51:17 -03:00
preview_enable_noisefilter ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , nf ) ,
FIELD_SIZEOF ( struct prev_params , nf ) ,
offsetof ( struct omap3isp_prev_update_config , nf ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_GAMMA */ {
2011-02-12 18:05:06 -03:00
preview_config_gammacorrn ,
2012-07-06 09:12:44 -03:00
preview_enable_gammacorrn ,
2012-04-09 09:25:34 -03:00
offsetof ( struct prev_params , gamma ) ,
FIELD_SIZEOF ( struct prev_params , gamma ) ,
offsetof ( struct omap3isp_prev_update_config , gamma ) ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_CONTRAST */ {
2011-02-12 18:05:06 -03:00
preview_config_contrast ,
2012-04-09 09:25:34 -03:00
NULL ,
2012-07-06 08:43:27 -03:00
0 , 0 , 0 , true ,
2012-04-05 13:51:17 -03:00
} , /* OMAP3ISP_PREV_BRIGHTNESS */ {
2011-02-12 18:05:06 -03:00
preview_config_brightness ,
2012-04-09 09:25:34 -03:00
NULL ,
2012-07-06 08:43:27 -03:00
0 , 0 , 0 , true ,
2012-04-05 13:51:17 -03:00
} ,
2011-02-12 18:05:06 -03:00
} ;
/*
* preview_config - Copy and update local structure with userspace preview
* configuration .
* @ prev : ISP preview engine
* @ cfg : Configuration
*
* Return zero if success or - EFAULT if the configuration can ' t be copied from
* userspace .
*/
static int preview_config ( struct isp_prev_device * prev ,
struct omap3isp_prev_update_config * cfg )
{
2012-03-26 10:24:50 -03:00
unsigned long flags ;
unsigned int i ;
int rval = 0 ;
u32 update ;
u32 active ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
if ( cfg - > update = = 0 )
return 0 ;
2012-03-26 10:24:50 -03:00
/* Mark the shadow parameters we're going to update as busy. */
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
preview_params_lock ( prev , cfg - > update , true ) ;
active = prev - > params . active ;
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
update = 0 ;
2011-02-12 18:05:06 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( update_attrs ) ; i + + ) {
2012-03-26 10:24:50 -03:00
const struct preview_update * attr = & update_attrs [ i ] ;
struct prev_params * params ;
unsigned int bit = 1 < < i ;
2011-02-12 18:05:06 -03:00
2012-04-05 13:51:17 -03:00
if ( attr - > skip | | ! ( cfg - > update & bit ) )
2011-02-12 18:05:06 -03:00
continue ;
2012-03-26 10:24:50 -03:00
params = & prev - > params . params [ ! ! ( active & bit ) ] ;
2012-04-05 13:51:17 -03:00
if ( cfg - > flag & bit ) {
2018-04-06 08:33:44 -04:00
void __user * from = * ( void __user * * )
2012-03-26 10:24:50 -03:00
( ( void * ) cfg + attr - > config_offset ) ;
void * to = ( void * ) params + attr - > param_offset ;
size_t size = attr - > param_size ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
if ( to & & from & & size ) {
if ( copy_from_user ( to , from , size ) ) {
2011-02-12 18:05:06 -03:00
rval = - EFAULT ;
break ;
}
}
2012-04-05 13:51:17 -03:00
params - > features | = bit ;
2011-02-12 18:05:06 -03:00
} else {
2012-04-05 13:51:17 -03:00
params - > features & = ~ bit ;
2011-02-12 18:05:06 -03:00
}
2012-03-26 10:24:50 -03:00
update | = bit ;
2011-02-12 18:05:06 -03:00
}
2012-03-26 10:24:50 -03:00
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
preview_params_unlock ( prev , update , true ) ;
preview_params_switch ( prev ) ;
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
return rval ;
}
/*
* preview_setup_hw - Setup preview registers and / or internal memory
* @ prev : pointer to preview private structure
2012-03-26 10:24:50 -03:00
* @ update : Bitmask of parameters to setup
* @ active : Bitmask of parameters active in set 0
2011-02-12 18:05:06 -03:00
* Note : can be called from interrupt context
* Return none
*/
2012-03-26 10:24:50 -03:00
static void preview_setup_hw ( struct isp_prev_device * prev , u32 update ,
u32 active )
2011-02-12 18:05:06 -03:00
{
2012-04-05 13:51:17 -03:00
unsigned int i ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
if ( update = = 0 )
2012-03-26 10:24:50 -03:00
return ;
2011-02-12 18:05:06 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( update_attrs ) ; i + + ) {
2012-03-26 10:24:50 -03:00
const struct preview_update * attr = & update_attrs [ i ] ;
struct prev_params * params ;
unsigned int bit = 1 < < i ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
if ( ! ( update & bit ) )
2011-02-12 18:05:06 -03:00
continue ;
2012-04-05 13:51:17 -03:00
2012-03-26 10:24:50 -03:00
params = & prev - > params . params [ ! ( active & bit ) ] ;
2012-04-05 13:51:17 -03:00
if ( params - > features & bit ) {
2012-07-06 08:43:27 -03:00
if ( attr - > config )
attr - > config ( prev , params ) ;
2011-02-12 18:05:06 -03:00
if ( attr - > enable )
2012-07-06 08:43:27 -03:00
attr - > enable ( prev , true ) ;
2012-03-26 10:24:50 -03:00
} else {
2011-02-12 18:05:06 -03:00
if ( attr - > enable )
2012-07-06 08:43:27 -03:00
attr - > enable ( prev , false ) ;
2012-03-26 10:24:50 -03:00
}
2011-02-12 18:05:06 -03:00
}
}
/*
* preview_config_ycpos - Configure byte layout of YUV image .
2014-02-21 09:07:23 -03:00
* @ prev : pointer to previewer private structure
* @ pixelcode : pixel code
2011-02-12 18:05:06 -03:00
*/
2014-11-10 14:28:31 -03:00
static void preview_config_ycpos ( struct isp_prev_device * prev , u32 pixelcode )
2011-02-12 18:05:06 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
enum preview_ycpos_mode mode ;
switch ( pixelcode ) {
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_YUYV8_1X16 :
2011-02-12 18:05:06 -03:00
mode = YCPOS_CrYCbY ;
break ;
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_UYVY8_1X16 :
2011-02-12 18:05:06 -03:00
mode = YCPOS_YCrYCb ;
break ;
default :
return ;
}
isp_reg_clr_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_YCPOS_CrYCbY ,
mode < < ISPPRV_PCR_YCPOS_SHIFT ) ;
}
/*
* preview_config_averager - Enable / disable / configure averager
* @ average : Average value to be configured .
*/
static void preview_config_averager ( struct isp_prev_device * prev , u8 average )
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-03-26 10:24:50 -03:00
2012-06-18 11:24:48 -03:00
isp_reg_writel ( isp , ISPPRV_AVE_EVENDIST_2 < < ISPPRV_AVE_EVENDIST_SHIFT |
ISPPRV_AVE_ODDDIST_2 < < ISPPRV_AVE_ODDDIST_SHIFT |
average , OMAP3_ISP_IOMEM_PREV , ISPPRV_AVE ) ;
2011-02-12 18:05:06 -03:00
}
2012-06-18 11:24:48 -03:00
2012-04-19 13:38:29 -03:00
/*
* preview_config_input_format - Configure the input format
* @ prev : The preview engine
2012-10-23 08:11:55 -03:00
* @ info : Sink pad format information
2012-04-19 13:38:29 -03:00
*
2012-06-18 11:24:48 -03:00
* Enable and configure CFA interpolation for Bayer formats and disable it for
* greyscale formats .
*
* The CFA table is organised in four blocks , one per Bayer component . The
* hardware expects blocks to follow the Bayer order of the input data , while
* the driver stores the table in GRBG order in memory . The blocks need to be
* reordered to support non - GRBG Bayer patterns .
2012-04-19 13:38:29 -03:00
*/
static void preview_config_input_format ( struct isp_prev_device * prev ,
2012-10-23 08:11:55 -03:00
const struct isp_format_info * info )
2012-04-19 13:38:29 -03:00
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-06-18 11:24:48 -03:00
struct prev_params * params ;
2012-04-19 13:38:29 -03:00
2012-10-23 08:11:55 -03:00
if ( info - > width = = 8 )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_WIDTH ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_WIDTH ) ;
switch ( info - > flavor ) {
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_SGRBG8_1X8 :
2012-06-18 11:24:48 -03:00
prev - > params . cfa_order = 0 ;
break ;
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_SRGGB8_1X8 :
2012-06-18 11:24:48 -03:00
prev - > params . cfa_order = 1 ;
break ;
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_SBGGR8_1X8 :
2012-06-18 11:24:48 -03:00
prev - > params . cfa_order = 2 ;
break ;
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_SGBRG8_1X8 :
2012-06-18 11:24:48 -03:00
prev - > params . cfa_order = 3 ;
break ;
default :
/* Disable CFA for non-Bayer formats. */
2012-04-19 13:38:29 -03:00
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_CFAEN ) ;
2012-06-18 11:24:48 -03:00
return ;
}
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR , ISPPRV_PCR_CFAEN ) ;
isp_reg_clr_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_CFAFMT_MASK , ISPPRV_PCR_CFAFMT_BAYER ) ;
params = ( prev - > params . active & OMAP3ISP_PREV_CFA )
? & prev - > params . params [ 0 ] : & prev - > params . params [ 1 ] ;
preview_config_cfa ( prev , params ) ;
2012-04-19 13:38:29 -03:00
}
2011-02-12 18:05:06 -03:00
/*
* preview_config_input_size - Configure the input frame size
*
* The preview engine crops several rows and columns internally depending on
* which processing blocks are enabled . The driver assumes all those blocks are
* enabled when reporting source pad formats to userspace . If this assumption is
* not true , rows and columns must be manually cropped at the preview engine
* input to avoid overflows at the end of lines and frames .
2011-09-21 20:05:45 -03:00
*
* See the explanation at the PREV_MARGIN_ * definitions for more details .
2011-02-12 18:05:06 -03:00
*/
2012-03-26 10:24:50 -03:00
static void preview_config_input_size ( struct isp_prev_device * prev , u32 active )
2011-02-12 18:05:06 -03:00
{
2014-01-17 16:37:38 -03:00
const struct v4l2_mbus_framefmt * format = & prev - > formats [ PREV_PAD_SINK ] ;
2011-02-12 18:05:06 -03:00
struct isp_device * isp = to_isp_device ( prev ) ;
2011-09-21 20:05:45 -03:00
unsigned int sph = prev - > crop . left ;
unsigned int eph = prev - > crop . left + prev - > crop . width - 1 ;
unsigned int slv = prev - > crop . top ;
unsigned int elv = prev - > crop . top + prev - > crop . height - 1 ;
2012-03-26 10:24:50 -03:00
u32 features ;
2011-09-21 20:05:45 -03:00
2014-11-10 14:28:31 -03:00
if ( format - > code ! = MEDIA_BUS_FMT_Y8_1X8 & &
format - > code ! = MEDIA_BUS_FMT_Y10_1X10 ) {
2014-01-17 16:37:38 -03:00
sph - = 2 ;
eph + = 2 ;
slv - = 2 ;
elv + = 2 ;
}
2012-04-19 13:38:29 -03:00
features = ( prev - > params . params [ 0 ] . features & active )
| ( prev - > params . params [ 1 ] . features & ~ active ) ;
2012-03-26 10:24:50 -03:00
if ( features & ( OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF ) ) {
2011-09-21 20:05:45 -03:00
sph - = 2 ;
eph + = 2 ;
slv - = 2 ;
elv + = 2 ;
2011-02-12 18:05:06 -03:00
}
2012-03-26 10:24:50 -03:00
if ( features & OMAP3ISP_PREV_HRZ_MED ) {
2011-09-21 20:05:45 -03:00
sph - = 2 ;
eph + = 2 ;
2011-02-12 18:05:06 -03:00
}
2012-03-26 10:24:50 -03:00
if ( features & ( OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH ) )
2011-09-21 20:05:45 -03:00
sph - = 2 ;
2011-02-12 18:05:06 -03:00
isp_reg_writel ( isp , ( sph < < ISPPRV_HORZ_INFO_SPH_SHIFT ) | eph ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_HORZ_INFO ) ;
isp_reg_writel ( isp , ( slv < < ISPPRV_VERT_INFO_SLV_SHIFT ) | elv ,
OMAP3_ISP_IOMEM_PREV , ISPPRV_VERT_INFO ) ;
}
/*
* preview_config_inlineoffset - Configures the Read address line offset .
* @ prev : Preview module
* @ offset : Line offset
*
* According to the TRM , the line offset must be aligned on a 32 bytes boundary .
* However , a hardware bug requires the memory start address to be aligned on a
* 64 bytes boundary , so the offset probably should be aligned on 64 bytes as
* well .
*/
static void
preview_config_inlineoffset ( struct isp_prev_device * prev , u32 offset )
{
struct isp_device * isp = to_isp_device ( prev ) ;
isp_reg_writel ( isp , offset & 0xffff , OMAP3_ISP_IOMEM_PREV ,
ISPPRV_RADR_OFFSET ) ;
}
/*
* preview_set_inaddr - Sets memory address of input frame .
* @ addr : 32 bit memory address aligned on 32 byte boundary .
*
* Configures the memory address from which the input frame is to be read .
*/
static void preview_set_inaddr ( struct isp_prev_device * prev , u32 addr )
{
struct isp_device * isp = to_isp_device ( prev ) ;
isp_reg_writel ( isp , addr , OMAP3_ISP_IOMEM_PREV , ISPPRV_RSDR_ADDR ) ;
}
/*
* preview_config_outlineoffset - Configures the Write address line offset .
* @ offset : Line Offset for the preview output .
*
* The offset must be a multiple of 32 bytes .
*/
static void preview_config_outlineoffset ( struct isp_prev_device * prev ,
u32 offset )
{
struct isp_device * isp = to_isp_device ( prev ) ;
isp_reg_writel ( isp , offset & 0xffff , OMAP3_ISP_IOMEM_PREV ,
ISPPRV_WADD_OFFSET ) ;
}
/*
* preview_set_outaddr - Sets the memory address to store output frame
* @ addr : 32 bit memory address aligned on 32 byte boundary .
*
* Configures the memory address to which the output frame is written .
*/
static void preview_set_outaddr ( struct isp_prev_device * prev , u32 addr )
{
struct isp_device * isp = to_isp_device ( prev ) ;
isp_reg_writel ( isp , addr , OMAP3_ISP_IOMEM_PREV , ISPPRV_WSDR_ADDR ) ;
}
static void preview_adjust_bandwidth ( struct isp_prev_device * prev )
{
struct isp_pipeline * pipe = to_isp_pipeline ( & prev - > subdev . entity ) ;
struct isp_device * isp = to_isp_device ( prev ) ;
const struct v4l2_mbus_framefmt * ifmt = & prev - > formats [ PREV_PAD_SINK ] ;
unsigned long l3_ick = pipe - > l3_ick ;
struct v4l2_fract * timeperframe ;
unsigned int cycles_per_frame ;
unsigned int requests_per_frame ;
unsigned int cycles_per_request ;
unsigned int minimum ;
unsigned int maximum ;
unsigned int value ;
if ( prev - > input ! = PREVIEW_INPUT_MEMORY ) {
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_SBL , ISPSBL_SDR_REQ_EXP ,
ISPSBL_SDR_REQ_PRV_EXP_MASK ) ;
return ;
}
/* Compute the minimum number of cycles per request, based on the
* pipeline maximum data rate . This is an absolute lower bound if we
* don ' t want SBL overflows , so round the value up .
*/
cycles_per_request = div_u64 ( ( u64 ) l3_ick / 2 * 256 + pipe - > max_rate - 1 ,
pipe - > max_rate ) ;
minimum = DIV_ROUND_UP ( cycles_per_request , 32 ) ;
/* Compute the maximum number of cycles per request, based on the
* requested frame rate . This is a soft upper bound to achieve a frame
* rate equal or higher than the requested value , so round the value
* down .
*/
timeperframe = & pipe - > max_timeperframe ;
requests_per_frame = DIV_ROUND_UP ( ifmt - > width * 2 , 256 ) * ifmt - > height ;
cycles_per_frame = div_u64 ( ( u64 ) l3_ick * timeperframe - > numerator ,
timeperframe - > denominator ) ;
cycles_per_request = cycles_per_frame / requests_per_frame ;
maximum = cycles_per_request / 32 ;
value = max ( minimum , maximum ) ;
dev_dbg ( isp - > dev , " %s: cycles per request = %u \n " , __func__ , value ) ;
isp_reg_clr_set ( isp , OMAP3_ISP_IOMEM_SBL , ISPSBL_SDR_REQ_EXP ,
ISPSBL_SDR_REQ_PRV_EXP_MASK ,
value < < ISPSBL_SDR_REQ_PRV_EXP_SHIFT ) ;
}
/*
* omap3isp_preview_busy - Gets busy state of preview module .
*/
int omap3isp_preview_busy ( struct isp_prev_device * prev )
{
struct isp_device * isp = to_isp_device ( prev ) ;
return isp_reg_readl ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR )
& ISPPRV_PCR_BUSY ;
}
/*
* omap3isp_preview_restore_context - Restores the values of preview registers
*/
void omap3isp_preview_restore_context ( struct isp_device * isp )
{
2012-03-26 10:24:50 -03:00
struct isp_prev_device * prev = & isp - > isp_prev ;
const u32 update = OMAP3ISP_PREV_FEATURES_END - 1 ;
prev - > params . params [ 0 ] . update = prev - > params . active & update ;
prev - > params . params [ 1 ] . update = ~ prev - > params . active & update ;
preview_setup_hw ( prev , update , prev - > params . active ) ;
prev - > params . params [ 0 ] . update = 0 ;
prev - > params . params [ 1 ] . update = 0 ;
2011-02-12 18:05:06 -03:00
}
/*
* preview_print_status - Dump preview module registers to the kernel log
*/
# define PREV_PRINT_REGISTER(isp, name)\
dev_dbg ( isp - > dev , " ###PRV " # name " =0x%08x \n " , \
isp_reg_readl ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_ # # name ) )
static void preview_print_status ( struct isp_prev_device * prev )
{
struct isp_device * isp = to_isp_device ( prev ) ;
dev_dbg ( isp - > dev , " -------------Preview Register dump---------- \n " ) ;
PREV_PRINT_REGISTER ( isp , PCR ) ;
PREV_PRINT_REGISTER ( isp , HORZ_INFO ) ;
PREV_PRINT_REGISTER ( isp , VERT_INFO ) ;
PREV_PRINT_REGISTER ( isp , RSDR_ADDR ) ;
PREV_PRINT_REGISTER ( isp , RADR_OFFSET ) ;
PREV_PRINT_REGISTER ( isp , DSDR_ADDR ) ;
PREV_PRINT_REGISTER ( isp , DRKF_OFFSET ) ;
PREV_PRINT_REGISTER ( isp , WSDR_ADDR ) ;
PREV_PRINT_REGISTER ( isp , WADD_OFFSET ) ;
PREV_PRINT_REGISTER ( isp , AVE ) ;
PREV_PRINT_REGISTER ( isp , HMED ) ;
PREV_PRINT_REGISTER ( isp , NF ) ;
PREV_PRINT_REGISTER ( isp , WB_DGAIN ) ;
PREV_PRINT_REGISTER ( isp , WBGAIN ) ;
PREV_PRINT_REGISTER ( isp , WBSEL ) ;
PREV_PRINT_REGISTER ( isp , CFA ) ;
PREV_PRINT_REGISTER ( isp , BLKADJOFF ) ;
PREV_PRINT_REGISTER ( isp , RGB_MAT1 ) ;
PREV_PRINT_REGISTER ( isp , RGB_MAT2 ) ;
PREV_PRINT_REGISTER ( isp , RGB_MAT3 ) ;
PREV_PRINT_REGISTER ( isp , RGB_MAT4 ) ;
PREV_PRINT_REGISTER ( isp , RGB_MAT5 ) ;
PREV_PRINT_REGISTER ( isp , RGB_OFF1 ) ;
PREV_PRINT_REGISTER ( isp , RGB_OFF2 ) ;
PREV_PRINT_REGISTER ( isp , CSC0 ) ;
PREV_PRINT_REGISTER ( isp , CSC1 ) ;
PREV_PRINT_REGISTER ( isp , CSC2 ) ;
PREV_PRINT_REGISTER ( isp , CSC_OFFSET ) ;
PREV_PRINT_REGISTER ( isp , CNT_BRT ) ;
PREV_PRINT_REGISTER ( isp , CSUP ) ;
PREV_PRINT_REGISTER ( isp , SETUP_YC ) ;
PREV_PRINT_REGISTER ( isp , SET_TBL_ADDR ) ;
PREV_PRINT_REGISTER ( isp , CDC_THR0 ) ;
PREV_PRINT_REGISTER ( isp , CDC_THR1 ) ;
PREV_PRINT_REGISTER ( isp , CDC_THR2 ) ;
PREV_PRINT_REGISTER ( isp , CDC_THR3 ) ;
dev_dbg ( isp - > dev , " -------------------------------------------- \n " ) ;
}
/*
* preview_init_params - init image processing parameters .
* @ prev : pointer to previewer private structure
*/
static void preview_init_params ( struct isp_prev_device * prev )
{
2012-03-26 10:24:50 -03:00
struct prev_params * params ;
unsigned int i ;
spin_lock_init ( & prev - > params . lock ) ;
prev - > params . active = ~ 0 ;
prev - > params . params [ 0 ] . busy = 0 ;
prev - > params . params [ 0 ] . update = OMAP3ISP_PREV_FEATURES_END - 1 ;
prev - > params . params [ 1 ] . busy = 0 ;
prev - > params . params [ 1 ] . update = 0 ;
params = & prev - > params . params [ 0 ] ;
2011-02-12 18:05:06 -03:00
/* Init values */
params - > contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS ;
params - > brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS ;
params - > cfa . format = OMAP3ISP_CFAFMT_BAYER ;
memcpy ( params - > cfa . table , cfa_coef_table ,
sizeof ( params - > cfa . table ) ) ;
params - > cfa . gradthrs_horz = FLR_CFA_GRADTHRS_HORZ ;
params - > cfa . gradthrs_vert = FLR_CFA_GRADTHRS_VERT ;
params - > csup . gain = FLR_CSUP_GAIN ;
params - > csup . thres = FLR_CSUP_THRES ;
params - > csup . hypf_en = 0 ;
memcpy ( params - > luma . table , luma_enhance_table ,
sizeof ( params - > luma . table ) ) ;
params - > nf . spread = FLR_NF_STRGTH ;
memcpy ( params - > nf . table , noise_filter_table , sizeof ( params - > nf . table ) ) ;
params - > dcor . couplet_mode_en = 1 ;
for ( i = 0 ; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS ; i + + )
params - > dcor . detect_correct [ i ] = DEF_DETECT_CORRECT_VAL ;
memcpy ( params - > gamma . blue , gamma_table , sizeof ( params - > gamma . blue ) ) ;
memcpy ( params - > gamma . green , gamma_table , sizeof ( params - > gamma . green ) ) ;
memcpy ( params - > gamma . red , gamma_table , sizeof ( params - > gamma . red ) ) ;
params - > wbal . dgain = FLR_WBAL_DGAIN ;
params - > wbal . coef0 = FLR_WBAL_COEF ;
params - > wbal . coef1 = FLR_WBAL_COEF ;
params - > wbal . coef2 = FLR_WBAL_COEF ;
params - > wbal . coef3 = FLR_WBAL_COEF ;
2012-04-05 13:51:17 -03:00
params - > blkadj . red = FLR_BLKADJ_RED ;
params - > blkadj . green = FLR_BLKADJ_GREEN ;
params - > blkadj . blue = FLR_BLKADJ_BLUE ;
2011-02-12 18:05:06 -03:00
params - > rgb2rgb = flr_rgb2rgb ;
2012-04-05 13:51:17 -03:00
params - > csc = flr_prev_csc ;
2011-02-12 18:05:06 -03:00
params - > yclimit . minC = ISPPRV_YC_MIN ;
params - > yclimit . maxC = ISPPRV_YC_MAX ;
params - > yclimit . minY = ISPPRV_YC_MIN ;
params - > yclimit . maxY = ISPPRV_YC_MAX ;
2012-04-05 12:38:23 -03:00
params - > features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
| OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
| OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
| OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
| OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
| OMAP3ISP_PREV_CONTRAST ;
2011-02-12 18:05:06 -03:00
}
/*
2014-02-21 09:07:21 -03:00
* preview_max_out_width - Handle previewer hardware output limitations
2014-02-21 09:07:23 -03:00
* @ prev : pointer to previewer private structure
2011-02-12 18:05:06 -03:00
* returns maximum width output for current isp revision
*/
static unsigned int preview_max_out_width ( struct isp_prev_device * prev )
{
struct isp_device * isp = to_isp_device ( prev ) ;
switch ( isp - > revision ) {
case ISP_REVISION_1_0 :
2011-10-03 07:56:15 -03:00
return PREV_MAX_OUT_WIDTH_REV_1 ;
2011-02-12 18:05:06 -03:00
case ISP_REVISION_2_0 :
default :
2011-10-03 07:56:15 -03:00
return PREV_MAX_OUT_WIDTH_REV_2 ;
2011-02-12 18:05:06 -03:00
case ISP_REVISION_15_0 :
2011-10-03 07:56:15 -03:00
return PREV_MAX_OUT_WIDTH_REV_15 ;
2011-02-12 18:05:06 -03:00
}
}
static void preview_configure ( struct isp_prev_device * prev )
{
struct isp_device * isp = to_isp_device ( prev ) ;
2012-10-23 08:11:55 -03:00
const struct isp_format_info * info ;
2011-02-12 18:05:06 -03:00
struct v4l2_mbus_framefmt * format ;
2012-03-26 10:24:50 -03:00
unsigned long flags ;
u32 update ;
u32 active ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
/* Mark all active parameters we are going to touch as busy. */
update = preview_params_lock ( prev , 0 , false ) ;
active = prev - > params . active ;
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
/* PREV_PAD_SINK */
format = & prev - > formats [ PREV_PAD_SINK ] ;
2012-10-23 08:11:55 -03:00
info = omap3isp_video_format_info ( format - > code ) ;
2011-02-12 18:05:06 -03:00
preview_adjust_bandwidth ( prev ) ;
2012-10-23 08:11:55 -03:00
preview_config_input_format ( prev , info ) ;
2012-03-26 10:24:50 -03:00
preview_config_input_size ( prev , active ) ;
2011-02-12 18:05:06 -03:00
if ( prev - > input = = PREVIEW_INPUT_CCDC )
preview_config_inlineoffset ( prev , 0 ) ;
else
2012-10-23 08:11:55 -03:00
preview_config_inlineoffset ( prev , ALIGN ( format - > width , 0x20 ) *
info - > bpp ) ;
2011-02-12 18:05:06 -03:00
2012-06-18 11:24:48 -03:00
preview_setup_hw ( prev , update , active ) ;
2011-02-12 18:05:06 -03:00
/* PREV_PAD_SOURCE */
format = & prev - > formats [ PREV_PAD_SOURCE ] ;
2012-06-18 11:24:48 -03:00
if ( prev - > output & PREVIEW_OUTPUT_MEMORY )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_SDRPORT ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_SDRPORT ) ;
if ( prev - > output & PREVIEW_OUTPUT_RESIZER )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_RSZPORT ) ;
else
isp_reg_clr ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_RSZPORT ) ;
2011-02-12 18:05:06 -03:00
if ( prev - > output & PREVIEW_OUTPUT_MEMORY )
preview_config_outlineoffset ( prev ,
ALIGN ( format - > width , 0x10 ) * 2 ) ;
2011-09-21 07:54:44 -03:00
preview_config_averager ( prev , 0 ) ;
2011-02-12 18:05:06 -03:00
preview_config_ycpos ( prev , format - > code ) ;
2012-03-26 10:24:50 -03:00
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
preview_params_unlock ( prev , update , false ) ;
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
}
/* -----------------------------------------------------------------------------
* Interrupt handling
*/
static void preview_enable_oneshot ( struct isp_prev_device * prev )
{
struct isp_device * isp = to_isp_device ( prev ) ;
/* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
* bit is set . As the preview engine is used in single - shot mode , we
* need to set PCR . SOURCE before enabling the preview engine .
*/
if ( prev - > input = = PREVIEW_INPUT_MEMORY )
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_SOURCE ) ;
isp_reg_set ( isp , OMAP3_ISP_IOMEM_PREV , ISPPRV_PCR ,
ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT ) ;
}
void omap3isp_preview_isr_frame_sync ( struct isp_prev_device * prev )
{
/*
* If ISP_VIDEO_DMAQUEUE_QUEUED is set , DMA queue had an underrun
* condition , the module was paused and now we have a buffer queued
* on the output again . Restart the pipeline if running in continuous
* mode .
*/
if ( prev - > state = = ISP_PIPELINE_STREAM_CONTINUOUS & &
prev - > video_out . dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ) {
preview_enable_oneshot ( prev ) ;
isp_video_dmaqueue_flags_clr ( & prev - > video_out ) ;
}
}
static void preview_isr_buffer ( struct isp_prev_device * prev )
{
struct isp_pipeline * pipe = to_isp_pipeline ( & prev - > subdev . entity ) ;
struct isp_buffer * buffer ;
int restart = 0 ;
if ( prev - > output & PREVIEW_OUTPUT_MEMORY ) {
2011-12-07 08:34:50 -03:00
buffer = omap3isp_video_buffer_next ( & prev - > video_out ) ;
2011-02-12 18:05:06 -03:00
if ( buffer ! = NULL ) {
2014-03-09 20:17:12 -03:00
preview_set_outaddr ( prev , buffer - > dma ) ;
2011-02-12 18:05:06 -03:00
restart = 1 ;
}
pipe - > state | = ISP_PIPELINE_IDLE_OUTPUT ;
}
2015-11-10 21:34:18 -02:00
if ( prev - > input = = PREVIEW_INPUT_MEMORY ) {
buffer = omap3isp_video_buffer_next ( & prev - > video_in ) ;
if ( buffer ! = NULL )
preview_set_inaddr ( prev , buffer - > dma ) ;
pipe - > state | = ISP_PIPELINE_IDLE_INPUT ;
}
2011-02-12 18:05:06 -03:00
switch ( prev - > state ) {
case ISP_PIPELINE_STREAM_SINGLESHOT :
if ( isp_pipeline_ready ( pipe ) )
omap3isp_pipeline_set_stream ( pipe ,
ISP_PIPELINE_STREAM_SINGLESHOT ) ;
break ;
case ISP_PIPELINE_STREAM_CONTINUOUS :
/* If an underrun occurs, the video queue operation handler will
* restart the preview engine . Otherwise restart it immediately .
*/
if ( restart )
preview_enable_oneshot ( prev ) ;
break ;
case ISP_PIPELINE_STREAM_STOPPED :
default :
return ;
}
}
/*
* omap3isp_preview_isr - ISP preview engine interrupt handler
*
* Manage the preview engine video buffers and configure shadowed registers .
*/
void omap3isp_preview_isr ( struct isp_prev_device * prev )
{
unsigned long flags ;
2012-03-26 10:24:50 -03:00
u32 update ;
u32 active ;
2011-02-12 18:05:06 -03:00
if ( omap3isp_module_sync_is_stopping ( & prev - > wait , & prev - > stopping ) )
return ;
2012-03-26 10:24:50 -03:00
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
preview_params_switch ( prev ) ;
update = preview_params_lock ( prev , 0 , false ) ;
active = prev - > params . active ;
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
2012-03-26 10:24:50 -03:00
preview_setup_hw ( prev , update , active ) ;
preview_config_input_size ( prev , active ) ;
2011-02-12 18:05:06 -03:00
if ( prev - > input = = PREVIEW_INPUT_MEMORY | |
prev - > output & PREVIEW_OUTPUT_MEMORY )
preview_isr_buffer ( prev ) ;
else if ( prev - > state = = ISP_PIPELINE_STREAM_CONTINUOUS )
preview_enable_oneshot ( prev ) ;
2012-03-26 10:24:50 -03:00
spin_lock_irqsave ( & prev - > params . lock , flags ) ;
preview_params_unlock ( prev , update , false ) ;
spin_unlock_irqrestore ( & prev - > params . lock , flags ) ;
2011-02-12 18:05:06 -03:00
}
/* -----------------------------------------------------------------------------
* ISP video operations
*/
static int preview_video_queue ( struct isp_video * video ,
struct isp_buffer * buffer )
{
struct isp_prev_device * prev = & video - > isp - > isp_prev ;
if ( video - > type = = V4L2_BUF_TYPE_VIDEO_OUTPUT )
2014-03-09 20:17:12 -03:00
preview_set_inaddr ( prev , buffer - > dma ) ;
2011-02-12 18:05:06 -03:00
if ( video - > type = = V4L2_BUF_TYPE_VIDEO_CAPTURE )
2014-03-09 20:17:12 -03:00
preview_set_outaddr ( prev , buffer - > dma ) ;
2011-02-12 18:05:06 -03:00
return 0 ;
}
static const struct isp_video_operations preview_video_ops = {
. queue = preview_video_queue ,
} ;
/* -----------------------------------------------------------------------------
* V4L2 subdev operations
*/
/*
* preview_s_ctrl - Handle set control subdev method
* @ ctrl : pointer to v4l2 control structure
*/
static int preview_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct isp_prev_device * prev =
container_of ( ctrl - > handler , struct isp_prev_device , ctrls ) ;
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
preview_update_brightness ( prev , ctrl - > val ) ;
break ;
case V4L2_CID_CONTRAST :
preview_update_contrast ( prev , ctrl - > val ) ;
break ;
}
return 0 ;
}
static const struct v4l2_ctrl_ops preview_ctrl_ops = {
. s_ctrl = preview_s_ctrl ,
} ;
/*
* preview_ioctl - Handle preview module private ioctl ' s
2014-02-21 09:07:23 -03:00
* @ sd : pointer to v4l2 subdev structure
2011-02-12 18:05:06 -03:00
* @ cmd : configuration command
* @ arg : configuration argument
* return - EINVAL or zero on success
*/
static long preview_ioctl ( struct v4l2_subdev * sd , unsigned int cmd , void * arg )
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
switch ( cmd ) {
case VIDIOC_OMAP3ISP_PRV_CFG :
return preview_config ( prev , arg ) ;
default :
return - ENOIOCTLCMD ;
}
}
/*
* preview_set_stream - Enable / Disable streaming on preview subdev
* @ sd : pointer to v4l2 subdev structure
* @ enable : 1 = = Enable , 0 = = Disable
2011-03-30 22:57:33 -03:00
* return - EINVAL or zero on success
2011-02-12 18:05:06 -03:00
*/
static int preview_set_stream ( struct v4l2_subdev * sd , int enable )
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
struct isp_video * video_out = & prev - > video_out ;
struct isp_device * isp = to_isp_device ( prev ) ;
struct device * dev = to_device ( prev ) ;
if ( prev - > state = = ISP_PIPELINE_STREAM_STOPPED ) {
if ( enable = = ISP_PIPELINE_STREAM_STOPPED )
return 0 ;
omap3isp_subclk_enable ( isp , OMAP3_ISP_SUBCLK_PREVIEW ) ;
preview_configure ( prev ) ;
atomic_set ( & prev - > stopping , 0 ) ;
preview_print_status ( prev ) ;
}
switch ( enable ) {
case ISP_PIPELINE_STREAM_CONTINUOUS :
if ( prev - > output & PREVIEW_OUTPUT_MEMORY )
omap3isp_sbl_enable ( isp , OMAP3_ISP_SBL_PREVIEW_WRITE ) ;
if ( video_out - > dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED | |
! ( prev - > output & PREVIEW_OUTPUT_MEMORY ) )
preview_enable_oneshot ( prev ) ;
isp_video_dmaqueue_flags_clr ( video_out ) ;
break ;
case ISP_PIPELINE_STREAM_SINGLESHOT :
if ( prev - > input = = PREVIEW_INPUT_MEMORY )
omap3isp_sbl_enable ( isp , OMAP3_ISP_SBL_PREVIEW_READ ) ;
if ( prev - > output & PREVIEW_OUTPUT_MEMORY )
omap3isp_sbl_enable ( isp , OMAP3_ISP_SBL_PREVIEW_WRITE ) ;
preview_enable_oneshot ( prev ) ;
break ;
case ISP_PIPELINE_STREAM_STOPPED :
if ( omap3isp_module_sync_idle ( & sd - > entity , & prev - > wait ,
& prev - > stopping ) )
dev_dbg ( dev , " %s: stop timeout. \n " , sd - > name ) ;
omap3isp_sbl_disable ( isp , OMAP3_ISP_SBL_PREVIEW_READ ) ;
omap3isp_sbl_disable ( isp , OMAP3_ISP_SBL_PREVIEW_WRITE ) ;
omap3isp_subclk_disable ( isp , OMAP3_ISP_SUBCLK_PREVIEW ) ;
isp_video_dmaqueue_flags_clr ( video_out ) ;
break ;
}
prev - > state = enable ;
return 0 ;
}
static struct v4l2_mbus_framefmt *
2015-03-04 01:47:54 -08:00
__preview_get_format ( struct isp_prev_device * prev , struct v4l2_subdev_pad_config * cfg ,
2011-02-12 18:05:06 -03:00
unsigned int pad , enum v4l2_subdev_format_whence which )
{
if ( which = = V4L2_SUBDEV_FORMAT_TRY )
2015-03-04 01:47:54 -08:00
return v4l2_subdev_get_try_format ( & prev - > subdev , cfg , pad ) ;
2011-02-12 18:05:06 -03:00
else
return & prev - > formats [ pad ] ;
}
2011-09-21 20:05:45 -03:00
static struct v4l2_rect *
2015-03-04 01:47:54 -08:00
__preview_get_crop ( struct isp_prev_device * prev , struct v4l2_subdev_pad_config * cfg ,
2011-09-21 20:05:45 -03:00
enum v4l2_subdev_format_whence which )
{
if ( which = = V4L2_SUBDEV_FORMAT_TRY )
2015-03-04 01:47:54 -08:00
return v4l2_subdev_get_try_crop ( & prev - > subdev , cfg , PREV_PAD_SINK ) ;
2011-09-21 20:05:45 -03:00
else
return & prev - > crop ;
}
2011-02-12 18:05:06 -03:00
/* previewer format descriptions */
static const unsigned int preview_input_fmts [ ] = {
2014-11-10 14:28:31 -03:00
MEDIA_BUS_FMT_Y8_1X8 ,
MEDIA_BUS_FMT_SGRBG8_1X8 ,
MEDIA_BUS_FMT_SRGGB8_1X8 ,
MEDIA_BUS_FMT_SBGGR8_1X8 ,
MEDIA_BUS_FMT_SGBRG8_1X8 ,
MEDIA_BUS_FMT_Y10_1X10 ,
MEDIA_BUS_FMT_SGRBG10_1X10 ,
MEDIA_BUS_FMT_SRGGB10_1X10 ,
MEDIA_BUS_FMT_SBGGR10_1X10 ,
MEDIA_BUS_FMT_SGBRG10_1X10 ,
2011-02-12 18:05:06 -03:00
} ;
static const unsigned int preview_output_fmts [ ] = {
2014-11-10 14:28:31 -03:00
MEDIA_BUS_FMT_UYVY8_1X16 ,
MEDIA_BUS_FMT_YUYV8_1X16 ,
2011-02-12 18:05:06 -03:00
} ;
/*
2011-09-21 20:05:45 -03:00
* preview_try_format - Validate a format
* @ prev : ISP preview engine
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2011-09-21 20:05:45 -03:00
* @ pad : pad number
* @ fmt : format to be validated
* @ which : try / active format selector
*
* Validate and adjust the given format for the given pad based on the preview
* engine limits and the format and crop rectangles on other pads .
2011-02-12 18:05:06 -03:00
*/
static void preview_try_format ( struct isp_prev_device * prev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg , unsigned int pad ,
2011-02-12 18:05:06 -03:00
struct v4l2_mbus_framefmt * fmt ,
enum v4l2_subdev_format_whence which )
{
2014-11-10 14:28:31 -03:00
u32 pixelcode ;
2011-09-21 20:05:45 -03:00
struct v4l2_rect * crop ;
2011-02-12 18:05:06 -03:00
unsigned int i ;
switch ( pad ) {
case PREV_PAD_SINK :
/* When reading data from the CCDC, the input size has already
* been mangled by the CCDC output pad so it can be accepted
* as - is .
*
* When reading data from memory , clamp the requested width and
* height . The TRM doesn ' t specify a minimum input height , make
* sure we got enough lines to enable the noise filter and color
* filter array interpolation .
*/
if ( prev - > input = = PREVIEW_INPUT_MEMORY ) {
2011-10-03 07:56:15 -03:00
fmt - > width = clamp_t ( u32 , fmt - > width , PREV_MIN_IN_WIDTH ,
preview_max_out_width ( prev ) ) ;
fmt - > height = clamp_t ( u32 , fmt - > height ,
PREV_MIN_IN_HEIGHT ,
PREV_MAX_IN_HEIGHT ) ;
2011-02-12 18:05:06 -03:00
}
fmt - > colorspace = V4L2_COLORSPACE_SRGB ;
for ( i = 0 ; i < ARRAY_SIZE ( preview_input_fmts ) ; i + + ) {
if ( fmt - > code = = preview_input_fmts [ i ] )
break ;
}
/* If not found, use SGRBG10 as default */
if ( i > = ARRAY_SIZE ( preview_input_fmts ) )
2014-11-10 14:28:31 -03:00
fmt - > code = MEDIA_BUS_FMT_SGRBG10_1X10 ;
2011-02-12 18:05:06 -03:00
break ;
case PREV_PAD_SOURCE :
pixelcode = fmt - > code ;
2015-03-04 01:47:54 -08:00
* fmt = * __preview_get_format ( prev , cfg , PREV_PAD_SINK , which ) ;
2011-02-12 18:05:06 -03:00
switch ( pixelcode ) {
2014-11-10 14:28:31 -03:00
case MEDIA_BUS_FMT_YUYV8_1X16 :
case MEDIA_BUS_FMT_UYVY8_1X16 :
2011-02-12 18:05:06 -03:00
fmt - > code = pixelcode ;
break ;
default :
2014-11-10 14:28:31 -03:00
fmt - > code = MEDIA_BUS_FMT_YUYV8_1X16 ;
2011-02-12 18:05:06 -03:00
break ;
}
2011-09-21 20:05:45 -03:00
/* The preview module output size is configurable through the
* averager ( horizontal scaling by 1 / 1 , 1 / 2 , 1 / 4 or 1 / 8 ) . This
* is not supported yet , hardcode the output size to the crop
* rectangle size .
2011-02-12 18:05:06 -03:00
*/
2015-03-04 01:47:54 -08:00
crop = __preview_get_crop ( prev , cfg , which ) ;
2011-09-21 20:05:45 -03:00
fmt - > width = crop - > width ;
fmt - > height = crop - > height ;
2011-02-12 18:05:06 -03:00
fmt - > colorspace = V4L2_COLORSPACE_JPEG ;
break ;
}
fmt - > field = V4L2_FIELD_NONE ;
}
2011-09-21 20:05:45 -03:00
/*
* preview_try_crop - Validate a crop rectangle
* @ prev : ISP preview engine
* @ sink : format on the sink pad
* @ crop : crop rectangle to be validated
*
* The preview engine crops lines and columns for its internal operation ,
* depending on which filters are enabled . Enforce minimum crop margins to
* handle that transparently for userspace .
*
* See the explanation at the PREV_MARGIN_ * definitions for more details .
*/
static void preview_try_crop ( struct isp_prev_device * prev ,
const struct v4l2_mbus_framefmt * sink ,
struct v4l2_rect * crop )
{
unsigned int left = PREV_MARGIN_LEFT ;
unsigned int right = sink - > width - PREV_MARGIN_RIGHT ;
unsigned int top = PREV_MARGIN_TOP ;
unsigned int bottom = sink - > height - PREV_MARGIN_BOTTOM ;
/* When processing data on-the-fly from the CCDC, at least 2 pixels must
* be cropped from the left and right sides of the image . As we don ' t
* know which filters will be enabled , increase the left and right
* margins by two .
*/
if ( prev - > input = = PREVIEW_INPUT_CCDC ) {
left + = 2 ;
right - = 2 ;
}
2012-12-07 07:48:55 -03:00
/* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines
* and no columns in other modes . Increase the margins based on the sink
* format .
*/
2014-11-10 14:28:31 -03:00
if ( sink - > code ! = MEDIA_BUS_FMT_Y8_1X8 & &
sink - > code ! = MEDIA_BUS_FMT_Y10_1X10 ) {
2012-12-07 07:48:55 -03:00
left + = 2 ;
right - = 2 ;
top + = 2 ;
bottom - = 2 ;
}
2011-09-21 20:05:45 -03:00
/* Restrict left/top to even values to keep the Bayer pattern. */
crop - > left & = ~ 1 ;
crop - > top & = ~ 1 ;
crop - > left = clamp_t ( u32 , crop - > left , left , right - PREV_MIN_OUT_WIDTH ) ;
crop - > top = clamp_t ( u32 , crop - > top , top , bottom - PREV_MIN_OUT_HEIGHT ) ;
crop - > width = clamp_t ( u32 , crop - > width , PREV_MIN_OUT_WIDTH ,
right - crop - > left ) ;
crop - > height = clamp_t ( u32 , crop - > height , PREV_MIN_OUT_HEIGHT ,
bottom - crop - > top ) ;
}
2011-02-12 18:05:06 -03:00
/*
* preview_enum_mbus_code - Handle pixel format enumeration
* @ sd : pointer to v4l2 subdev structure
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2011-02-12 18:05:06 -03:00
* @ code : pointer to v4l2_subdev_mbus_code_enum structure
* return - EINVAL or zero on success
*/
static int preview_enum_mbus_code ( struct v4l2_subdev * sd ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2011-02-12 18:05:06 -03:00
struct v4l2_subdev_mbus_code_enum * code )
{
switch ( code - > pad ) {
case PREV_PAD_SINK :
if ( code - > index > = ARRAY_SIZE ( preview_input_fmts ) )
return - EINVAL ;
code - > code = preview_input_fmts [ code - > index ] ;
break ;
case PREV_PAD_SOURCE :
if ( code - > index > = ARRAY_SIZE ( preview_output_fmts ) )
return - EINVAL ;
code - > code = preview_output_fmts [ code - > index ] ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int preview_enum_frame_size ( struct v4l2_subdev * sd ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2011-02-12 18:05:06 -03:00
struct v4l2_subdev_frame_size_enum * fse )
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
struct v4l2_mbus_framefmt format ;
if ( fse - > index ! = 0 )
return - EINVAL ;
format . code = fse - > code ;
format . width = 1 ;
format . height = 1 ;
2015-03-04 01:47:58 -08:00
preview_try_format ( prev , cfg , fse - > pad , & format , fse - > which ) ;
2011-02-12 18:05:06 -03:00
fse - > min_width = format . width ;
fse - > min_height = format . height ;
if ( format . code ! = fse - > code )
return - EINVAL ;
format . code = fse - > code ;
format . width = - 1 ;
format . height = - 1 ;
2015-03-04 01:47:58 -08:00
preview_try_format ( prev , cfg , fse - > pad , & format , fse - > which ) ;
2011-02-12 18:05:06 -03:00
fse - > max_width = format . width ;
fse - > max_height = format . height ;
return 0 ;
}
2011-09-21 20:05:45 -03:00
/*
2012-04-20 05:47:49 -03:00
* preview_get_selection - Retrieve a selection rectangle on a pad
2011-09-21 20:05:45 -03:00
* @ sd : ISP preview V4L2 subdevice
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2012-04-20 05:47:49 -03:00
* @ sel : Selection rectangle
*
* The only supported rectangles are the crop rectangles on the sink pad .
2011-09-21 20:05:45 -03:00
*
* Return 0 on success or a negative error code otherwise .
*/
2012-04-20 05:47:49 -03:00
static int preview_get_selection ( struct v4l2_subdev * sd ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2012-04-20 05:47:49 -03:00
struct v4l2_subdev_selection * sel )
2011-09-21 20:05:45 -03:00
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
2012-04-20 05:47:49 -03:00
struct v4l2_mbus_framefmt * format ;
if ( sel - > pad ! = PREV_PAD_SINK )
return - EINVAL ;
switch ( sel - > target ) {
2012-05-18 09:31:18 -03:00
case V4L2_SEL_TGT_CROP_BOUNDS :
2012-04-20 05:47:49 -03:00
sel - > r . left = 0 ;
sel - > r . top = 0 ;
sel - > r . width = INT_MAX ;
sel - > r . height = INT_MAX ;
2015-03-04 01:47:54 -08:00
format = __preview_get_format ( prev , cfg , PREV_PAD_SINK ,
2012-04-20 05:47:49 -03:00
sel - > which ) ;
preview_try_crop ( prev , format , & sel - > r ) ;
break ;
2012-05-18 09:31:18 -03:00
case V4L2_SEL_TGT_CROP :
2015-03-04 01:47:54 -08:00
sel - > r = * __preview_get_crop ( prev , cfg , sel - > which ) ;
2012-04-20 05:47:49 -03:00
break ;
2011-09-21 20:05:45 -03:00
2012-04-20 05:47:49 -03:00
default :
2011-09-21 20:05:45 -03:00
return - EINVAL ;
2012-04-20 05:47:49 -03:00
}
2011-09-21 20:05:45 -03:00
return 0 ;
}
/*
2012-04-20 05:47:49 -03:00
* preview_set_selection - Set a selection rectangle on a pad
2011-09-21 20:05:45 -03:00
* @ sd : ISP preview V4L2 subdevice
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2012-04-20 05:47:49 -03:00
* @ sel : Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the sink pad .
2011-09-21 20:05:45 -03:00
*
* Return 0 on success or a negative error code otherwise .
*/
2012-04-20 05:47:49 -03:00
static int preview_set_selection ( struct v4l2_subdev * sd ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2012-04-20 05:47:49 -03:00
struct v4l2_subdev_selection * sel )
2011-09-21 20:05:45 -03:00
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
struct v4l2_mbus_framefmt * format ;
2012-05-18 09:31:18 -03:00
if ( sel - > target ! = V4L2_SEL_TGT_CROP | |
2012-04-20 05:47:49 -03:00
sel - > pad ! = PREV_PAD_SINK )
2011-09-21 20:05:45 -03:00
return - EINVAL ;
/* The crop rectangle can't be changed while streaming. */
if ( prev - > state ! = ISP_PIPELINE_STREAM_STOPPED )
return - EBUSY ;
2012-04-20 05:47:49 -03:00
/* Modifying the crop rectangle always changes the format on the source
* pad . If the KEEP_CONFIG flag is set , just return the current crop
* rectangle .
*/
2012-06-13 16:01:10 -03:00
if ( sel - > flags & V4L2_SEL_FLAG_KEEP_CONFIG ) {
2015-03-04 01:47:54 -08:00
sel - > r = * __preview_get_crop ( prev , cfg , sel - > which ) ;
2012-04-20 05:47:49 -03:00
return 0 ;
}
2015-03-04 01:47:54 -08:00
format = __preview_get_format ( prev , cfg , PREV_PAD_SINK , sel - > which ) ;
2012-04-20 05:47:49 -03:00
preview_try_crop ( prev , format , & sel - > r ) ;
2015-03-04 01:47:54 -08:00
* __preview_get_crop ( prev , cfg , sel - > which ) = sel - > r ;
2011-09-21 20:05:45 -03:00
/* Update the source format. */
2015-03-04 01:47:54 -08:00
format = __preview_get_format ( prev , cfg , PREV_PAD_SOURCE , sel - > which ) ;
preview_try_format ( prev , cfg , PREV_PAD_SOURCE , format , sel - > which ) ;
2011-09-21 20:05:45 -03:00
return 0 ;
}
2011-02-12 18:05:06 -03:00
/*
* preview_get_format - Handle get format by pads subdev method
* @ sd : pointer to v4l2 subdev structure
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2011-02-12 18:05:06 -03:00
* @ fmt : pointer to v4l2 subdev format structure
2011-03-30 22:57:33 -03:00
* return - EINVAL or zero on success
2011-02-12 18:05:06 -03:00
*/
2015-03-04 01:47:54 -08:00
static int preview_get_format ( struct v4l2_subdev * sd , struct v4l2_subdev_pad_config * cfg ,
2011-02-12 18:05:06 -03:00
struct v4l2_subdev_format * fmt )
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
struct v4l2_mbus_framefmt * format ;
2015-03-04 01:47:54 -08:00
format = __preview_get_format ( prev , cfg , fmt - > pad , fmt - > which ) ;
2011-02-12 18:05:06 -03:00
if ( format = = NULL )
return - EINVAL ;
fmt - > format = * format ;
return 0 ;
}
/*
* preview_set_format - Handle set format by pads subdev method
* @ sd : pointer to v4l2 subdev structure
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2011-02-12 18:05:06 -03:00
* @ fmt : pointer to v4l2 subdev format structure
* return - EINVAL or zero on success
*/
2015-03-04 01:47:54 -08:00
static int preview_set_format ( struct v4l2_subdev * sd , struct v4l2_subdev_pad_config * cfg ,
2011-02-12 18:05:06 -03:00
struct v4l2_subdev_format * fmt )
{
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
struct v4l2_mbus_framefmt * format ;
2011-09-21 20:05:45 -03:00
struct v4l2_rect * crop ;
2011-02-12 18:05:06 -03:00
2015-03-04 01:47:54 -08:00
format = __preview_get_format ( prev , cfg , fmt - > pad , fmt - > which ) ;
2011-02-12 18:05:06 -03:00
if ( format = = NULL )
return - EINVAL ;
2015-03-04 01:47:54 -08:00
preview_try_format ( prev , cfg , fmt - > pad , & fmt - > format , fmt - > which ) ;
2011-02-12 18:05:06 -03:00
* format = fmt - > format ;
/* Propagate the format from sink to source */
if ( fmt - > pad = = PREV_PAD_SINK ) {
2011-09-21 20:05:45 -03:00
/* Reset the crop rectangle. */
2015-03-04 01:47:54 -08:00
crop = __preview_get_crop ( prev , cfg , fmt - > which ) ;
2011-09-21 20:05:45 -03:00
crop - > left = 0 ;
crop - > top = 0 ;
crop - > width = fmt - > format . width ;
crop - > height = fmt - > format . height ;
preview_try_crop ( prev , & fmt - > format , crop ) ;
/* Update the source format. */
2015-03-04 01:47:54 -08:00
format = __preview_get_format ( prev , cfg , PREV_PAD_SOURCE ,
2011-02-12 18:05:06 -03:00
fmt - > which ) ;
2015-03-04 01:47:54 -08:00
preview_try_format ( prev , cfg , PREV_PAD_SOURCE , format ,
2011-02-12 18:05:06 -03:00
fmt - > which ) ;
}
return 0 ;
}
/*
* preview_init_formats - Initialize formats on all pads
* @ sd : ISP preview V4L2 subdevice
* @ fh : V4L2 subdev file handle
*
* Initialize all pad formats with default values . If fh is not NULL , try
* formats are initialized on the file handle . Otherwise active formats are
* initialized on the device .
*/
static int preview_init_formats ( struct v4l2_subdev * sd ,
struct v4l2_subdev_fh * fh )
{
struct v4l2_subdev_format format ;
memset ( & format , 0 , sizeof ( format ) ) ;
format . pad = PREV_PAD_SINK ;
format . which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE ;
2014-11-10 14:28:31 -03:00
format . format . code = MEDIA_BUS_FMT_SGRBG10_1X10 ;
2011-02-12 18:05:06 -03:00
format . format . width = 4096 ;
format . format . height = 4096 ;
2015-03-04 01:47:54 -08:00
preview_set_format ( sd , fh ? fh - > pad : NULL , & format ) ;
2011-02-12 18:05:06 -03:00
return 0 ;
}
/* subdev core operations */
static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
. ioctl = preview_ioctl ,
} ;
/* subdev video operations */
static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
. s_stream = preview_set_stream ,
} ;
/* subdev pad operations */
static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
. enum_mbus_code = preview_enum_mbus_code ,
. enum_frame_size = preview_enum_frame_size ,
. get_fmt = preview_get_format ,
. set_fmt = preview_set_format ,
2012-04-20 05:47:49 -03:00
. get_selection = preview_get_selection ,
. set_selection = preview_set_selection ,
2011-02-12 18:05:06 -03:00
} ;
/* subdev operations */
static const struct v4l2_subdev_ops preview_v4l2_ops = {
. core = & preview_v4l2_core_ops ,
. video = & preview_v4l2_video_ops ,
. pad = & preview_v4l2_pad_ops ,
} ;
/* subdev internal operations */
static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
. open = preview_init_formats ,
} ;
/* -----------------------------------------------------------------------------
* Media entity operations
*/
/*
* preview_link_setup - Setup previewer connections .
* @ entity : Pointer to media entity structure
* @ local : Pointer to local pad array
* @ remote : Pointer to remote pad array
* @ flags : Link flags
* return - EINVAL or zero on success
*/
static int preview_link_setup ( struct media_entity * entity ,
const struct media_pad * local ,
const struct media_pad * remote , u32 flags )
{
struct v4l2_subdev * sd = media_entity_to_v4l2_subdev ( entity ) ;
struct isp_prev_device * prev = v4l2_get_subdevdata ( sd ) ;
2015-12-11 12:23:23 -02:00
unsigned int index = local - > index ;
2011-02-12 18:05:06 -03:00
2015-05-07 22:12:33 -03:00
/* FIXME: this is actually a hack! */
if ( is_media_entity_v4l2_subdev ( remote - > entity ) )
index | = 2 < < 16 ;
switch ( index ) {
case PREV_PAD_SINK :
2011-02-12 18:05:06 -03:00
/* read from memory */
if ( flags & MEDIA_LNK_FL_ENABLED ) {
if ( prev - > input = = PREVIEW_INPUT_CCDC )
return - EBUSY ;
prev - > input = PREVIEW_INPUT_MEMORY ;
} else {
if ( prev - > input = = PREVIEW_INPUT_MEMORY )
prev - > input = PREVIEW_INPUT_NONE ;
}
break ;
2015-05-07 22:12:33 -03:00
case PREV_PAD_SINK | 2 < < 16 :
2011-02-12 18:05:06 -03:00
/* read from ccdc */
if ( flags & MEDIA_LNK_FL_ENABLED ) {
if ( prev - > input = = PREVIEW_INPUT_MEMORY )
return - EBUSY ;
prev - > input = PREVIEW_INPUT_CCDC ;
} else {
if ( prev - > input = = PREVIEW_INPUT_CCDC )
prev - > input = PREVIEW_INPUT_NONE ;
}
break ;
/*
* The ISP core doesn ' t support pipelines with multiple video outputs .
* Revisit this when it will be implemented , and return - EBUSY for now .
*/
2015-05-07 22:12:33 -03:00
case PREV_PAD_SOURCE :
2011-02-12 18:05:06 -03:00
/* write to memory */
if ( flags & MEDIA_LNK_FL_ENABLED ) {
if ( prev - > output & ~ PREVIEW_OUTPUT_MEMORY )
return - EBUSY ;
prev - > output | = PREVIEW_OUTPUT_MEMORY ;
} else {
prev - > output & = ~ PREVIEW_OUTPUT_MEMORY ;
}
break ;
2015-05-07 22:12:33 -03:00
case PREV_PAD_SOURCE | 2 < < 16 :
2011-02-12 18:05:06 -03:00
/* write to resizer */
if ( flags & MEDIA_LNK_FL_ENABLED ) {
if ( prev - > output & ~ PREVIEW_OUTPUT_RESIZER )
return - EBUSY ;
prev - > output | = PREVIEW_OUTPUT_RESIZER ;
} else {
prev - > output & = ~ PREVIEW_OUTPUT_RESIZER ;
}
break ;
default :
return - EINVAL ;
}
return 0 ;
}
/* media operations */
static const struct media_entity_operations preview_media_ops = {
. link_setup = preview_link_setup ,
2012-01-11 13:27:02 -03:00
. link_validate = v4l2_subdev_link_validate ,
2011-02-12 18:05:06 -03:00
} ;
2011-09-22 16:59:26 -03:00
void omap3isp_preview_unregister_entities ( struct isp_prev_device * prev )
{
v4l2_device_unregister_subdev ( & prev - > subdev ) ;
omap3isp_video_unregister ( & prev - > video_in ) ;
omap3isp_video_unregister ( & prev - > video_out ) ;
}
int omap3isp_preview_register_entities ( struct isp_prev_device * prev ,
struct v4l2_device * vdev )
{
int ret ;
/* Register the subdev and video nodes. */
2019-08-07 11:19:00 -03:00
prev - > subdev . dev = vdev - > mdev - > dev ;
2011-09-22 16:59:26 -03:00
ret = v4l2_device_register_subdev ( vdev , & prev - > subdev ) ;
if ( ret < 0 )
goto error ;
ret = omap3isp_video_register ( & prev - > video_in , vdev ) ;
if ( ret < 0 )
goto error ;
ret = omap3isp_video_register ( & prev - > video_out , vdev ) ;
if ( ret < 0 )
goto error ;
return 0 ;
error :
omap3isp_preview_unregister_entities ( prev ) ;
return ret ;
}
/* -----------------------------------------------------------------------------
* ISP previewer initialisation and cleanup
*/
2011-02-12 18:05:06 -03:00
/*
2011-09-22 16:59:26 -03:00
* preview_init_entities - Initialize subdev and media entity .
2011-02-12 18:05:06 -03:00
* @ prev : Pointer to preview structure
* return - ENOMEM or zero on success
*/
static int preview_init_entities ( struct isp_prev_device * prev )
{
struct v4l2_subdev * sd = & prev - > subdev ;
struct media_pad * pads = prev - > pads ;
struct media_entity * me = & sd - > entity ;
int ret ;
prev - > input = PREVIEW_INPUT_NONE ;
v4l2_subdev_init ( sd , & preview_v4l2_ops ) ;
sd - > internal_ops = & preview_v4l2_internal_ops ;
2018-09-10 08:19:14 -04:00
strscpy ( sd - > name , " OMAP3 ISP preview " , sizeof ( sd - > name ) ) ;
2011-02-12 18:05:06 -03:00
sd - > grp_id = 1 < < 16 ; /* group ID for isp subdevs */
v4l2_set_subdevdata ( sd , prev ) ;
sd - > flags | = V4L2_SUBDEV_FL_HAS_DEVNODE ;
v4l2_ctrl_handler_init ( & prev - > ctrls , 2 ) ;
v4l2_ctrl_new_std ( & prev - > ctrls , & preview_ctrl_ops , V4L2_CID_BRIGHTNESS ,
ISPPRV_BRIGHT_LOW , ISPPRV_BRIGHT_HIGH ,
ISPPRV_BRIGHT_STEP , ISPPRV_BRIGHT_DEF ) ;
v4l2_ctrl_new_std ( & prev - > ctrls , & preview_ctrl_ops , V4L2_CID_CONTRAST ,
ISPPRV_CONTRAST_LOW , ISPPRV_CONTRAST_HIGH ,
ISPPRV_CONTRAST_STEP , ISPPRV_CONTRAST_DEF ) ;
v4l2_ctrl_handler_setup ( & prev - > ctrls ) ;
sd - > ctrl_handler = & prev - > ctrls ;
2013-10-02 20:17:52 -03:00
pads [ PREV_PAD_SINK ] . flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT ;
2011-02-12 18:05:06 -03:00
pads [ PREV_PAD_SOURCE ] . flags = MEDIA_PAD_FL_SOURCE ;
me - > ops = & preview_media_ops ;
2015-12-11 07:44:40 -02:00
ret = media_entity_pads_init ( me , PREV_PADS_NUM , pads ) ;
2011-02-12 18:05:06 -03:00
if ( ret < 0 )
return ret ;
preview_init_formats ( sd , NULL ) ;
/* According to the OMAP34xx TRM, video buffers need to be aligned on a
* 32 bytes boundary . However , an undocumented hardware bug requires a
* 64 bytes boundary at the preview engine input .
*/
prev - > video_in . type = V4L2_BUF_TYPE_VIDEO_OUTPUT ;
prev - > video_in . ops = & preview_video_ops ;
prev - > video_in . isp = to_isp_device ( prev ) ;
prev - > video_in . capture_mem = PAGE_ALIGN ( 4096 * 4096 ) * 2 * 3 ;
prev - > video_in . bpl_alignment = 64 ;
prev - > video_out . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
prev - > video_out . ops = & preview_video_ops ;
prev - > video_out . isp = to_isp_device ( prev ) ;
prev - > video_out . capture_mem = PAGE_ALIGN ( 4096 * 4096 ) * 2 * 3 ;
prev - > video_out . bpl_alignment = 32 ;
ret = omap3isp_video_init ( & prev - > video_in , " preview " ) ;
if ( ret < 0 )
2011-09-22 17:10:30 -03:00
goto error_video_in ;
2011-02-12 18:05:06 -03:00
ret = omap3isp_video_init ( & prev - > video_out , " preview " ) ;
if ( ret < 0 )
2011-09-22 17:10:30 -03:00
goto error_video_out ;
2011-02-12 18:05:06 -03:00
return 0 ;
2011-09-22 17:10:30 -03:00
error_video_out :
omap3isp_video_cleanup ( & prev - > video_in ) ;
error_video_in :
media_entity_cleanup ( & prev - > subdev . entity ) ;
return ret ;
2011-02-12 18:05:06 -03:00
}
/*
2012-03-26 10:24:50 -03:00
* omap3isp_preview_init - Previewer initialization .
2014-02-21 09:07:23 -03:00
* @ isp : Pointer to ISP device
2011-02-12 18:05:06 -03:00
* return - ENOMEM or zero on success
*/
int omap3isp_preview_init ( struct isp_device * isp )
{
struct isp_prev_device * prev = & isp - > isp_prev ;
init_waitqueue_head ( & prev - > wait ) ;
2012-03-26 10:24:50 -03:00
2011-02-12 18:05:06 -03:00
preview_init_params ( prev ) ;
2011-09-22 17:10:30 -03:00
return preview_init_entities ( prev ) ;
2011-02-12 18:05:06 -03:00
}
2011-09-22 16:59:26 -03:00
void omap3isp_preview_cleanup ( struct isp_device * isp )
{
struct isp_prev_device * prev = & isp - > isp_prev ;
v4l2_ctrl_handler_free ( & prev - > ctrls ) ;
omap3isp_video_cleanup ( & prev - > video_in ) ;
omap3isp_video_cleanup ( & prev - > video_out ) ;
media_entity_cleanup ( & prev - > subdev . entity ) ;
}