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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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