162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * isppreview.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * TI OMAP3 ISP driver - Preview module
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2010 Nokia Corporation
862306a36Sopenharmony_ci * Copyright (C) 2009 Texas Instruments, Inc.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
1162306a36Sopenharmony_ci *	     Sakari Ailus <sakari.ailus@iki.fi>
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/mm.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/mutex.h>
1862306a36Sopenharmony_ci#include <linux/uaccess.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "isp.h"
2162306a36Sopenharmony_ci#include "ispreg.h"
2262306a36Sopenharmony_ci#include "isppreview.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
2562306a36Sopenharmony_cistatic const struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
2662306a36Sopenharmony_ci	{	/* RGB-RGB Matrix */
2762306a36Sopenharmony_ci		{0x01E2, 0x0F30, 0x0FEE},
2862306a36Sopenharmony_ci		{0x0F9B, 0x01AC, 0x0FB9},
2962306a36Sopenharmony_ci		{0x0FE0, 0x0EC0, 0x0260}
3062306a36Sopenharmony_ci	},	/* RGB Offset */
3162306a36Sopenharmony_ci	{0x0000, 0x0000, 0x0000}
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
3562306a36Sopenharmony_cistatic const struct omap3isp_prev_csc flr_prev_csc = {
3662306a36Sopenharmony_ci	{	/* CSC Coef Matrix */
3762306a36Sopenharmony_ci		{66, 129, 25},
3862306a36Sopenharmony_ci		{-38, -75, 112},
3962306a36Sopenharmony_ci		{112, -94 , -18}
4062306a36Sopenharmony_ci	},	/* CSC Offset */
4162306a36Sopenharmony_ci	{0x0, 0x0, 0x0}
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* Default values in Office Fluorescent Light for CFA Gradient*/
4562306a36Sopenharmony_ci#define FLR_CFA_GRADTHRS_HORZ	0x28
4662306a36Sopenharmony_ci#define FLR_CFA_GRADTHRS_VERT	0x28
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Default values in Office Fluorescent Light for Chroma Suppression*/
4962306a36Sopenharmony_ci#define FLR_CSUP_GAIN		0x0D
5062306a36Sopenharmony_ci#define FLR_CSUP_THRES		0xEB
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* Default values in Office Fluorescent Light for Noise Filter*/
5362306a36Sopenharmony_ci#define FLR_NF_STRGTH		0x03
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Default values for White Balance */
5662306a36Sopenharmony_ci#define FLR_WBAL_DGAIN		0x100
5762306a36Sopenharmony_ci#define FLR_WBAL_COEF		0x20
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Default values in Office Fluorescent Light for Black Adjustment*/
6062306a36Sopenharmony_ci#define FLR_BLKADJ_BLUE		0x0
6162306a36Sopenharmony_ci#define FLR_BLKADJ_GREEN	0x0
6262306a36Sopenharmony_ci#define FLR_BLKADJ_RED		0x0
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define DEF_DETECT_CORRECT_VAL	0xe
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*
6762306a36Sopenharmony_ci * Margins and image size limits.
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * The preview engine crops several rows and columns internally depending on
7062306a36Sopenharmony_ci * which filters are enabled. To avoid format changes when the filters are
7162306a36Sopenharmony_ci * enabled or disabled (which would prevent them from being turned on or off
7262306a36Sopenharmony_ci * during streaming), the driver assumes all filters that can be configured
7362306a36Sopenharmony_ci * during streaming are enabled when computing sink crop and source format
7462306a36Sopenharmony_ci * limits.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * If a filter is disabled, additional cropping is automatically added at the
7762306a36Sopenharmony_ci * preview engine input by the driver to avoid overflow at line and frame end.
7862306a36Sopenharmony_ci * This is completely transparent for applications.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Median filter		4 pixels
8162306a36Sopenharmony_ci * Noise filter,
8262306a36Sopenharmony_ci * Faulty pixels correction	4 pixels, 4 lines
8362306a36Sopenharmony_ci * Color suppression		2 pixels
8462306a36Sopenharmony_ci * or luma enhancement
8562306a36Sopenharmony_ci * -------------------------------------------------------------
8662306a36Sopenharmony_ci * Maximum total		10 pixels, 4 lines
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * The color suppression and luma enhancement filters are applied after bayer to
8962306a36Sopenharmony_ci * YUV conversion. They thus can crop one pixel on the left and one pixel on the
9062306a36Sopenharmony_ci * right side of the image without changing the color pattern. When both those
9162306a36Sopenharmony_ci * filters are disabled, the driver must crop the two pixels on the same side of
9262306a36Sopenharmony_ci * the image to avoid changing the bayer pattern. The left margin is thus set to
9362306a36Sopenharmony_ci * 6 pixels and the right margin to 4 pixels.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define PREV_MARGIN_LEFT	6
9762306a36Sopenharmony_ci#define PREV_MARGIN_RIGHT	4
9862306a36Sopenharmony_ci#define PREV_MARGIN_TOP		2
9962306a36Sopenharmony_ci#define PREV_MARGIN_BOTTOM	2
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define PREV_MIN_IN_WIDTH	64
10262306a36Sopenharmony_ci#define PREV_MIN_IN_HEIGHT	8
10362306a36Sopenharmony_ci#define PREV_MAX_IN_HEIGHT	16384
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define PREV_MIN_OUT_WIDTH		0
10662306a36Sopenharmony_ci#define PREV_MIN_OUT_HEIGHT		0
10762306a36Sopenharmony_ci#define PREV_MAX_OUT_WIDTH_REV_1	1280
10862306a36Sopenharmony_ci#define PREV_MAX_OUT_WIDTH_REV_2	3300
10962306a36Sopenharmony_ci#define PREV_MAX_OUT_WIDTH_REV_15	4096
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/*
11262306a36Sopenharmony_ci * Coefficient Tables for the submodules in Preview.
11362306a36Sopenharmony_ci * Array is initialised with the values from.the tables text file.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/*
11762306a36Sopenharmony_ci * CFA Filter Coefficient Table
11862306a36Sopenharmony_ci *
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = {
12162306a36Sopenharmony_ci#include "cfa_coef_table.h"
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * Default Gamma Correction Table - All components
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistatic u32 gamma_table[] = {
12862306a36Sopenharmony_ci#include "gamma_table.h"
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/*
13262306a36Sopenharmony_ci * Noise Filter Threshold table
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_cistatic u32 noise_filter_table[] = {
13562306a36Sopenharmony_ci#include "noise_filter_table.h"
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * Luminance Enhancement Table
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_cistatic u32 luma_enhance_table[] = {
14262306a36Sopenharmony_ci#include "luma_enhance_table.h"
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/*
14662306a36Sopenharmony_ci * preview_config_luma_enhancement - Configure the Luminance Enhancement table
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_cistatic void
14962306a36Sopenharmony_cipreview_config_luma_enhancement(struct isp_prev_device *prev,
15062306a36Sopenharmony_ci				const struct prev_params *params)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
15362306a36Sopenharmony_ci	const struct omap3isp_prev_luma *yt = &params->luma;
15462306a36Sopenharmony_ci	unsigned int i;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
15762306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
15862306a36Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
15962306a36Sopenharmony_ci		isp_reg_writel(isp, yt->table[i],
16062306a36Sopenharmony_ci			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/*
16562306a36Sopenharmony_ci * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement
16662306a36Sopenharmony_ci */
16762306a36Sopenharmony_cistatic void
16862306a36Sopenharmony_cipreview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (enable)
17362306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
17462306a36Sopenharmony_ci			    ISPPRV_PCR_YNENHEN);
17562306a36Sopenharmony_ci	else
17662306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
17762306a36Sopenharmony_ci			    ISPPRV_PCR_YNENHEN);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * preview_enable_invalaw - Enable/disable Inverse A-Law decompression
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic void preview_enable_invalaw(struct isp_prev_device *prev, bool enable)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (enable)
18862306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
18962306a36Sopenharmony_ci			    ISPPRV_PCR_INVALAW);
19062306a36Sopenharmony_ci	else
19162306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
19262306a36Sopenharmony_ci			    ISPPRV_PCR_INVALAW);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/*
19662306a36Sopenharmony_ci * preview_config_hmed - Configure the Horizontal Median Filter
19762306a36Sopenharmony_ci */
19862306a36Sopenharmony_cistatic void preview_config_hmed(struct isp_prev_device *prev,
19962306a36Sopenharmony_ci				const struct prev_params *params)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
20262306a36Sopenharmony_ci	const struct omap3isp_prev_hmed *hmed = &params->hmed;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
20562306a36Sopenharmony_ci		       (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
20662306a36Sopenharmony_ci		       (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
20762306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/*
21162306a36Sopenharmony_ci * preview_enable_hmed - Enable/disable the Horizontal Median Filter
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_cistatic void preview_enable_hmed(struct isp_prev_device *prev, bool enable)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (enable)
21862306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
21962306a36Sopenharmony_ci			    ISPPRV_PCR_HMEDEN);
22062306a36Sopenharmony_ci	else
22162306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
22262306a36Sopenharmony_ci			    ISPPRV_PCR_HMEDEN);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/*
22662306a36Sopenharmony_ci * preview_config_cfa - Configure CFA Interpolation for Bayer formats
22762306a36Sopenharmony_ci *
22862306a36Sopenharmony_ci * The CFA table is organised in four blocks, one per Bayer component. The
22962306a36Sopenharmony_ci * hardware expects blocks to follow the Bayer order of the input data, while
23062306a36Sopenharmony_ci * the driver stores the table in GRBG order in memory. The blocks need to be
23162306a36Sopenharmony_ci * reordered to support non-GRBG Bayer patterns.
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_cistatic void preview_config_cfa(struct isp_prev_device *prev,
23462306a36Sopenharmony_ci			       const struct prev_params *params)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	static const unsigned int cfa_coef_order[4][4] = {
23762306a36Sopenharmony_ci		{ 0, 1, 2, 3 }, /* GRBG */
23862306a36Sopenharmony_ci		{ 1, 0, 3, 2 }, /* RGGB */
23962306a36Sopenharmony_ci		{ 2, 3, 0, 1 }, /* BGGR */
24062306a36Sopenharmony_ci		{ 3, 2, 1, 0 }, /* GBRG */
24162306a36Sopenharmony_ci	};
24262306a36Sopenharmony_ci	const unsigned int *order = cfa_coef_order[prev->params.cfa_order];
24362306a36Sopenharmony_ci	const struct omap3isp_prev_cfa *cfa = &params->cfa;
24462306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
24562306a36Sopenharmony_ci	unsigned int i;
24662306a36Sopenharmony_ci	unsigned int j;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	isp_reg_writel(isp,
24962306a36Sopenharmony_ci		(cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
25062306a36Sopenharmony_ci		(cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
25162306a36Sopenharmony_ci		OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
25462306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	for (i = 0; i < 4; ++i) {
25762306a36Sopenharmony_ci		const __u32 *block = cfa->table[order[i]];
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j)
26062306a36Sopenharmony_ci			isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV,
26162306a36Sopenharmony_ci				       ISPPRV_SET_TBL_DATA);
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/*
26662306a36Sopenharmony_ci * preview_config_chroma_suppression - Configure Chroma Suppression
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_cistatic void
26962306a36Sopenharmony_cipreview_config_chroma_suppression(struct isp_prev_device *prev,
27062306a36Sopenharmony_ci				  const struct prev_params *params)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
27362306a36Sopenharmony_ci	const struct omap3isp_prev_csup *cs = &params->csup;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	isp_reg_writel(isp,
27662306a36Sopenharmony_ci		       cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
27762306a36Sopenharmony_ci		       (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
27862306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_cistatic void
28562306a36Sopenharmony_cipreview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (enable)
29062306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
29162306a36Sopenharmony_ci			    ISPPRV_PCR_SUPEN);
29262306a36Sopenharmony_ci	else
29362306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
29462306a36Sopenharmony_ci			    ISPPRV_PCR_SUPEN);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/*
29862306a36Sopenharmony_ci * preview_config_whitebalance - Configure White Balance parameters
29962306a36Sopenharmony_ci *
30062306a36Sopenharmony_ci * Coefficient matrix always with default values.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cistatic void
30362306a36Sopenharmony_cipreview_config_whitebalance(struct isp_prev_device *prev,
30462306a36Sopenharmony_ci			    const struct prev_params *params)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
30762306a36Sopenharmony_ci	const struct omap3isp_prev_wbal *wbal = &params->wbal;
30862306a36Sopenharmony_ci	u32 val;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
31362306a36Sopenharmony_ci	val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
31462306a36Sopenharmony_ci	val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
31562306a36Sopenharmony_ci	val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
31662306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	isp_reg_writel(isp,
31962306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
32062306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
32162306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
32262306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
32362306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
32462306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
32562306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
32662306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
32762306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
32862306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
32962306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
33062306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
33162306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
33262306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
33362306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
33462306a36Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
33562306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci/*
33962306a36Sopenharmony_ci * preview_config_blkadj - Configure Black Adjustment
34062306a36Sopenharmony_ci */
34162306a36Sopenharmony_cistatic void
34262306a36Sopenharmony_cipreview_config_blkadj(struct isp_prev_device *prev,
34362306a36Sopenharmony_ci		      const struct prev_params *params)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
34662306a36Sopenharmony_ci	const struct omap3isp_prev_blkadj *blkadj = &params->blkadj;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
34962306a36Sopenharmony_ci		       (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
35062306a36Sopenharmony_ci		       (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
35162306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/*
35562306a36Sopenharmony_ci * preview_config_rgb_blending - Configure RGB-RGB Blending
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_cistatic void
35862306a36Sopenharmony_cipreview_config_rgb_blending(struct isp_prev_device *prev,
35962306a36Sopenharmony_ci			    const struct prev_params *params)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
36262306a36Sopenharmony_ci	const struct omap3isp_prev_rgbtorgb *rgbrgb = &params->rgb2rgb;
36362306a36Sopenharmony_ci	u32 val;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
36662306a36Sopenharmony_ci	val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
36762306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
37062306a36Sopenharmony_ci	val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
37162306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
37462306a36Sopenharmony_ci	val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
37562306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
37862306a36Sopenharmony_ci	val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
37962306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
38262306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
38562306a36Sopenharmony_ci	val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
38662306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
38962306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/*
39362306a36Sopenharmony_ci * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr)
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_cistatic void
39662306a36Sopenharmony_cipreview_config_csc(struct isp_prev_device *prev,
39762306a36Sopenharmony_ci		   const struct prev_params *params)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
40062306a36Sopenharmony_ci	const struct omap3isp_prev_csc *csc = &params->csc;
40162306a36Sopenharmony_ci	u32 val;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
40462306a36Sopenharmony_ci	val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
40562306a36Sopenharmony_ci	val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
40662306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
40962306a36Sopenharmony_ci	val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
41062306a36Sopenharmony_ci	val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
41162306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
41462306a36Sopenharmony_ci	val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
41562306a36Sopenharmony_ci	val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
41662306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
41962306a36Sopenharmony_ci	val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
42062306a36Sopenharmony_ci	val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
42162306a36Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/*
42562306a36Sopenharmony_ci * preview_config_yc_range - Configure the max and min Y and C values
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_cistatic void
42862306a36Sopenharmony_cipreview_config_yc_range(struct isp_prev_device *prev,
42962306a36Sopenharmony_ci			const struct prev_params *params)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
43262306a36Sopenharmony_ci	const struct omap3isp_prev_yclimit *yc = &params->yclimit;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	isp_reg_writel(isp,
43562306a36Sopenharmony_ci		       yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
43662306a36Sopenharmony_ci		       yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
43762306a36Sopenharmony_ci		       yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
43862306a36Sopenharmony_ci		       yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
43962306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci/*
44362306a36Sopenharmony_ci * preview_config_dcor - Configure Couplet Defect Correction
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_cistatic void
44662306a36Sopenharmony_cipreview_config_dcor(struct isp_prev_device *prev,
44762306a36Sopenharmony_ci		    const struct prev_params *params)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
45062306a36Sopenharmony_ci	const struct omap3isp_prev_dcor *dcor = &params->dcor;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[0],
45362306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
45462306a36Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[1],
45562306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
45662306a36Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[2],
45762306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
45862306a36Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[3],
45962306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
46062306a36Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
46162306a36Sopenharmony_ci			ISPPRV_PCR_DCCOUP,
46262306a36Sopenharmony_ci			dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci/*
46662306a36Sopenharmony_ci * preview_enable_dcor - Enable/disable Couplet Defect Correction
46762306a36Sopenharmony_ci */
46862306a36Sopenharmony_cistatic void preview_enable_dcor(struct isp_prev_device *prev, bool enable)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (enable)
47362306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
47462306a36Sopenharmony_ci			    ISPPRV_PCR_DCOREN);
47562306a36Sopenharmony_ci	else
47662306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
47762306a36Sopenharmony_ci			    ISPPRV_PCR_DCOREN);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/*
48162306a36Sopenharmony_ci * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cistatic void
48462306a36Sopenharmony_cipreview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (enable)
48962306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
49062306a36Sopenharmony_ci			    ISPPRV_PCR_DRKFCAP);
49162306a36Sopenharmony_ci	else
49262306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
49362306a36Sopenharmony_ci			    ISPPRV_PCR_DRKFCAP);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/*
49762306a36Sopenharmony_ci * preview_enable_drkframe - Enable/disable Dark Frame Subtraction
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_cistatic void preview_enable_drkframe(struct isp_prev_device *prev, bool enable)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (enable)
50462306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
50562306a36Sopenharmony_ci			    ISPPRV_PCR_DRKFEN);
50662306a36Sopenharmony_ci	else
50762306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
50862306a36Sopenharmony_ci			    ISPPRV_PCR_DRKFEN);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci/*
51262306a36Sopenharmony_ci * preview_config_noisefilter - Configure the Noise Filter
51362306a36Sopenharmony_ci */
51462306a36Sopenharmony_cistatic void
51562306a36Sopenharmony_cipreview_config_noisefilter(struct isp_prev_device *prev,
51662306a36Sopenharmony_ci			   const struct prev_params *params)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
51962306a36Sopenharmony_ci	const struct omap3isp_prev_nf *nf = &params->nf;
52062306a36Sopenharmony_ci	unsigned int i;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
52362306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
52462306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
52562306a36Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
52662306a36Sopenharmony_ci		isp_reg_writel(isp, nf->table[i],
52762306a36Sopenharmony_ci			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci/*
53262306a36Sopenharmony_ci * preview_enable_noisefilter - Enable/disable the Noise Filter
53362306a36Sopenharmony_ci */
53462306a36Sopenharmony_cistatic void
53562306a36Sopenharmony_cipreview_enable_noisefilter(struct isp_prev_device *prev, bool enable)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (enable)
54062306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
54162306a36Sopenharmony_ci			    ISPPRV_PCR_NFEN);
54262306a36Sopenharmony_ci	else
54362306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
54462306a36Sopenharmony_ci			    ISPPRV_PCR_NFEN);
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/*
54862306a36Sopenharmony_ci * preview_config_gammacorrn - Configure the Gamma Correction tables
54962306a36Sopenharmony_ci */
55062306a36Sopenharmony_cistatic void
55162306a36Sopenharmony_cipreview_config_gammacorrn(struct isp_prev_device *prev,
55262306a36Sopenharmony_ci			  const struct prev_params *params)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
55562306a36Sopenharmony_ci	const struct omap3isp_prev_gtables *gt = &params->gamma;
55662306a36Sopenharmony_ci	unsigned int i;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
55962306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
56062306a36Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
56162306a36Sopenharmony_ci		isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
56262306a36Sopenharmony_ci			       ISPPRV_SET_TBL_DATA);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
56562306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
56662306a36Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
56762306a36Sopenharmony_ci		isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
56862306a36Sopenharmony_ci			       ISPPRV_SET_TBL_DATA);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
57162306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
57262306a36Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
57362306a36Sopenharmony_ci		isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
57462306a36Sopenharmony_ci			       ISPPRV_SET_TBL_DATA);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/*
57862306a36Sopenharmony_ci * preview_enable_gammacorrn - Enable/disable Gamma Correction
57962306a36Sopenharmony_ci *
58062306a36Sopenharmony_ci * When gamma correction is disabled, the module is bypassed and its output is
58162306a36Sopenharmony_ci * the 8 MSB of the 10-bit input .
58262306a36Sopenharmony_ci */
58362306a36Sopenharmony_cistatic void
58462306a36Sopenharmony_cipreview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (enable)
58962306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
59062306a36Sopenharmony_ci			    ISPPRV_PCR_GAMMA_BYPASS);
59162306a36Sopenharmony_ci	else
59262306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
59362306a36Sopenharmony_ci			    ISPPRV_PCR_GAMMA_BYPASS);
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci/*
59762306a36Sopenharmony_ci * preview_config_contrast - Configure the Contrast
59862306a36Sopenharmony_ci *
59962306a36Sopenharmony_ci * Value should be programmed before enabling the module.
60062306a36Sopenharmony_ci */
60162306a36Sopenharmony_cistatic void
60262306a36Sopenharmony_cipreview_config_contrast(struct isp_prev_device *prev,
60362306a36Sopenharmony_ci			const struct prev_params *params)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
60862306a36Sopenharmony_ci			0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
60962306a36Sopenharmony_ci			params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci/*
61362306a36Sopenharmony_ci * preview_config_brightness - Configure the Brightness
61462306a36Sopenharmony_ci */
61562306a36Sopenharmony_cistatic void
61662306a36Sopenharmony_cipreview_config_brightness(struct isp_prev_device *prev,
61762306a36Sopenharmony_ci			  const struct prev_params *params)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
62262306a36Sopenharmony_ci			0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
62362306a36Sopenharmony_ci			params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci/*
62762306a36Sopenharmony_ci * preview_update_contrast - Updates the contrast.
62862306a36Sopenharmony_ci * @contrast: Pointer to hold the current programmed contrast value.
62962306a36Sopenharmony_ci *
63062306a36Sopenharmony_ci * Value should be programmed before enabling the module.
63162306a36Sopenharmony_ci */
63262306a36Sopenharmony_cistatic void
63362306a36Sopenharmony_cipreview_update_contrast(struct isp_prev_device *prev, u8 contrast)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct prev_params *params;
63662306a36Sopenharmony_ci	unsigned long flags;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
63962306a36Sopenharmony_ci	params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
64062306a36Sopenharmony_ci	       ? &prev->params.params[0] : &prev->params.params[1];
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
64362306a36Sopenharmony_ci		params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
64462306a36Sopenharmony_ci		params->update |= OMAP3ISP_PREV_CONTRAST;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci/*
65062306a36Sopenharmony_ci * preview_update_brightness - Updates the brightness in preview module.
65162306a36Sopenharmony_ci * @brightness: Pointer to hold the current programmed brightness value.
65262306a36Sopenharmony_ci *
65362306a36Sopenharmony_ci */
65462306a36Sopenharmony_cistatic void
65562306a36Sopenharmony_cipreview_update_brightness(struct isp_prev_device *prev, u8 brightness)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	struct prev_params *params;
65862306a36Sopenharmony_ci	unsigned long flags;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
66162306a36Sopenharmony_ci	params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
66262306a36Sopenharmony_ci	       ? &prev->params.params[0] : &prev->params.params[1];
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
66562306a36Sopenharmony_ci		params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
66662306a36Sopenharmony_ci		params->update |= OMAP3ISP_PREV_BRIGHTNESS;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic u32
67262306a36Sopenharmony_cipreview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	u32 active = prev->params.active;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (shadow) {
67762306a36Sopenharmony_ci		/* Mark all shadow parameters we are going to touch as busy. */
67862306a36Sopenharmony_ci		prev->params.params[0].busy |= ~active & update;
67962306a36Sopenharmony_ci		prev->params.params[1].busy |= active & update;
68062306a36Sopenharmony_ci	} else {
68162306a36Sopenharmony_ci		/* Mark all active parameters we are going to touch as busy. */
68262306a36Sopenharmony_ci		update = (prev->params.params[0].update & active)
68362306a36Sopenharmony_ci		       | (prev->params.params[1].update & ~active);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		prev->params.params[0].busy |= active & update;
68662306a36Sopenharmony_ci		prev->params.params[1].busy |= ~active & update;
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	return update;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic void
69362306a36Sopenharmony_cipreview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	u32 active = prev->params.active;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (shadow) {
69862306a36Sopenharmony_ci		/* Set the update flag for shadow parameters that have been
69962306a36Sopenharmony_ci		 * updated and clear the busy flag for all shadow parameters.
70062306a36Sopenharmony_ci		 */
70162306a36Sopenharmony_ci		prev->params.params[0].update |= (~active & update);
70262306a36Sopenharmony_ci		prev->params.params[1].update |= (active & update);
70362306a36Sopenharmony_ci		prev->params.params[0].busy &= active;
70462306a36Sopenharmony_ci		prev->params.params[1].busy &= ~active;
70562306a36Sopenharmony_ci	} else {
70662306a36Sopenharmony_ci		/* Clear the update flag for active parameters that have been
70762306a36Sopenharmony_ci		 * applied and the busy flag for all active parameters.
70862306a36Sopenharmony_ci		 */
70962306a36Sopenharmony_ci		prev->params.params[0].update &= ~(active & update);
71062306a36Sopenharmony_ci		prev->params.params[1].update &= ~(~active & update);
71162306a36Sopenharmony_ci		prev->params.params[0].busy &= ~active;
71262306a36Sopenharmony_ci		prev->params.params[1].busy &= active;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic void preview_params_switch(struct isp_prev_device *prev)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	u32 to_switch;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	/* Switch active parameters with updated shadow parameters when the
72162306a36Sopenharmony_ci	 * shadow parameter has been updated and neither the active not the
72262306a36Sopenharmony_ci	 * shadow parameter is busy.
72362306a36Sopenharmony_ci	 */
72462306a36Sopenharmony_ci	to_switch = (prev->params.params[0].update & ~prev->params.active)
72562306a36Sopenharmony_ci		  | (prev->params.params[1].update & prev->params.active);
72662306a36Sopenharmony_ci	to_switch &= ~(prev->params.params[0].busy |
72762306a36Sopenharmony_ci		       prev->params.params[1].busy);
72862306a36Sopenharmony_ci	if (to_switch == 0)
72962306a36Sopenharmony_ci		return;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	prev->params.active ^= to_switch;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	/* Remove the update flag for the shadow copy of parameters we have
73462306a36Sopenharmony_ci	 * switched.
73562306a36Sopenharmony_ci	 */
73662306a36Sopenharmony_ci	prev->params.params[0].update &= ~(~prev->params.active & to_switch);
73762306a36Sopenharmony_ci	prev->params.params[1].update &= ~(prev->params.active & to_switch);
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/* preview parameters update structure */
74162306a36Sopenharmony_cistruct preview_update {
74262306a36Sopenharmony_ci	void (*config)(struct isp_prev_device *, const struct prev_params *);
74362306a36Sopenharmony_ci	void (*enable)(struct isp_prev_device *, bool);
74462306a36Sopenharmony_ci	unsigned int param_offset;
74562306a36Sopenharmony_ci	unsigned int param_size;
74662306a36Sopenharmony_ci	unsigned int config_offset;
74762306a36Sopenharmony_ci	bool skip;
74862306a36Sopenharmony_ci};
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
75162306a36Sopenharmony_cistatic const struct preview_update update_attrs[] = {
75262306a36Sopenharmony_ci	/* OMAP3ISP_PREV_LUMAENH */ {
75362306a36Sopenharmony_ci		preview_config_luma_enhancement,
75462306a36Sopenharmony_ci		preview_enable_luma_enhancement,
75562306a36Sopenharmony_ci		offsetof(struct prev_params, luma),
75662306a36Sopenharmony_ci		sizeof_field(struct prev_params, luma),
75762306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, luma),
75862306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_INVALAW */ {
75962306a36Sopenharmony_ci		NULL,
76062306a36Sopenharmony_ci		preview_enable_invalaw,
76162306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_HRZ_MED */ {
76262306a36Sopenharmony_ci		preview_config_hmed,
76362306a36Sopenharmony_ci		preview_enable_hmed,
76462306a36Sopenharmony_ci		offsetof(struct prev_params, hmed),
76562306a36Sopenharmony_ci		sizeof_field(struct prev_params, hmed),
76662306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, hmed),
76762306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_CFA */ {
76862306a36Sopenharmony_ci		preview_config_cfa,
76962306a36Sopenharmony_ci		NULL,
77062306a36Sopenharmony_ci		offsetof(struct prev_params, cfa),
77162306a36Sopenharmony_ci		sizeof_field(struct prev_params, cfa),
77262306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, cfa),
77362306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
77462306a36Sopenharmony_ci		preview_config_chroma_suppression,
77562306a36Sopenharmony_ci		preview_enable_chroma_suppression,
77662306a36Sopenharmony_ci		offsetof(struct prev_params, csup),
77762306a36Sopenharmony_ci		sizeof_field(struct prev_params, csup),
77862306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, csup),
77962306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_WB */ {
78062306a36Sopenharmony_ci		preview_config_whitebalance,
78162306a36Sopenharmony_ci		NULL,
78262306a36Sopenharmony_ci		offsetof(struct prev_params, wbal),
78362306a36Sopenharmony_ci		sizeof_field(struct prev_params, wbal),
78462306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, wbal),
78562306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_BLKADJ */ {
78662306a36Sopenharmony_ci		preview_config_blkadj,
78762306a36Sopenharmony_ci		NULL,
78862306a36Sopenharmony_ci		offsetof(struct prev_params, blkadj),
78962306a36Sopenharmony_ci		sizeof_field(struct prev_params, blkadj),
79062306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, blkadj),
79162306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_RGB2RGB */ {
79262306a36Sopenharmony_ci		preview_config_rgb_blending,
79362306a36Sopenharmony_ci		NULL,
79462306a36Sopenharmony_ci		offsetof(struct prev_params, rgb2rgb),
79562306a36Sopenharmony_ci		sizeof_field(struct prev_params, rgb2rgb),
79662306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, rgb2rgb),
79762306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_COLOR_CONV */ {
79862306a36Sopenharmony_ci		preview_config_csc,
79962306a36Sopenharmony_ci		NULL,
80062306a36Sopenharmony_ci		offsetof(struct prev_params, csc),
80162306a36Sopenharmony_ci		sizeof_field(struct prev_params, csc),
80262306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, csc),
80362306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_YC_LIMIT */ {
80462306a36Sopenharmony_ci		preview_config_yc_range,
80562306a36Sopenharmony_ci		NULL,
80662306a36Sopenharmony_ci		offsetof(struct prev_params, yclimit),
80762306a36Sopenharmony_ci		sizeof_field(struct prev_params, yclimit),
80862306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, yclimit),
80962306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_DEFECT_COR */ {
81062306a36Sopenharmony_ci		preview_config_dcor,
81162306a36Sopenharmony_ci		preview_enable_dcor,
81262306a36Sopenharmony_ci		offsetof(struct prev_params, dcor),
81362306a36Sopenharmony_ci		sizeof_field(struct prev_params, dcor),
81462306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, dcor),
81562306a36Sopenharmony_ci	}, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
81662306a36Sopenharmony_ci		NULL,
81762306a36Sopenharmony_ci		NULL,
81862306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
81962306a36Sopenharmony_ci		NULL,
82062306a36Sopenharmony_ci		preview_enable_drkframe_capture,
82162306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
82262306a36Sopenharmony_ci		NULL,
82362306a36Sopenharmony_ci		preview_enable_drkframe,
82462306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_LENS_SHADING */ {
82562306a36Sopenharmony_ci		NULL,
82662306a36Sopenharmony_ci		preview_enable_drkframe,
82762306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_NF */ {
82862306a36Sopenharmony_ci		preview_config_noisefilter,
82962306a36Sopenharmony_ci		preview_enable_noisefilter,
83062306a36Sopenharmony_ci		offsetof(struct prev_params, nf),
83162306a36Sopenharmony_ci		sizeof_field(struct prev_params, nf),
83262306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, nf),
83362306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_GAMMA */ {
83462306a36Sopenharmony_ci		preview_config_gammacorrn,
83562306a36Sopenharmony_ci		preview_enable_gammacorrn,
83662306a36Sopenharmony_ci		offsetof(struct prev_params, gamma),
83762306a36Sopenharmony_ci		sizeof_field(struct prev_params, gamma),
83862306a36Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, gamma),
83962306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_CONTRAST */ {
84062306a36Sopenharmony_ci		preview_config_contrast,
84162306a36Sopenharmony_ci		NULL,
84262306a36Sopenharmony_ci		0, 0, 0, true,
84362306a36Sopenharmony_ci	}, /* OMAP3ISP_PREV_BRIGHTNESS */ {
84462306a36Sopenharmony_ci		preview_config_brightness,
84562306a36Sopenharmony_ci		NULL,
84662306a36Sopenharmony_ci		0, 0, 0, true,
84762306a36Sopenharmony_ci	},
84862306a36Sopenharmony_ci};
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci/*
85162306a36Sopenharmony_ci * preview_config - Copy and update local structure with userspace preview
85262306a36Sopenharmony_ci *                  configuration.
85362306a36Sopenharmony_ci * @prev: ISP preview engine
85462306a36Sopenharmony_ci * @cfg: Configuration
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci * Return zero if success or -EFAULT if the configuration can't be copied from
85762306a36Sopenharmony_ci * userspace.
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_cistatic int preview_config(struct isp_prev_device *prev,
86062306a36Sopenharmony_ci			  struct omap3isp_prev_update_config *cfg)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	unsigned long flags;
86362306a36Sopenharmony_ci	unsigned int i;
86462306a36Sopenharmony_ci	int rval = 0;
86562306a36Sopenharmony_ci	u32 update;
86662306a36Sopenharmony_ci	u32 active;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (cfg->update == 0)
86962306a36Sopenharmony_ci		return 0;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* Mark the shadow parameters we're going to update as busy. */
87262306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
87362306a36Sopenharmony_ci	preview_params_lock(prev, cfg->update, true);
87462306a36Sopenharmony_ci	active = prev->params.active;
87562306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	update = 0;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
88062306a36Sopenharmony_ci		const struct preview_update *attr = &update_attrs[i];
88162306a36Sopenharmony_ci		struct prev_params *params;
88262306a36Sopenharmony_ci		unsigned int bit = 1 << i;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		if (attr->skip || !(cfg->update & bit))
88562306a36Sopenharmony_ci			continue;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci		params = &prev->params.params[!!(active & bit)];
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		if (cfg->flag & bit) {
89062306a36Sopenharmony_ci			void __user *from = *(void __user **)
89162306a36Sopenharmony_ci				((void *)cfg + attr->config_offset);
89262306a36Sopenharmony_ci			void *to = (void *)params + attr->param_offset;
89362306a36Sopenharmony_ci			size_t size = attr->param_size;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci			if (to && from && size) {
89662306a36Sopenharmony_ci				if (copy_from_user(to, from, size)) {
89762306a36Sopenharmony_ci					rval = -EFAULT;
89862306a36Sopenharmony_ci					break;
89962306a36Sopenharmony_ci				}
90062306a36Sopenharmony_ci			}
90162306a36Sopenharmony_ci			params->features |= bit;
90262306a36Sopenharmony_ci		} else {
90362306a36Sopenharmony_ci			params->features &= ~bit;
90462306a36Sopenharmony_ci		}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci		update |= bit;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
91062306a36Sopenharmony_ci	preview_params_unlock(prev, update, true);
91162306a36Sopenharmony_ci	preview_params_switch(prev);
91262306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return rval;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/*
91862306a36Sopenharmony_ci * preview_setup_hw - Setup preview registers and/or internal memory
91962306a36Sopenharmony_ci * @prev: pointer to preview private structure
92062306a36Sopenharmony_ci * @update: Bitmask of parameters to setup
92162306a36Sopenharmony_ci * @active: Bitmask of parameters active in set 0
92262306a36Sopenharmony_ci * Note: can be called from interrupt context
92362306a36Sopenharmony_ci * Return none
92462306a36Sopenharmony_ci */
92562306a36Sopenharmony_cistatic void preview_setup_hw(struct isp_prev_device *prev, u32 update,
92662306a36Sopenharmony_ci			     u32 active)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	unsigned int i;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (update == 0)
93162306a36Sopenharmony_ci		return;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
93462306a36Sopenharmony_ci		const struct preview_update *attr = &update_attrs[i];
93562306a36Sopenharmony_ci		struct prev_params *params;
93662306a36Sopenharmony_ci		unsigned int bit = 1 << i;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		if (!(update & bit))
93962306a36Sopenharmony_ci			continue;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci		params = &prev->params.params[!(active & bit)];
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		if (params->features & bit) {
94462306a36Sopenharmony_ci			if (attr->config)
94562306a36Sopenharmony_ci				attr->config(prev, params);
94662306a36Sopenharmony_ci			if (attr->enable)
94762306a36Sopenharmony_ci				attr->enable(prev, true);
94862306a36Sopenharmony_ci		} else {
94962306a36Sopenharmony_ci			if (attr->enable)
95062306a36Sopenharmony_ci				attr->enable(prev, false);
95162306a36Sopenharmony_ci		}
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/*
95662306a36Sopenharmony_ci * preview_config_ycpos - Configure byte layout of YUV image.
95762306a36Sopenharmony_ci * @prev: pointer to previewer private structure
95862306a36Sopenharmony_ci * @pixelcode: pixel code
95962306a36Sopenharmony_ci */
96062306a36Sopenharmony_cistatic void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
96362306a36Sopenharmony_ci	enum preview_ycpos_mode mode;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	switch (pixelcode) {
96662306a36Sopenharmony_ci	case MEDIA_BUS_FMT_YUYV8_1X16:
96762306a36Sopenharmony_ci		mode = YCPOS_CrYCbY;
96862306a36Sopenharmony_ci		break;
96962306a36Sopenharmony_ci	case MEDIA_BUS_FMT_UYVY8_1X16:
97062306a36Sopenharmony_ci		mode = YCPOS_YCrYCb;
97162306a36Sopenharmony_ci		break;
97262306a36Sopenharmony_ci	default:
97362306a36Sopenharmony_ci		return;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
97762306a36Sopenharmony_ci			ISPPRV_PCR_YCPOS_CrYCbY,
97862306a36Sopenharmony_ci			mode << ISPPRV_PCR_YCPOS_SHIFT);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci/*
98262306a36Sopenharmony_ci * preview_config_averager - Enable / disable / configure averager
98362306a36Sopenharmony_ci * @average: Average value to be configured.
98462306a36Sopenharmony_ci */
98562306a36Sopenharmony_cistatic void preview_config_averager(struct isp_prev_device *prev, u8 average)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
99062306a36Sopenharmony_ci		       ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
99162306a36Sopenharmony_ci		       average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci/*
99662306a36Sopenharmony_ci * preview_config_input_format - Configure the input format
99762306a36Sopenharmony_ci * @prev: The preview engine
99862306a36Sopenharmony_ci * @info: Sink pad format information
99962306a36Sopenharmony_ci *
100062306a36Sopenharmony_ci * Enable and configure CFA interpolation for Bayer formats and disable it for
100162306a36Sopenharmony_ci * greyscale formats.
100262306a36Sopenharmony_ci *
100362306a36Sopenharmony_ci * The CFA table is organised in four blocks, one per Bayer component. The
100462306a36Sopenharmony_ci * hardware expects blocks to follow the Bayer order of the input data, while
100562306a36Sopenharmony_ci * the driver stores the table in GRBG order in memory. The blocks need to be
100662306a36Sopenharmony_ci * reordered to support non-GRBG Bayer patterns.
100762306a36Sopenharmony_ci */
100862306a36Sopenharmony_cistatic void preview_config_input_format(struct isp_prev_device *prev,
100962306a36Sopenharmony_ci					const struct isp_format_info *info)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
101262306a36Sopenharmony_ci	struct prev_params *params;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (info->width == 8)
101562306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
101662306a36Sopenharmony_ci			    ISPPRV_PCR_WIDTH);
101762306a36Sopenharmony_ci	else
101862306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
101962306a36Sopenharmony_ci			    ISPPRV_PCR_WIDTH);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	switch (info->flavor) {
102262306a36Sopenharmony_ci	case MEDIA_BUS_FMT_SGRBG8_1X8:
102362306a36Sopenharmony_ci		prev->params.cfa_order = 0;
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci	case MEDIA_BUS_FMT_SRGGB8_1X8:
102662306a36Sopenharmony_ci		prev->params.cfa_order = 1;
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci	case MEDIA_BUS_FMT_SBGGR8_1X8:
102962306a36Sopenharmony_ci		prev->params.cfa_order = 2;
103062306a36Sopenharmony_ci		break;
103162306a36Sopenharmony_ci	case MEDIA_BUS_FMT_SGBRG8_1X8:
103262306a36Sopenharmony_ci		prev->params.cfa_order = 3;
103362306a36Sopenharmony_ci		break;
103462306a36Sopenharmony_ci	default:
103562306a36Sopenharmony_ci		/* Disable CFA for non-Bayer formats. */
103662306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
103762306a36Sopenharmony_ci			    ISPPRV_PCR_CFAEN);
103862306a36Sopenharmony_ci		return;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
104262306a36Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
104362306a36Sopenharmony_ci			ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	params = (prev->params.active & OMAP3ISP_PREV_CFA)
104662306a36Sopenharmony_ci	       ? &prev->params.params[0] : &prev->params.params[1];
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	preview_config_cfa(prev, params);
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci/*
105262306a36Sopenharmony_ci * preview_config_input_size - Configure the input frame size
105362306a36Sopenharmony_ci *
105462306a36Sopenharmony_ci * The preview engine crops several rows and columns internally depending on
105562306a36Sopenharmony_ci * which processing blocks are enabled. The driver assumes all those blocks are
105662306a36Sopenharmony_ci * enabled when reporting source pad formats to userspace. If this assumption is
105762306a36Sopenharmony_ci * not true, rows and columns must be manually cropped at the preview engine
105862306a36Sopenharmony_ci * input to avoid overflows at the end of lines and frames.
105962306a36Sopenharmony_ci *
106062306a36Sopenharmony_ci * See the explanation at the PREV_MARGIN_* definitions for more details.
106162306a36Sopenharmony_ci */
106262306a36Sopenharmony_cistatic void preview_config_input_size(struct isp_prev_device *prev, u32 active)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
106562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
106662306a36Sopenharmony_ci	unsigned int sph = prev->crop.left;
106762306a36Sopenharmony_ci	unsigned int eph = prev->crop.left + prev->crop.width - 1;
106862306a36Sopenharmony_ci	unsigned int slv = prev->crop.top;
106962306a36Sopenharmony_ci	unsigned int elv = prev->crop.top + prev->crop.height - 1;
107062306a36Sopenharmony_ci	u32 features;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	if (format->code != MEDIA_BUS_FMT_Y8_1X8 &&
107362306a36Sopenharmony_ci	    format->code != MEDIA_BUS_FMT_Y10_1X10) {
107462306a36Sopenharmony_ci		sph -= 2;
107562306a36Sopenharmony_ci		eph += 2;
107662306a36Sopenharmony_ci		slv -= 2;
107762306a36Sopenharmony_ci		elv += 2;
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	features = (prev->params.params[0].features & active)
108162306a36Sopenharmony_ci		 | (prev->params.params[1].features & ~active);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
108462306a36Sopenharmony_ci		sph -= 2;
108562306a36Sopenharmony_ci		eph += 2;
108662306a36Sopenharmony_ci		slv -= 2;
108762306a36Sopenharmony_ci		elv += 2;
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci	if (features & OMAP3ISP_PREV_HRZ_MED) {
109062306a36Sopenharmony_ci		sph -= 2;
109162306a36Sopenharmony_ci		eph += 2;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci	if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
109462306a36Sopenharmony_ci		sph -= 2;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
109762306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
109862306a36Sopenharmony_ci	isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
109962306a36Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci/*
110362306a36Sopenharmony_ci * preview_config_inlineoffset - Configures the Read address line offset.
110462306a36Sopenharmony_ci * @prev: Preview module
110562306a36Sopenharmony_ci * @offset: Line offset
110662306a36Sopenharmony_ci *
110762306a36Sopenharmony_ci * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
110862306a36Sopenharmony_ci * However, a hardware bug requires the memory start address to be aligned on a
110962306a36Sopenharmony_ci * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
111062306a36Sopenharmony_ci * well.
111162306a36Sopenharmony_ci */
111262306a36Sopenharmony_cistatic void
111362306a36Sopenharmony_cipreview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
111862306a36Sopenharmony_ci		       ISPPRV_RADR_OFFSET);
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci/*
112262306a36Sopenharmony_ci * preview_set_inaddr - Sets memory address of input frame.
112362306a36Sopenharmony_ci * @addr: 32bit memory address aligned on 32byte boundary.
112462306a36Sopenharmony_ci *
112562306a36Sopenharmony_ci * Configures the memory address from which the input frame is to be read.
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_cistatic void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci/*
113562306a36Sopenharmony_ci * preview_config_outlineoffset - Configures the Write address line offset.
113662306a36Sopenharmony_ci * @offset: Line Offset for the preview output.
113762306a36Sopenharmony_ci *
113862306a36Sopenharmony_ci * The offset must be a multiple of 32 bytes.
113962306a36Sopenharmony_ci */
114062306a36Sopenharmony_cistatic void preview_config_outlineoffset(struct isp_prev_device *prev,
114162306a36Sopenharmony_ci				    u32 offset)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
114662306a36Sopenharmony_ci		       ISPPRV_WADD_OFFSET);
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/*
115062306a36Sopenharmony_ci * preview_set_outaddr - Sets the memory address to store output frame
115162306a36Sopenharmony_ci * @addr: 32bit memory address aligned on 32byte boundary.
115262306a36Sopenharmony_ci *
115362306a36Sopenharmony_ci * Configures the memory address to which the output frame is written.
115462306a36Sopenharmony_ci */
115562306a36Sopenharmony_cistatic void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_cistatic void preview_adjust_bandwidth(struct isp_prev_device *prev)
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
116562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
116662306a36Sopenharmony_ci	const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
116762306a36Sopenharmony_ci	unsigned long l3_ick = pipe->l3_ick;
116862306a36Sopenharmony_ci	struct v4l2_fract *timeperframe;
116962306a36Sopenharmony_ci	unsigned int cycles_per_frame;
117062306a36Sopenharmony_ci	unsigned int requests_per_frame;
117162306a36Sopenharmony_ci	unsigned int cycles_per_request;
117262306a36Sopenharmony_ci	unsigned int minimum;
117362306a36Sopenharmony_ci	unsigned int maximum;
117462306a36Sopenharmony_ci	unsigned int value;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	if (prev->input != PREVIEW_INPUT_MEMORY) {
117762306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
117862306a36Sopenharmony_ci			    ISPSBL_SDR_REQ_PRV_EXP_MASK);
117962306a36Sopenharmony_ci		return;
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/* Compute the minimum number of cycles per request, based on the
118362306a36Sopenharmony_ci	 * pipeline maximum data rate. This is an absolute lower bound if we
118462306a36Sopenharmony_ci	 * don't want SBL overflows, so round the value up.
118562306a36Sopenharmony_ci	 */
118662306a36Sopenharmony_ci	cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
118762306a36Sopenharmony_ci				     pipe->max_rate);
118862306a36Sopenharmony_ci	minimum = DIV_ROUND_UP(cycles_per_request, 32);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/* Compute the maximum number of cycles per request, based on the
119162306a36Sopenharmony_ci	 * requested frame rate. This is a soft upper bound to achieve a frame
119262306a36Sopenharmony_ci	 * rate equal or higher than the requested value, so round the value
119362306a36Sopenharmony_ci	 * down.
119462306a36Sopenharmony_ci	 */
119562306a36Sopenharmony_ci	timeperframe = &pipe->max_timeperframe;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
119862306a36Sopenharmony_ci	cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
119962306a36Sopenharmony_ci				   timeperframe->denominator);
120062306a36Sopenharmony_ci	cycles_per_request = cycles_per_frame / requests_per_frame;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	maximum = cycles_per_request / 32;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	value = max(minimum, maximum);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
120762306a36Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
120862306a36Sopenharmony_ci			ISPSBL_SDR_REQ_PRV_EXP_MASK,
120962306a36Sopenharmony_ci			value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci/*
121362306a36Sopenharmony_ci * omap3isp_preview_busy - Gets busy state of preview module.
121462306a36Sopenharmony_ci */
121562306a36Sopenharmony_ciint omap3isp_preview_busy(struct isp_prev_device *prev)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
122062306a36Sopenharmony_ci		& ISPPRV_PCR_BUSY;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci/*
122462306a36Sopenharmony_ci * omap3isp_preview_restore_context - Restores the values of preview registers
122562306a36Sopenharmony_ci */
122662306a36Sopenharmony_civoid omap3isp_preview_restore_context(struct isp_device *isp)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	struct isp_prev_device *prev = &isp->isp_prev;
122962306a36Sopenharmony_ci	const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	prev->params.params[0].update = prev->params.active & update;
123262306a36Sopenharmony_ci	prev->params.params[1].update = ~prev->params.active & update;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	preview_setup_hw(prev, update, prev->params.active);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	prev->params.params[0].update = 0;
123762306a36Sopenharmony_ci	prev->params.params[1].update = 0;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci/*
124162306a36Sopenharmony_ci * preview_print_status - Dump preview module registers to the kernel log
124262306a36Sopenharmony_ci */
124362306a36Sopenharmony_ci#define PREV_PRINT_REGISTER(isp, name)\
124462306a36Sopenharmony_ci	dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
124562306a36Sopenharmony_ci		isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic void preview_print_status(struct isp_prev_device *prev)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, PCR);
125462306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, HORZ_INFO);
125562306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, VERT_INFO);
125662306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RSDR_ADDR);
125762306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RADR_OFFSET);
125862306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, DSDR_ADDR);
125962306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
126062306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WSDR_ADDR);
126162306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WADD_OFFSET);
126262306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, AVE);
126362306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, HMED);
126462306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, NF);
126562306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WB_DGAIN);
126662306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WBGAIN);
126762306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WBSEL);
126862306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CFA);
126962306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, BLKADJOFF);
127062306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT1);
127162306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT2);
127262306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT3);
127362306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT4);
127462306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT5);
127562306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_OFF1);
127662306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_OFF2);
127762306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC0);
127862306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC1);
127962306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC2);
128062306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC_OFFSET);
128162306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CNT_BRT);
128262306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSUP);
128362306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, SETUP_YC);
128462306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
128562306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR0);
128662306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR1);
128762306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR2);
128862306a36Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR3);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	dev_dbg(isp->dev, "--------------------------------------------\n");
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci/*
129462306a36Sopenharmony_ci * preview_init_params - init image processing parameters.
129562306a36Sopenharmony_ci * @prev: pointer to previewer private structure
129662306a36Sopenharmony_ci */
129762306a36Sopenharmony_cistatic void preview_init_params(struct isp_prev_device *prev)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	struct prev_params *params;
130062306a36Sopenharmony_ci	unsigned int i;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	spin_lock_init(&prev->params.lock);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	prev->params.active = ~0;
130562306a36Sopenharmony_ci	prev->params.params[0].busy = 0;
130662306a36Sopenharmony_ci	prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
130762306a36Sopenharmony_ci	prev->params.params[1].busy = 0;
130862306a36Sopenharmony_ci	prev->params.params[1].update = 0;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	params = &prev->params.params[0];
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	/* Init values */
131362306a36Sopenharmony_ci	params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
131462306a36Sopenharmony_ci	params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
131562306a36Sopenharmony_ci	params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
131662306a36Sopenharmony_ci	memcpy(params->cfa.table, cfa_coef_table,
131762306a36Sopenharmony_ci	       sizeof(params->cfa.table));
131862306a36Sopenharmony_ci	params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
131962306a36Sopenharmony_ci	params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
132062306a36Sopenharmony_ci	params->csup.gain = FLR_CSUP_GAIN;
132162306a36Sopenharmony_ci	params->csup.thres = FLR_CSUP_THRES;
132262306a36Sopenharmony_ci	params->csup.hypf_en = 0;
132362306a36Sopenharmony_ci	memcpy(params->luma.table, luma_enhance_table,
132462306a36Sopenharmony_ci	       sizeof(params->luma.table));
132562306a36Sopenharmony_ci	params->nf.spread = FLR_NF_STRGTH;
132662306a36Sopenharmony_ci	memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
132762306a36Sopenharmony_ci	params->dcor.couplet_mode_en = 1;
132862306a36Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
132962306a36Sopenharmony_ci		params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
133062306a36Sopenharmony_ci	memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
133162306a36Sopenharmony_ci	memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
133262306a36Sopenharmony_ci	memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
133362306a36Sopenharmony_ci	params->wbal.dgain = FLR_WBAL_DGAIN;
133462306a36Sopenharmony_ci	params->wbal.coef0 = FLR_WBAL_COEF;
133562306a36Sopenharmony_ci	params->wbal.coef1 = FLR_WBAL_COEF;
133662306a36Sopenharmony_ci	params->wbal.coef2 = FLR_WBAL_COEF;
133762306a36Sopenharmony_ci	params->wbal.coef3 = FLR_WBAL_COEF;
133862306a36Sopenharmony_ci	params->blkadj.red = FLR_BLKADJ_RED;
133962306a36Sopenharmony_ci	params->blkadj.green = FLR_BLKADJ_GREEN;
134062306a36Sopenharmony_ci	params->blkadj.blue = FLR_BLKADJ_BLUE;
134162306a36Sopenharmony_ci	params->rgb2rgb = flr_rgb2rgb;
134262306a36Sopenharmony_ci	params->csc = flr_prev_csc;
134362306a36Sopenharmony_ci	params->yclimit.minC = ISPPRV_YC_MIN;
134462306a36Sopenharmony_ci	params->yclimit.maxC = ISPPRV_YC_MAX;
134562306a36Sopenharmony_ci	params->yclimit.minY = ISPPRV_YC_MIN;
134662306a36Sopenharmony_ci	params->yclimit.maxY = ISPPRV_YC_MAX;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
134962306a36Sopenharmony_ci			 | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
135062306a36Sopenharmony_ci			 | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
135162306a36Sopenharmony_ci			 | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
135262306a36Sopenharmony_ci			 | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
135362306a36Sopenharmony_ci			 | OMAP3ISP_PREV_CONTRAST;
135462306a36Sopenharmony_ci}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci/*
135762306a36Sopenharmony_ci * preview_max_out_width - Handle previewer hardware output limitations
135862306a36Sopenharmony_ci * @prev: pointer to previewer private structure
135962306a36Sopenharmony_ci * returns maximum width output for current isp revision
136062306a36Sopenharmony_ci */
136162306a36Sopenharmony_cistatic unsigned int preview_max_out_width(struct isp_prev_device *prev)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	switch (isp->revision) {
136662306a36Sopenharmony_ci	case ISP_REVISION_1_0:
136762306a36Sopenharmony_ci		return PREV_MAX_OUT_WIDTH_REV_1;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	case ISP_REVISION_2_0:
137062306a36Sopenharmony_ci	default:
137162306a36Sopenharmony_ci		return PREV_MAX_OUT_WIDTH_REV_2;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	case ISP_REVISION_15_0:
137462306a36Sopenharmony_ci		return PREV_MAX_OUT_WIDTH_REV_15;
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic void preview_configure(struct isp_prev_device *prev)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
138162306a36Sopenharmony_ci	const struct isp_format_info *info;
138262306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
138362306a36Sopenharmony_ci	unsigned long flags;
138462306a36Sopenharmony_ci	u32 update;
138562306a36Sopenharmony_ci	u32 active;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
138862306a36Sopenharmony_ci	/* Mark all active parameters we are going to touch as busy. */
138962306a36Sopenharmony_ci	update = preview_params_lock(prev, 0, false);
139062306a36Sopenharmony_ci	active = prev->params.active;
139162306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* PREV_PAD_SINK */
139462306a36Sopenharmony_ci	format = &prev->formats[PREV_PAD_SINK];
139562306a36Sopenharmony_ci	info = omap3isp_video_format_info(format->code);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	preview_adjust_bandwidth(prev);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	preview_config_input_format(prev, info);
140062306a36Sopenharmony_ci	preview_config_input_size(prev, active);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_CCDC)
140362306a36Sopenharmony_ci		preview_config_inlineoffset(prev, 0);
140462306a36Sopenharmony_ci	else
140562306a36Sopenharmony_ci		preview_config_inlineoffset(prev, ALIGN(format->width, 0x20) *
140662306a36Sopenharmony_ci					    info->bpp);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	preview_setup_hw(prev, update, active);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	/* PREV_PAD_SOURCE */
141162306a36Sopenharmony_ci	format = &prev->formats[PREV_PAD_SOURCE];
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_MEMORY)
141462306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
141562306a36Sopenharmony_ci			    ISPPRV_PCR_SDRPORT);
141662306a36Sopenharmony_ci	else
141762306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
141862306a36Sopenharmony_ci			    ISPPRV_PCR_SDRPORT);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_RESIZER)
142162306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
142262306a36Sopenharmony_ci			    ISPPRV_PCR_RSZPORT);
142362306a36Sopenharmony_ci	else
142462306a36Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
142562306a36Sopenharmony_ci			    ISPPRV_PCR_RSZPORT);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_MEMORY)
142862306a36Sopenharmony_ci		preview_config_outlineoffset(prev,
142962306a36Sopenharmony_ci				ALIGN(format->width, 0x10) * 2);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	preview_config_averager(prev, 0);
143262306a36Sopenharmony_ci	preview_config_ycpos(prev, format->code);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
143562306a36Sopenharmony_ci	preview_params_unlock(prev, update, false);
143662306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
143762306a36Sopenharmony_ci}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
144062306a36Sopenharmony_ci * Interrupt handling
144162306a36Sopenharmony_ci */
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic void preview_enable_oneshot(struct isp_prev_device *prev)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	/* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
144862306a36Sopenharmony_ci	 * bit is set. As the preview engine is used in single-shot mode, we
144962306a36Sopenharmony_ci	 * need to set PCR.SOURCE before enabling the preview engine.
145062306a36Sopenharmony_ci	 */
145162306a36Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_MEMORY)
145262306a36Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
145362306a36Sopenharmony_ci			    ISPPRV_PCR_SOURCE);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
145662306a36Sopenharmony_ci		    ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_civoid omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	/*
146262306a36Sopenharmony_ci	 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
146362306a36Sopenharmony_ci	 * condition, the module was paused and now we have a buffer queued
146462306a36Sopenharmony_ci	 * on the output again. Restart the pipeline if running in continuous
146562306a36Sopenharmony_ci	 * mode.
146662306a36Sopenharmony_ci	 */
146762306a36Sopenharmony_ci	if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
146862306a36Sopenharmony_ci	    prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
146962306a36Sopenharmony_ci		preview_enable_oneshot(prev);
147062306a36Sopenharmony_ci		isp_video_dmaqueue_flags_clr(&prev->video_out);
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic void preview_isr_buffer(struct isp_prev_device *prev)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
147762306a36Sopenharmony_ci	struct isp_buffer *buffer;
147862306a36Sopenharmony_ci	int restart = 0;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_MEMORY) {
148162306a36Sopenharmony_ci		buffer = omap3isp_video_buffer_next(&prev->video_out);
148262306a36Sopenharmony_ci		if (buffer != NULL) {
148362306a36Sopenharmony_ci			preview_set_outaddr(prev, buffer->dma);
148462306a36Sopenharmony_ci			restart = 1;
148562306a36Sopenharmony_ci		}
148662306a36Sopenharmony_ci		pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_MEMORY) {
149062306a36Sopenharmony_ci		buffer = omap3isp_video_buffer_next(&prev->video_in);
149162306a36Sopenharmony_ci		if (buffer != NULL)
149262306a36Sopenharmony_ci			preview_set_inaddr(prev, buffer->dma);
149362306a36Sopenharmony_ci		pipe->state |= ISP_PIPELINE_IDLE_INPUT;
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	switch (prev->state) {
149762306a36Sopenharmony_ci	case ISP_PIPELINE_STREAM_SINGLESHOT:
149862306a36Sopenharmony_ci		if (isp_pipeline_ready(pipe))
149962306a36Sopenharmony_ci			omap3isp_pipeline_set_stream(pipe,
150062306a36Sopenharmony_ci						ISP_PIPELINE_STREAM_SINGLESHOT);
150162306a36Sopenharmony_ci		break;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	case ISP_PIPELINE_STREAM_CONTINUOUS:
150462306a36Sopenharmony_ci		/* If an underrun occurs, the video queue operation handler will
150562306a36Sopenharmony_ci		 * restart the preview engine. Otherwise restart it immediately.
150662306a36Sopenharmony_ci		 */
150762306a36Sopenharmony_ci		if (restart)
150862306a36Sopenharmony_ci			preview_enable_oneshot(prev);
150962306a36Sopenharmony_ci		break;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	case ISP_PIPELINE_STREAM_STOPPED:
151262306a36Sopenharmony_ci	default:
151362306a36Sopenharmony_ci		return;
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci/*
151862306a36Sopenharmony_ci * omap3isp_preview_isr - ISP preview engine interrupt handler
151962306a36Sopenharmony_ci *
152062306a36Sopenharmony_ci * Manage the preview engine video buffers and configure shadowed registers.
152162306a36Sopenharmony_ci */
152262306a36Sopenharmony_civoid omap3isp_preview_isr(struct isp_prev_device *prev)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	unsigned long flags;
152562306a36Sopenharmony_ci	u32 update;
152662306a36Sopenharmony_ci	u32 active;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
152962306a36Sopenharmony_ci		return;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
153262306a36Sopenharmony_ci	preview_params_switch(prev);
153362306a36Sopenharmony_ci	update = preview_params_lock(prev, 0, false);
153462306a36Sopenharmony_ci	active = prev->params.active;
153562306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	preview_setup_hw(prev, update, active);
153862306a36Sopenharmony_ci	preview_config_input_size(prev, active);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_MEMORY ||
154162306a36Sopenharmony_ci	    prev->output & PREVIEW_OUTPUT_MEMORY)
154262306a36Sopenharmony_ci		preview_isr_buffer(prev);
154362306a36Sopenharmony_ci	else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
154462306a36Sopenharmony_ci		preview_enable_oneshot(prev);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
154762306a36Sopenharmony_ci	preview_params_unlock(prev, update, false);
154862306a36Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
155262306a36Sopenharmony_ci * ISP video operations
155362306a36Sopenharmony_ci */
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_cistatic int preview_video_queue(struct isp_video *video,
155662306a36Sopenharmony_ci			       struct isp_buffer *buffer)
155762306a36Sopenharmony_ci{
155862306a36Sopenharmony_ci	struct isp_prev_device *prev = &video->isp->isp_prev;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
156162306a36Sopenharmony_ci		preview_set_inaddr(prev, buffer->dma);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
156462306a36Sopenharmony_ci		preview_set_outaddr(prev, buffer->dma);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	return 0;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic const struct isp_video_operations preview_video_ops = {
157062306a36Sopenharmony_ci	.queue = preview_video_queue,
157162306a36Sopenharmony_ci};
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
157462306a36Sopenharmony_ci * V4L2 subdev operations
157562306a36Sopenharmony_ci */
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci/*
157862306a36Sopenharmony_ci * preview_s_ctrl - Handle set control subdev method
157962306a36Sopenharmony_ci * @ctrl: pointer to v4l2 control structure
158062306a36Sopenharmony_ci */
158162306a36Sopenharmony_cistatic int preview_s_ctrl(struct v4l2_ctrl *ctrl)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	struct isp_prev_device *prev =
158462306a36Sopenharmony_ci		container_of(ctrl->handler, struct isp_prev_device, ctrls);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	switch (ctrl->id) {
158762306a36Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
158862306a36Sopenharmony_ci		preview_update_brightness(prev, ctrl->val);
158962306a36Sopenharmony_ci		break;
159062306a36Sopenharmony_ci	case V4L2_CID_CONTRAST:
159162306a36Sopenharmony_ci		preview_update_contrast(prev, ctrl->val);
159262306a36Sopenharmony_ci		break;
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	return 0;
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops preview_ctrl_ops = {
159962306a36Sopenharmony_ci	.s_ctrl = preview_s_ctrl,
160062306a36Sopenharmony_ci};
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci/*
160362306a36Sopenharmony_ci * preview_ioctl - Handle preview module private ioctl's
160462306a36Sopenharmony_ci * @sd: pointer to v4l2 subdev structure
160562306a36Sopenharmony_ci * @cmd: configuration command
160662306a36Sopenharmony_ci * @arg: configuration argument
160762306a36Sopenharmony_ci * return -EINVAL or zero on success
160862306a36Sopenharmony_ci */
160962306a36Sopenharmony_cistatic long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
161062306a36Sopenharmony_ci{
161162306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	switch (cmd) {
161462306a36Sopenharmony_ci	case VIDIOC_OMAP3ISP_PRV_CFG:
161562306a36Sopenharmony_ci		return preview_config(prev, arg);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	default:
161862306a36Sopenharmony_ci		return -ENOIOCTLCMD;
161962306a36Sopenharmony_ci	}
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci/*
162362306a36Sopenharmony_ci * preview_set_stream - Enable/Disable streaming on preview subdev
162462306a36Sopenharmony_ci * @sd    : pointer to v4l2 subdev structure
162562306a36Sopenharmony_ci * @enable: 1 == Enable, 0 == Disable
162662306a36Sopenharmony_ci * return -EINVAL or zero on success
162762306a36Sopenharmony_ci */
162862306a36Sopenharmony_cistatic int preview_set_stream(struct v4l2_subdev *sd, int enable)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
163162306a36Sopenharmony_ci	struct isp_video *video_out = &prev->video_out;
163262306a36Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
163362306a36Sopenharmony_ci	struct device *dev = to_device(prev);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
163662306a36Sopenharmony_ci		if (enable == ISP_PIPELINE_STREAM_STOPPED)
163762306a36Sopenharmony_ci			return 0;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci		omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
164062306a36Sopenharmony_ci		preview_configure(prev);
164162306a36Sopenharmony_ci		atomic_set(&prev->stopping, 0);
164262306a36Sopenharmony_ci		preview_print_status(prev);
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	switch (enable) {
164662306a36Sopenharmony_ci	case ISP_PIPELINE_STREAM_CONTINUOUS:
164762306a36Sopenharmony_ci		if (prev->output & PREVIEW_OUTPUT_MEMORY)
164862306a36Sopenharmony_ci			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci		if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
165162306a36Sopenharmony_ci		    !(prev->output & PREVIEW_OUTPUT_MEMORY))
165262306a36Sopenharmony_ci			preview_enable_oneshot(prev);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		isp_video_dmaqueue_flags_clr(video_out);
165562306a36Sopenharmony_ci		break;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	case ISP_PIPELINE_STREAM_SINGLESHOT:
165862306a36Sopenharmony_ci		if (prev->input == PREVIEW_INPUT_MEMORY)
165962306a36Sopenharmony_ci			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
166062306a36Sopenharmony_ci		if (prev->output & PREVIEW_OUTPUT_MEMORY)
166162306a36Sopenharmony_ci			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci		preview_enable_oneshot(prev);
166462306a36Sopenharmony_ci		break;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	case ISP_PIPELINE_STREAM_STOPPED:
166762306a36Sopenharmony_ci		if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
166862306a36Sopenharmony_ci					      &prev->stopping))
166962306a36Sopenharmony_ci			dev_dbg(dev, "%s: stop timeout.\n", sd->name);
167062306a36Sopenharmony_ci		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
167162306a36Sopenharmony_ci		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
167262306a36Sopenharmony_ci		omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
167362306a36Sopenharmony_ci		isp_video_dmaqueue_flags_clr(video_out);
167462306a36Sopenharmony_ci		break;
167562306a36Sopenharmony_ci	}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	prev->state = enable;
167862306a36Sopenharmony_ci	return 0;
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cistatic struct v4l2_mbus_framefmt *
168262306a36Sopenharmony_ci__preview_get_format(struct isp_prev_device *prev,
168362306a36Sopenharmony_ci		     struct v4l2_subdev_state *sd_state,
168462306a36Sopenharmony_ci		     unsigned int pad, enum v4l2_subdev_format_whence which)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	if (which == V4L2_SUBDEV_FORMAT_TRY)
168762306a36Sopenharmony_ci		return v4l2_subdev_get_try_format(&prev->subdev, sd_state,
168862306a36Sopenharmony_ci						  pad);
168962306a36Sopenharmony_ci	else
169062306a36Sopenharmony_ci		return &prev->formats[pad];
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_cistatic struct v4l2_rect *
169462306a36Sopenharmony_ci__preview_get_crop(struct isp_prev_device *prev,
169562306a36Sopenharmony_ci		   struct v4l2_subdev_state *sd_state,
169662306a36Sopenharmony_ci		   enum v4l2_subdev_format_whence which)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	if (which == V4L2_SUBDEV_FORMAT_TRY)
169962306a36Sopenharmony_ci		return v4l2_subdev_get_try_crop(&prev->subdev, sd_state,
170062306a36Sopenharmony_ci						PREV_PAD_SINK);
170162306a36Sopenharmony_ci	else
170262306a36Sopenharmony_ci		return &prev->crop;
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci/* previewer format descriptions */
170662306a36Sopenharmony_cistatic const unsigned int preview_input_fmts[] = {
170762306a36Sopenharmony_ci	MEDIA_BUS_FMT_Y8_1X8,
170862306a36Sopenharmony_ci	MEDIA_BUS_FMT_SGRBG8_1X8,
170962306a36Sopenharmony_ci	MEDIA_BUS_FMT_SRGGB8_1X8,
171062306a36Sopenharmony_ci	MEDIA_BUS_FMT_SBGGR8_1X8,
171162306a36Sopenharmony_ci	MEDIA_BUS_FMT_SGBRG8_1X8,
171262306a36Sopenharmony_ci	MEDIA_BUS_FMT_Y10_1X10,
171362306a36Sopenharmony_ci	MEDIA_BUS_FMT_SGRBG10_1X10,
171462306a36Sopenharmony_ci	MEDIA_BUS_FMT_SRGGB10_1X10,
171562306a36Sopenharmony_ci	MEDIA_BUS_FMT_SBGGR10_1X10,
171662306a36Sopenharmony_ci	MEDIA_BUS_FMT_SGBRG10_1X10,
171762306a36Sopenharmony_ci};
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_cistatic const unsigned int preview_output_fmts[] = {
172062306a36Sopenharmony_ci	MEDIA_BUS_FMT_UYVY8_1X16,
172162306a36Sopenharmony_ci	MEDIA_BUS_FMT_YUYV8_1X16,
172262306a36Sopenharmony_ci};
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci/*
172562306a36Sopenharmony_ci * preview_try_format - Validate a format
172662306a36Sopenharmony_ci * @prev: ISP preview engine
172762306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
172862306a36Sopenharmony_ci * @pad: pad number
172962306a36Sopenharmony_ci * @fmt: format to be validated
173062306a36Sopenharmony_ci * @which: try/active format selector
173162306a36Sopenharmony_ci *
173262306a36Sopenharmony_ci * Validate and adjust the given format for the given pad based on the preview
173362306a36Sopenharmony_ci * engine limits and the format and crop rectangles on other pads.
173462306a36Sopenharmony_ci */
173562306a36Sopenharmony_cistatic void preview_try_format(struct isp_prev_device *prev,
173662306a36Sopenharmony_ci			       struct v4l2_subdev_state *sd_state,
173762306a36Sopenharmony_ci			       unsigned int pad,
173862306a36Sopenharmony_ci			       struct v4l2_mbus_framefmt *fmt,
173962306a36Sopenharmony_ci			       enum v4l2_subdev_format_whence which)
174062306a36Sopenharmony_ci{
174162306a36Sopenharmony_ci	u32 pixelcode;
174262306a36Sopenharmony_ci	struct v4l2_rect *crop;
174362306a36Sopenharmony_ci	unsigned int i;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	switch (pad) {
174662306a36Sopenharmony_ci	case PREV_PAD_SINK:
174762306a36Sopenharmony_ci		/* When reading data from the CCDC, the input size has already
174862306a36Sopenharmony_ci		 * been mangled by the CCDC output pad so it can be accepted
174962306a36Sopenharmony_ci		 * as-is.
175062306a36Sopenharmony_ci		 *
175162306a36Sopenharmony_ci		 * When reading data from memory, clamp the requested width and
175262306a36Sopenharmony_ci		 * height. The TRM doesn't specify a minimum input height, make
175362306a36Sopenharmony_ci		 * sure we got enough lines to enable the noise filter and color
175462306a36Sopenharmony_ci		 * filter array interpolation.
175562306a36Sopenharmony_ci		 */
175662306a36Sopenharmony_ci		if (prev->input == PREVIEW_INPUT_MEMORY) {
175762306a36Sopenharmony_ci			fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
175862306a36Sopenharmony_ci					     preview_max_out_width(prev));
175962306a36Sopenharmony_ci			fmt->height = clamp_t(u32, fmt->height,
176062306a36Sopenharmony_ci					      PREV_MIN_IN_HEIGHT,
176162306a36Sopenharmony_ci					      PREV_MAX_IN_HEIGHT);
176262306a36Sopenharmony_ci		}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci		fmt->colorspace = V4L2_COLORSPACE_SRGB;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
176762306a36Sopenharmony_ci			if (fmt->code == preview_input_fmts[i])
176862306a36Sopenharmony_ci				break;
176962306a36Sopenharmony_ci		}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		/* If not found, use SGRBG10 as default */
177262306a36Sopenharmony_ci		if (i >= ARRAY_SIZE(preview_input_fmts))
177362306a36Sopenharmony_ci			fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
177462306a36Sopenharmony_ci		break;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	case PREV_PAD_SOURCE:
177762306a36Sopenharmony_ci		pixelcode = fmt->code;
177862306a36Sopenharmony_ci		*fmt = *__preview_get_format(prev, sd_state, PREV_PAD_SINK,
177962306a36Sopenharmony_ci					     which);
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci		switch (pixelcode) {
178262306a36Sopenharmony_ci		case MEDIA_BUS_FMT_YUYV8_1X16:
178362306a36Sopenharmony_ci		case MEDIA_BUS_FMT_UYVY8_1X16:
178462306a36Sopenharmony_ci			fmt->code = pixelcode;
178562306a36Sopenharmony_ci			break;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci		default:
178862306a36Sopenharmony_ci			fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
178962306a36Sopenharmony_ci			break;
179062306a36Sopenharmony_ci		}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci		/* The preview module output size is configurable through the
179362306a36Sopenharmony_ci		 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
179462306a36Sopenharmony_ci		 * is not supported yet, hardcode the output size to the crop
179562306a36Sopenharmony_ci		 * rectangle size.
179662306a36Sopenharmony_ci		 */
179762306a36Sopenharmony_ci		crop = __preview_get_crop(prev, sd_state, which);
179862306a36Sopenharmony_ci		fmt->width = crop->width;
179962306a36Sopenharmony_ci		fmt->height = crop->height;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci		fmt->colorspace = V4L2_COLORSPACE_JPEG;
180262306a36Sopenharmony_ci		break;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	fmt->field = V4L2_FIELD_NONE;
180662306a36Sopenharmony_ci}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci/*
180962306a36Sopenharmony_ci * preview_try_crop - Validate a crop rectangle
181062306a36Sopenharmony_ci * @prev: ISP preview engine
181162306a36Sopenharmony_ci * @sink: format on the sink pad
181262306a36Sopenharmony_ci * @crop: crop rectangle to be validated
181362306a36Sopenharmony_ci *
181462306a36Sopenharmony_ci * The preview engine crops lines and columns for its internal operation,
181562306a36Sopenharmony_ci * depending on which filters are enabled. Enforce minimum crop margins to
181662306a36Sopenharmony_ci * handle that transparently for userspace.
181762306a36Sopenharmony_ci *
181862306a36Sopenharmony_ci * See the explanation at the PREV_MARGIN_* definitions for more details.
181962306a36Sopenharmony_ci */
182062306a36Sopenharmony_cistatic void preview_try_crop(struct isp_prev_device *prev,
182162306a36Sopenharmony_ci			     const struct v4l2_mbus_framefmt *sink,
182262306a36Sopenharmony_ci			     struct v4l2_rect *crop)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	unsigned int left = PREV_MARGIN_LEFT;
182562306a36Sopenharmony_ci	unsigned int right = sink->width - PREV_MARGIN_RIGHT;
182662306a36Sopenharmony_ci	unsigned int top = PREV_MARGIN_TOP;
182762306a36Sopenharmony_ci	unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	/* When processing data on-the-fly from the CCDC, at least 2 pixels must
183062306a36Sopenharmony_ci	 * be cropped from the left and right sides of the image. As we don't
183162306a36Sopenharmony_ci	 * know which filters will be enabled, increase the left and right
183262306a36Sopenharmony_ci	 * margins by two.
183362306a36Sopenharmony_ci	 */
183462306a36Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_CCDC) {
183562306a36Sopenharmony_ci		left += 2;
183662306a36Sopenharmony_ci		right -= 2;
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	/* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines
184062306a36Sopenharmony_ci	 * and no columns in other modes. Increase the margins based on the sink
184162306a36Sopenharmony_ci	 * format.
184262306a36Sopenharmony_ci	 */
184362306a36Sopenharmony_ci	if (sink->code != MEDIA_BUS_FMT_Y8_1X8 &&
184462306a36Sopenharmony_ci	    sink->code != MEDIA_BUS_FMT_Y10_1X10) {
184562306a36Sopenharmony_ci		left += 2;
184662306a36Sopenharmony_ci		right -= 2;
184762306a36Sopenharmony_ci		top += 2;
184862306a36Sopenharmony_ci		bottom -= 2;
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* Restrict left/top to even values to keep the Bayer pattern. */
185262306a36Sopenharmony_ci	crop->left &= ~1;
185362306a36Sopenharmony_ci	crop->top &= ~1;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
185662306a36Sopenharmony_ci	crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
185762306a36Sopenharmony_ci	crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
185862306a36Sopenharmony_ci			      right - crop->left);
185962306a36Sopenharmony_ci	crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
186062306a36Sopenharmony_ci			       bottom - crop->top);
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci/*
186462306a36Sopenharmony_ci * preview_enum_mbus_code - Handle pixel format enumeration
186562306a36Sopenharmony_ci * @sd     : pointer to v4l2 subdev structure
186662306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
186762306a36Sopenharmony_ci * @code   : pointer to v4l2_subdev_mbus_code_enum structure
186862306a36Sopenharmony_ci * return -EINVAL or zero on success
186962306a36Sopenharmony_ci */
187062306a36Sopenharmony_cistatic int preview_enum_mbus_code(struct v4l2_subdev *sd,
187162306a36Sopenharmony_ci				  struct v4l2_subdev_state *sd_state,
187262306a36Sopenharmony_ci				  struct v4l2_subdev_mbus_code_enum *code)
187362306a36Sopenharmony_ci{
187462306a36Sopenharmony_ci	switch (code->pad) {
187562306a36Sopenharmony_ci	case PREV_PAD_SINK:
187662306a36Sopenharmony_ci		if (code->index >= ARRAY_SIZE(preview_input_fmts))
187762306a36Sopenharmony_ci			return -EINVAL;
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci		code->code = preview_input_fmts[code->index];
188062306a36Sopenharmony_ci		break;
188162306a36Sopenharmony_ci	case PREV_PAD_SOURCE:
188262306a36Sopenharmony_ci		if (code->index >= ARRAY_SIZE(preview_output_fmts))
188362306a36Sopenharmony_ci			return -EINVAL;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci		code->code = preview_output_fmts[code->index];
188662306a36Sopenharmony_ci		break;
188762306a36Sopenharmony_ci	default:
188862306a36Sopenharmony_ci		return -EINVAL;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	return 0;
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_cistatic int preview_enum_frame_size(struct v4l2_subdev *sd,
189562306a36Sopenharmony_ci				   struct v4l2_subdev_state *sd_state,
189662306a36Sopenharmony_ci				   struct v4l2_subdev_frame_size_enum *fse)
189762306a36Sopenharmony_ci{
189862306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
189962306a36Sopenharmony_ci	struct v4l2_mbus_framefmt format;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	if (fse->index != 0)
190262306a36Sopenharmony_ci		return -EINVAL;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	format.code = fse->code;
190562306a36Sopenharmony_ci	format.width = 1;
190662306a36Sopenharmony_ci	format.height = 1;
190762306a36Sopenharmony_ci	preview_try_format(prev, sd_state, fse->pad, &format, fse->which);
190862306a36Sopenharmony_ci	fse->min_width = format.width;
190962306a36Sopenharmony_ci	fse->min_height = format.height;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	if (format.code != fse->code)
191262306a36Sopenharmony_ci		return -EINVAL;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	format.code = fse->code;
191562306a36Sopenharmony_ci	format.width = -1;
191662306a36Sopenharmony_ci	format.height = -1;
191762306a36Sopenharmony_ci	preview_try_format(prev, sd_state, fse->pad, &format, fse->which);
191862306a36Sopenharmony_ci	fse->max_width = format.width;
191962306a36Sopenharmony_ci	fse->max_height = format.height;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	return 0;
192262306a36Sopenharmony_ci}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci/*
192562306a36Sopenharmony_ci * preview_get_selection - Retrieve a selection rectangle on a pad
192662306a36Sopenharmony_ci * @sd: ISP preview V4L2 subdevice
192762306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
192862306a36Sopenharmony_ci * @sel: Selection rectangle
192962306a36Sopenharmony_ci *
193062306a36Sopenharmony_ci * The only supported rectangles are the crop rectangles on the sink pad.
193162306a36Sopenharmony_ci *
193262306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise.
193362306a36Sopenharmony_ci */
193462306a36Sopenharmony_cistatic int preview_get_selection(struct v4l2_subdev *sd,
193562306a36Sopenharmony_ci				 struct v4l2_subdev_state *sd_state,
193662306a36Sopenharmony_ci				 struct v4l2_subdev_selection *sel)
193762306a36Sopenharmony_ci{
193862306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
193962306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (sel->pad != PREV_PAD_SINK)
194262306a36Sopenharmony_ci		return -EINVAL;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	switch (sel->target) {
194562306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
194662306a36Sopenharmony_ci		sel->r.left = 0;
194762306a36Sopenharmony_ci		sel->r.top = 0;
194862306a36Sopenharmony_ci		sel->r.width = INT_MAX;
194962306a36Sopenharmony_ci		sel->r.height = INT_MAX;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci		format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
195262306a36Sopenharmony_ci					      sel->which);
195362306a36Sopenharmony_ci		preview_try_crop(prev, format, &sel->r);
195462306a36Sopenharmony_ci		break;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP:
195762306a36Sopenharmony_ci		sel->r = *__preview_get_crop(prev, sd_state, sel->which);
195862306a36Sopenharmony_ci		break;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	default:
196162306a36Sopenharmony_ci		return -EINVAL;
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	return 0;
196562306a36Sopenharmony_ci}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci/*
196862306a36Sopenharmony_ci * preview_set_selection - Set a selection rectangle on a pad
196962306a36Sopenharmony_ci * @sd: ISP preview V4L2 subdevice
197062306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
197162306a36Sopenharmony_ci * @sel: Selection rectangle
197262306a36Sopenharmony_ci *
197362306a36Sopenharmony_ci * The only supported rectangle is the actual crop rectangle on the sink pad.
197462306a36Sopenharmony_ci *
197562306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise.
197662306a36Sopenharmony_ci */
197762306a36Sopenharmony_cistatic int preview_set_selection(struct v4l2_subdev *sd,
197862306a36Sopenharmony_ci				 struct v4l2_subdev_state *sd_state,
197962306a36Sopenharmony_ci				 struct v4l2_subdev_selection *sel)
198062306a36Sopenharmony_ci{
198162306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
198262306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	if (sel->target != V4L2_SEL_TGT_CROP ||
198562306a36Sopenharmony_ci	    sel->pad != PREV_PAD_SINK)
198662306a36Sopenharmony_ci		return -EINVAL;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	/* The crop rectangle can't be changed while streaming. */
198962306a36Sopenharmony_ci	if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
199062306a36Sopenharmony_ci		return -EBUSY;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	/* Modifying the crop rectangle always changes the format on the source
199362306a36Sopenharmony_ci	 * pad. If the KEEP_CONFIG flag is set, just return the current crop
199462306a36Sopenharmony_ci	 * rectangle.
199562306a36Sopenharmony_ci	 */
199662306a36Sopenharmony_ci	if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
199762306a36Sopenharmony_ci		sel->r = *__preview_get_crop(prev, sd_state, sel->which);
199862306a36Sopenharmony_ci		return 0;
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
200262306a36Sopenharmony_ci				      sel->which);
200362306a36Sopenharmony_ci	preview_try_crop(prev, format, &sel->r);
200462306a36Sopenharmony_ci	*__preview_get_crop(prev, sd_state, sel->which) = sel->r;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	/* Update the source format. */
200762306a36Sopenharmony_ci	format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
200862306a36Sopenharmony_ci				      sel->which);
200962306a36Sopenharmony_ci	preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
201062306a36Sopenharmony_ci			   sel->which);
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	return 0;
201362306a36Sopenharmony_ci}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci/*
201662306a36Sopenharmony_ci * preview_get_format - Handle get format by pads subdev method
201762306a36Sopenharmony_ci * @sd : pointer to v4l2 subdev structure
201862306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
201962306a36Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure
202062306a36Sopenharmony_ci * return -EINVAL or zero on success
202162306a36Sopenharmony_ci */
202262306a36Sopenharmony_cistatic int preview_get_format(struct v4l2_subdev *sd,
202362306a36Sopenharmony_ci			      struct v4l2_subdev_state *sd_state,
202462306a36Sopenharmony_ci			      struct v4l2_subdev_format *fmt)
202562306a36Sopenharmony_ci{
202662306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
202762306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which);
203062306a36Sopenharmony_ci	if (format == NULL)
203162306a36Sopenharmony_ci		return -EINVAL;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	fmt->format = *format;
203462306a36Sopenharmony_ci	return 0;
203562306a36Sopenharmony_ci}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci/*
203862306a36Sopenharmony_ci * preview_set_format - Handle set format by pads subdev method
203962306a36Sopenharmony_ci * @sd : pointer to v4l2 subdev structure
204062306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
204162306a36Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure
204262306a36Sopenharmony_ci * return -EINVAL or zero on success
204362306a36Sopenharmony_ci */
204462306a36Sopenharmony_cistatic int preview_set_format(struct v4l2_subdev *sd,
204562306a36Sopenharmony_ci			      struct v4l2_subdev_state *sd_state,
204662306a36Sopenharmony_ci			      struct v4l2_subdev_format *fmt)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
204962306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
205062306a36Sopenharmony_ci	struct v4l2_rect *crop;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which);
205362306a36Sopenharmony_ci	if (format == NULL)
205462306a36Sopenharmony_ci		return -EINVAL;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	preview_try_format(prev, sd_state, fmt->pad, &fmt->format, fmt->which);
205762306a36Sopenharmony_ci	*format = fmt->format;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	/* Propagate the format from sink to source */
206062306a36Sopenharmony_ci	if (fmt->pad == PREV_PAD_SINK) {
206162306a36Sopenharmony_ci		/* Reset the crop rectangle. */
206262306a36Sopenharmony_ci		crop = __preview_get_crop(prev, sd_state, fmt->which);
206362306a36Sopenharmony_ci		crop->left = 0;
206462306a36Sopenharmony_ci		crop->top = 0;
206562306a36Sopenharmony_ci		crop->width = fmt->format.width;
206662306a36Sopenharmony_ci		crop->height = fmt->format.height;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci		preview_try_crop(prev, &fmt->format, crop);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci		/* Update the source format. */
207162306a36Sopenharmony_ci		format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
207262306a36Sopenharmony_ci					      fmt->which);
207362306a36Sopenharmony_ci		preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
207462306a36Sopenharmony_ci				   fmt->which);
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	return 0;
207862306a36Sopenharmony_ci}
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci/*
208162306a36Sopenharmony_ci * preview_init_formats - Initialize formats on all pads
208262306a36Sopenharmony_ci * @sd: ISP preview V4L2 subdevice
208362306a36Sopenharmony_ci * @fh: V4L2 subdev file handle
208462306a36Sopenharmony_ci *
208562306a36Sopenharmony_ci * Initialize all pad formats with default values. If fh is not NULL, try
208662306a36Sopenharmony_ci * formats are initialized on the file handle. Otherwise active formats are
208762306a36Sopenharmony_ci * initialized on the device.
208862306a36Sopenharmony_ci */
208962306a36Sopenharmony_cistatic int preview_init_formats(struct v4l2_subdev *sd,
209062306a36Sopenharmony_ci				struct v4l2_subdev_fh *fh)
209162306a36Sopenharmony_ci{
209262306a36Sopenharmony_ci	struct v4l2_subdev_format format;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	memset(&format, 0, sizeof(format));
209562306a36Sopenharmony_ci	format.pad = PREV_PAD_SINK;
209662306a36Sopenharmony_ci	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
209762306a36Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
209862306a36Sopenharmony_ci	format.format.width = 4096;
209962306a36Sopenharmony_ci	format.format.height = 4096;
210062306a36Sopenharmony_ci	preview_set_format(sd, fh ? fh->state : NULL, &format);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	return 0;
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci/* subdev core operations */
210662306a36Sopenharmony_cistatic const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
210762306a36Sopenharmony_ci	.ioctl = preview_ioctl,
210862306a36Sopenharmony_ci};
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci/* subdev video operations */
211162306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
211262306a36Sopenharmony_ci	.s_stream = preview_set_stream,
211362306a36Sopenharmony_ci};
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci/* subdev pad operations */
211662306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
211762306a36Sopenharmony_ci	.enum_mbus_code = preview_enum_mbus_code,
211862306a36Sopenharmony_ci	.enum_frame_size = preview_enum_frame_size,
211962306a36Sopenharmony_ci	.get_fmt = preview_get_format,
212062306a36Sopenharmony_ci	.set_fmt = preview_set_format,
212162306a36Sopenharmony_ci	.get_selection = preview_get_selection,
212262306a36Sopenharmony_ci	.set_selection = preview_set_selection,
212362306a36Sopenharmony_ci};
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci/* subdev operations */
212662306a36Sopenharmony_cistatic const struct v4l2_subdev_ops preview_v4l2_ops = {
212762306a36Sopenharmony_ci	.core = &preview_v4l2_core_ops,
212862306a36Sopenharmony_ci	.video = &preview_v4l2_video_ops,
212962306a36Sopenharmony_ci	.pad = &preview_v4l2_pad_ops,
213062306a36Sopenharmony_ci};
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci/* subdev internal operations */
213362306a36Sopenharmony_cistatic const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
213462306a36Sopenharmony_ci	.open = preview_init_formats,
213562306a36Sopenharmony_ci};
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
213862306a36Sopenharmony_ci * Media entity operations
213962306a36Sopenharmony_ci */
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci/*
214262306a36Sopenharmony_ci * preview_link_setup - Setup previewer connections.
214362306a36Sopenharmony_ci * @entity : Pointer to media entity structure
214462306a36Sopenharmony_ci * @local  : Pointer to local pad array
214562306a36Sopenharmony_ci * @remote : Pointer to remote pad array
214662306a36Sopenharmony_ci * @flags  : Link flags
214762306a36Sopenharmony_ci * return -EINVAL or zero on success
214862306a36Sopenharmony_ci */
214962306a36Sopenharmony_cistatic int preview_link_setup(struct media_entity *entity,
215062306a36Sopenharmony_ci			      const struct media_pad *local,
215162306a36Sopenharmony_ci			      const struct media_pad *remote, u32 flags)
215262306a36Sopenharmony_ci{
215362306a36Sopenharmony_ci	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
215462306a36Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
215562306a36Sopenharmony_ci	unsigned int index = local->index;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	/* FIXME: this is actually a hack! */
215862306a36Sopenharmony_ci	if (is_media_entity_v4l2_subdev(remote->entity))
215962306a36Sopenharmony_ci		index |= 2 << 16;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	switch (index) {
216262306a36Sopenharmony_ci	case PREV_PAD_SINK:
216362306a36Sopenharmony_ci		/* read from memory */
216462306a36Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
216562306a36Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_CCDC)
216662306a36Sopenharmony_ci				return -EBUSY;
216762306a36Sopenharmony_ci			prev->input = PREVIEW_INPUT_MEMORY;
216862306a36Sopenharmony_ci		} else {
216962306a36Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_MEMORY)
217062306a36Sopenharmony_ci				prev->input = PREVIEW_INPUT_NONE;
217162306a36Sopenharmony_ci		}
217262306a36Sopenharmony_ci		break;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	case PREV_PAD_SINK | 2 << 16:
217562306a36Sopenharmony_ci		/* read from ccdc */
217662306a36Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
217762306a36Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_MEMORY)
217862306a36Sopenharmony_ci				return -EBUSY;
217962306a36Sopenharmony_ci			prev->input = PREVIEW_INPUT_CCDC;
218062306a36Sopenharmony_ci		} else {
218162306a36Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_CCDC)
218262306a36Sopenharmony_ci				prev->input = PREVIEW_INPUT_NONE;
218362306a36Sopenharmony_ci		}
218462306a36Sopenharmony_ci		break;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	/*
218762306a36Sopenharmony_ci	 * The ISP core doesn't support pipelines with multiple video outputs.
218862306a36Sopenharmony_ci	 * Revisit this when it will be implemented, and return -EBUSY for now.
218962306a36Sopenharmony_ci	 */
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	case PREV_PAD_SOURCE:
219262306a36Sopenharmony_ci		/* write to memory */
219362306a36Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
219462306a36Sopenharmony_ci			if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
219562306a36Sopenharmony_ci				return -EBUSY;
219662306a36Sopenharmony_ci			prev->output |= PREVIEW_OUTPUT_MEMORY;
219762306a36Sopenharmony_ci		} else {
219862306a36Sopenharmony_ci			prev->output &= ~PREVIEW_OUTPUT_MEMORY;
219962306a36Sopenharmony_ci		}
220062306a36Sopenharmony_ci		break;
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	case PREV_PAD_SOURCE | 2 << 16:
220362306a36Sopenharmony_ci		/* write to resizer */
220462306a36Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
220562306a36Sopenharmony_ci			if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
220662306a36Sopenharmony_ci				return -EBUSY;
220762306a36Sopenharmony_ci			prev->output |= PREVIEW_OUTPUT_RESIZER;
220862306a36Sopenharmony_ci		} else {
220962306a36Sopenharmony_ci			prev->output &= ~PREVIEW_OUTPUT_RESIZER;
221062306a36Sopenharmony_ci		}
221162306a36Sopenharmony_ci		break;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	default:
221462306a36Sopenharmony_ci		return -EINVAL;
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	return 0;
221862306a36Sopenharmony_ci}
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci/* media operations */
222162306a36Sopenharmony_cistatic const struct media_entity_operations preview_media_ops = {
222262306a36Sopenharmony_ci	.link_setup = preview_link_setup,
222362306a36Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
222462306a36Sopenharmony_ci};
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_civoid omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
222762306a36Sopenharmony_ci{
222862306a36Sopenharmony_ci	v4l2_device_unregister_subdev(&prev->subdev);
222962306a36Sopenharmony_ci	omap3isp_video_unregister(&prev->video_in);
223062306a36Sopenharmony_ci	omap3isp_video_unregister(&prev->video_out);
223162306a36Sopenharmony_ci}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ciint omap3isp_preview_register_entities(struct isp_prev_device *prev,
223462306a36Sopenharmony_ci	struct v4l2_device *vdev)
223562306a36Sopenharmony_ci{
223662306a36Sopenharmony_ci	int ret;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	/* Register the subdev and video nodes. */
223962306a36Sopenharmony_ci	prev->subdev.dev = vdev->mdev->dev;
224062306a36Sopenharmony_ci	ret = v4l2_device_register_subdev(vdev, &prev->subdev);
224162306a36Sopenharmony_ci	if (ret < 0)
224262306a36Sopenharmony_ci		goto error;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	ret = omap3isp_video_register(&prev->video_in, vdev);
224562306a36Sopenharmony_ci	if (ret < 0)
224662306a36Sopenharmony_ci		goto error;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	ret = omap3isp_video_register(&prev->video_out, vdev);
224962306a36Sopenharmony_ci	if (ret < 0)
225062306a36Sopenharmony_ci		goto error;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	return 0;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_cierror:
225562306a36Sopenharmony_ci	omap3isp_preview_unregister_entities(prev);
225662306a36Sopenharmony_ci	return ret;
225762306a36Sopenharmony_ci}
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
226062306a36Sopenharmony_ci * ISP previewer initialisation and cleanup
226162306a36Sopenharmony_ci */
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci/*
226462306a36Sopenharmony_ci * preview_init_entities - Initialize subdev and media entity.
226562306a36Sopenharmony_ci * @prev : Pointer to preview structure
226662306a36Sopenharmony_ci * return -ENOMEM or zero on success
226762306a36Sopenharmony_ci */
226862306a36Sopenharmony_cistatic int preview_init_entities(struct isp_prev_device *prev)
226962306a36Sopenharmony_ci{
227062306a36Sopenharmony_ci	struct v4l2_subdev *sd = &prev->subdev;
227162306a36Sopenharmony_ci	struct media_pad *pads = prev->pads;
227262306a36Sopenharmony_ci	struct media_entity *me = &sd->entity;
227362306a36Sopenharmony_ci	int ret;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	prev->input = PREVIEW_INPUT_NONE;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	v4l2_subdev_init(sd, &preview_v4l2_ops);
227862306a36Sopenharmony_ci	sd->internal_ops = &preview_v4l2_internal_ops;
227962306a36Sopenharmony_ci	strscpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
228062306a36Sopenharmony_ci	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
228162306a36Sopenharmony_ci	v4l2_set_subdevdata(sd, prev);
228262306a36Sopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	v4l2_ctrl_handler_init(&prev->ctrls, 2);
228562306a36Sopenharmony_ci	v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
228662306a36Sopenharmony_ci			  ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
228762306a36Sopenharmony_ci			  ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
228862306a36Sopenharmony_ci	v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
228962306a36Sopenharmony_ci			  ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
229062306a36Sopenharmony_ci			  ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
229162306a36Sopenharmony_ci	v4l2_ctrl_handler_setup(&prev->ctrls);
229262306a36Sopenharmony_ci	sd->ctrl_handler = &prev->ctrls;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK
229562306a36Sopenharmony_ci				    | MEDIA_PAD_FL_MUST_CONNECT;
229662306a36Sopenharmony_ci	pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	me->ops = &preview_media_ops;
229962306a36Sopenharmony_ci	ret = media_entity_pads_init(me, PREV_PADS_NUM, pads);
230062306a36Sopenharmony_ci	if (ret < 0)
230162306a36Sopenharmony_ci		goto error_handler_free;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	preview_init_formats(sd, NULL);
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	/* According to the OMAP34xx TRM, video buffers need to be aligned on a
230662306a36Sopenharmony_ci	 * 32 bytes boundary. However, an undocumented hardware bug requires a
230762306a36Sopenharmony_ci	 * 64 bytes boundary at the preview engine input.
230862306a36Sopenharmony_ci	 */
230962306a36Sopenharmony_ci	prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
231062306a36Sopenharmony_ci	prev->video_in.ops = &preview_video_ops;
231162306a36Sopenharmony_ci	prev->video_in.isp = to_isp_device(prev);
231262306a36Sopenharmony_ci	prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
231362306a36Sopenharmony_ci	prev->video_in.bpl_alignment = 64;
231462306a36Sopenharmony_ci	prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
231562306a36Sopenharmony_ci	prev->video_out.ops = &preview_video_ops;
231662306a36Sopenharmony_ci	prev->video_out.isp = to_isp_device(prev);
231762306a36Sopenharmony_ci	prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
231862306a36Sopenharmony_ci	prev->video_out.bpl_alignment = 32;
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	ret = omap3isp_video_init(&prev->video_in, "preview");
232162306a36Sopenharmony_ci	if (ret < 0)
232262306a36Sopenharmony_ci		goto error_video_in;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	ret = omap3isp_video_init(&prev->video_out, "preview");
232562306a36Sopenharmony_ci	if (ret < 0)
232662306a36Sopenharmony_ci		goto error_video_out;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	return 0;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_cierror_video_out:
233162306a36Sopenharmony_ci	omap3isp_video_cleanup(&prev->video_in);
233262306a36Sopenharmony_cierror_video_in:
233362306a36Sopenharmony_ci	media_entity_cleanup(&prev->subdev.entity);
233462306a36Sopenharmony_cierror_handler_free:
233562306a36Sopenharmony_ci	v4l2_ctrl_handler_free(&prev->ctrls);
233662306a36Sopenharmony_ci	return ret;
233762306a36Sopenharmony_ci}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci/*
234062306a36Sopenharmony_ci * omap3isp_preview_init - Previewer initialization.
234162306a36Sopenharmony_ci * @isp : Pointer to ISP device
234262306a36Sopenharmony_ci * return -ENOMEM or zero on success
234362306a36Sopenharmony_ci */
234462306a36Sopenharmony_ciint omap3isp_preview_init(struct isp_device *isp)
234562306a36Sopenharmony_ci{
234662306a36Sopenharmony_ci	struct isp_prev_device *prev = &isp->isp_prev;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	init_waitqueue_head(&prev->wait);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	preview_init_params(prev);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	return preview_init_entities(prev);
235362306a36Sopenharmony_ci}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_civoid omap3isp_preview_cleanup(struct isp_device *isp)
235662306a36Sopenharmony_ci{
235762306a36Sopenharmony_ci	struct isp_prev_device *prev = &isp->isp_prev;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	v4l2_ctrl_handler_free(&prev->ctrls);
236062306a36Sopenharmony_ci	omap3isp_video_cleanup(&prev->video_in);
236162306a36Sopenharmony_ci	omap3isp_video_cleanup(&prev->video_out);
236262306a36Sopenharmony_ci	media_entity_cleanup(&prev->subdev.entity);
236362306a36Sopenharmony_ci}
2364