18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * isppreview.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * TI OMAP3 ISP driver - Preview module
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Nokia Corporation
88c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments, Inc.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
118c2ecf20Sopenharmony_ci *	     Sakari Ailus <sakari.ailus@iki.fi>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/mm.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/mutex.h>
188c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "isp.h"
218c2ecf20Sopenharmony_ci#include "ispreg.h"
228c2ecf20Sopenharmony_ci#include "isppreview.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
258c2ecf20Sopenharmony_cistatic const struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
268c2ecf20Sopenharmony_ci	{	/* RGB-RGB Matrix */
278c2ecf20Sopenharmony_ci		{0x01E2, 0x0F30, 0x0FEE},
288c2ecf20Sopenharmony_ci		{0x0F9B, 0x01AC, 0x0FB9},
298c2ecf20Sopenharmony_ci		{0x0FE0, 0x0EC0, 0x0260}
308c2ecf20Sopenharmony_ci	},	/* RGB Offset */
318c2ecf20Sopenharmony_ci	{0x0000, 0x0000, 0x0000}
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
358c2ecf20Sopenharmony_cistatic const struct omap3isp_prev_csc flr_prev_csc = {
368c2ecf20Sopenharmony_ci	{	/* CSC Coef Matrix */
378c2ecf20Sopenharmony_ci		{66, 129, 25},
388c2ecf20Sopenharmony_ci		{-38, -75, 112},
398c2ecf20Sopenharmony_ci		{112, -94 , -18}
408c2ecf20Sopenharmony_ci	},	/* CSC Offset */
418c2ecf20Sopenharmony_ci	{0x0, 0x0, 0x0}
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Default values in Office Fluorescent Light for CFA Gradient*/
458c2ecf20Sopenharmony_ci#define FLR_CFA_GRADTHRS_HORZ	0x28
468c2ecf20Sopenharmony_ci#define FLR_CFA_GRADTHRS_VERT	0x28
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* Default values in Office Fluorescent Light for Chroma Suppression*/
498c2ecf20Sopenharmony_ci#define FLR_CSUP_GAIN		0x0D
508c2ecf20Sopenharmony_ci#define FLR_CSUP_THRES		0xEB
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* Default values in Office Fluorescent Light for Noise Filter*/
538c2ecf20Sopenharmony_ci#define FLR_NF_STRGTH		0x03
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Default values for White Balance */
568c2ecf20Sopenharmony_ci#define FLR_WBAL_DGAIN		0x100
578c2ecf20Sopenharmony_ci#define FLR_WBAL_COEF		0x20
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/* Default values in Office Fluorescent Light for Black Adjustment*/
608c2ecf20Sopenharmony_ci#define FLR_BLKADJ_BLUE		0x0
618c2ecf20Sopenharmony_ci#define FLR_BLKADJ_GREEN	0x0
628c2ecf20Sopenharmony_ci#define FLR_BLKADJ_RED		0x0
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define DEF_DETECT_CORRECT_VAL	0xe
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/*
678c2ecf20Sopenharmony_ci * Margins and image size limits.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * The preview engine crops several rows and columns internally depending on
708c2ecf20Sopenharmony_ci * which filters are enabled. To avoid format changes when the filters are
718c2ecf20Sopenharmony_ci * enabled or disabled (which would prevent them from being turned on or off
728c2ecf20Sopenharmony_ci * during streaming), the driver assumes all filters that can be configured
738c2ecf20Sopenharmony_ci * during streaming are enabled when computing sink crop and source format
748c2ecf20Sopenharmony_ci * limits.
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci * If a filter is disabled, additional cropping is automatically added at the
778c2ecf20Sopenharmony_ci * preview engine input by the driver to avoid overflow at line and frame end.
788c2ecf20Sopenharmony_ci * This is completely transparent for applications.
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * Median filter		4 pixels
818c2ecf20Sopenharmony_ci * Noise filter,
828c2ecf20Sopenharmony_ci * Faulty pixels correction	4 pixels, 4 lines
838c2ecf20Sopenharmony_ci * Color suppression		2 pixels
848c2ecf20Sopenharmony_ci * or luma enhancement
858c2ecf20Sopenharmony_ci * -------------------------------------------------------------
868c2ecf20Sopenharmony_ci * Maximum total		10 pixels, 4 lines
878c2ecf20Sopenharmony_ci *
888c2ecf20Sopenharmony_ci * The color suppression and luma enhancement filters are applied after bayer to
898c2ecf20Sopenharmony_ci * YUV conversion. They thus can crop one pixel on the left and one pixel on the
908c2ecf20Sopenharmony_ci * right side of the image without changing the color pattern. When both those
918c2ecf20Sopenharmony_ci * filters are disabled, the driver must crop the two pixels on the same side of
928c2ecf20Sopenharmony_ci * the image to avoid changing the bayer pattern. The left margin is thus set to
938c2ecf20Sopenharmony_ci * 6 pixels and the right margin to 4 pixels.
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define PREV_MARGIN_LEFT	6
978c2ecf20Sopenharmony_ci#define PREV_MARGIN_RIGHT	4
988c2ecf20Sopenharmony_ci#define PREV_MARGIN_TOP		2
998c2ecf20Sopenharmony_ci#define PREV_MARGIN_BOTTOM	2
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define PREV_MIN_IN_WIDTH	64
1028c2ecf20Sopenharmony_ci#define PREV_MIN_IN_HEIGHT	8
1038c2ecf20Sopenharmony_ci#define PREV_MAX_IN_HEIGHT	16384
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define PREV_MIN_OUT_WIDTH		0
1068c2ecf20Sopenharmony_ci#define PREV_MIN_OUT_HEIGHT		0
1078c2ecf20Sopenharmony_ci#define PREV_MAX_OUT_WIDTH_REV_1	1280
1088c2ecf20Sopenharmony_ci#define PREV_MAX_OUT_WIDTH_REV_2	3300
1098c2ecf20Sopenharmony_ci#define PREV_MAX_OUT_WIDTH_REV_15	4096
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/*
1128c2ecf20Sopenharmony_ci * Coefficient Tables for the submodules in Preview.
1138c2ecf20Sopenharmony_ci * Array is initialised with the values from.the tables text file.
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/*
1178c2ecf20Sopenharmony_ci * CFA Filter Coefficient Table
1188c2ecf20Sopenharmony_ci *
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistatic u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = {
1218c2ecf20Sopenharmony_ci#include "cfa_coef_table.h"
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/*
1258c2ecf20Sopenharmony_ci * Default Gamma Correction Table - All components
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_cistatic u32 gamma_table[] = {
1288c2ecf20Sopenharmony_ci#include "gamma_table.h"
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/*
1328c2ecf20Sopenharmony_ci * Noise Filter Threshold table
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cistatic u32 noise_filter_table[] = {
1358c2ecf20Sopenharmony_ci#include "noise_filter_table.h"
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/*
1398c2ecf20Sopenharmony_ci * Luminance Enhancement Table
1408c2ecf20Sopenharmony_ci */
1418c2ecf20Sopenharmony_cistatic u32 luma_enhance_table[] = {
1428c2ecf20Sopenharmony_ci#include "luma_enhance_table.h"
1438c2ecf20Sopenharmony_ci};
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/*
1468c2ecf20Sopenharmony_ci * preview_config_luma_enhancement - Configure the Luminance Enhancement table
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_cistatic void
1498c2ecf20Sopenharmony_cipreview_config_luma_enhancement(struct isp_prev_device *prev,
1508c2ecf20Sopenharmony_ci				const struct prev_params *params)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
1538c2ecf20Sopenharmony_ci	const struct omap3isp_prev_luma *yt = &params->luma;
1548c2ecf20Sopenharmony_ci	unsigned int i;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
1578c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
1588c2ecf20Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
1598c2ecf20Sopenharmony_ci		isp_reg_writel(isp, yt->table[i],
1608c2ecf20Sopenharmony_ci			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/*
1658c2ecf20Sopenharmony_ci * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistatic void
1688c2ecf20Sopenharmony_cipreview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (enable)
1738c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1748c2ecf20Sopenharmony_ci			    ISPPRV_PCR_YNENHEN);
1758c2ecf20Sopenharmony_ci	else
1768c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1778c2ecf20Sopenharmony_ci			    ISPPRV_PCR_YNENHEN);
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/*
1818c2ecf20Sopenharmony_ci * preview_enable_invalaw - Enable/disable Inverse A-Law decompression
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_cistatic void preview_enable_invalaw(struct isp_prev_device *prev, bool enable)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (enable)
1888c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1898c2ecf20Sopenharmony_ci			    ISPPRV_PCR_INVALAW);
1908c2ecf20Sopenharmony_ci	else
1918c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1928c2ecf20Sopenharmony_ci			    ISPPRV_PCR_INVALAW);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/*
1968c2ecf20Sopenharmony_ci * preview_config_hmed - Configure the Horizontal Median Filter
1978c2ecf20Sopenharmony_ci */
1988c2ecf20Sopenharmony_cistatic void preview_config_hmed(struct isp_prev_device *prev,
1998c2ecf20Sopenharmony_ci				const struct prev_params *params)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
2028c2ecf20Sopenharmony_ci	const struct omap3isp_prev_hmed *hmed = &params->hmed;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
2058c2ecf20Sopenharmony_ci		       (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
2068c2ecf20Sopenharmony_ci		       (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
2078c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci * preview_enable_hmed - Enable/disable the Horizontal Median Filter
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic void preview_enable_hmed(struct isp_prev_device *prev, bool enable)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (enable)
2188c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
2198c2ecf20Sopenharmony_ci			    ISPPRV_PCR_HMEDEN);
2208c2ecf20Sopenharmony_ci	else
2218c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
2228c2ecf20Sopenharmony_ci			    ISPPRV_PCR_HMEDEN);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/*
2268c2ecf20Sopenharmony_ci * preview_config_cfa - Configure CFA Interpolation for Bayer formats
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * The CFA table is organised in four blocks, one per Bayer component. The
2298c2ecf20Sopenharmony_ci * hardware expects blocks to follow the Bayer order of the input data, while
2308c2ecf20Sopenharmony_ci * the driver stores the table in GRBG order in memory. The blocks need to be
2318c2ecf20Sopenharmony_ci * reordered to support non-GRBG Bayer patterns.
2328c2ecf20Sopenharmony_ci */
2338c2ecf20Sopenharmony_cistatic void preview_config_cfa(struct isp_prev_device *prev,
2348c2ecf20Sopenharmony_ci			       const struct prev_params *params)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	static const unsigned int cfa_coef_order[4][4] = {
2378c2ecf20Sopenharmony_ci		{ 0, 1, 2, 3 }, /* GRBG */
2388c2ecf20Sopenharmony_ci		{ 1, 0, 3, 2 }, /* RGGB */
2398c2ecf20Sopenharmony_ci		{ 2, 3, 0, 1 }, /* BGGR */
2408c2ecf20Sopenharmony_ci		{ 3, 2, 1, 0 }, /* GBRG */
2418c2ecf20Sopenharmony_ci	};
2428c2ecf20Sopenharmony_ci	const unsigned int *order = cfa_coef_order[prev->params.cfa_order];
2438c2ecf20Sopenharmony_ci	const struct omap3isp_prev_cfa *cfa = &params->cfa;
2448c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
2458c2ecf20Sopenharmony_ci	unsigned int i;
2468c2ecf20Sopenharmony_ci	unsigned int j;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	isp_reg_writel(isp,
2498c2ecf20Sopenharmony_ci		(cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
2508c2ecf20Sopenharmony_ci		(cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
2518c2ecf20Sopenharmony_ci		OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
2548c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	for (i = 0; i < 4; ++i) {
2578c2ecf20Sopenharmony_ci		const __u32 *block = cfa->table[order[i]];
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j)
2608c2ecf20Sopenharmony_ci			isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV,
2618c2ecf20Sopenharmony_ci				       ISPPRV_SET_TBL_DATA);
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/*
2668c2ecf20Sopenharmony_ci * preview_config_chroma_suppression - Configure Chroma Suppression
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistatic void
2698c2ecf20Sopenharmony_cipreview_config_chroma_suppression(struct isp_prev_device *prev,
2708c2ecf20Sopenharmony_ci				  const struct prev_params *params)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
2738c2ecf20Sopenharmony_ci	const struct omap3isp_prev_csup *cs = &params->csup;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	isp_reg_writel(isp,
2768c2ecf20Sopenharmony_ci		       cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
2778c2ecf20Sopenharmony_ci		       (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
2788c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/*
2828c2ecf20Sopenharmony_ci * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_cistatic void
2858c2ecf20Sopenharmony_cipreview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (enable)
2908c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
2918c2ecf20Sopenharmony_ci			    ISPPRV_PCR_SUPEN);
2928c2ecf20Sopenharmony_ci	else
2938c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
2948c2ecf20Sopenharmony_ci			    ISPPRV_PCR_SUPEN);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/*
2988c2ecf20Sopenharmony_ci * preview_config_whitebalance - Configure White Balance parameters
2998c2ecf20Sopenharmony_ci *
3008c2ecf20Sopenharmony_ci * Coefficient matrix always with default values.
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_cistatic void
3038c2ecf20Sopenharmony_cipreview_config_whitebalance(struct isp_prev_device *prev,
3048c2ecf20Sopenharmony_ci			    const struct prev_params *params)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
3078c2ecf20Sopenharmony_ci	const struct omap3isp_prev_wbal *wbal = &params->wbal;
3088c2ecf20Sopenharmony_ci	u32 val;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
3138c2ecf20Sopenharmony_ci	val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
3148c2ecf20Sopenharmony_ci	val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
3158c2ecf20Sopenharmony_ci	val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
3168c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	isp_reg_writel(isp,
3198c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
3208c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
3218c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
3228c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
3238c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
3248c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
3258c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
3268c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
3278c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
3288c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
3298c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
3308c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
3318c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
3328c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
3338c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
3348c2ecf20Sopenharmony_ci		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
3358c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci/*
3398c2ecf20Sopenharmony_ci * preview_config_blkadj - Configure Black Adjustment
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_cistatic void
3428c2ecf20Sopenharmony_cipreview_config_blkadj(struct isp_prev_device *prev,
3438c2ecf20Sopenharmony_ci		      const struct prev_params *params)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
3468c2ecf20Sopenharmony_ci	const struct omap3isp_prev_blkadj *blkadj = &params->blkadj;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
3498c2ecf20Sopenharmony_ci		       (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
3508c2ecf20Sopenharmony_ci		       (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
3518c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci/*
3558c2ecf20Sopenharmony_ci * preview_config_rgb_blending - Configure RGB-RGB Blending
3568c2ecf20Sopenharmony_ci */
3578c2ecf20Sopenharmony_cistatic void
3588c2ecf20Sopenharmony_cipreview_config_rgb_blending(struct isp_prev_device *prev,
3598c2ecf20Sopenharmony_ci			    const struct prev_params *params)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
3628c2ecf20Sopenharmony_ci	const struct omap3isp_prev_rgbtorgb *rgbrgb = &params->rgb2rgb;
3638c2ecf20Sopenharmony_ci	u32 val;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
3668c2ecf20Sopenharmony_ci	val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
3678c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
3708c2ecf20Sopenharmony_ci	val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
3718c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
3748c2ecf20Sopenharmony_ci	val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
3758c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
3788c2ecf20Sopenharmony_ci	val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
3798c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
3828c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
3858c2ecf20Sopenharmony_ci	val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
3868c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
3898c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/*
3938c2ecf20Sopenharmony_ci * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr)
3948c2ecf20Sopenharmony_ci */
3958c2ecf20Sopenharmony_cistatic void
3968c2ecf20Sopenharmony_cipreview_config_csc(struct isp_prev_device *prev,
3978c2ecf20Sopenharmony_ci		   const struct prev_params *params)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
4008c2ecf20Sopenharmony_ci	const struct omap3isp_prev_csc *csc = &params->csc;
4018c2ecf20Sopenharmony_ci	u32 val;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
4048c2ecf20Sopenharmony_ci	val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
4058c2ecf20Sopenharmony_ci	val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
4068c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
4098c2ecf20Sopenharmony_ci	val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
4108c2ecf20Sopenharmony_ci	val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
4118c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
4148c2ecf20Sopenharmony_ci	val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
4158c2ecf20Sopenharmony_ci	val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
4168c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
4198c2ecf20Sopenharmony_ci	val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
4208c2ecf20Sopenharmony_ci	val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
4218c2ecf20Sopenharmony_ci	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/*
4258c2ecf20Sopenharmony_ci * preview_config_yc_range - Configure the max and min Y and C values
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic void
4288c2ecf20Sopenharmony_cipreview_config_yc_range(struct isp_prev_device *prev,
4298c2ecf20Sopenharmony_ci			const struct prev_params *params)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
4328c2ecf20Sopenharmony_ci	const struct omap3isp_prev_yclimit *yc = &params->yclimit;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	isp_reg_writel(isp,
4358c2ecf20Sopenharmony_ci		       yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
4368c2ecf20Sopenharmony_ci		       yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
4378c2ecf20Sopenharmony_ci		       yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
4388c2ecf20Sopenharmony_ci		       yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
4398c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/*
4438c2ecf20Sopenharmony_ci * preview_config_dcor - Configure Couplet Defect Correction
4448c2ecf20Sopenharmony_ci */
4458c2ecf20Sopenharmony_cistatic void
4468c2ecf20Sopenharmony_cipreview_config_dcor(struct isp_prev_device *prev,
4478c2ecf20Sopenharmony_ci		    const struct prev_params *params)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
4508c2ecf20Sopenharmony_ci	const struct omap3isp_prev_dcor *dcor = &params->dcor;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[0],
4538c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
4548c2ecf20Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[1],
4558c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
4568c2ecf20Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[2],
4578c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
4588c2ecf20Sopenharmony_ci	isp_reg_writel(isp, dcor->detect_correct[3],
4598c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
4608c2ecf20Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
4618c2ecf20Sopenharmony_ci			ISPPRV_PCR_DCCOUP,
4628c2ecf20Sopenharmony_ci			dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/*
4668c2ecf20Sopenharmony_ci * preview_enable_dcor - Enable/disable Couplet Defect Correction
4678c2ecf20Sopenharmony_ci */
4688c2ecf20Sopenharmony_cistatic void preview_enable_dcor(struct isp_prev_device *prev, bool enable)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (enable)
4738c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
4748c2ecf20Sopenharmony_ci			    ISPPRV_PCR_DCOREN);
4758c2ecf20Sopenharmony_ci	else
4768c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
4778c2ecf20Sopenharmony_ci			    ISPPRV_PCR_DCOREN);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci/*
4818c2ecf20Sopenharmony_ci * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture
4828c2ecf20Sopenharmony_ci */
4838c2ecf20Sopenharmony_cistatic void
4848c2ecf20Sopenharmony_cipreview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (enable)
4898c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
4908c2ecf20Sopenharmony_ci			    ISPPRV_PCR_DRKFCAP);
4918c2ecf20Sopenharmony_ci	else
4928c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
4938c2ecf20Sopenharmony_ci			    ISPPRV_PCR_DRKFCAP);
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci/*
4978c2ecf20Sopenharmony_ci * preview_enable_drkframe - Enable/disable Dark Frame Subtraction
4988c2ecf20Sopenharmony_ci */
4998c2ecf20Sopenharmony_cistatic void preview_enable_drkframe(struct isp_prev_device *prev, bool enable)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (enable)
5048c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
5058c2ecf20Sopenharmony_ci			    ISPPRV_PCR_DRKFEN);
5068c2ecf20Sopenharmony_ci	else
5078c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
5088c2ecf20Sopenharmony_ci			    ISPPRV_PCR_DRKFEN);
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci/*
5128c2ecf20Sopenharmony_ci * preview_config_noisefilter - Configure the Noise Filter
5138c2ecf20Sopenharmony_ci */
5148c2ecf20Sopenharmony_cistatic void
5158c2ecf20Sopenharmony_cipreview_config_noisefilter(struct isp_prev_device *prev,
5168c2ecf20Sopenharmony_ci			   const struct prev_params *params)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
5198c2ecf20Sopenharmony_ci	const struct omap3isp_prev_nf *nf = &params->nf;
5208c2ecf20Sopenharmony_ci	unsigned int i;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
5238c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
5248c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
5258c2ecf20Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
5268c2ecf20Sopenharmony_ci		isp_reg_writel(isp, nf->table[i],
5278c2ecf20Sopenharmony_ci			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci/*
5328c2ecf20Sopenharmony_ci * preview_enable_noisefilter - Enable/disable the Noise Filter
5338c2ecf20Sopenharmony_ci */
5348c2ecf20Sopenharmony_cistatic void
5358c2ecf20Sopenharmony_cipreview_enable_noisefilter(struct isp_prev_device *prev, bool enable)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (enable)
5408c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
5418c2ecf20Sopenharmony_ci			    ISPPRV_PCR_NFEN);
5428c2ecf20Sopenharmony_ci	else
5438c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
5448c2ecf20Sopenharmony_ci			    ISPPRV_PCR_NFEN);
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/*
5488c2ecf20Sopenharmony_ci * preview_config_gammacorrn - Configure the Gamma Correction tables
5498c2ecf20Sopenharmony_ci */
5508c2ecf20Sopenharmony_cistatic void
5518c2ecf20Sopenharmony_cipreview_config_gammacorrn(struct isp_prev_device *prev,
5528c2ecf20Sopenharmony_ci			  const struct prev_params *params)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
5558c2ecf20Sopenharmony_ci	const struct omap3isp_prev_gtables *gt = &params->gamma;
5568c2ecf20Sopenharmony_ci	unsigned int i;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
5598c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
5608c2ecf20Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
5618c2ecf20Sopenharmony_ci		isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
5628c2ecf20Sopenharmony_ci			       ISPPRV_SET_TBL_DATA);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
5658c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
5668c2ecf20Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
5678c2ecf20Sopenharmony_ci		isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
5688c2ecf20Sopenharmony_ci			       ISPPRV_SET_TBL_DATA);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
5718c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
5728c2ecf20Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
5738c2ecf20Sopenharmony_ci		isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
5748c2ecf20Sopenharmony_ci			       ISPPRV_SET_TBL_DATA);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/*
5788c2ecf20Sopenharmony_ci * preview_enable_gammacorrn - Enable/disable Gamma Correction
5798c2ecf20Sopenharmony_ci *
5808c2ecf20Sopenharmony_ci * When gamma correction is disabled, the module is bypassed and its output is
5818c2ecf20Sopenharmony_ci * the 8 MSB of the 10-bit input .
5828c2ecf20Sopenharmony_ci */
5838c2ecf20Sopenharmony_cistatic void
5848c2ecf20Sopenharmony_cipreview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (enable)
5898c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
5908c2ecf20Sopenharmony_ci			    ISPPRV_PCR_GAMMA_BYPASS);
5918c2ecf20Sopenharmony_ci	else
5928c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
5938c2ecf20Sopenharmony_ci			    ISPPRV_PCR_GAMMA_BYPASS);
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/*
5978c2ecf20Sopenharmony_ci * preview_config_contrast - Configure the Contrast
5988c2ecf20Sopenharmony_ci *
5998c2ecf20Sopenharmony_ci * Value should be programmed before enabling the module.
6008c2ecf20Sopenharmony_ci */
6018c2ecf20Sopenharmony_cistatic void
6028c2ecf20Sopenharmony_cipreview_config_contrast(struct isp_prev_device *prev,
6038c2ecf20Sopenharmony_ci			const struct prev_params *params)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
6088c2ecf20Sopenharmony_ci			0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
6098c2ecf20Sopenharmony_ci			params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci/*
6138c2ecf20Sopenharmony_ci * preview_config_brightness - Configure the Brightness
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_cistatic void
6168c2ecf20Sopenharmony_cipreview_config_brightness(struct isp_prev_device *prev,
6178c2ecf20Sopenharmony_ci			  const struct prev_params *params)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
6228c2ecf20Sopenharmony_ci			0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
6238c2ecf20Sopenharmony_ci			params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT);
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci/*
6278c2ecf20Sopenharmony_ci * preview_update_contrast - Updates the contrast.
6288c2ecf20Sopenharmony_ci * @contrast: Pointer to hold the current programmed contrast value.
6298c2ecf20Sopenharmony_ci *
6308c2ecf20Sopenharmony_ci * Value should be programmed before enabling the module.
6318c2ecf20Sopenharmony_ci */
6328c2ecf20Sopenharmony_cistatic void
6338c2ecf20Sopenharmony_cipreview_update_contrast(struct isp_prev_device *prev, u8 contrast)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct prev_params *params;
6368c2ecf20Sopenharmony_ci	unsigned long flags;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
6398c2ecf20Sopenharmony_ci	params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
6408c2ecf20Sopenharmony_ci	       ? &prev->params.params[0] : &prev->params.params[1];
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
6438c2ecf20Sopenharmony_ci		params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
6448c2ecf20Sopenharmony_ci		params->update |= OMAP3ISP_PREV_CONTRAST;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
6478c2ecf20Sopenharmony_ci}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci/*
6508c2ecf20Sopenharmony_ci * preview_update_brightness - Updates the brightness in preview module.
6518c2ecf20Sopenharmony_ci * @brightness: Pointer to hold the current programmed brightness value.
6528c2ecf20Sopenharmony_ci *
6538c2ecf20Sopenharmony_ci */
6548c2ecf20Sopenharmony_cistatic void
6558c2ecf20Sopenharmony_cipreview_update_brightness(struct isp_prev_device *prev, u8 brightness)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct prev_params *params;
6588c2ecf20Sopenharmony_ci	unsigned long flags;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
6618c2ecf20Sopenharmony_ci	params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
6628c2ecf20Sopenharmony_ci	       ? &prev->params.params[0] : &prev->params.params[1];
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
6658c2ecf20Sopenharmony_ci		params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
6668c2ecf20Sopenharmony_ci		params->update |= OMAP3ISP_PREV_BRIGHTNESS;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic u32
6728c2ecf20Sopenharmony_cipreview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	u32 active = prev->params.active;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (shadow) {
6778c2ecf20Sopenharmony_ci		/* Mark all shadow parameters we are going to touch as busy. */
6788c2ecf20Sopenharmony_ci		prev->params.params[0].busy |= ~active & update;
6798c2ecf20Sopenharmony_ci		prev->params.params[1].busy |= active & update;
6808c2ecf20Sopenharmony_ci	} else {
6818c2ecf20Sopenharmony_ci		/* Mark all active parameters we are going to touch as busy. */
6828c2ecf20Sopenharmony_ci		update = (prev->params.params[0].update & active)
6838c2ecf20Sopenharmony_ci		       | (prev->params.params[1].update & ~active);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		prev->params.params[0].busy |= active & update;
6868c2ecf20Sopenharmony_ci		prev->params.params[1].busy |= ~active & update;
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	return update;
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic void
6938c2ecf20Sopenharmony_cipreview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	u32 active = prev->params.active;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	if (shadow) {
6988c2ecf20Sopenharmony_ci		/* Set the update flag for shadow parameters that have been
6998c2ecf20Sopenharmony_ci		 * updated and clear the busy flag for all shadow parameters.
7008c2ecf20Sopenharmony_ci		 */
7018c2ecf20Sopenharmony_ci		prev->params.params[0].update |= (~active & update);
7028c2ecf20Sopenharmony_ci		prev->params.params[1].update |= (active & update);
7038c2ecf20Sopenharmony_ci		prev->params.params[0].busy &= active;
7048c2ecf20Sopenharmony_ci		prev->params.params[1].busy &= ~active;
7058c2ecf20Sopenharmony_ci	} else {
7068c2ecf20Sopenharmony_ci		/* Clear the update flag for active parameters that have been
7078c2ecf20Sopenharmony_ci		 * applied and the busy flag for all active parameters.
7088c2ecf20Sopenharmony_ci		 */
7098c2ecf20Sopenharmony_ci		prev->params.params[0].update &= ~(active & update);
7108c2ecf20Sopenharmony_ci		prev->params.params[1].update &= ~(~active & update);
7118c2ecf20Sopenharmony_ci		prev->params.params[0].busy &= ~active;
7128c2ecf20Sopenharmony_ci		prev->params.params[1].busy &= active;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic void preview_params_switch(struct isp_prev_device *prev)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	u32 to_switch;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	/* Switch active parameters with updated shadow parameters when the
7218c2ecf20Sopenharmony_ci	 * shadow parameter has been updated and neither the active not the
7228c2ecf20Sopenharmony_ci	 * shadow parameter is busy.
7238c2ecf20Sopenharmony_ci	 */
7248c2ecf20Sopenharmony_ci	to_switch = (prev->params.params[0].update & ~prev->params.active)
7258c2ecf20Sopenharmony_ci		  | (prev->params.params[1].update & prev->params.active);
7268c2ecf20Sopenharmony_ci	to_switch &= ~(prev->params.params[0].busy |
7278c2ecf20Sopenharmony_ci		       prev->params.params[1].busy);
7288c2ecf20Sopenharmony_ci	if (to_switch == 0)
7298c2ecf20Sopenharmony_ci		return;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	prev->params.active ^= to_switch;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/* Remove the update flag for the shadow copy of parameters we have
7348c2ecf20Sopenharmony_ci	 * switched.
7358c2ecf20Sopenharmony_ci	 */
7368c2ecf20Sopenharmony_ci	prev->params.params[0].update &= ~(~prev->params.active & to_switch);
7378c2ecf20Sopenharmony_ci	prev->params.params[1].update &= ~(prev->params.active & to_switch);
7388c2ecf20Sopenharmony_ci}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci/* preview parameters update structure */
7418c2ecf20Sopenharmony_cistruct preview_update {
7428c2ecf20Sopenharmony_ci	void (*config)(struct isp_prev_device *, const struct prev_params *);
7438c2ecf20Sopenharmony_ci	void (*enable)(struct isp_prev_device *, bool);
7448c2ecf20Sopenharmony_ci	unsigned int param_offset;
7458c2ecf20Sopenharmony_ci	unsigned int param_size;
7468c2ecf20Sopenharmony_ci	unsigned int config_offset;
7478c2ecf20Sopenharmony_ci	bool skip;
7488c2ecf20Sopenharmony_ci};
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
7518c2ecf20Sopenharmony_cistatic const struct preview_update update_attrs[] = {
7528c2ecf20Sopenharmony_ci	/* OMAP3ISP_PREV_LUMAENH */ {
7538c2ecf20Sopenharmony_ci		preview_config_luma_enhancement,
7548c2ecf20Sopenharmony_ci		preview_enable_luma_enhancement,
7558c2ecf20Sopenharmony_ci		offsetof(struct prev_params, luma),
7568c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, luma),
7578c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, luma),
7588c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_INVALAW */ {
7598c2ecf20Sopenharmony_ci		NULL,
7608c2ecf20Sopenharmony_ci		preview_enable_invalaw,
7618c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_HRZ_MED */ {
7628c2ecf20Sopenharmony_ci		preview_config_hmed,
7638c2ecf20Sopenharmony_ci		preview_enable_hmed,
7648c2ecf20Sopenharmony_ci		offsetof(struct prev_params, hmed),
7658c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, hmed),
7668c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, hmed),
7678c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_CFA */ {
7688c2ecf20Sopenharmony_ci		preview_config_cfa,
7698c2ecf20Sopenharmony_ci		NULL,
7708c2ecf20Sopenharmony_ci		offsetof(struct prev_params, cfa),
7718c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, cfa),
7728c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, cfa),
7738c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
7748c2ecf20Sopenharmony_ci		preview_config_chroma_suppression,
7758c2ecf20Sopenharmony_ci		preview_enable_chroma_suppression,
7768c2ecf20Sopenharmony_ci		offsetof(struct prev_params, csup),
7778c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, csup),
7788c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, csup),
7798c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_WB */ {
7808c2ecf20Sopenharmony_ci		preview_config_whitebalance,
7818c2ecf20Sopenharmony_ci		NULL,
7828c2ecf20Sopenharmony_ci		offsetof(struct prev_params, wbal),
7838c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, wbal),
7848c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, wbal),
7858c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_BLKADJ */ {
7868c2ecf20Sopenharmony_ci		preview_config_blkadj,
7878c2ecf20Sopenharmony_ci		NULL,
7888c2ecf20Sopenharmony_ci		offsetof(struct prev_params, blkadj),
7898c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, blkadj),
7908c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, blkadj),
7918c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_RGB2RGB */ {
7928c2ecf20Sopenharmony_ci		preview_config_rgb_blending,
7938c2ecf20Sopenharmony_ci		NULL,
7948c2ecf20Sopenharmony_ci		offsetof(struct prev_params, rgb2rgb),
7958c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, rgb2rgb),
7968c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, rgb2rgb),
7978c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_COLOR_CONV */ {
7988c2ecf20Sopenharmony_ci		preview_config_csc,
7998c2ecf20Sopenharmony_ci		NULL,
8008c2ecf20Sopenharmony_ci		offsetof(struct prev_params, csc),
8018c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, csc),
8028c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, csc),
8038c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_YC_LIMIT */ {
8048c2ecf20Sopenharmony_ci		preview_config_yc_range,
8058c2ecf20Sopenharmony_ci		NULL,
8068c2ecf20Sopenharmony_ci		offsetof(struct prev_params, yclimit),
8078c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, yclimit),
8088c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, yclimit),
8098c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_DEFECT_COR */ {
8108c2ecf20Sopenharmony_ci		preview_config_dcor,
8118c2ecf20Sopenharmony_ci		preview_enable_dcor,
8128c2ecf20Sopenharmony_ci		offsetof(struct prev_params, dcor),
8138c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, dcor),
8148c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, dcor),
8158c2ecf20Sopenharmony_ci	}, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
8168c2ecf20Sopenharmony_ci		NULL,
8178c2ecf20Sopenharmony_ci		NULL,
8188c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
8198c2ecf20Sopenharmony_ci		NULL,
8208c2ecf20Sopenharmony_ci		preview_enable_drkframe_capture,
8218c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
8228c2ecf20Sopenharmony_ci		NULL,
8238c2ecf20Sopenharmony_ci		preview_enable_drkframe,
8248c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_LENS_SHADING */ {
8258c2ecf20Sopenharmony_ci		NULL,
8268c2ecf20Sopenharmony_ci		preview_enable_drkframe,
8278c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_NF */ {
8288c2ecf20Sopenharmony_ci		preview_config_noisefilter,
8298c2ecf20Sopenharmony_ci		preview_enable_noisefilter,
8308c2ecf20Sopenharmony_ci		offsetof(struct prev_params, nf),
8318c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, nf),
8328c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, nf),
8338c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_GAMMA */ {
8348c2ecf20Sopenharmony_ci		preview_config_gammacorrn,
8358c2ecf20Sopenharmony_ci		preview_enable_gammacorrn,
8368c2ecf20Sopenharmony_ci		offsetof(struct prev_params, gamma),
8378c2ecf20Sopenharmony_ci		sizeof_field(struct prev_params, gamma),
8388c2ecf20Sopenharmony_ci		offsetof(struct omap3isp_prev_update_config, gamma),
8398c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_CONTRAST */ {
8408c2ecf20Sopenharmony_ci		preview_config_contrast,
8418c2ecf20Sopenharmony_ci		NULL,
8428c2ecf20Sopenharmony_ci		0, 0, 0, true,
8438c2ecf20Sopenharmony_ci	}, /* OMAP3ISP_PREV_BRIGHTNESS */ {
8448c2ecf20Sopenharmony_ci		preview_config_brightness,
8458c2ecf20Sopenharmony_ci		NULL,
8468c2ecf20Sopenharmony_ci		0, 0, 0, true,
8478c2ecf20Sopenharmony_ci	},
8488c2ecf20Sopenharmony_ci};
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci/*
8518c2ecf20Sopenharmony_ci * preview_config - Copy and update local structure with userspace preview
8528c2ecf20Sopenharmony_ci *                  configuration.
8538c2ecf20Sopenharmony_ci * @prev: ISP preview engine
8548c2ecf20Sopenharmony_ci * @cfg: Configuration
8558c2ecf20Sopenharmony_ci *
8568c2ecf20Sopenharmony_ci * Return zero if success or -EFAULT if the configuration can't be copied from
8578c2ecf20Sopenharmony_ci * userspace.
8588c2ecf20Sopenharmony_ci */
8598c2ecf20Sopenharmony_cistatic int preview_config(struct isp_prev_device *prev,
8608c2ecf20Sopenharmony_ci			  struct omap3isp_prev_update_config *cfg)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	unsigned long flags;
8638c2ecf20Sopenharmony_ci	unsigned int i;
8648c2ecf20Sopenharmony_ci	int rval = 0;
8658c2ecf20Sopenharmony_ci	u32 update;
8668c2ecf20Sopenharmony_ci	u32 active;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (cfg->update == 0)
8698c2ecf20Sopenharmony_ci		return 0;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* Mark the shadow parameters we're going to update as busy. */
8728c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
8738c2ecf20Sopenharmony_ci	preview_params_lock(prev, cfg->update, true);
8748c2ecf20Sopenharmony_ci	active = prev->params.active;
8758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	update = 0;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
8808c2ecf20Sopenharmony_ci		const struct preview_update *attr = &update_attrs[i];
8818c2ecf20Sopenharmony_ci		struct prev_params *params;
8828c2ecf20Sopenharmony_ci		unsigned int bit = 1 << i;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		if (attr->skip || !(cfg->update & bit))
8858c2ecf20Sopenharmony_ci			continue;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci		params = &prev->params.params[!!(active & bit)];
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		if (cfg->flag & bit) {
8908c2ecf20Sopenharmony_ci			void __user *from = *(void __user **)
8918c2ecf20Sopenharmony_ci				((void *)cfg + attr->config_offset);
8928c2ecf20Sopenharmony_ci			void *to = (void *)params + attr->param_offset;
8938c2ecf20Sopenharmony_ci			size_t size = attr->param_size;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci			if (to && from && size) {
8968c2ecf20Sopenharmony_ci				if (copy_from_user(to, from, size)) {
8978c2ecf20Sopenharmony_ci					rval = -EFAULT;
8988c2ecf20Sopenharmony_ci					break;
8998c2ecf20Sopenharmony_ci				}
9008c2ecf20Sopenharmony_ci			}
9018c2ecf20Sopenharmony_ci			params->features |= bit;
9028c2ecf20Sopenharmony_ci		} else {
9038c2ecf20Sopenharmony_ci			params->features &= ~bit;
9048c2ecf20Sopenharmony_ci		}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci		update |= bit;
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
9108c2ecf20Sopenharmony_ci	preview_params_unlock(prev, update, true);
9118c2ecf20Sopenharmony_ci	preview_params_switch(prev);
9128c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return rval;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci/*
9188c2ecf20Sopenharmony_ci * preview_setup_hw - Setup preview registers and/or internal memory
9198c2ecf20Sopenharmony_ci * @prev: pointer to preview private structure
9208c2ecf20Sopenharmony_ci * @update: Bitmask of parameters to setup
9218c2ecf20Sopenharmony_ci * @active: Bitmask of parameters active in set 0
9228c2ecf20Sopenharmony_ci * Note: can be called from interrupt context
9238c2ecf20Sopenharmony_ci * Return none
9248c2ecf20Sopenharmony_ci */
9258c2ecf20Sopenharmony_cistatic void preview_setup_hw(struct isp_prev_device *prev, u32 update,
9268c2ecf20Sopenharmony_ci			     u32 active)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	unsigned int i;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (update == 0)
9318c2ecf20Sopenharmony_ci		return;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
9348c2ecf20Sopenharmony_ci		const struct preview_update *attr = &update_attrs[i];
9358c2ecf20Sopenharmony_ci		struct prev_params *params;
9368c2ecf20Sopenharmony_ci		unsigned int bit = 1 << i;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci		if (!(update & bit))
9398c2ecf20Sopenharmony_ci			continue;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		params = &prev->params.params[!(active & bit)];
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		if (params->features & bit) {
9448c2ecf20Sopenharmony_ci			if (attr->config)
9458c2ecf20Sopenharmony_ci				attr->config(prev, params);
9468c2ecf20Sopenharmony_ci			if (attr->enable)
9478c2ecf20Sopenharmony_ci				attr->enable(prev, true);
9488c2ecf20Sopenharmony_ci		} else {
9498c2ecf20Sopenharmony_ci			if (attr->enable)
9508c2ecf20Sopenharmony_ci				attr->enable(prev, false);
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci/*
9568c2ecf20Sopenharmony_ci * preview_config_ycpos - Configure byte layout of YUV image.
9578c2ecf20Sopenharmony_ci * @prev: pointer to previewer private structure
9588c2ecf20Sopenharmony_ci * @pixelcode: pixel code
9598c2ecf20Sopenharmony_ci */
9608c2ecf20Sopenharmony_cistatic void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
9638c2ecf20Sopenharmony_ci	enum preview_ycpos_mode mode;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	switch (pixelcode) {
9668c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_YUYV8_1X16:
9678c2ecf20Sopenharmony_ci		mode = YCPOS_CrYCbY;
9688c2ecf20Sopenharmony_ci		break;
9698c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_UYVY8_1X16:
9708c2ecf20Sopenharmony_ci		mode = YCPOS_YCrYCb;
9718c2ecf20Sopenharmony_ci		break;
9728c2ecf20Sopenharmony_ci	default:
9738c2ecf20Sopenharmony_ci		return;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
9778c2ecf20Sopenharmony_ci			ISPPRV_PCR_YCPOS_CrYCbY,
9788c2ecf20Sopenharmony_ci			mode << ISPPRV_PCR_YCPOS_SHIFT);
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci/*
9828c2ecf20Sopenharmony_ci * preview_config_averager - Enable / disable / configure averager
9838c2ecf20Sopenharmony_ci * @average: Average value to be configured.
9848c2ecf20Sopenharmony_ci */
9858c2ecf20Sopenharmony_cistatic void preview_config_averager(struct isp_prev_device *prev, u8 average)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
9908c2ecf20Sopenharmony_ci		       ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
9918c2ecf20Sopenharmony_ci		       average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci/*
9968c2ecf20Sopenharmony_ci * preview_config_input_format - Configure the input format
9978c2ecf20Sopenharmony_ci * @prev: The preview engine
9988c2ecf20Sopenharmony_ci * @info: Sink pad format information
9998c2ecf20Sopenharmony_ci *
10008c2ecf20Sopenharmony_ci * Enable and configure CFA interpolation for Bayer formats and disable it for
10018c2ecf20Sopenharmony_ci * greyscale formats.
10028c2ecf20Sopenharmony_ci *
10038c2ecf20Sopenharmony_ci * The CFA table is organised in four blocks, one per Bayer component. The
10048c2ecf20Sopenharmony_ci * hardware expects blocks to follow the Bayer order of the input data, while
10058c2ecf20Sopenharmony_ci * the driver stores the table in GRBG order in memory. The blocks need to be
10068c2ecf20Sopenharmony_ci * reordered to support non-GRBG Bayer patterns.
10078c2ecf20Sopenharmony_ci */
10088c2ecf20Sopenharmony_cistatic void preview_config_input_format(struct isp_prev_device *prev,
10098c2ecf20Sopenharmony_ci					const struct isp_format_info *info)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
10128c2ecf20Sopenharmony_ci	struct prev_params *params;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (info->width == 8)
10158c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
10168c2ecf20Sopenharmony_ci			    ISPPRV_PCR_WIDTH);
10178c2ecf20Sopenharmony_ci	else
10188c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
10198c2ecf20Sopenharmony_ci			    ISPPRV_PCR_WIDTH);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	switch (info->flavor) {
10228c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SGRBG8_1X8:
10238c2ecf20Sopenharmony_ci		prev->params.cfa_order = 0;
10248c2ecf20Sopenharmony_ci		break;
10258c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SRGGB8_1X8:
10268c2ecf20Sopenharmony_ci		prev->params.cfa_order = 1;
10278c2ecf20Sopenharmony_ci		break;
10288c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SBGGR8_1X8:
10298c2ecf20Sopenharmony_ci		prev->params.cfa_order = 2;
10308c2ecf20Sopenharmony_ci		break;
10318c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SGBRG8_1X8:
10328c2ecf20Sopenharmony_ci		prev->params.cfa_order = 3;
10338c2ecf20Sopenharmony_ci		break;
10348c2ecf20Sopenharmony_ci	default:
10358c2ecf20Sopenharmony_ci		/* Disable CFA for non-Bayer formats. */
10368c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
10378c2ecf20Sopenharmony_ci			    ISPPRV_PCR_CFAEN);
10388c2ecf20Sopenharmony_ci		return;
10398c2ecf20Sopenharmony_ci	}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
10428c2ecf20Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
10438c2ecf20Sopenharmony_ci			ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	params = (prev->params.active & OMAP3ISP_PREV_CFA)
10468c2ecf20Sopenharmony_ci	       ? &prev->params.params[0] : &prev->params.params[1];
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	preview_config_cfa(prev, params);
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci/*
10528c2ecf20Sopenharmony_ci * preview_config_input_size - Configure the input frame size
10538c2ecf20Sopenharmony_ci *
10548c2ecf20Sopenharmony_ci * The preview engine crops several rows and columns internally depending on
10558c2ecf20Sopenharmony_ci * which processing blocks are enabled. The driver assumes all those blocks are
10568c2ecf20Sopenharmony_ci * enabled when reporting source pad formats to userspace. If this assumption is
10578c2ecf20Sopenharmony_ci * not true, rows and columns must be manually cropped at the preview engine
10588c2ecf20Sopenharmony_ci * input to avoid overflows at the end of lines and frames.
10598c2ecf20Sopenharmony_ci *
10608c2ecf20Sopenharmony_ci * See the explanation at the PREV_MARGIN_* definitions for more details.
10618c2ecf20Sopenharmony_ci */
10628c2ecf20Sopenharmony_cistatic void preview_config_input_size(struct isp_prev_device *prev, u32 active)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
10658c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
10668c2ecf20Sopenharmony_ci	unsigned int sph = prev->crop.left;
10678c2ecf20Sopenharmony_ci	unsigned int eph = prev->crop.left + prev->crop.width - 1;
10688c2ecf20Sopenharmony_ci	unsigned int slv = prev->crop.top;
10698c2ecf20Sopenharmony_ci	unsigned int elv = prev->crop.top + prev->crop.height - 1;
10708c2ecf20Sopenharmony_ci	u32 features;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	if (format->code != MEDIA_BUS_FMT_Y8_1X8 &&
10738c2ecf20Sopenharmony_ci	    format->code != MEDIA_BUS_FMT_Y10_1X10) {
10748c2ecf20Sopenharmony_ci		sph -= 2;
10758c2ecf20Sopenharmony_ci		eph += 2;
10768c2ecf20Sopenharmony_ci		slv -= 2;
10778c2ecf20Sopenharmony_ci		elv += 2;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	features = (prev->params.params[0].features & active)
10818c2ecf20Sopenharmony_ci		 | (prev->params.params[1].features & ~active);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
10848c2ecf20Sopenharmony_ci		sph -= 2;
10858c2ecf20Sopenharmony_ci		eph += 2;
10868c2ecf20Sopenharmony_ci		slv -= 2;
10878c2ecf20Sopenharmony_ci		elv += 2;
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci	if (features & OMAP3ISP_PREV_HRZ_MED) {
10908c2ecf20Sopenharmony_ci		sph -= 2;
10918c2ecf20Sopenharmony_ci		eph += 2;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci	if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
10948c2ecf20Sopenharmony_ci		sph -= 2;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
10978c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
10988c2ecf20Sopenharmony_ci	isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
10998c2ecf20Sopenharmony_ci		       OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci/*
11038c2ecf20Sopenharmony_ci * preview_config_inlineoffset - Configures the Read address line offset.
11048c2ecf20Sopenharmony_ci * @prev: Preview module
11058c2ecf20Sopenharmony_ci * @offset: Line offset
11068c2ecf20Sopenharmony_ci *
11078c2ecf20Sopenharmony_ci * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
11088c2ecf20Sopenharmony_ci * However, a hardware bug requires the memory start address to be aligned on a
11098c2ecf20Sopenharmony_ci * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
11108c2ecf20Sopenharmony_ci * well.
11118c2ecf20Sopenharmony_ci */
11128c2ecf20Sopenharmony_cistatic void
11138c2ecf20Sopenharmony_cipreview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
11188c2ecf20Sopenharmony_ci		       ISPPRV_RADR_OFFSET);
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci/*
11228c2ecf20Sopenharmony_ci * preview_set_inaddr - Sets memory address of input frame.
11238c2ecf20Sopenharmony_ci * @addr: 32bit memory address aligned on 32byte boundary.
11248c2ecf20Sopenharmony_ci *
11258c2ecf20Sopenharmony_ci * Configures the memory address from which the input frame is to be read.
11268c2ecf20Sopenharmony_ci */
11278c2ecf20Sopenharmony_cistatic void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci/*
11358c2ecf20Sopenharmony_ci * preview_config_outlineoffset - Configures the Write address line offset.
11368c2ecf20Sopenharmony_ci * @offset: Line Offset for the preview output.
11378c2ecf20Sopenharmony_ci *
11388c2ecf20Sopenharmony_ci * The offset must be a multiple of 32 bytes.
11398c2ecf20Sopenharmony_ci */
11408c2ecf20Sopenharmony_cistatic void preview_config_outlineoffset(struct isp_prev_device *prev,
11418c2ecf20Sopenharmony_ci				    u32 offset)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
11468c2ecf20Sopenharmony_ci		       ISPPRV_WADD_OFFSET);
11478c2ecf20Sopenharmony_ci}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci/*
11508c2ecf20Sopenharmony_ci * preview_set_outaddr - Sets the memory address to store output frame
11518c2ecf20Sopenharmony_ci * @addr: 32bit memory address aligned on 32byte boundary.
11528c2ecf20Sopenharmony_ci *
11538c2ecf20Sopenharmony_ci * Configures the memory address to which the output frame is written.
11548c2ecf20Sopenharmony_ci */
11558c2ecf20Sopenharmony_cistatic void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_cistatic void preview_adjust_bandwidth(struct isp_prev_device *prev)
11638c2ecf20Sopenharmony_ci{
11648c2ecf20Sopenharmony_ci	struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
11658c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
11668c2ecf20Sopenharmony_ci	const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
11678c2ecf20Sopenharmony_ci	unsigned long l3_ick = pipe->l3_ick;
11688c2ecf20Sopenharmony_ci	struct v4l2_fract *timeperframe;
11698c2ecf20Sopenharmony_ci	unsigned int cycles_per_frame;
11708c2ecf20Sopenharmony_ci	unsigned int requests_per_frame;
11718c2ecf20Sopenharmony_ci	unsigned int cycles_per_request;
11728c2ecf20Sopenharmony_ci	unsigned int minimum;
11738c2ecf20Sopenharmony_ci	unsigned int maximum;
11748c2ecf20Sopenharmony_ci	unsigned int value;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	if (prev->input != PREVIEW_INPUT_MEMORY) {
11778c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
11788c2ecf20Sopenharmony_ci			    ISPSBL_SDR_REQ_PRV_EXP_MASK);
11798c2ecf20Sopenharmony_ci		return;
11808c2ecf20Sopenharmony_ci	}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	/* Compute the minimum number of cycles per request, based on the
11838c2ecf20Sopenharmony_ci	 * pipeline maximum data rate. This is an absolute lower bound if we
11848c2ecf20Sopenharmony_ci	 * don't want SBL overflows, so round the value up.
11858c2ecf20Sopenharmony_ci	 */
11868c2ecf20Sopenharmony_ci	cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
11878c2ecf20Sopenharmony_ci				     pipe->max_rate);
11888c2ecf20Sopenharmony_ci	minimum = DIV_ROUND_UP(cycles_per_request, 32);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/* Compute the maximum number of cycles per request, based on the
11918c2ecf20Sopenharmony_ci	 * requested frame rate. This is a soft upper bound to achieve a frame
11928c2ecf20Sopenharmony_ci	 * rate equal or higher than the requested value, so round the value
11938c2ecf20Sopenharmony_ci	 * down.
11948c2ecf20Sopenharmony_ci	 */
11958c2ecf20Sopenharmony_ci	timeperframe = &pipe->max_timeperframe;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
11988c2ecf20Sopenharmony_ci	cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
11998c2ecf20Sopenharmony_ci				   timeperframe->denominator);
12008c2ecf20Sopenharmony_ci	cycles_per_request = cycles_per_frame / requests_per_frame;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	maximum = cycles_per_request / 32;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	value = max(minimum, maximum);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
12078c2ecf20Sopenharmony_ci	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
12088c2ecf20Sopenharmony_ci			ISPSBL_SDR_REQ_PRV_EXP_MASK,
12098c2ecf20Sopenharmony_ci			value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci/*
12138c2ecf20Sopenharmony_ci * omap3isp_preview_busy - Gets busy state of preview module.
12148c2ecf20Sopenharmony_ci */
12158c2ecf20Sopenharmony_ciint omap3isp_preview_busy(struct isp_prev_device *prev)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
12208c2ecf20Sopenharmony_ci		& ISPPRV_PCR_BUSY;
12218c2ecf20Sopenharmony_ci}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci/*
12248c2ecf20Sopenharmony_ci * omap3isp_preview_restore_context - Restores the values of preview registers
12258c2ecf20Sopenharmony_ci */
12268c2ecf20Sopenharmony_civoid omap3isp_preview_restore_context(struct isp_device *isp)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = &isp->isp_prev;
12298c2ecf20Sopenharmony_ci	const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	prev->params.params[0].update = prev->params.active & update;
12328c2ecf20Sopenharmony_ci	prev->params.params[1].update = ~prev->params.active & update;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	preview_setup_hw(prev, update, prev->params.active);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	prev->params.params[0].update = 0;
12378c2ecf20Sopenharmony_ci	prev->params.params[1].update = 0;
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci/*
12418c2ecf20Sopenharmony_ci * preview_print_status - Dump preview module registers to the kernel log
12428c2ecf20Sopenharmony_ci */
12438c2ecf20Sopenharmony_ci#define PREV_PRINT_REGISTER(isp, name)\
12448c2ecf20Sopenharmony_ci	dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
12458c2ecf20Sopenharmony_ci		isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_cistatic void preview_print_status(struct isp_prev_device *prev)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, PCR);
12548c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, HORZ_INFO);
12558c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, VERT_INFO);
12568c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RSDR_ADDR);
12578c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RADR_OFFSET);
12588c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, DSDR_ADDR);
12598c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
12608c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WSDR_ADDR);
12618c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WADD_OFFSET);
12628c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, AVE);
12638c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, HMED);
12648c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, NF);
12658c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WB_DGAIN);
12668c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WBGAIN);
12678c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, WBSEL);
12688c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CFA);
12698c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, BLKADJOFF);
12708c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT1);
12718c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT2);
12728c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT3);
12738c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT4);
12748c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_MAT5);
12758c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_OFF1);
12768c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, RGB_OFF2);
12778c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC0);
12788c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC1);
12798c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC2);
12808c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSC_OFFSET);
12818c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CNT_BRT);
12828c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CSUP);
12838c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, SETUP_YC);
12848c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
12858c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR0);
12868c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR1);
12878c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR2);
12888c2ecf20Sopenharmony_ci	PREV_PRINT_REGISTER(isp, CDC_THR3);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	dev_dbg(isp->dev, "--------------------------------------------\n");
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci/*
12948c2ecf20Sopenharmony_ci * preview_init_params - init image processing parameters.
12958c2ecf20Sopenharmony_ci * @prev: pointer to previewer private structure
12968c2ecf20Sopenharmony_ci */
12978c2ecf20Sopenharmony_cistatic void preview_init_params(struct isp_prev_device *prev)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct prev_params *params;
13008c2ecf20Sopenharmony_ci	unsigned int i;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	spin_lock_init(&prev->params.lock);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	prev->params.active = ~0;
13058c2ecf20Sopenharmony_ci	prev->params.params[0].busy = 0;
13068c2ecf20Sopenharmony_ci	prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
13078c2ecf20Sopenharmony_ci	prev->params.params[1].busy = 0;
13088c2ecf20Sopenharmony_ci	prev->params.params[1].update = 0;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	params = &prev->params.params[0];
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	/* Init values */
13138c2ecf20Sopenharmony_ci	params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
13148c2ecf20Sopenharmony_ci	params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
13158c2ecf20Sopenharmony_ci	params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
13168c2ecf20Sopenharmony_ci	memcpy(params->cfa.table, cfa_coef_table,
13178c2ecf20Sopenharmony_ci	       sizeof(params->cfa.table));
13188c2ecf20Sopenharmony_ci	params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
13198c2ecf20Sopenharmony_ci	params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
13208c2ecf20Sopenharmony_ci	params->csup.gain = FLR_CSUP_GAIN;
13218c2ecf20Sopenharmony_ci	params->csup.thres = FLR_CSUP_THRES;
13228c2ecf20Sopenharmony_ci	params->csup.hypf_en = 0;
13238c2ecf20Sopenharmony_ci	memcpy(params->luma.table, luma_enhance_table,
13248c2ecf20Sopenharmony_ci	       sizeof(params->luma.table));
13258c2ecf20Sopenharmony_ci	params->nf.spread = FLR_NF_STRGTH;
13268c2ecf20Sopenharmony_ci	memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
13278c2ecf20Sopenharmony_ci	params->dcor.couplet_mode_en = 1;
13288c2ecf20Sopenharmony_ci	for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
13298c2ecf20Sopenharmony_ci		params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
13308c2ecf20Sopenharmony_ci	memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
13318c2ecf20Sopenharmony_ci	memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
13328c2ecf20Sopenharmony_ci	memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
13338c2ecf20Sopenharmony_ci	params->wbal.dgain = FLR_WBAL_DGAIN;
13348c2ecf20Sopenharmony_ci	params->wbal.coef0 = FLR_WBAL_COEF;
13358c2ecf20Sopenharmony_ci	params->wbal.coef1 = FLR_WBAL_COEF;
13368c2ecf20Sopenharmony_ci	params->wbal.coef2 = FLR_WBAL_COEF;
13378c2ecf20Sopenharmony_ci	params->wbal.coef3 = FLR_WBAL_COEF;
13388c2ecf20Sopenharmony_ci	params->blkadj.red = FLR_BLKADJ_RED;
13398c2ecf20Sopenharmony_ci	params->blkadj.green = FLR_BLKADJ_GREEN;
13408c2ecf20Sopenharmony_ci	params->blkadj.blue = FLR_BLKADJ_BLUE;
13418c2ecf20Sopenharmony_ci	params->rgb2rgb = flr_rgb2rgb;
13428c2ecf20Sopenharmony_ci	params->csc = flr_prev_csc;
13438c2ecf20Sopenharmony_ci	params->yclimit.minC = ISPPRV_YC_MIN;
13448c2ecf20Sopenharmony_ci	params->yclimit.maxC = ISPPRV_YC_MAX;
13458c2ecf20Sopenharmony_ci	params->yclimit.minY = ISPPRV_YC_MIN;
13468c2ecf20Sopenharmony_ci	params->yclimit.maxY = ISPPRV_YC_MAX;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
13498c2ecf20Sopenharmony_ci			 | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
13508c2ecf20Sopenharmony_ci			 | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
13518c2ecf20Sopenharmony_ci			 | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
13528c2ecf20Sopenharmony_ci			 | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
13538c2ecf20Sopenharmony_ci			 | OMAP3ISP_PREV_CONTRAST;
13548c2ecf20Sopenharmony_ci}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci/*
13578c2ecf20Sopenharmony_ci * preview_max_out_width - Handle previewer hardware output limitations
13588c2ecf20Sopenharmony_ci * @prev: pointer to previewer private structure
13598c2ecf20Sopenharmony_ci * returns maximum width output for current isp revision
13608c2ecf20Sopenharmony_ci */
13618c2ecf20Sopenharmony_cistatic unsigned int preview_max_out_width(struct isp_prev_device *prev)
13628c2ecf20Sopenharmony_ci{
13638c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	switch (isp->revision) {
13668c2ecf20Sopenharmony_ci	case ISP_REVISION_1_0:
13678c2ecf20Sopenharmony_ci		return PREV_MAX_OUT_WIDTH_REV_1;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	case ISP_REVISION_2_0:
13708c2ecf20Sopenharmony_ci	default:
13718c2ecf20Sopenharmony_ci		return PREV_MAX_OUT_WIDTH_REV_2;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	case ISP_REVISION_15_0:
13748c2ecf20Sopenharmony_ci		return PREV_MAX_OUT_WIDTH_REV_15;
13758c2ecf20Sopenharmony_ci	}
13768c2ecf20Sopenharmony_ci}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_cistatic void preview_configure(struct isp_prev_device *prev)
13798c2ecf20Sopenharmony_ci{
13808c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
13818c2ecf20Sopenharmony_ci	const struct isp_format_info *info;
13828c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
13838c2ecf20Sopenharmony_ci	unsigned long flags;
13848c2ecf20Sopenharmony_ci	u32 update;
13858c2ecf20Sopenharmony_ci	u32 active;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
13888c2ecf20Sopenharmony_ci	/* Mark all active parameters we are going to touch as busy. */
13898c2ecf20Sopenharmony_ci	update = preview_params_lock(prev, 0, false);
13908c2ecf20Sopenharmony_ci	active = prev->params.active;
13918c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	/* PREV_PAD_SINK */
13948c2ecf20Sopenharmony_ci	format = &prev->formats[PREV_PAD_SINK];
13958c2ecf20Sopenharmony_ci	info = omap3isp_video_format_info(format->code);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	preview_adjust_bandwidth(prev);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	preview_config_input_format(prev, info);
14008c2ecf20Sopenharmony_ci	preview_config_input_size(prev, active);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_CCDC)
14038c2ecf20Sopenharmony_ci		preview_config_inlineoffset(prev, 0);
14048c2ecf20Sopenharmony_ci	else
14058c2ecf20Sopenharmony_ci		preview_config_inlineoffset(prev, ALIGN(format->width, 0x20) *
14068c2ecf20Sopenharmony_ci					    info->bpp);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	preview_setup_hw(prev, update, active);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* PREV_PAD_SOURCE */
14118c2ecf20Sopenharmony_ci	format = &prev->formats[PREV_PAD_SOURCE];
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_MEMORY)
14148c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
14158c2ecf20Sopenharmony_ci			    ISPPRV_PCR_SDRPORT);
14168c2ecf20Sopenharmony_ci	else
14178c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
14188c2ecf20Sopenharmony_ci			    ISPPRV_PCR_SDRPORT);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_RESIZER)
14218c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
14228c2ecf20Sopenharmony_ci			    ISPPRV_PCR_RSZPORT);
14238c2ecf20Sopenharmony_ci	else
14248c2ecf20Sopenharmony_ci		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
14258c2ecf20Sopenharmony_ci			    ISPPRV_PCR_RSZPORT);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_MEMORY)
14288c2ecf20Sopenharmony_ci		preview_config_outlineoffset(prev,
14298c2ecf20Sopenharmony_ci				ALIGN(format->width, 0x10) * 2);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	preview_config_averager(prev, 0);
14328c2ecf20Sopenharmony_ci	preview_config_ycpos(prev, format->code);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
14358c2ecf20Sopenharmony_ci	preview_params_unlock(prev, update, false);
14368c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
14378c2ecf20Sopenharmony_ci}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
14408c2ecf20Sopenharmony_ci * Interrupt handling
14418c2ecf20Sopenharmony_ci */
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_cistatic void preview_enable_oneshot(struct isp_prev_device *prev)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	/* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
14488c2ecf20Sopenharmony_ci	 * bit is set. As the preview engine is used in single-shot mode, we
14498c2ecf20Sopenharmony_ci	 * need to set PCR.SOURCE before enabling the preview engine.
14508c2ecf20Sopenharmony_ci	 */
14518c2ecf20Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_MEMORY)
14528c2ecf20Sopenharmony_ci		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
14538c2ecf20Sopenharmony_ci			    ISPPRV_PCR_SOURCE);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
14568c2ecf20Sopenharmony_ci		    ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
14578c2ecf20Sopenharmony_ci}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_civoid omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
14608c2ecf20Sopenharmony_ci{
14618c2ecf20Sopenharmony_ci	/*
14628c2ecf20Sopenharmony_ci	 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
14638c2ecf20Sopenharmony_ci	 * condition, the module was paused and now we have a buffer queued
14648c2ecf20Sopenharmony_ci	 * on the output again. Restart the pipeline if running in continuous
14658c2ecf20Sopenharmony_ci	 * mode.
14668c2ecf20Sopenharmony_ci	 */
14678c2ecf20Sopenharmony_ci	if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
14688c2ecf20Sopenharmony_ci	    prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
14698c2ecf20Sopenharmony_ci		preview_enable_oneshot(prev);
14708c2ecf20Sopenharmony_ci		isp_video_dmaqueue_flags_clr(&prev->video_out);
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_cistatic void preview_isr_buffer(struct isp_prev_device *prev)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
14778c2ecf20Sopenharmony_ci	struct isp_buffer *buffer;
14788c2ecf20Sopenharmony_ci	int restart = 0;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	if (prev->output & PREVIEW_OUTPUT_MEMORY) {
14818c2ecf20Sopenharmony_ci		buffer = omap3isp_video_buffer_next(&prev->video_out);
14828c2ecf20Sopenharmony_ci		if (buffer != NULL) {
14838c2ecf20Sopenharmony_ci			preview_set_outaddr(prev, buffer->dma);
14848c2ecf20Sopenharmony_ci			restart = 1;
14858c2ecf20Sopenharmony_ci		}
14868c2ecf20Sopenharmony_ci		pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_MEMORY) {
14908c2ecf20Sopenharmony_ci		buffer = omap3isp_video_buffer_next(&prev->video_in);
14918c2ecf20Sopenharmony_ci		if (buffer != NULL)
14928c2ecf20Sopenharmony_ci			preview_set_inaddr(prev, buffer->dma);
14938c2ecf20Sopenharmony_ci		pipe->state |= ISP_PIPELINE_IDLE_INPUT;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	switch (prev->state) {
14978c2ecf20Sopenharmony_ci	case ISP_PIPELINE_STREAM_SINGLESHOT:
14988c2ecf20Sopenharmony_ci		if (isp_pipeline_ready(pipe))
14998c2ecf20Sopenharmony_ci			omap3isp_pipeline_set_stream(pipe,
15008c2ecf20Sopenharmony_ci						ISP_PIPELINE_STREAM_SINGLESHOT);
15018c2ecf20Sopenharmony_ci		break;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	case ISP_PIPELINE_STREAM_CONTINUOUS:
15048c2ecf20Sopenharmony_ci		/* If an underrun occurs, the video queue operation handler will
15058c2ecf20Sopenharmony_ci		 * restart the preview engine. Otherwise restart it immediately.
15068c2ecf20Sopenharmony_ci		 */
15078c2ecf20Sopenharmony_ci		if (restart)
15088c2ecf20Sopenharmony_ci			preview_enable_oneshot(prev);
15098c2ecf20Sopenharmony_ci		break;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	case ISP_PIPELINE_STREAM_STOPPED:
15128c2ecf20Sopenharmony_ci	default:
15138c2ecf20Sopenharmony_ci		return;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci/*
15188c2ecf20Sopenharmony_ci * omap3isp_preview_isr - ISP preview engine interrupt handler
15198c2ecf20Sopenharmony_ci *
15208c2ecf20Sopenharmony_ci * Manage the preview engine video buffers and configure shadowed registers.
15218c2ecf20Sopenharmony_ci */
15228c2ecf20Sopenharmony_civoid omap3isp_preview_isr(struct isp_prev_device *prev)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	unsigned long flags;
15258c2ecf20Sopenharmony_ci	u32 update;
15268c2ecf20Sopenharmony_ci	u32 active;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
15298c2ecf20Sopenharmony_ci		return;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
15328c2ecf20Sopenharmony_ci	preview_params_switch(prev);
15338c2ecf20Sopenharmony_ci	update = preview_params_lock(prev, 0, false);
15348c2ecf20Sopenharmony_ci	active = prev->params.active;
15358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	preview_setup_hw(prev, update, active);
15388c2ecf20Sopenharmony_ci	preview_config_input_size(prev, active);
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_MEMORY ||
15418c2ecf20Sopenharmony_ci	    prev->output & PREVIEW_OUTPUT_MEMORY)
15428c2ecf20Sopenharmony_ci		preview_isr_buffer(prev);
15438c2ecf20Sopenharmony_ci	else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
15448c2ecf20Sopenharmony_ci		preview_enable_oneshot(prev);
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prev->params.lock, flags);
15478c2ecf20Sopenharmony_ci	preview_params_unlock(prev, update, false);
15488c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prev->params.lock, flags);
15498c2ecf20Sopenharmony_ci}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
15528c2ecf20Sopenharmony_ci * ISP video operations
15538c2ecf20Sopenharmony_ci */
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_cistatic int preview_video_queue(struct isp_video *video,
15568c2ecf20Sopenharmony_ci			       struct isp_buffer *buffer)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = &video->isp->isp_prev;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
15618c2ecf20Sopenharmony_ci		preview_set_inaddr(prev, buffer->dma);
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
15648c2ecf20Sopenharmony_ci		preview_set_outaddr(prev, buffer->dma);
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	return 0;
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic const struct isp_video_operations preview_video_ops = {
15708c2ecf20Sopenharmony_ci	.queue = preview_video_queue,
15718c2ecf20Sopenharmony_ci};
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
15748c2ecf20Sopenharmony_ci * V4L2 subdev operations
15758c2ecf20Sopenharmony_ci */
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci/*
15788c2ecf20Sopenharmony_ci * preview_s_ctrl - Handle set control subdev method
15798c2ecf20Sopenharmony_ci * @ctrl: pointer to v4l2 control structure
15808c2ecf20Sopenharmony_ci */
15818c2ecf20Sopenharmony_cistatic int preview_s_ctrl(struct v4l2_ctrl *ctrl)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	struct isp_prev_device *prev =
15848c2ecf20Sopenharmony_ci		container_of(ctrl->handler, struct isp_prev_device, ctrls);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	switch (ctrl->id) {
15878c2ecf20Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
15888c2ecf20Sopenharmony_ci		preview_update_brightness(prev, ctrl->val);
15898c2ecf20Sopenharmony_ci		break;
15908c2ecf20Sopenharmony_ci	case V4L2_CID_CONTRAST:
15918c2ecf20Sopenharmony_ci		preview_update_contrast(prev, ctrl->val);
15928c2ecf20Sopenharmony_ci		break;
15938c2ecf20Sopenharmony_ci	}
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	return 0;
15968c2ecf20Sopenharmony_ci}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops preview_ctrl_ops = {
15998c2ecf20Sopenharmony_ci	.s_ctrl = preview_s_ctrl,
16008c2ecf20Sopenharmony_ci};
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci/*
16038c2ecf20Sopenharmony_ci * preview_ioctl - Handle preview module private ioctl's
16048c2ecf20Sopenharmony_ci * @sd: pointer to v4l2 subdev structure
16058c2ecf20Sopenharmony_ci * @cmd: configuration command
16068c2ecf20Sopenharmony_ci * @arg: configuration argument
16078c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
16088c2ecf20Sopenharmony_ci */
16098c2ecf20Sopenharmony_cistatic long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	switch (cmd) {
16148c2ecf20Sopenharmony_ci	case VIDIOC_OMAP3ISP_PRV_CFG:
16158c2ecf20Sopenharmony_ci		return preview_config(prev, arg);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	default:
16188c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci/*
16238c2ecf20Sopenharmony_ci * preview_set_stream - Enable/Disable streaming on preview subdev
16248c2ecf20Sopenharmony_ci * @sd    : pointer to v4l2 subdev structure
16258c2ecf20Sopenharmony_ci * @enable: 1 == Enable, 0 == Disable
16268c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
16278c2ecf20Sopenharmony_ci */
16288c2ecf20Sopenharmony_cistatic int preview_set_stream(struct v4l2_subdev *sd, int enable)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
16318c2ecf20Sopenharmony_ci	struct isp_video *video_out = &prev->video_out;
16328c2ecf20Sopenharmony_ci	struct isp_device *isp = to_isp_device(prev);
16338c2ecf20Sopenharmony_ci	struct device *dev = to_device(prev);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
16368c2ecf20Sopenharmony_ci		if (enable == ISP_PIPELINE_STREAM_STOPPED)
16378c2ecf20Sopenharmony_ci			return 0;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci		omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
16408c2ecf20Sopenharmony_ci		preview_configure(prev);
16418c2ecf20Sopenharmony_ci		atomic_set(&prev->stopping, 0);
16428c2ecf20Sopenharmony_ci		preview_print_status(prev);
16438c2ecf20Sopenharmony_ci	}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	switch (enable) {
16468c2ecf20Sopenharmony_ci	case ISP_PIPELINE_STREAM_CONTINUOUS:
16478c2ecf20Sopenharmony_ci		if (prev->output & PREVIEW_OUTPUT_MEMORY)
16488c2ecf20Sopenharmony_ci			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci		if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
16518c2ecf20Sopenharmony_ci		    !(prev->output & PREVIEW_OUTPUT_MEMORY))
16528c2ecf20Sopenharmony_ci			preview_enable_oneshot(prev);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci		isp_video_dmaqueue_flags_clr(video_out);
16558c2ecf20Sopenharmony_ci		break;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	case ISP_PIPELINE_STREAM_SINGLESHOT:
16588c2ecf20Sopenharmony_ci		if (prev->input == PREVIEW_INPUT_MEMORY)
16598c2ecf20Sopenharmony_ci			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
16608c2ecf20Sopenharmony_ci		if (prev->output & PREVIEW_OUTPUT_MEMORY)
16618c2ecf20Sopenharmony_ci			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci		preview_enable_oneshot(prev);
16648c2ecf20Sopenharmony_ci		break;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	case ISP_PIPELINE_STREAM_STOPPED:
16678c2ecf20Sopenharmony_ci		if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
16688c2ecf20Sopenharmony_ci					      &prev->stopping))
16698c2ecf20Sopenharmony_ci			dev_dbg(dev, "%s: stop timeout.\n", sd->name);
16708c2ecf20Sopenharmony_ci		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
16718c2ecf20Sopenharmony_ci		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
16728c2ecf20Sopenharmony_ci		omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
16738c2ecf20Sopenharmony_ci		isp_video_dmaqueue_flags_clr(video_out);
16748c2ecf20Sopenharmony_ci		break;
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	prev->state = enable;
16788c2ecf20Sopenharmony_ci	return 0;
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt *
16828c2ecf20Sopenharmony_ci__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
16838c2ecf20Sopenharmony_ci		     unsigned int pad, enum v4l2_subdev_format_whence which)
16848c2ecf20Sopenharmony_ci{
16858c2ecf20Sopenharmony_ci	if (which == V4L2_SUBDEV_FORMAT_TRY)
16868c2ecf20Sopenharmony_ci		return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad);
16878c2ecf20Sopenharmony_ci	else
16888c2ecf20Sopenharmony_ci		return &prev->formats[pad];
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_cistatic struct v4l2_rect *
16928c2ecf20Sopenharmony_ci__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
16938c2ecf20Sopenharmony_ci		   enum v4l2_subdev_format_whence which)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	if (which == V4L2_SUBDEV_FORMAT_TRY)
16968c2ecf20Sopenharmony_ci		return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK);
16978c2ecf20Sopenharmony_ci	else
16988c2ecf20Sopenharmony_ci		return &prev->crop;
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci/* previewer format descriptions */
17028c2ecf20Sopenharmony_cistatic const unsigned int preview_input_fmts[] = {
17038c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_Y8_1X8,
17048c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SGRBG8_1X8,
17058c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SRGGB8_1X8,
17068c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SBGGR8_1X8,
17078c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SGBRG8_1X8,
17088c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_Y10_1X10,
17098c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SGRBG10_1X10,
17108c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SRGGB10_1X10,
17118c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SBGGR10_1X10,
17128c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_SGBRG10_1X10,
17138c2ecf20Sopenharmony_ci};
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_cistatic const unsigned int preview_output_fmts[] = {
17168c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_UYVY8_1X16,
17178c2ecf20Sopenharmony_ci	MEDIA_BUS_FMT_YUYV8_1X16,
17188c2ecf20Sopenharmony_ci};
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci/*
17218c2ecf20Sopenharmony_ci * preview_try_format - Validate a format
17228c2ecf20Sopenharmony_ci * @prev: ISP preview engine
17238c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
17248c2ecf20Sopenharmony_ci * @pad: pad number
17258c2ecf20Sopenharmony_ci * @fmt: format to be validated
17268c2ecf20Sopenharmony_ci * @which: try/active format selector
17278c2ecf20Sopenharmony_ci *
17288c2ecf20Sopenharmony_ci * Validate and adjust the given format for the given pad based on the preview
17298c2ecf20Sopenharmony_ci * engine limits and the format and crop rectangles on other pads.
17308c2ecf20Sopenharmony_ci */
17318c2ecf20Sopenharmony_cistatic void preview_try_format(struct isp_prev_device *prev,
17328c2ecf20Sopenharmony_ci			       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
17338c2ecf20Sopenharmony_ci			       struct v4l2_mbus_framefmt *fmt,
17348c2ecf20Sopenharmony_ci			       enum v4l2_subdev_format_whence which)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	u32 pixelcode;
17378c2ecf20Sopenharmony_ci	struct v4l2_rect *crop;
17388c2ecf20Sopenharmony_ci	unsigned int i;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	switch (pad) {
17418c2ecf20Sopenharmony_ci	case PREV_PAD_SINK:
17428c2ecf20Sopenharmony_ci		/* When reading data from the CCDC, the input size has already
17438c2ecf20Sopenharmony_ci		 * been mangled by the CCDC output pad so it can be accepted
17448c2ecf20Sopenharmony_ci		 * as-is.
17458c2ecf20Sopenharmony_ci		 *
17468c2ecf20Sopenharmony_ci		 * When reading data from memory, clamp the requested width and
17478c2ecf20Sopenharmony_ci		 * height. The TRM doesn't specify a minimum input height, make
17488c2ecf20Sopenharmony_ci		 * sure we got enough lines to enable the noise filter and color
17498c2ecf20Sopenharmony_ci		 * filter array interpolation.
17508c2ecf20Sopenharmony_ci		 */
17518c2ecf20Sopenharmony_ci		if (prev->input == PREVIEW_INPUT_MEMORY) {
17528c2ecf20Sopenharmony_ci			fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
17538c2ecf20Sopenharmony_ci					     preview_max_out_width(prev));
17548c2ecf20Sopenharmony_ci			fmt->height = clamp_t(u32, fmt->height,
17558c2ecf20Sopenharmony_ci					      PREV_MIN_IN_HEIGHT,
17568c2ecf20Sopenharmony_ci					      PREV_MAX_IN_HEIGHT);
17578c2ecf20Sopenharmony_ci		}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci		fmt->colorspace = V4L2_COLORSPACE_SRGB;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
17628c2ecf20Sopenharmony_ci			if (fmt->code == preview_input_fmts[i])
17638c2ecf20Sopenharmony_ci				break;
17648c2ecf20Sopenharmony_ci		}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci		/* If not found, use SGRBG10 as default */
17678c2ecf20Sopenharmony_ci		if (i >= ARRAY_SIZE(preview_input_fmts))
17688c2ecf20Sopenharmony_ci			fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
17698c2ecf20Sopenharmony_ci		break;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	case PREV_PAD_SOURCE:
17728c2ecf20Sopenharmony_ci		pixelcode = fmt->code;
17738c2ecf20Sopenharmony_ci		*fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci		switch (pixelcode) {
17768c2ecf20Sopenharmony_ci		case MEDIA_BUS_FMT_YUYV8_1X16:
17778c2ecf20Sopenharmony_ci		case MEDIA_BUS_FMT_UYVY8_1X16:
17788c2ecf20Sopenharmony_ci			fmt->code = pixelcode;
17798c2ecf20Sopenharmony_ci			break;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci		default:
17828c2ecf20Sopenharmony_ci			fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
17838c2ecf20Sopenharmony_ci			break;
17848c2ecf20Sopenharmony_ci		}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci		/* The preview module output size is configurable through the
17878c2ecf20Sopenharmony_ci		 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
17888c2ecf20Sopenharmony_ci		 * is not supported yet, hardcode the output size to the crop
17898c2ecf20Sopenharmony_ci		 * rectangle size.
17908c2ecf20Sopenharmony_ci		 */
17918c2ecf20Sopenharmony_ci		crop = __preview_get_crop(prev, cfg, which);
17928c2ecf20Sopenharmony_ci		fmt->width = crop->width;
17938c2ecf20Sopenharmony_ci		fmt->height = crop->height;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		fmt->colorspace = V4L2_COLORSPACE_JPEG;
17968c2ecf20Sopenharmony_ci		break;
17978c2ecf20Sopenharmony_ci	}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	fmt->field = V4L2_FIELD_NONE;
18008c2ecf20Sopenharmony_ci}
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci/*
18038c2ecf20Sopenharmony_ci * preview_try_crop - Validate a crop rectangle
18048c2ecf20Sopenharmony_ci * @prev: ISP preview engine
18058c2ecf20Sopenharmony_ci * @sink: format on the sink pad
18068c2ecf20Sopenharmony_ci * @crop: crop rectangle to be validated
18078c2ecf20Sopenharmony_ci *
18088c2ecf20Sopenharmony_ci * The preview engine crops lines and columns for its internal operation,
18098c2ecf20Sopenharmony_ci * depending on which filters are enabled. Enforce minimum crop margins to
18108c2ecf20Sopenharmony_ci * handle that transparently for userspace.
18118c2ecf20Sopenharmony_ci *
18128c2ecf20Sopenharmony_ci * See the explanation at the PREV_MARGIN_* definitions for more details.
18138c2ecf20Sopenharmony_ci */
18148c2ecf20Sopenharmony_cistatic void preview_try_crop(struct isp_prev_device *prev,
18158c2ecf20Sopenharmony_ci			     const struct v4l2_mbus_framefmt *sink,
18168c2ecf20Sopenharmony_ci			     struct v4l2_rect *crop)
18178c2ecf20Sopenharmony_ci{
18188c2ecf20Sopenharmony_ci	unsigned int left = PREV_MARGIN_LEFT;
18198c2ecf20Sopenharmony_ci	unsigned int right = sink->width - PREV_MARGIN_RIGHT;
18208c2ecf20Sopenharmony_ci	unsigned int top = PREV_MARGIN_TOP;
18218c2ecf20Sopenharmony_ci	unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	/* When processing data on-the-fly from the CCDC, at least 2 pixels must
18248c2ecf20Sopenharmony_ci	 * be cropped from the left and right sides of the image. As we don't
18258c2ecf20Sopenharmony_ci	 * know which filters will be enabled, increase the left and right
18268c2ecf20Sopenharmony_ci	 * margins by two.
18278c2ecf20Sopenharmony_ci	 */
18288c2ecf20Sopenharmony_ci	if (prev->input == PREVIEW_INPUT_CCDC) {
18298c2ecf20Sopenharmony_ci		left += 2;
18308c2ecf20Sopenharmony_ci		right -= 2;
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	/* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines
18348c2ecf20Sopenharmony_ci	 * and no columns in other modes. Increase the margins based on the sink
18358c2ecf20Sopenharmony_ci	 * format.
18368c2ecf20Sopenharmony_ci	 */
18378c2ecf20Sopenharmony_ci	if (sink->code != MEDIA_BUS_FMT_Y8_1X8 &&
18388c2ecf20Sopenharmony_ci	    sink->code != MEDIA_BUS_FMT_Y10_1X10) {
18398c2ecf20Sopenharmony_ci		left += 2;
18408c2ecf20Sopenharmony_ci		right -= 2;
18418c2ecf20Sopenharmony_ci		top += 2;
18428c2ecf20Sopenharmony_ci		bottom -= 2;
18438c2ecf20Sopenharmony_ci	}
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	/* Restrict left/top to even values to keep the Bayer pattern. */
18468c2ecf20Sopenharmony_ci	crop->left &= ~1;
18478c2ecf20Sopenharmony_ci	crop->top &= ~1;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
18508c2ecf20Sopenharmony_ci	crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
18518c2ecf20Sopenharmony_ci	crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
18528c2ecf20Sopenharmony_ci			      right - crop->left);
18538c2ecf20Sopenharmony_ci	crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
18548c2ecf20Sopenharmony_ci			       bottom - crop->top);
18558c2ecf20Sopenharmony_ci}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci/*
18588c2ecf20Sopenharmony_ci * preview_enum_mbus_code - Handle pixel format enumeration
18598c2ecf20Sopenharmony_ci * @sd     : pointer to v4l2 subdev structure
18608c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
18618c2ecf20Sopenharmony_ci * @code   : pointer to v4l2_subdev_mbus_code_enum structure
18628c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
18638c2ecf20Sopenharmony_ci */
18648c2ecf20Sopenharmony_cistatic int preview_enum_mbus_code(struct v4l2_subdev *sd,
18658c2ecf20Sopenharmony_ci				  struct v4l2_subdev_pad_config *cfg,
18668c2ecf20Sopenharmony_ci				  struct v4l2_subdev_mbus_code_enum *code)
18678c2ecf20Sopenharmony_ci{
18688c2ecf20Sopenharmony_ci	switch (code->pad) {
18698c2ecf20Sopenharmony_ci	case PREV_PAD_SINK:
18708c2ecf20Sopenharmony_ci		if (code->index >= ARRAY_SIZE(preview_input_fmts))
18718c2ecf20Sopenharmony_ci			return -EINVAL;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci		code->code = preview_input_fmts[code->index];
18748c2ecf20Sopenharmony_ci		break;
18758c2ecf20Sopenharmony_ci	case PREV_PAD_SOURCE:
18768c2ecf20Sopenharmony_ci		if (code->index >= ARRAY_SIZE(preview_output_fmts))
18778c2ecf20Sopenharmony_ci			return -EINVAL;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci		code->code = preview_output_fmts[code->index];
18808c2ecf20Sopenharmony_ci		break;
18818c2ecf20Sopenharmony_ci	default:
18828c2ecf20Sopenharmony_ci		return -EINVAL;
18838c2ecf20Sopenharmony_ci	}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	return 0;
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic int preview_enum_frame_size(struct v4l2_subdev *sd,
18898c2ecf20Sopenharmony_ci				   struct v4l2_subdev_pad_config *cfg,
18908c2ecf20Sopenharmony_ci				   struct v4l2_subdev_frame_size_enum *fse)
18918c2ecf20Sopenharmony_ci{
18928c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
18938c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt format;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if (fse->index != 0)
18968c2ecf20Sopenharmony_ci		return -EINVAL;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	format.code = fse->code;
18998c2ecf20Sopenharmony_ci	format.width = 1;
19008c2ecf20Sopenharmony_ci	format.height = 1;
19018c2ecf20Sopenharmony_ci	preview_try_format(prev, cfg, fse->pad, &format, fse->which);
19028c2ecf20Sopenharmony_ci	fse->min_width = format.width;
19038c2ecf20Sopenharmony_ci	fse->min_height = format.height;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	if (format.code != fse->code)
19068c2ecf20Sopenharmony_ci		return -EINVAL;
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	format.code = fse->code;
19098c2ecf20Sopenharmony_ci	format.width = -1;
19108c2ecf20Sopenharmony_ci	format.height = -1;
19118c2ecf20Sopenharmony_ci	preview_try_format(prev, cfg, fse->pad, &format, fse->which);
19128c2ecf20Sopenharmony_ci	fse->max_width = format.width;
19138c2ecf20Sopenharmony_ci	fse->max_height = format.height;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	return 0;
19168c2ecf20Sopenharmony_ci}
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci/*
19198c2ecf20Sopenharmony_ci * preview_get_selection - Retrieve a selection rectangle on a pad
19208c2ecf20Sopenharmony_ci * @sd: ISP preview V4L2 subdevice
19218c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
19228c2ecf20Sopenharmony_ci * @sel: Selection rectangle
19238c2ecf20Sopenharmony_ci *
19248c2ecf20Sopenharmony_ci * The only supported rectangles are the crop rectangles on the sink pad.
19258c2ecf20Sopenharmony_ci *
19268c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise.
19278c2ecf20Sopenharmony_ci */
19288c2ecf20Sopenharmony_cistatic int preview_get_selection(struct v4l2_subdev *sd,
19298c2ecf20Sopenharmony_ci				 struct v4l2_subdev_pad_config *cfg,
19308c2ecf20Sopenharmony_ci				 struct v4l2_subdev_selection *sel)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
19338c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	if (sel->pad != PREV_PAD_SINK)
19368c2ecf20Sopenharmony_ci		return -EINVAL;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	switch (sel->target) {
19398c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
19408c2ecf20Sopenharmony_ci		sel->r.left = 0;
19418c2ecf20Sopenharmony_ci		sel->r.top = 0;
19428c2ecf20Sopenharmony_ci		sel->r.width = INT_MAX;
19438c2ecf20Sopenharmony_ci		sel->r.height = INT_MAX;
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci		format = __preview_get_format(prev, cfg, PREV_PAD_SINK,
19468c2ecf20Sopenharmony_ci					      sel->which);
19478c2ecf20Sopenharmony_ci		preview_try_crop(prev, format, &sel->r);
19488c2ecf20Sopenharmony_ci		break;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP:
19518c2ecf20Sopenharmony_ci		sel->r = *__preview_get_crop(prev, cfg, sel->which);
19528c2ecf20Sopenharmony_ci		break;
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	default:
19558c2ecf20Sopenharmony_ci		return -EINVAL;
19568c2ecf20Sopenharmony_ci	}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	return 0;
19598c2ecf20Sopenharmony_ci}
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci/*
19628c2ecf20Sopenharmony_ci * preview_set_selection - Set a selection rectangle on a pad
19638c2ecf20Sopenharmony_ci * @sd: ISP preview V4L2 subdevice
19648c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
19658c2ecf20Sopenharmony_ci * @sel: Selection rectangle
19668c2ecf20Sopenharmony_ci *
19678c2ecf20Sopenharmony_ci * The only supported rectangle is the actual crop rectangle on the sink pad.
19688c2ecf20Sopenharmony_ci *
19698c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise.
19708c2ecf20Sopenharmony_ci */
19718c2ecf20Sopenharmony_cistatic int preview_set_selection(struct v4l2_subdev *sd,
19728c2ecf20Sopenharmony_ci				 struct v4l2_subdev_pad_config *cfg,
19738c2ecf20Sopenharmony_ci				 struct v4l2_subdev_selection *sel)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
19768c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (sel->target != V4L2_SEL_TGT_CROP ||
19798c2ecf20Sopenharmony_ci	    sel->pad != PREV_PAD_SINK)
19808c2ecf20Sopenharmony_ci		return -EINVAL;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	/* The crop rectangle can't be changed while streaming. */
19838c2ecf20Sopenharmony_ci	if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
19848c2ecf20Sopenharmony_ci		return -EBUSY;
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	/* Modifying the crop rectangle always changes the format on the source
19878c2ecf20Sopenharmony_ci	 * pad. If the KEEP_CONFIG flag is set, just return the current crop
19888c2ecf20Sopenharmony_ci	 * rectangle.
19898c2ecf20Sopenharmony_ci	 */
19908c2ecf20Sopenharmony_ci	if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
19918c2ecf20Sopenharmony_ci		sel->r = *__preview_get_crop(prev, cfg, sel->which);
19928c2ecf20Sopenharmony_ci		return 0;
19938c2ecf20Sopenharmony_ci	}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which);
19968c2ecf20Sopenharmony_ci	preview_try_crop(prev, format, &sel->r);
19978c2ecf20Sopenharmony_ci	*__preview_get_crop(prev, cfg, sel->which) = sel->r;
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	/* Update the source format. */
20008c2ecf20Sopenharmony_ci	format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which);
20018c2ecf20Sopenharmony_ci	preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	return 0;
20048c2ecf20Sopenharmony_ci}
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci/*
20078c2ecf20Sopenharmony_ci * preview_get_format - Handle get format by pads subdev method
20088c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure
20098c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
20108c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure
20118c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
20128c2ecf20Sopenharmony_ci */
20138c2ecf20Sopenharmony_cistatic int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
20148c2ecf20Sopenharmony_ci			      struct v4l2_subdev_format *fmt)
20158c2ecf20Sopenharmony_ci{
20168c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
20178c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
20208c2ecf20Sopenharmony_ci	if (format == NULL)
20218c2ecf20Sopenharmony_ci		return -EINVAL;
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	fmt->format = *format;
20248c2ecf20Sopenharmony_ci	return 0;
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci/*
20288c2ecf20Sopenharmony_ci * preview_set_format - Handle set format by pads subdev method
20298c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure
20308c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
20318c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure
20328c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
20338c2ecf20Sopenharmony_ci */
20348c2ecf20Sopenharmony_cistatic int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
20358c2ecf20Sopenharmony_ci			      struct v4l2_subdev_format *fmt)
20368c2ecf20Sopenharmony_ci{
20378c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
20388c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
20398c2ecf20Sopenharmony_ci	struct v4l2_rect *crop;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
20428c2ecf20Sopenharmony_ci	if (format == NULL)
20438c2ecf20Sopenharmony_ci		return -EINVAL;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which);
20468c2ecf20Sopenharmony_ci	*format = fmt->format;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	/* Propagate the format from sink to source */
20498c2ecf20Sopenharmony_ci	if (fmt->pad == PREV_PAD_SINK) {
20508c2ecf20Sopenharmony_ci		/* Reset the crop rectangle. */
20518c2ecf20Sopenharmony_ci		crop = __preview_get_crop(prev, cfg, fmt->which);
20528c2ecf20Sopenharmony_ci		crop->left = 0;
20538c2ecf20Sopenharmony_ci		crop->top = 0;
20548c2ecf20Sopenharmony_ci		crop->width = fmt->format.width;
20558c2ecf20Sopenharmony_ci		crop->height = fmt->format.height;
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci		preview_try_crop(prev, &fmt->format, crop);
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci		/* Update the source format. */
20608c2ecf20Sopenharmony_ci		format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE,
20618c2ecf20Sopenharmony_ci					      fmt->which);
20628c2ecf20Sopenharmony_ci		preview_try_format(prev, cfg, PREV_PAD_SOURCE, format,
20638c2ecf20Sopenharmony_ci				   fmt->which);
20648c2ecf20Sopenharmony_ci	}
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	return 0;
20678c2ecf20Sopenharmony_ci}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci/*
20708c2ecf20Sopenharmony_ci * preview_init_formats - Initialize formats on all pads
20718c2ecf20Sopenharmony_ci * @sd: ISP preview V4L2 subdevice
20728c2ecf20Sopenharmony_ci * @fh: V4L2 subdev file handle
20738c2ecf20Sopenharmony_ci *
20748c2ecf20Sopenharmony_ci * Initialize all pad formats with default values. If fh is not NULL, try
20758c2ecf20Sopenharmony_ci * formats are initialized on the file handle. Otherwise active formats are
20768c2ecf20Sopenharmony_ci * initialized on the device.
20778c2ecf20Sopenharmony_ci */
20788c2ecf20Sopenharmony_cistatic int preview_init_formats(struct v4l2_subdev *sd,
20798c2ecf20Sopenharmony_ci				struct v4l2_subdev_fh *fh)
20808c2ecf20Sopenharmony_ci{
20818c2ecf20Sopenharmony_ci	struct v4l2_subdev_format format;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	memset(&format, 0, sizeof(format));
20848c2ecf20Sopenharmony_ci	format.pad = PREV_PAD_SINK;
20858c2ecf20Sopenharmony_ci	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
20868c2ecf20Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
20878c2ecf20Sopenharmony_ci	format.format.width = 4096;
20888c2ecf20Sopenharmony_ci	format.format.height = 4096;
20898c2ecf20Sopenharmony_ci	preview_set_format(sd, fh ? fh->pad : NULL, &format);
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci	return 0;
20928c2ecf20Sopenharmony_ci}
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci/* subdev core operations */
20958c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
20968c2ecf20Sopenharmony_ci	.ioctl = preview_ioctl,
20978c2ecf20Sopenharmony_ci};
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci/* subdev video operations */
21008c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
21018c2ecf20Sopenharmony_ci	.s_stream = preview_set_stream,
21028c2ecf20Sopenharmony_ci};
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci/* subdev pad operations */
21058c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
21068c2ecf20Sopenharmony_ci	.enum_mbus_code = preview_enum_mbus_code,
21078c2ecf20Sopenharmony_ci	.enum_frame_size = preview_enum_frame_size,
21088c2ecf20Sopenharmony_ci	.get_fmt = preview_get_format,
21098c2ecf20Sopenharmony_ci	.set_fmt = preview_set_format,
21108c2ecf20Sopenharmony_ci	.get_selection = preview_get_selection,
21118c2ecf20Sopenharmony_ci	.set_selection = preview_set_selection,
21128c2ecf20Sopenharmony_ci};
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci/* subdev operations */
21158c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops preview_v4l2_ops = {
21168c2ecf20Sopenharmony_ci	.core = &preview_v4l2_core_ops,
21178c2ecf20Sopenharmony_ci	.video = &preview_v4l2_video_ops,
21188c2ecf20Sopenharmony_ci	.pad = &preview_v4l2_pad_ops,
21198c2ecf20Sopenharmony_ci};
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci/* subdev internal operations */
21228c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
21238c2ecf20Sopenharmony_ci	.open = preview_init_formats,
21248c2ecf20Sopenharmony_ci};
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
21278c2ecf20Sopenharmony_ci * Media entity operations
21288c2ecf20Sopenharmony_ci */
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci/*
21318c2ecf20Sopenharmony_ci * preview_link_setup - Setup previewer connections.
21328c2ecf20Sopenharmony_ci * @entity : Pointer to media entity structure
21338c2ecf20Sopenharmony_ci * @local  : Pointer to local pad array
21348c2ecf20Sopenharmony_ci * @remote : Pointer to remote pad array
21358c2ecf20Sopenharmony_ci * @flags  : Link flags
21368c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
21378c2ecf20Sopenharmony_ci */
21388c2ecf20Sopenharmony_cistatic int preview_link_setup(struct media_entity *entity,
21398c2ecf20Sopenharmony_ci			      const struct media_pad *local,
21408c2ecf20Sopenharmony_ci			      const struct media_pad *remote, u32 flags)
21418c2ecf20Sopenharmony_ci{
21428c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
21438c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
21448c2ecf20Sopenharmony_ci	unsigned int index = local->index;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	/* FIXME: this is actually a hack! */
21478c2ecf20Sopenharmony_ci	if (is_media_entity_v4l2_subdev(remote->entity))
21488c2ecf20Sopenharmony_ci		index |= 2 << 16;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	switch (index) {
21518c2ecf20Sopenharmony_ci	case PREV_PAD_SINK:
21528c2ecf20Sopenharmony_ci		/* read from memory */
21538c2ecf20Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
21548c2ecf20Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_CCDC)
21558c2ecf20Sopenharmony_ci				return -EBUSY;
21568c2ecf20Sopenharmony_ci			prev->input = PREVIEW_INPUT_MEMORY;
21578c2ecf20Sopenharmony_ci		} else {
21588c2ecf20Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_MEMORY)
21598c2ecf20Sopenharmony_ci				prev->input = PREVIEW_INPUT_NONE;
21608c2ecf20Sopenharmony_ci		}
21618c2ecf20Sopenharmony_ci		break;
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	case PREV_PAD_SINK | 2 << 16:
21648c2ecf20Sopenharmony_ci		/* read from ccdc */
21658c2ecf20Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
21668c2ecf20Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_MEMORY)
21678c2ecf20Sopenharmony_ci				return -EBUSY;
21688c2ecf20Sopenharmony_ci			prev->input = PREVIEW_INPUT_CCDC;
21698c2ecf20Sopenharmony_ci		} else {
21708c2ecf20Sopenharmony_ci			if (prev->input == PREVIEW_INPUT_CCDC)
21718c2ecf20Sopenharmony_ci				prev->input = PREVIEW_INPUT_NONE;
21728c2ecf20Sopenharmony_ci		}
21738c2ecf20Sopenharmony_ci		break;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	/*
21768c2ecf20Sopenharmony_ci	 * The ISP core doesn't support pipelines with multiple video outputs.
21778c2ecf20Sopenharmony_ci	 * Revisit this when it will be implemented, and return -EBUSY for now.
21788c2ecf20Sopenharmony_ci	 */
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	case PREV_PAD_SOURCE:
21818c2ecf20Sopenharmony_ci		/* write to memory */
21828c2ecf20Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
21838c2ecf20Sopenharmony_ci			if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
21848c2ecf20Sopenharmony_ci				return -EBUSY;
21858c2ecf20Sopenharmony_ci			prev->output |= PREVIEW_OUTPUT_MEMORY;
21868c2ecf20Sopenharmony_ci		} else {
21878c2ecf20Sopenharmony_ci			prev->output &= ~PREVIEW_OUTPUT_MEMORY;
21888c2ecf20Sopenharmony_ci		}
21898c2ecf20Sopenharmony_ci		break;
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	case PREV_PAD_SOURCE | 2 << 16:
21928c2ecf20Sopenharmony_ci		/* write to resizer */
21938c2ecf20Sopenharmony_ci		if (flags & MEDIA_LNK_FL_ENABLED) {
21948c2ecf20Sopenharmony_ci			if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
21958c2ecf20Sopenharmony_ci				return -EBUSY;
21968c2ecf20Sopenharmony_ci			prev->output |= PREVIEW_OUTPUT_RESIZER;
21978c2ecf20Sopenharmony_ci		} else {
21988c2ecf20Sopenharmony_ci			prev->output &= ~PREVIEW_OUTPUT_RESIZER;
21998c2ecf20Sopenharmony_ci		}
22008c2ecf20Sopenharmony_ci		break;
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	default:
22038c2ecf20Sopenharmony_ci		return -EINVAL;
22048c2ecf20Sopenharmony_ci	}
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	return 0;
22078c2ecf20Sopenharmony_ci}
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci/* media operations */
22108c2ecf20Sopenharmony_cistatic const struct media_entity_operations preview_media_ops = {
22118c2ecf20Sopenharmony_ci	.link_setup = preview_link_setup,
22128c2ecf20Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
22138c2ecf20Sopenharmony_ci};
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_civoid omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
22168c2ecf20Sopenharmony_ci{
22178c2ecf20Sopenharmony_ci	v4l2_device_unregister_subdev(&prev->subdev);
22188c2ecf20Sopenharmony_ci	omap3isp_video_unregister(&prev->video_in);
22198c2ecf20Sopenharmony_ci	omap3isp_video_unregister(&prev->video_out);
22208c2ecf20Sopenharmony_ci}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ciint omap3isp_preview_register_entities(struct isp_prev_device *prev,
22238c2ecf20Sopenharmony_ci	struct v4l2_device *vdev)
22248c2ecf20Sopenharmony_ci{
22258c2ecf20Sopenharmony_ci	int ret;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	/* Register the subdev and video nodes. */
22288c2ecf20Sopenharmony_ci	prev->subdev.dev = vdev->mdev->dev;
22298c2ecf20Sopenharmony_ci	ret = v4l2_device_register_subdev(vdev, &prev->subdev);
22308c2ecf20Sopenharmony_ci	if (ret < 0)
22318c2ecf20Sopenharmony_ci		goto error;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	ret = omap3isp_video_register(&prev->video_in, vdev);
22348c2ecf20Sopenharmony_ci	if (ret < 0)
22358c2ecf20Sopenharmony_ci		goto error;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	ret = omap3isp_video_register(&prev->video_out, vdev);
22388c2ecf20Sopenharmony_ci	if (ret < 0)
22398c2ecf20Sopenharmony_ci		goto error;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	return 0;
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_cierror:
22448c2ecf20Sopenharmony_ci	omap3isp_preview_unregister_entities(prev);
22458c2ecf20Sopenharmony_ci	return ret;
22468c2ecf20Sopenharmony_ci}
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
22498c2ecf20Sopenharmony_ci * ISP previewer initialisation and cleanup
22508c2ecf20Sopenharmony_ci */
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci/*
22538c2ecf20Sopenharmony_ci * preview_init_entities - Initialize subdev and media entity.
22548c2ecf20Sopenharmony_ci * @prev : Pointer to preview structure
22558c2ecf20Sopenharmony_ci * return -ENOMEM or zero on success
22568c2ecf20Sopenharmony_ci */
22578c2ecf20Sopenharmony_cistatic int preview_init_entities(struct isp_prev_device *prev)
22588c2ecf20Sopenharmony_ci{
22598c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = &prev->subdev;
22608c2ecf20Sopenharmony_ci	struct media_pad *pads = prev->pads;
22618c2ecf20Sopenharmony_ci	struct media_entity *me = &sd->entity;
22628c2ecf20Sopenharmony_ci	int ret;
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	prev->input = PREVIEW_INPUT_NONE;
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	v4l2_subdev_init(sd, &preview_v4l2_ops);
22678c2ecf20Sopenharmony_ci	sd->internal_ops = &preview_v4l2_internal_ops;
22688c2ecf20Sopenharmony_ci	strscpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
22698c2ecf20Sopenharmony_ci	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
22708c2ecf20Sopenharmony_ci	v4l2_set_subdevdata(sd, prev);
22718c2ecf20Sopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(&prev->ctrls, 2);
22748c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
22758c2ecf20Sopenharmony_ci			  ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
22768c2ecf20Sopenharmony_ci			  ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
22778c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
22788c2ecf20Sopenharmony_ci			  ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
22798c2ecf20Sopenharmony_ci			  ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
22808c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_setup(&prev->ctrls);
22818c2ecf20Sopenharmony_ci	sd->ctrl_handler = &prev->ctrls;
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK
22848c2ecf20Sopenharmony_ci				    | MEDIA_PAD_FL_MUST_CONNECT;
22858c2ecf20Sopenharmony_ci	pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	me->ops = &preview_media_ops;
22888c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(me, PREV_PADS_NUM, pads);
22898c2ecf20Sopenharmony_ci	if (ret < 0)
22908c2ecf20Sopenharmony_ci		goto error_handler_free;
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci	preview_init_formats(sd, NULL);
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	/* According to the OMAP34xx TRM, video buffers need to be aligned on a
22958c2ecf20Sopenharmony_ci	 * 32 bytes boundary. However, an undocumented hardware bug requires a
22968c2ecf20Sopenharmony_ci	 * 64 bytes boundary at the preview engine input.
22978c2ecf20Sopenharmony_ci	 */
22988c2ecf20Sopenharmony_ci	prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
22998c2ecf20Sopenharmony_ci	prev->video_in.ops = &preview_video_ops;
23008c2ecf20Sopenharmony_ci	prev->video_in.isp = to_isp_device(prev);
23018c2ecf20Sopenharmony_ci	prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
23028c2ecf20Sopenharmony_ci	prev->video_in.bpl_alignment = 64;
23038c2ecf20Sopenharmony_ci	prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
23048c2ecf20Sopenharmony_ci	prev->video_out.ops = &preview_video_ops;
23058c2ecf20Sopenharmony_ci	prev->video_out.isp = to_isp_device(prev);
23068c2ecf20Sopenharmony_ci	prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
23078c2ecf20Sopenharmony_ci	prev->video_out.bpl_alignment = 32;
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	ret = omap3isp_video_init(&prev->video_in, "preview");
23108c2ecf20Sopenharmony_ci	if (ret < 0)
23118c2ecf20Sopenharmony_ci		goto error_video_in;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	ret = omap3isp_video_init(&prev->video_out, "preview");
23148c2ecf20Sopenharmony_ci	if (ret < 0)
23158c2ecf20Sopenharmony_ci		goto error_video_out;
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	return 0;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_cierror_video_out:
23208c2ecf20Sopenharmony_ci	omap3isp_video_cleanup(&prev->video_in);
23218c2ecf20Sopenharmony_cierror_video_in:
23228c2ecf20Sopenharmony_ci	media_entity_cleanup(&prev->subdev.entity);
23238c2ecf20Sopenharmony_cierror_handler_free:
23248c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&prev->ctrls);
23258c2ecf20Sopenharmony_ci	return ret;
23268c2ecf20Sopenharmony_ci}
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci/*
23298c2ecf20Sopenharmony_ci * omap3isp_preview_init - Previewer initialization.
23308c2ecf20Sopenharmony_ci * @isp : Pointer to ISP device
23318c2ecf20Sopenharmony_ci * return -ENOMEM or zero on success
23328c2ecf20Sopenharmony_ci */
23338c2ecf20Sopenharmony_ciint omap3isp_preview_init(struct isp_device *isp)
23348c2ecf20Sopenharmony_ci{
23358c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = &isp->isp_prev;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	init_waitqueue_head(&prev->wait);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	preview_init_params(prev);
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	return preview_init_entities(prev);
23428c2ecf20Sopenharmony_ci}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_civoid omap3isp_preview_cleanup(struct isp_device *isp)
23458c2ecf20Sopenharmony_ci{
23468c2ecf20Sopenharmony_ci	struct isp_prev_device *prev = &isp->isp_prev;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&prev->ctrls);
23498c2ecf20Sopenharmony_ci	omap3isp_video_cleanup(&prev->video_in);
23508c2ecf20Sopenharmony_ci	omap3isp_video_cleanup(&prev->video_out);
23518c2ecf20Sopenharmony_ci	media_entity_cleanup(&prev->subdev.entity);
23528c2ecf20Sopenharmony_ci}
2353