isppreview.c (70112B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * isppreview.c 4 * 5 * TI OMAP3 ISP driver - Preview module 6 * 7 * Copyright (C) 2010 Nokia Corporation 8 * Copyright (C) 2009 Texas Instruments, Inc. 9 * 10 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 11 * Sakari Ailus <sakari.ailus@iki.fi> 12 */ 13 14#include <linux/device.h> 15#include <linux/mm.h> 16#include <linux/module.h> 17#include <linux/mutex.h> 18#include <linux/uaccess.h> 19 20#include "isp.h" 21#include "ispreg.h" 22#include "isppreview.h" 23 24/* Default values in Office Fluorescent Light for RGBtoRGB Blending */ 25static const struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { 26 { /* RGB-RGB Matrix */ 27 {0x01E2, 0x0F30, 0x0FEE}, 28 {0x0F9B, 0x01AC, 0x0FB9}, 29 {0x0FE0, 0x0EC0, 0x0260} 30 }, /* RGB Offset */ 31 {0x0000, 0x0000, 0x0000} 32}; 33 34/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/ 35static const struct omap3isp_prev_csc flr_prev_csc = { 36 { /* CSC Coef Matrix */ 37 {66, 129, 25}, 38 {-38, -75, 112}, 39 {112, -94 , -18} 40 }, /* CSC Offset */ 41 {0x0, 0x0, 0x0} 42}; 43 44/* Default values in Office Fluorescent Light for CFA Gradient*/ 45#define FLR_CFA_GRADTHRS_HORZ 0x28 46#define FLR_CFA_GRADTHRS_VERT 0x28 47 48/* Default values in Office Fluorescent Light for Chroma Suppression*/ 49#define FLR_CSUP_GAIN 0x0D 50#define FLR_CSUP_THRES 0xEB 51 52/* Default values in Office Fluorescent Light for Noise Filter*/ 53#define FLR_NF_STRGTH 0x03 54 55/* Default values for White Balance */ 56#define FLR_WBAL_DGAIN 0x100 57#define FLR_WBAL_COEF 0x20 58 59/* Default values in Office Fluorescent Light for Black Adjustment*/ 60#define FLR_BLKADJ_BLUE 0x0 61#define FLR_BLKADJ_GREEN 0x0 62#define FLR_BLKADJ_RED 0x0 63 64#define DEF_DETECT_CORRECT_VAL 0xe 65 66/* 67 * Margins and image size limits. 68 * 69 * The preview engine crops several rows and columns internally depending on 70 * which filters are enabled. To avoid format changes when the filters are 71 * enabled or disabled (which would prevent them from being turned on or off 72 * during streaming), the driver assumes all filters that can be configured 73 * during streaming are enabled when computing sink crop and source format 74 * limits. 75 * 76 * If a filter is disabled, additional cropping is automatically added at the 77 * preview engine input by the driver to avoid overflow at line and frame end. 78 * This is completely transparent for applications. 79 * 80 * Median filter 4 pixels 81 * Noise filter, 82 * Faulty pixels correction 4 pixels, 4 lines 83 * Color suppression 2 pixels 84 * or luma enhancement 85 * ------------------------------------------------------------- 86 * Maximum total 10 pixels, 4 lines 87 * 88 * The color suppression and luma enhancement filters are applied after bayer to 89 * YUV conversion. They thus can crop one pixel on the left and one pixel on the 90 * right side of the image without changing the color pattern. When both those 91 * filters are disabled, the driver must crop the two pixels on the same side of 92 * the image to avoid changing the bayer pattern. The left margin is thus set to 93 * 6 pixels and the right margin to 4 pixels. 94 */ 95 96#define PREV_MARGIN_LEFT 6 97#define PREV_MARGIN_RIGHT 4 98#define PREV_MARGIN_TOP 2 99#define PREV_MARGIN_BOTTOM 2 100 101#define PREV_MIN_IN_WIDTH 64 102#define PREV_MIN_IN_HEIGHT 8 103#define PREV_MAX_IN_HEIGHT 16384 104 105#define PREV_MIN_OUT_WIDTH 0 106#define PREV_MIN_OUT_HEIGHT 0 107#define PREV_MAX_OUT_WIDTH_REV_1 1280 108#define PREV_MAX_OUT_WIDTH_REV_2 3300 109#define PREV_MAX_OUT_WIDTH_REV_15 4096 110 111/* 112 * Coefficient Tables for the submodules in Preview. 113 * Array is initialised with the values from.the tables text file. 114 */ 115 116/* 117 * CFA Filter Coefficient Table 118 * 119 */ 120static u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = { 121#include "cfa_coef_table.h" 122}; 123 124/* 125 * Default Gamma Correction Table - All components 126 */ 127static u32 gamma_table[] = { 128#include "gamma_table.h" 129}; 130 131/* 132 * Noise Filter Threshold table 133 */ 134static u32 noise_filter_table[] = { 135#include "noise_filter_table.h" 136}; 137 138/* 139 * Luminance Enhancement Table 140 */ 141static u32 luma_enhance_table[] = { 142#include "luma_enhance_table.h" 143}; 144 145/* 146 * preview_config_luma_enhancement - Configure the Luminance Enhancement table 147 */ 148static void 149preview_config_luma_enhancement(struct isp_prev_device *prev, 150 const struct prev_params *params) 151{ 152 struct isp_device *isp = to_isp_device(prev); 153 const struct omap3isp_prev_luma *yt = ¶ms->luma; 154 unsigned int i; 155 156 isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR, 157 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); 158 for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) { 159 isp_reg_writel(isp, yt->table[i], 160 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); 161 } 162} 163 164/* 165 * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement 166 */ 167static void 168preview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable) 169{ 170 struct isp_device *isp = to_isp_device(prev); 171 172 if (enable) 173 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 174 ISPPRV_PCR_YNENHEN); 175 else 176 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 177 ISPPRV_PCR_YNENHEN); 178} 179 180/* 181 * preview_enable_invalaw - Enable/disable Inverse A-Law decompression 182 */ 183static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable) 184{ 185 struct isp_device *isp = to_isp_device(prev); 186 187 if (enable) 188 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 189 ISPPRV_PCR_INVALAW); 190 else 191 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 192 ISPPRV_PCR_INVALAW); 193} 194 195/* 196 * preview_config_hmed - Configure the Horizontal Median Filter 197 */ 198static void preview_config_hmed(struct isp_prev_device *prev, 199 const struct prev_params *params) 200{ 201 struct isp_device *isp = to_isp_device(prev); 202 const struct omap3isp_prev_hmed *hmed = ¶ms->hmed; 203 204 isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) | 205 (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) | 206 (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT), 207 OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED); 208} 209 210/* 211 * preview_enable_hmed - Enable/disable the Horizontal Median Filter 212 */ 213static void preview_enable_hmed(struct isp_prev_device *prev, bool enable) 214{ 215 struct isp_device *isp = to_isp_device(prev); 216 217 if (enable) 218 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 219 ISPPRV_PCR_HMEDEN); 220 else 221 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 222 ISPPRV_PCR_HMEDEN); 223} 224 225/* 226 * preview_config_cfa - Configure CFA Interpolation for Bayer formats 227 * 228 * The CFA table is organised in four blocks, one per Bayer component. The 229 * hardware expects blocks to follow the Bayer order of the input data, while 230 * the driver stores the table in GRBG order in memory. The blocks need to be 231 * reordered to support non-GRBG Bayer patterns. 232 */ 233static void preview_config_cfa(struct isp_prev_device *prev, 234 const struct prev_params *params) 235{ 236 static const unsigned int cfa_coef_order[4][4] = { 237 { 0, 1, 2, 3 }, /* GRBG */ 238 { 1, 0, 3, 2 }, /* RGGB */ 239 { 2, 3, 0, 1 }, /* BGGR */ 240 { 3, 2, 1, 0 }, /* GBRG */ 241 }; 242 const unsigned int *order = cfa_coef_order[prev->params.cfa_order]; 243 const struct omap3isp_prev_cfa *cfa = ¶ms->cfa; 244 struct isp_device *isp = to_isp_device(prev); 245 unsigned int i; 246 unsigned int j; 247 248 isp_reg_writel(isp, 249 (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) | 250 (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT), 251 OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA); 252 253 isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR, 254 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); 255 256 for (i = 0; i < 4; ++i) { 257 const __u32 *block = cfa->table[order[i]]; 258 259 for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j) 260 isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV, 261 ISPPRV_SET_TBL_DATA); 262 } 263} 264 265/* 266 * preview_config_chroma_suppression - Configure Chroma Suppression 267 */ 268static void 269preview_config_chroma_suppression(struct isp_prev_device *prev, 270 const struct prev_params *params) 271{ 272 struct isp_device *isp = to_isp_device(prev); 273 const struct omap3isp_prev_csup *cs = ¶ms->csup; 274 275 isp_reg_writel(isp, 276 cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) | 277 (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT), 278 OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP); 279} 280 281/* 282 * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression 283 */ 284static void 285preview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable) 286{ 287 struct isp_device *isp = to_isp_device(prev); 288 289 if (enable) 290 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 291 ISPPRV_PCR_SUPEN); 292 else 293 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 294 ISPPRV_PCR_SUPEN); 295} 296 297/* 298 * preview_config_whitebalance - Configure White Balance parameters 299 * 300 * Coefficient matrix always with default values. 301 */ 302static void 303preview_config_whitebalance(struct isp_prev_device *prev, 304 const struct prev_params *params) 305{ 306 struct isp_device *isp = to_isp_device(prev); 307 const struct omap3isp_prev_wbal *wbal = ¶ms->wbal; 308 u32 val; 309 310 isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN); 311 312 val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT; 313 val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT; 314 val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT; 315 val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT; 316 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN); 317 318 isp_reg_writel(isp, 319 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT | 320 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT | 321 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT | 322 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT | 323 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT | 324 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT | 325 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT | 326 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT | 327 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT | 328 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT | 329 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT | 330 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT | 331 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT | 332 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT | 333 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT | 334 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT, 335 OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL); 336} 337 338/* 339 * preview_config_blkadj - Configure Black Adjustment 340 */ 341static void 342preview_config_blkadj(struct isp_prev_device *prev, 343 const struct prev_params *params) 344{ 345 struct isp_device *isp = to_isp_device(prev); 346 const struct omap3isp_prev_blkadj *blkadj = ¶ms->blkadj; 347 348 isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) | 349 (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) | 350 (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT), 351 OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF); 352} 353 354/* 355 * preview_config_rgb_blending - Configure RGB-RGB Blending 356 */ 357static void 358preview_config_rgb_blending(struct isp_prev_device *prev, 359 const struct prev_params *params) 360{ 361 struct isp_device *isp = to_isp_device(prev); 362 const struct omap3isp_prev_rgbtorgb *rgbrgb = ¶ms->rgb2rgb; 363 u32 val; 364 365 val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT; 366 val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT; 367 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1); 368 369 val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT; 370 val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT; 371 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2); 372 373 val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT; 374 val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT; 375 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3); 376 377 val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT; 378 val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT; 379 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4); 380 381 val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT; 382 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5); 383 384 val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT; 385 val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT; 386 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1); 387 388 val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT; 389 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2); 390} 391 392/* 393 * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr) 394 */ 395static void 396preview_config_csc(struct isp_prev_device *prev, 397 const struct prev_params *params) 398{ 399 struct isp_device *isp = to_isp_device(prev); 400 const struct omap3isp_prev_csc *csc = ¶ms->csc; 401 u32 val; 402 403 val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT; 404 val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT; 405 val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT; 406 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0); 407 408 val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT; 409 val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT; 410 val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT; 411 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1); 412 413 val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT; 414 val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT; 415 val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT; 416 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2); 417 418 val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT; 419 val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT; 420 val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT; 421 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET); 422} 423 424/* 425 * preview_config_yc_range - Configure the max and min Y and C values 426 */ 427static void 428preview_config_yc_range(struct isp_prev_device *prev, 429 const struct prev_params *params) 430{ 431 struct isp_device *isp = to_isp_device(prev); 432 const struct omap3isp_prev_yclimit *yc = ¶ms->yclimit; 433 434 isp_reg_writel(isp, 435 yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT | 436 yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT | 437 yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT | 438 yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT, 439 OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC); 440} 441 442/* 443 * preview_config_dcor - Configure Couplet Defect Correction 444 */ 445static void 446preview_config_dcor(struct isp_prev_device *prev, 447 const struct prev_params *params) 448{ 449 struct isp_device *isp = to_isp_device(prev); 450 const struct omap3isp_prev_dcor *dcor = ¶ms->dcor; 451 452 isp_reg_writel(isp, dcor->detect_correct[0], 453 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0); 454 isp_reg_writel(isp, dcor->detect_correct[1], 455 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1); 456 isp_reg_writel(isp, dcor->detect_correct[2], 457 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2); 458 isp_reg_writel(isp, dcor->detect_correct[3], 459 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3); 460 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 461 ISPPRV_PCR_DCCOUP, 462 dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0); 463} 464 465/* 466 * preview_enable_dcor - Enable/disable Couplet Defect Correction 467 */ 468static void preview_enable_dcor(struct isp_prev_device *prev, bool enable) 469{ 470 struct isp_device *isp = to_isp_device(prev); 471 472 if (enable) 473 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 474 ISPPRV_PCR_DCOREN); 475 else 476 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 477 ISPPRV_PCR_DCOREN); 478} 479 480/* 481 * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture 482 */ 483static void 484preview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable) 485{ 486 struct isp_device *isp = to_isp_device(prev); 487 488 if (enable) 489 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 490 ISPPRV_PCR_DRKFCAP); 491 else 492 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 493 ISPPRV_PCR_DRKFCAP); 494} 495 496/* 497 * preview_enable_drkframe - Enable/disable Dark Frame Subtraction 498 */ 499static void preview_enable_drkframe(struct isp_prev_device *prev, bool enable) 500{ 501 struct isp_device *isp = to_isp_device(prev); 502 503 if (enable) 504 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 505 ISPPRV_PCR_DRKFEN); 506 else 507 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 508 ISPPRV_PCR_DRKFEN); 509} 510 511/* 512 * preview_config_noisefilter - Configure the Noise Filter 513 */ 514static void 515preview_config_noisefilter(struct isp_prev_device *prev, 516 const struct prev_params *params) 517{ 518 struct isp_device *isp = to_isp_device(prev); 519 const struct omap3isp_prev_nf *nf = ¶ms->nf; 520 unsigned int i; 521 522 isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF); 523 isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR, 524 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); 525 for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) { 526 isp_reg_writel(isp, nf->table[i], 527 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); 528 } 529} 530 531/* 532 * preview_enable_noisefilter - Enable/disable the Noise Filter 533 */ 534static void 535preview_enable_noisefilter(struct isp_prev_device *prev, bool enable) 536{ 537 struct isp_device *isp = to_isp_device(prev); 538 539 if (enable) 540 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 541 ISPPRV_PCR_NFEN); 542 else 543 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 544 ISPPRV_PCR_NFEN); 545} 546 547/* 548 * preview_config_gammacorrn - Configure the Gamma Correction tables 549 */ 550static void 551preview_config_gammacorrn(struct isp_prev_device *prev, 552 const struct prev_params *params) 553{ 554 struct isp_device *isp = to_isp_device(prev); 555 const struct omap3isp_prev_gtables *gt = ¶ms->gamma; 556 unsigned int i; 557 558 isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR, 559 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); 560 for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) 561 isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV, 562 ISPPRV_SET_TBL_DATA); 563 564 isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR, 565 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); 566 for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) 567 isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV, 568 ISPPRV_SET_TBL_DATA); 569 570 isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR, 571 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); 572 for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) 573 isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV, 574 ISPPRV_SET_TBL_DATA); 575} 576 577/* 578 * preview_enable_gammacorrn - Enable/disable Gamma Correction 579 * 580 * When gamma correction is disabled, the module is bypassed and its output is 581 * the 8 MSB of the 10-bit input . 582 */ 583static void 584preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable) 585{ 586 struct isp_device *isp = to_isp_device(prev); 587 588 if (enable) 589 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 590 ISPPRV_PCR_GAMMA_BYPASS); 591 else 592 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 593 ISPPRV_PCR_GAMMA_BYPASS); 594} 595 596/* 597 * preview_config_contrast - Configure the Contrast 598 * 599 * Value should be programmed before enabling the module. 600 */ 601static void 602preview_config_contrast(struct isp_prev_device *prev, 603 const struct prev_params *params) 604{ 605 struct isp_device *isp = to_isp_device(prev); 606 607 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT, 608 0xff << ISPPRV_CNT_BRT_CNT_SHIFT, 609 params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT); 610} 611 612/* 613 * preview_config_brightness - Configure the Brightness 614 */ 615static void 616preview_config_brightness(struct isp_prev_device *prev, 617 const struct prev_params *params) 618{ 619 struct isp_device *isp = to_isp_device(prev); 620 621 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT, 622 0xff << ISPPRV_CNT_BRT_BRT_SHIFT, 623 params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT); 624} 625 626/* 627 * preview_update_contrast - Updates the contrast. 628 * @contrast: Pointer to hold the current programmed contrast value. 629 * 630 * Value should be programmed before enabling the module. 631 */ 632static void 633preview_update_contrast(struct isp_prev_device *prev, u8 contrast) 634{ 635 struct prev_params *params; 636 unsigned long flags; 637 638 spin_lock_irqsave(&prev->params.lock, flags); 639 params = (prev->params.active & OMAP3ISP_PREV_CONTRAST) 640 ? &prev->params.params[0] : &prev->params.params[1]; 641 642 if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) { 643 params->contrast = contrast * ISPPRV_CONTRAST_UNITS; 644 params->update |= OMAP3ISP_PREV_CONTRAST; 645 } 646 spin_unlock_irqrestore(&prev->params.lock, flags); 647} 648 649/* 650 * preview_update_brightness - Updates the brightness in preview module. 651 * @brightness: Pointer to hold the current programmed brightness value. 652 * 653 */ 654static void 655preview_update_brightness(struct isp_prev_device *prev, u8 brightness) 656{ 657 struct prev_params *params; 658 unsigned long flags; 659 660 spin_lock_irqsave(&prev->params.lock, flags); 661 params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS) 662 ? &prev->params.params[0] : &prev->params.params[1]; 663 664 if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) { 665 params->brightness = brightness * ISPPRV_BRIGHT_UNITS; 666 params->update |= OMAP3ISP_PREV_BRIGHTNESS; 667 } 668 spin_unlock_irqrestore(&prev->params.lock, flags); 669} 670 671static u32 672preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow) 673{ 674 u32 active = prev->params.active; 675 676 if (shadow) { 677 /* Mark all shadow parameters we are going to touch as busy. */ 678 prev->params.params[0].busy |= ~active & update; 679 prev->params.params[1].busy |= active & update; 680 } else { 681 /* Mark all active parameters we are going to touch as busy. */ 682 update = (prev->params.params[0].update & active) 683 | (prev->params.params[1].update & ~active); 684 685 prev->params.params[0].busy |= active & update; 686 prev->params.params[1].busy |= ~active & update; 687 } 688 689 return update; 690} 691 692static void 693preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow) 694{ 695 u32 active = prev->params.active; 696 697 if (shadow) { 698 /* Set the update flag for shadow parameters that have been 699 * updated and clear the busy flag for all shadow parameters. 700 */ 701 prev->params.params[0].update |= (~active & update); 702 prev->params.params[1].update |= (active & update); 703 prev->params.params[0].busy &= active; 704 prev->params.params[1].busy &= ~active; 705 } else { 706 /* Clear the update flag for active parameters that have been 707 * applied and the busy flag for all active parameters. 708 */ 709 prev->params.params[0].update &= ~(active & update); 710 prev->params.params[1].update &= ~(~active & update); 711 prev->params.params[0].busy &= ~active; 712 prev->params.params[1].busy &= active; 713 } 714} 715 716static void preview_params_switch(struct isp_prev_device *prev) 717{ 718 u32 to_switch; 719 720 /* Switch active parameters with updated shadow parameters when the 721 * shadow parameter has been updated and neither the active not the 722 * shadow parameter is busy. 723 */ 724 to_switch = (prev->params.params[0].update & ~prev->params.active) 725 | (prev->params.params[1].update & prev->params.active); 726 to_switch &= ~(prev->params.params[0].busy | 727 prev->params.params[1].busy); 728 if (to_switch == 0) 729 return; 730 731 prev->params.active ^= to_switch; 732 733 /* Remove the update flag for the shadow copy of parameters we have 734 * switched. 735 */ 736 prev->params.params[0].update &= ~(~prev->params.active & to_switch); 737 prev->params.params[1].update &= ~(prev->params.active & to_switch); 738} 739 740/* preview parameters update structure */ 741struct preview_update { 742 void (*config)(struct isp_prev_device *, const struct prev_params *); 743 void (*enable)(struct isp_prev_device *, bool); 744 unsigned int param_offset; 745 unsigned int param_size; 746 unsigned int config_offset; 747 bool skip; 748}; 749 750/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */ 751static const struct preview_update update_attrs[] = { 752 /* OMAP3ISP_PREV_LUMAENH */ { 753 preview_config_luma_enhancement, 754 preview_enable_luma_enhancement, 755 offsetof(struct prev_params, luma), 756 sizeof_field(struct prev_params, luma), 757 offsetof(struct omap3isp_prev_update_config, luma), 758 }, /* OMAP3ISP_PREV_INVALAW */ { 759 NULL, 760 preview_enable_invalaw, 761 }, /* OMAP3ISP_PREV_HRZ_MED */ { 762 preview_config_hmed, 763 preview_enable_hmed, 764 offsetof(struct prev_params, hmed), 765 sizeof_field(struct prev_params, hmed), 766 offsetof(struct omap3isp_prev_update_config, hmed), 767 }, /* OMAP3ISP_PREV_CFA */ { 768 preview_config_cfa, 769 NULL, 770 offsetof(struct prev_params, cfa), 771 sizeof_field(struct prev_params, cfa), 772 offsetof(struct omap3isp_prev_update_config, cfa), 773 }, /* OMAP3ISP_PREV_CHROMA_SUPP */ { 774 preview_config_chroma_suppression, 775 preview_enable_chroma_suppression, 776 offsetof(struct prev_params, csup), 777 sizeof_field(struct prev_params, csup), 778 offsetof(struct omap3isp_prev_update_config, csup), 779 }, /* OMAP3ISP_PREV_WB */ { 780 preview_config_whitebalance, 781 NULL, 782 offsetof(struct prev_params, wbal), 783 sizeof_field(struct prev_params, wbal), 784 offsetof(struct omap3isp_prev_update_config, wbal), 785 }, /* OMAP3ISP_PREV_BLKADJ */ { 786 preview_config_blkadj, 787 NULL, 788 offsetof(struct prev_params, blkadj), 789 sizeof_field(struct prev_params, blkadj), 790 offsetof(struct omap3isp_prev_update_config, blkadj), 791 }, /* OMAP3ISP_PREV_RGB2RGB */ { 792 preview_config_rgb_blending, 793 NULL, 794 offsetof(struct prev_params, rgb2rgb), 795 sizeof_field(struct prev_params, rgb2rgb), 796 offsetof(struct omap3isp_prev_update_config, rgb2rgb), 797 }, /* OMAP3ISP_PREV_COLOR_CONV */ { 798 preview_config_csc, 799 NULL, 800 offsetof(struct prev_params, csc), 801 sizeof_field(struct prev_params, csc), 802 offsetof(struct omap3isp_prev_update_config, csc), 803 }, /* OMAP3ISP_PREV_YC_LIMIT */ { 804 preview_config_yc_range, 805 NULL, 806 offsetof(struct prev_params, yclimit), 807 sizeof_field(struct prev_params, yclimit), 808 offsetof(struct omap3isp_prev_update_config, yclimit), 809 }, /* OMAP3ISP_PREV_DEFECT_COR */ { 810 preview_config_dcor, 811 preview_enable_dcor, 812 offsetof(struct prev_params, dcor), 813 sizeof_field(struct prev_params, dcor), 814 offsetof(struct omap3isp_prev_update_config, dcor), 815 }, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ { 816 NULL, 817 NULL, 818 }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ { 819 NULL, 820 preview_enable_drkframe_capture, 821 }, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ { 822 NULL, 823 preview_enable_drkframe, 824 }, /* OMAP3ISP_PREV_LENS_SHADING */ { 825 NULL, 826 preview_enable_drkframe, 827 }, /* OMAP3ISP_PREV_NF */ { 828 preview_config_noisefilter, 829 preview_enable_noisefilter, 830 offsetof(struct prev_params, nf), 831 sizeof_field(struct prev_params, nf), 832 offsetof(struct omap3isp_prev_update_config, nf), 833 }, /* OMAP3ISP_PREV_GAMMA */ { 834 preview_config_gammacorrn, 835 preview_enable_gammacorrn, 836 offsetof(struct prev_params, gamma), 837 sizeof_field(struct prev_params, gamma), 838 offsetof(struct omap3isp_prev_update_config, gamma), 839 }, /* OMAP3ISP_PREV_CONTRAST */ { 840 preview_config_contrast, 841 NULL, 842 0, 0, 0, true, 843 }, /* OMAP3ISP_PREV_BRIGHTNESS */ { 844 preview_config_brightness, 845 NULL, 846 0, 0, 0, true, 847 }, 848}; 849 850/* 851 * preview_config - Copy and update local structure with userspace preview 852 * configuration. 853 * @prev: ISP preview engine 854 * @cfg: Configuration 855 * 856 * Return zero if success or -EFAULT if the configuration can't be copied from 857 * userspace. 858 */ 859static int preview_config(struct isp_prev_device *prev, 860 struct omap3isp_prev_update_config *cfg) 861{ 862 unsigned long flags; 863 unsigned int i; 864 int rval = 0; 865 u32 update; 866 u32 active; 867 868 if (cfg->update == 0) 869 return 0; 870 871 /* Mark the shadow parameters we're going to update as busy. */ 872 spin_lock_irqsave(&prev->params.lock, flags); 873 preview_params_lock(prev, cfg->update, true); 874 active = prev->params.active; 875 spin_unlock_irqrestore(&prev->params.lock, flags); 876 877 update = 0; 878 879 for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { 880 const struct preview_update *attr = &update_attrs[i]; 881 struct prev_params *params; 882 unsigned int bit = 1 << i; 883 884 if (attr->skip || !(cfg->update & bit)) 885 continue; 886 887 params = &prev->params.params[!!(active & bit)]; 888 889 if (cfg->flag & bit) { 890 void __user *from = *(void __user **) 891 ((void *)cfg + attr->config_offset); 892 void *to = (void *)params + attr->param_offset; 893 size_t size = attr->param_size; 894 895 if (to && from && size) { 896 if (copy_from_user(to, from, size)) { 897 rval = -EFAULT; 898 break; 899 } 900 } 901 params->features |= bit; 902 } else { 903 params->features &= ~bit; 904 } 905 906 update |= bit; 907 } 908 909 spin_lock_irqsave(&prev->params.lock, flags); 910 preview_params_unlock(prev, update, true); 911 preview_params_switch(prev); 912 spin_unlock_irqrestore(&prev->params.lock, flags); 913 914 return rval; 915} 916 917/* 918 * preview_setup_hw - Setup preview registers and/or internal memory 919 * @prev: pointer to preview private structure 920 * @update: Bitmask of parameters to setup 921 * @active: Bitmask of parameters active in set 0 922 * Note: can be called from interrupt context 923 * Return none 924 */ 925static void preview_setup_hw(struct isp_prev_device *prev, u32 update, 926 u32 active) 927{ 928 unsigned int i; 929 930 if (update == 0) 931 return; 932 933 for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { 934 const struct preview_update *attr = &update_attrs[i]; 935 struct prev_params *params; 936 unsigned int bit = 1 << i; 937 938 if (!(update & bit)) 939 continue; 940 941 params = &prev->params.params[!(active & bit)]; 942 943 if (params->features & bit) { 944 if (attr->config) 945 attr->config(prev, params); 946 if (attr->enable) 947 attr->enable(prev, true); 948 } else { 949 if (attr->enable) 950 attr->enable(prev, false); 951 } 952 } 953} 954 955/* 956 * preview_config_ycpos - Configure byte layout of YUV image. 957 * @prev: pointer to previewer private structure 958 * @pixelcode: pixel code 959 */ 960static void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode) 961{ 962 struct isp_device *isp = to_isp_device(prev); 963 enum preview_ycpos_mode mode; 964 965 switch (pixelcode) { 966 case MEDIA_BUS_FMT_YUYV8_1X16: 967 mode = YCPOS_CrYCbY; 968 break; 969 case MEDIA_BUS_FMT_UYVY8_1X16: 970 mode = YCPOS_YCrYCb; 971 break; 972 default: 973 return; 974 } 975 976 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 977 ISPPRV_PCR_YCPOS_CrYCbY, 978 mode << ISPPRV_PCR_YCPOS_SHIFT); 979} 980 981/* 982 * preview_config_averager - Enable / disable / configure averager 983 * @average: Average value to be configured. 984 */ 985static void preview_config_averager(struct isp_prev_device *prev, u8 average) 986{ 987 struct isp_device *isp = to_isp_device(prev); 988 989 isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT | 990 ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT | 991 average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE); 992} 993 994 995/* 996 * preview_config_input_format - Configure the input format 997 * @prev: The preview engine 998 * @info: Sink pad format information 999 * 1000 * Enable and configure CFA interpolation for Bayer formats and disable it for 1001 * greyscale formats. 1002 * 1003 * The CFA table is organised in four blocks, one per Bayer component. The 1004 * hardware expects blocks to follow the Bayer order of the input data, while 1005 * the driver stores the table in GRBG order in memory. The blocks need to be 1006 * reordered to support non-GRBG Bayer patterns. 1007 */ 1008static void preview_config_input_format(struct isp_prev_device *prev, 1009 const struct isp_format_info *info) 1010{ 1011 struct isp_device *isp = to_isp_device(prev); 1012 struct prev_params *params; 1013 1014 if (info->width == 8) 1015 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1016 ISPPRV_PCR_WIDTH); 1017 else 1018 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1019 ISPPRV_PCR_WIDTH); 1020 1021 switch (info->flavor) { 1022 case MEDIA_BUS_FMT_SGRBG8_1X8: 1023 prev->params.cfa_order = 0; 1024 break; 1025 case MEDIA_BUS_FMT_SRGGB8_1X8: 1026 prev->params.cfa_order = 1; 1027 break; 1028 case MEDIA_BUS_FMT_SBGGR8_1X8: 1029 prev->params.cfa_order = 2; 1030 break; 1031 case MEDIA_BUS_FMT_SGBRG8_1X8: 1032 prev->params.cfa_order = 3; 1033 break; 1034 default: 1035 /* Disable CFA for non-Bayer formats. */ 1036 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1037 ISPPRV_PCR_CFAEN); 1038 return; 1039 } 1040 1041 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN); 1042 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1043 ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER); 1044 1045 params = (prev->params.active & OMAP3ISP_PREV_CFA) 1046 ? &prev->params.params[0] : &prev->params.params[1]; 1047 1048 preview_config_cfa(prev, params); 1049} 1050 1051/* 1052 * preview_config_input_size - Configure the input frame size 1053 * 1054 * The preview engine crops several rows and columns internally depending on 1055 * which processing blocks are enabled. The driver assumes all those blocks are 1056 * enabled when reporting source pad formats to userspace. If this assumption is 1057 * not true, rows and columns must be manually cropped at the preview engine 1058 * input to avoid overflows at the end of lines and frames. 1059 * 1060 * See the explanation at the PREV_MARGIN_* definitions for more details. 1061 */ 1062static void preview_config_input_size(struct isp_prev_device *prev, u32 active) 1063{ 1064 const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; 1065 struct isp_device *isp = to_isp_device(prev); 1066 unsigned int sph = prev->crop.left; 1067 unsigned int eph = prev->crop.left + prev->crop.width - 1; 1068 unsigned int slv = prev->crop.top; 1069 unsigned int elv = prev->crop.top + prev->crop.height - 1; 1070 u32 features; 1071 1072 if (format->code != MEDIA_BUS_FMT_Y8_1X8 && 1073 format->code != MEDIA_BUS_FMT_Y10_1X10) { 1074 sph -= 2; 1075 eph += 2; 1076 slv -= 2; 1077 elv += 2; 1078 } 1079 1080 features = (prev->params.params[0].features & active) 1081 | (prev->params.params[1].features & ~active); 1082 1083 if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) { 1084 sph -= 2; 1085 eph += 2; 1086 slv -= 2; 1087 elv += 2; 1088 } 1089 if (features & OMAP3ISP_PREV_HRZ_MED) { 1090 sph -= 2; 1091 eph += 2; 1092 } 1093 if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH)) 1094 sph -= 2; 1095 1096 isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, 1097 OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); 1098 isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv, 1099 OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO); 1100} 1101 1102/* 1103 * preview_config_inlineoffset - Configures the Read address line offset. 1104 * @prev: Preview module 1105 * @offset: Line offset 1106 * 1107 * According to the TRM, the line offset must be aligned on a 32 bytes boundary. 1108 * However, a hardware bug requires the memory start address to be aligned on a 1109 * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as 1110 * well. 1111 */ 1112static void 1113preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset) 1114{ 1115 struct isp_device *isp = to_isp_device(prev); 1116 1117 isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV, 1118 ISPPRV_RADR_OFFSET); 1119} 1120 1121/* 1122 * preview_set_inaddr - Sets memory address of input frame. 1123 * @addr: 32bit memory address aligned on 32byte boundary. 1124 * 1125 * Configures the memory address from which the input frame is to be read. 1126 */ 1127static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr) 1128{ 1129 struct isp_device *isp = to_isp_device(prev); 1130 1131 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR); 1132} 1133 1134/* 1135 * preview_config_outlineoffset - Configures the Write address line offset. 1136 * @offset: Line Offset for the preview output. 1137 * 1138 * The offset must be a multiple of 32 bytes. 1139 */ 1140static void preview_config_outlineoffset(struct isp_prev_device *prev, 1141 u32 offset) 1142{ 1143 struct isp_device *isp = to_isp_device(prev); 1144 1145 isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV, 1146 ISPPRV_WADD_OFFSET); 1147} 1148 1149/* 1150 * preview_set_outaddr - Sets the memory address to store output frame 1151 * @addr: 32bit memory address aligned on 32byte boundary. 1152 * 1153 * Configures the memory address to which the output frame is written. 1154 */ 1155static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr) 1156{ 1157 struct isp_device *isp = to_isp_device(prev); 1158 1159 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR); 1160} 1161 1162static void preview_adjust_bandwidth(struct isp_prev_device *prev) 1163{ 1164 struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity); 1165 struct isp_device *isp = to_isp_device(prev); 1166 const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK]; 1167 unsigned long l3_ick = pipe->l3_ick; 1168 struct v4l2_fract *timeperframe; 1169 unsigned int cycles_per_frame; 1170 unsigned int requests_per_frame; 1171 unsigned int cycles_per_request; 1172 unsigned int minimum; 1173 unsigned int maximum; 1174 unsigned int value; 1175 1176 if (prev->input != PREVIEW_INPUT_MEMORY) { 1177 isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, 1178 ISPSBL_SDR_REQ_PRV_EXP_MASK); 1179 return; 1180 } 1181 1182 /* Compute the minimum number of cycles per request, based on the 1183 * pipeline maximum data rate. This is an absolute lower bound if we 1184 * don't want SBL overflows, so round the value up. 1185 */ 1186 cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1, 1187 pipe->max_rate); 1188 minimum = DIV_ROUND_UP(cycles_per_request, 32); 1189 1190 /* Compute the maximum number of cycles per request, based on the 1191 * requested frame rate. This is a soft upper bound to achieve a frame 1192 * rate equal or higher than the requested value, so round the value 1193 * down. 1194 */ 1195 timeperframe = &pipe->max_timeperframe; 1196 1197 requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height; 1198 cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator, 1199 timeperframe->denominator); 1200 cycles_per_request = cycles_per_frame / requests_per_frame; 1201 1202 maximum = cycles_per_request / 32; 1203 1204 value = max(minimum, maximum); 1205 1206 dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value); 1207 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, 1208 ISPSBL_SDR_REQ_PRV_EXP_MASK, 1209 value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT); 1210} 1211 1212/* 1213 * omap3isp_preview_busy - Gets busy state of preview module. 1214 */ 1215int omap3isp_preview_busy(struct isp_prev_device *prev) 1216{ 1217 struct isp_device *isp = to_isp_device(prev); 1218 1219 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR) 1220 & ISPPRV_PCR_BUSY; 1221} 1222 1223/* 1224 * omap3isp_preview_restore_context - Restores the values of preview registers 1225 */ 1226void omap3isp_preview_restore_context(struct isp_device *isp) 1227{ 1228 struct isp_prev_device *prev = &isp->isp_prev; 1229 const u32 update = OMAP3ISP_PREV_FEATURES_END - 1; 1230 1231 prev->params.params[0].update = prev->params.active & update; 1232 prev->params.params[1].update = ~prev->params.active & update; 1233 1234 preview_setup_hw(prev, update, prev->params.active); 1235 1236 prev->params.params[0].update = 0; 1237 prev->params.params[1].update = 0; 1238} 1239 1240/* 1241 * preview_print_status - Dump preview module registers to the kernel log 1242 */ 1243#define PREV_PRINT_REGISTER(isp, name)\ 1244 dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \ 1245 isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name)) 1246 1247static void preview_print_status(struct isp_prev_device *prev) 1248{ 1249 struct isp_device *isp = to_isp_device(prev); 1250 1251 dev_dbg(isp->dev, "-------------Preview Register dump----------\n"); 1252 1253 PREV_PRINT_REGISTER(isp, PCR); 1254 PREV_PRINT_REGISTER(isp, HORZ_INFO); 1255 PREV_PRINT_REGISTER(isp, VERT_INFO); 1256 PREV_PRINT_REGISTER(isp, RSDR_ADDR); 1257 PREV_PRINT_REGISTER(isp, RADR_OFFSET); 1258 PREV_PRINT_REGISTER(isp, DSDR_ADDR); 1259 PREV_PRINT_REGISTER(isp, DRKF_OFFSET); 1260 PREV_PRINT_REGISTER(isp, WSDR_ADDR); 1261 PREV_PRINT_REGISTER(isp, WADD_OFFSET); 1262 PREV_PRINT_REGISTER(isp, AVE); 1263 PREV_PRINT_REGISTER(isp, HMED); 1264 PREV_PRINT_REGISTER(isp, NF); 1265 PREV_PRINT_REGISTER(isp, WB_DGAIN); 1266 PREV_PRINT_REGISTER(isp, WBGAIN); 1267 PREV_PRINT_REGISTER(isp, WBSEL); 1268 PREV_PRINT_REGISTER(isp, CFA); 1269 PREV_PRINT_REGISTER(isp, BLKADJOFF); 1270 PREV_PRINT_REGISTER(isp, RGB_MAT1); 1271 PREV_PRINT_REGISTER(isp, RGB_MAT2); 1272 PREV_PRINT_REGISTER(isp, RGB_MAT3); 1273 PREV_PRINT_REGISTER(isp, RGB_MAT4); 1274 PREV_PRINT_REGISTER(isp, RGB_MAT5); 1275 PREV_PRINT_REGISTER(isp, RGB_OFF1); 1276 PREV_PRINT_REGISTER(isp, RGB_OFF2); 1277 PREV_PRINT_REGISTER(isp, CSC0); 1278 PREV_PRINT_REGISTER(isp, CSC1); 1279 PREV_PRINT_REGISTER(isp, CSC2); 1280 PREV_PRINT_REGISTER(isp, CSC_OFFSET); 1281 PREV_PRINT_REGISTER(isp, CNT_BRT); 1282 PREV_PRINT_REGISTER(isp, CSUP); 1283 PREV_PRINT_REGISTER(isp, SETUP_YC); 1284 PREV_PRINT_REGISTER(isp, SET_TBL_ADDR); 1285 PREV_PRINT_REGISTER(isp, CDC_THR0); 1286 PREV_PRINT_REGISTER(isp, CDC_THR1); 1287 PREV_PRINT_REGISTER(isp, CDC_THR2); 1288 PREV_PRINT_REGISTER(isp, CDC_THR3); 1289 1290 dev_dbg(isp->dev, "--------------------------------------------\n"); 1291} 1292 1293/* 1294 * preview_init_params - init image processing parameters. 1295 * @prev: pointer to previewer private structure 1296 */ 1297static void preview_init_params(struct isp_prev_device *prev) 1298{ 1299 struct prev_params *params; 1300 unsigned int i; 1301 1302 spin_lock_init(&prev->params.lock); 1303 1304 prev->params.active = ~0; 1305 prev->params.params[0].busy = 0; 1306 prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1; 1307 prev->params.params[1].busy = 0; 1308 prev->params.params[1].update = 0; 1309 1310 params = &prev->params.params[0]; 1311 1312 /* Init values */ 1313 params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; 1314 params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; 1315 params->cfa.format = OMAP3ISP_CFAFMT_BAYER; 1316 memcpy(params->cfa.table, cfa_coef_table, 1317 sizeof(params->cfa.table)); 1318 params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ; 1319 params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT; 1320 params->csup.gain = FLR_CSUP_GAIN; 1321 params->csup.thres = FLR_CSUP_THRES; 1322 params->csup.hypf_en = 0; 1323 memcpy(params->luma.table, luma_enhance_table, 1324 sizeof(params->luma.table)); 1325 params->nf.spread = FLR_NF_STRGTH; 1326 memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table)); 1327 params->dcor.couplet_mode_en = 1; 1328 for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++) 1329 params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL; 1330 memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue)); 1331 memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green)); 1332 memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red)); 1333 params->wbal.dgain = FLR_WBAL_DGAIN; 1334 params->wbal.coef0 = FLR_WBAL_COEF; 1335 params->wbal.coef1 = FLR_WBAL_COEF; 1336 params->wbal.coef2 = FLR_WBAL_COEF; 1337 params->wbal.coef3 = FLR_WBAL_COEF; 1338 params->blkadj.red = FLR_BLKADJ_RED; 1339 params->blkadj.green = FLR_BLKADJ_GREEN; 1340 params->blkadj.blue = FLR_BLKADJ_BLUE; 1341 params->rgb2rgb = flr_rgb2rgb; 1342 params->csc = flr_prev_csc; 1343 params->yclimit.minC = ISPPRV_YC_MIN; 1344 params->yclimit.maxC = ISPPRV_YC_MAX; 1345 params->yclimit.minY = ISPPRV_YC_MIN; 1346 params->yclimit.maxY = ISPPRV_YC_MAX; 1347 1348 params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR 1349 | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA 1350 | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT 1351 | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV 1352 | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS 1353 | OMAP3ISP_PREV_CONTRAST; 1354} 1355 1356/* 1357 * preview_max_out_width - Handle previewer hardware output limitations 1358 * @prev: pointer to previewer private structure 1359 * returns maximum width output for current isp revision 1360 */ 1361static unsigned int preview_max_out_width(struct isp_prev_device *prev) 1362{ 1363 struct isp_device *isp = to_isp_device(prev); 1364 1365 switch (isp->revision) { 1366 case ISP_REVISION_1_0: 1367 return PREV_MAX_OUT_WIDTH_REV_1; 1368 1369 case ISP_REVISION_2_0: 1370 default: 1371 return PREV_MAX_OUT_WIDTH_REV_2; 1372 1373 case ISP_REVISION_15_0: 1374 return PREV_MAX_OUT_WIDTH_REV_15; 1375 } 1376} 1377 1378static void preview_configure(struct isp_prev_device *prev) 1379{ 1380 struct isp_device *isp = to_isp_device(prev); 1381 const struct isp_format_info *info; 1382 struct v4l2_mbus_framefmt *format; 1383 unsigned long flags; 1384 u32 update; 1385 u32 active; 1386 1387 spin_lock_irqsave(&prev->params.lock, flags); 1388 /* Mark all active parameters we are going to touch as busy. */ 1389 update = preview_params_lock(prev, 0, false); 1390 active = prev->params.active; 1391 spin_unlock_irqrestore(&prev->params.lock, flags); 1392 1393 /* PREV_PAD_SINK */ 1394 format = &prev->formats[PREV_PAD_SINK]; 1395 info = omap3isp_video_format_info(format->code); 1396 1397 preview_adjust_bandwidth(prev); 1398 1399 preview_config_input_format(prev, info); 1400 preview_config_input_size(prev, active); 1401 1402 if (prev->input == PREVIEW_INPUT_CCDC) 1403 preview_config_inlineoffset(prev, 0); 1404 else 1405 preview_config_inlineoffset(prev, ALIGN(format->width, 0x20) * 1406 info->bpp); 1407 1408 preview_setup_hw(prev, update, active); 1409 1410 /* PREV_PAD_SOURCE */ 1411 format = &prev->formats[PREV_PAD_SOURCE]; 1412 1413 if (prev->output & PREVIEW_OUTPUT_MEMORY) 1414 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1415 ISPPRV_PCR_SDRPORT); 1416 else 1417 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1418 ISPPRV_PCR_SDRPORT); 1419 1420 if (prev->output & PREVIEW_OUTPUT_RESIZER) 1421 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1422 ISPPRV_PCR_RSZPORT); 1423 else 1424 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1425 ISPPRV_PCR_RSZPORT); 1426 1427 if (prev->output & PREVIEW_OUTPUT_MEMORY) 1428 preview_config_outlineoffset(prev, 1429 ALIGN(format->width, 0x10) * 2); 1430 1431 preview_config_averager(prev, 0); 1432 preview_config_ycpos(prev, format->code); 1433 1434 spin_lock_irqsave(&prev->params.lock, flags); 1435 preview_params_unlock(prev, update, false); 1436 spin_unlock_irqrestore(&prev->params.lock, flags); 1437} 1438 1439/* ----------------------------------------------------------------------------- 1440 * Interrupt handling 1441 */ 1442 1443static void preview_enable_oneshot(struct isp_prev_device *prev) 1444{ 1445 struct isp_device *isp = to_isp_device(prev); 1446 1447 /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE 1448 * bit is set. As the preview engine is used in single-shot mode, we 1449 * need to set PCR.SOURCE before enabling the preview engine. 1450 */ 1451 if (prev->input == PREVIEW_INPUT_MEMORY) 1452 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1453 ISPPRV_PCR_SOURCE); 1454 1455 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 1456 ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT); 1457} 1458 1459void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev) 1460{ 1461 /* 1462 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun 1463 * condition, the module was paused and now we have a buffer queued 1464 * on the output again. Restart the pipeline if running in continuous 1465 * mode. 1466 */ 1467 if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS && 1468 prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { 1469 preview_enable_oneshot(prev); 1470 isp_video_dmaqueue_flags_clr(&prev->video_out); 1471 } 1472} 1473 1474static void preview_isr_buffer(struct isp_prev_device *prev) 1475{ 1476 struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity); 1477 struct isp_buffer *buffer; 1478 int restart = 0; 1479 1480 if (prev->output & PREVIEW_OUTPUT_MEMORY) { 1481 buffer = omap3isp_video_buffer_next(&prev->video_out); 1482 if (buffer != NULL) { 1483 preview_set_outaddr(prev, buffer->dma); 1484 restart = 1; 1485 } 1486 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; 1487 } 1488 1489 if (prev->input == PREVIEW_INPUT_MEMORY) { 1490 buffer = omap3isp_video_buffer_next(&prev->video_in); 1491 if (buffer != NULL) 1492 preview_set_inaddr(prev, buffer->dma); 1493 pipe->state |= ISP_PIPELINE_IDLE_INPUT; 1494 } 1495 1496 switch (prev->state) { 1497 case ISP_PIPELINE_STREAM_SINGLESHOT: 1498 if (isp_pipeline_ready(pipe)) 1499 omap3isp_pipeline_set_stream(pipe, 1500 ISP_PIPELINE_STREAM_SINGLESHOT); 1501 break; 1502 1503 case ISP_PIPELINE_STREAM_CONTINUOUS: 1504 /* If an underrun occurs, the video queue operation handler will 1505 * restart the preview engine. Otherwise restart it immediately. 1506 */ 1507 if (restart) 1508 preview_enable_oneshot(prev); 1509 break; 1510 1511 case ISP_PIPELINE_STREAM_STOPPED: 1512 default: 1513 return; 1514 } 1515} 1516 1517/* 1518 * omap3isp_preview_isr - ISP preview engine interrupt handler 1519 * 1520 * Manage the preview engine video buffers and configure shadowed registers. 1521 */ 1522void omap3isp_preview_isr(struct isp_prev_device *prev) 1523{ 1524 unsigned long flags; 1525 u32 update; 1526 u32 active; 1527 1528 if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping)) 1529 return; 1530 1531 spin_lock_irqsave(&prev->params.lock, flags); 1532 preview_params_switch(prev); 1533 update = preview_params_lock(prev, 0, false); 1534 active = prev->params.active; 1535 spin_unlock_irqrestore(&prev->params.lock, flags); 1536 1537 preview_setup_hw(prev, update, active); 1538 preview_config_input_size(prev, active); 1539 1540 if (prev->input == PREVIEW_INPUT_MEMORY || 1541 prev->output & PREVIEW_OUTPUT_MEMORY) 1542 preview_isr_buffer(prev); 1543 else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS) 1544 preview_enable_oneshot(prev); 1545 1546 spin_lock_irqsave(&prev->params.lock, flags); 1547 preview_params_unlock(prev, update, false); 1548 spin_unlock_irqrestore(&prev->params.lock, flags); 1549} 1550 1551/* ----------------------------------------------------------------------------- 1552 * ISP video operations 1553 */ 1554 1555static int preview_video_queue(struct isp_video *video, 1556 struct isp_buffer *buffer) 1557{ 1558 struct isp_prev_device *prev = &video->isp->isp_prev; 1559 1560 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 1561 preview_set_inaddr(prev, buffer->dma); 1562 1563 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1564 preview_set_outaddr(prev, buffer->dma); 1565 1566 return 0; 1567} 1568 1569static const struct isp_video_operations preview_video_ops = { 1570 .queue = preview_video_queue, 1571}; 1572 1573/* ----------------------------------------------------------------------------- 1574 * V4L2 subdev operations 1575 */ 1576 1577/* 1578 * preview_s_ctrl - Handle set control subdev method 1579 * @ctrl: pointer to v4l2 control structure 1580 */ 1581static int preview_s_ctrl(struct v4l2_ctrl *ctrl) 1582{ 1583 struct isp_prev_device *prev = 1584 container_of(ctrl->handler, struct isp_prev_device, ctrls); 1585 1586 switch (ctrl->id) { 1587 case V4L2_CID_BRIGHTNESS: 1588 preview_update_brightness(prev, ctrl->val); 1589 break; 1590 case V4L2_CID_CONTRAST: 1591 preview_update_contrast(prev, ctrl->val); 1592 break; 1593 } 1594 1595 return 0; 1596} 1597 1598static const struct v4l2_ctrl_ops preview_ctrl_ops = { 1599 .s_ctrl = preview_s_ctrl, 1600}; 1601 1602/* 1603 * preview_ioctl - Handle preview module private ioctl's 1604 * @sd: pointer to v4l2 subdev structure 1605 * @cmd: configuration command 1606 * @arg: configuration argument 1607 * return -EINVAL or zero on success 1608 */ 1609static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 1610{ 1611 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 1612 1613 switch (cmd) { 1614 case VIDIOC_OMAP3ISP_PRV_CFG: 1615 return preview_config(prev, arg); 1616 1617 default: 1618 return -ENOIOCTLCMD; 1619 } 1620} 1621 1622/* 1623 * preview_set_stream - Enable/Disable streaming on preview subdev 1624 * @sd : pointer to v4l2 subdev structure 1625 * @enable: 1 == Enable, 0 == Disable 1626 * return -EINVAL or zero on success 1627 */ 1628static int preview_set_stream(struct v4l2_subdev *sd, int enable) 1629{ 1630 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 1631 struct isp_video *video_out = &prev->video_out; 1632 struct isp_device *isp = to_isp_device(prev); 1633 struct device *dev = to_device(prev); 1634 1635 if (prev->state == ISP_PIPELINE_STREAM_STOPPED) { 1636 if (enable == ISP_PIPELINE_STREAM_STOPPED) 1637 return 0; 1638 1639 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW); 1640 preview_configure(prev); 1641 atomic_set(&prev->stopping, 0); 1642 preview_print_status(prev); 1643 } 1644 1645 switch (enable) { 1646 case ISP_PIPELINE_STREAM_CONTINUOUS: 1647 if (prev->output & PREVIEW_OUTPUT_MEMORY) 1648 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); 1649 1650 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED || 1651 !(prev->output & PREVIEW_OUTPUT_MEMORY)) 1652 preview_enable_oneshot(prev); 1653 1654 isp_video_dmaqueue_flags_clr(video_out); 1655 break; 1656 1657 case ISP_PIPELINE_STREAM_SINGLESHOT: 1658 if (prev->input == PREVIEW_INPUT_MEMORY) 1659 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ); 1660 if (prev->output & PREVIEW_OUTPUT_MEMORY) 1661 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); 1662 1663 preview_enable_oneshot(prev); 1664 break; 1665 1666 case ISP_PIPELINE_STREAM_STOPPED: 1667 if (omap3isp_module_sync_idle(&sd->entity, &prev->wait, 1668 &prev->stopping)) 1669 dev_dbg(dev, "%s: stop timeout.\n", sd->name); 1670 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ); 1671 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); 1672 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW); 1673 isp_video_dmaqueue_flags_clr(video_out); 1674 break; 1675 } 1676 1677 prev->state = enable; 1678 return 0; 1679} 1680 1681static struct v4l2_mbus_framefmt * 1682__preview_get_format(struct isp_prev_device *prev, 1683 struct v4l2_subdev_state *sd_state, 1684 unsigned int pad, enum v4l2_subdev_format_whence which) 1685{ 1686 if (which == V4L2_SUBDEV_FORMAT_TRY) 1687 return v4l2_subdev_get_try_format(&prev->subdev, sd_state, 1688 pad); 1689 else 1690 return &prev->formats[pad]; 1691} 1692 1693static struct v4l2_rect * 1694__preview_get_crop(struct isp_prev_device *prev, 1695 struct v4l2_subdev_state *sd_state, 1696 enum v4l2_subdev_format_whence which) 1697{ 1698 if (which == V4L2_SUBDEV_FORMAT_TRY) 1699 return v4l2_subdev_get_try_crop(&prev->subdev, sd_state, 1700 PREV_PAD_SINK); 1701 else 1702 return &prev->crop; 1703} 1704 1705/* previewer format descriptions */ 1706static const unsigned int preview_input_fmts[] = { 1707 MEDIA_BUS_FMT_Y8_1X8, 1708 MEDIA_BUS_FMT_SGRBG8_1X8, 1709 MEDIA_BUS_FMT_SRGGB8_1X8, 1710 MEDIA_BUS_FMT_SBGGR8_1X8, 1711 MEDIA_BUS_FMT_SGBRG8_1X8, 1712 MEDIA_BUS_FMT_Y10_1X10, 1713 MEDIA_BUS_FMT_SGRBG10_1X10, 1714 MEDIA_BUS_FMT_SRGGB10_1X10, 1715 MEDIA_BUS_FMT_SBGGR10_1X10, 1716 MEDIA_BUS_FMT_SGBRG10_1X10, 1717}; 1718 1719static const unsigned int preview_output_fmts[] = { 1720 MEDIA_BUS_FMT_UYVY8_1X16, 1721 MEDIA_BUS_FMT_YUYV8_1X16, 1722}; 1723 1724/* 1725 * preview_try_format - Validate a format 1726 * @prev: ISP preview engine 1727 * @cfg: V4L2 subdev pad configuration 1728 * @pad: pad number 1729 * @fmt: format to be validated 1730 * @which: try/active format selector 1731 * 1732 * Validate and adjust the given format for the given pad based on the preview 1733 * engine limits and the format and crop rectangles on other pads. 1734 */ 1735static void preview_try_format(struct isp_prev_device *prev, 1736 struct v4l2_subdev_state *sd_state, 1737 unsigned int pad, 1738 struct v4l2_mbus_framefmt *fmt, 1739 enum v4l2_subdev_format_whence which) 1740{ 1741 u32 pixelcode; 1742 struct v4l2_rect *crop; 1743 unsigned int i; 1744 1745 switch (pad) { 1746 case PREV_PAD_SINK: 1747 /* When reading data from the CCDC, the input size has already 1748 * been mangled by the CCDC output pad so it can be accepted 1749 * as-is. 1750 * 1751 * When reading data from memory, clamp the requested width and 1752 * height. The TRM doesn't specify a minimum input height, make 1753 * sure we got enough lines to enable the noise filter and color 1754 * filter array interpolation. 1755 */ 1756 if (prev->input == PREVIEW_INPUT_MEMORY) { 1757 fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, 1758 preview_max_out_width(prev)); 1759 fmt->height = clamp_t(u32, fmt->height, 1760 PREV_MIN_IN_HEIGHT, 1761 PREV_MAX_IN_HEIGHT); 1762 } 1763 1764 fmt->colorspace = V4L2_COLORSPACE_SRGB; 1765 1766 for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) { 1767 if (fmt->code == preview_input_fmts[i]) 1768 break; 1769 } 1770 1771 /* If not found, use SGRBG10 as default */ 1772 if (i >= ARRAY_SIZE(preview_input_fmts)) 1773 fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 1774 break; 1775 1776 case PREV_PAD_SOURCE: 1777 pixelcode = fmt->code; 1778 *fmt = *__preview_get_format(prev, sd_state, PREV_PAD_SINK, 1779 which); 1780 1781 switch (pixelcode) { 1782 case MEDIA_BUS_FMT_YUYV8_1X16: 1783 case MEDIA_BUS_FMT_UYVY8_1X16: 1784 fmt->code = pixelcode; 1785 break; 1786 1787 default: 1788 fmt->code = MEDIA_BUS_FMT_YUYV8_1X16; 1789 break; 1790 } 1791 1792 /* The preview module output size is configurable through the 1793 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This 1794 * is not supported yet, hardcode the output size to the crop 1795 * rectangle size. 1796 */ 1797 crop = __preview_get_crop(prev, sd_state, which); 1798 fmt->width = crop->width; 1799 fmt->height = crop->height; 1800 1801 fmt->colorspace = V4L2_COLORSPACE_JPEG; 1802 break; 1803 } 1804 1805 fmt->field = V4L2_FIELD_NONE; 1806} 1807 1808/* 1809 * preview_try_crop - Validate a crop rectangle 1810 * @prev: ISP preview engine 1811 * @sink: format on the sink pad 1812 * @crop: crop rectangle to be validated 1813 * 1814 * The preview engine crops lines and columns for its internal operation, 1815 * depending on which filters are enabled. Enforce minimum crop margins to 1816 * handle that transparently for userspace. 1817 * 1818 * See the explanation at the PREV_MARGIN_* definitions for more details. 1819 */ 1820static void preview_try_crop(struct isp_prev_device *prev, 1821 const struct v4l2_mbus_framefmt *sink, 1822 struct v4l2_rect *crop) 1823{ 1824 unsigned int left = PREV_MARGIN_LEFT; 1825 unsigned int right = sink->width - PREV_MARGIN_RIGHT; 1826 unsigned int top = PREV_MARGIN_TOP; 1827 unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; 1828 1829 /* When processing data on-the-fly from the CCDC, at least 2 pixels must 1830 * be cropped from the left and right sides of the image. As we don't 1831 * know which filters will be enabled, increase the left and right 1832 * margins by two. 1833 */ 1834 if (prev->input == PREVIEW_INPUT_CCDC) { 1835 left += 2; 1836 right -= 2; 1837 } 1838 1839 /* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines 1840 * and no columns in other modes. Increase the margins based on the sink 1841 * format. 1842 */ 1843 if (sink->code != MEDIA_BUS_FMT_Y8_1X8 && 1844 sink->code != MEDIA_BUS_FMT_Y10_1X10) { 1845 left += 2; 1846 right -= 2; 1847 top += 2; 1848 bottom -= 2; 1849 } 1850 1851 /* Restrict left/top to even values to keep the Bayer pattern. */ 1852 crop->left &= ~1; 1853 crop->top &= ~1; 1854 1855 crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); 1856 crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); 1857 crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, 1858 right - crop->left); 1859 crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, 1860 bottom - crop->top); 1861} 1862 1863/* 1864 * preview_enum_mbus_code - Handle pixel format enumeration 1865 * @sd : pointer to v4l2 subdev structure 1866 * @cfg: V4L2 subdev pad configuration 1867 * @code : pointer to v4l2_subdev_mbus_code_enum structure 1868 * return -EINVAL or zero on success 1869 */ 1870static int preview_enum_mbus_code(struct v4l2_subdev *sd, 1871 struct v4l2_subdev_state *sd_state, 1872 struct v4l2_subdev_mbus_code_enum *code) 1873{ 1874 switch (code->pad) { 1875 case PREV_PAD_SINK: 1876 if (code->index >= ARRAY_SIZE(preview_input_fmts)) 1877 return -EINVAL; 1878 1879 code->code = preview_input_fmts[code->index]; 1880 break; 1881 case PREV_PAD_SOURCE: 1882 if (code->index >= ARRAY_SIZE(preview_output_fmts)) 1883 return -EINVAL; 1884 1885 code->code = preview_output_fmts[code->index]; 1886 break; 1887 default: 1888 return -EINVAL; 1889 } 1890 1891 return 0; 1892} 1893 1894static int preview_enum_frame_size(struct v4l2_subdev *sd, 1895 struct v4l2_subdev_state *sd_state, 1896 struct v4l2_subdev_frame_size_enum *fse) 1897{ 1898 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 1899 struct v4l2_mbus_framefmt format; 1900 1901 if (fse->index != 0) 1902 return -EINVAL; 1903 1904 format.code = fse->code; 1905 format.width = 1; 1906 format.height = 1; 1907 preview_try_format(prev, sd_state, fse->pad, &format, fse->which); 1908 fse->min_width = format.width; 1909 fse->min_height = format.height; 1910 1911 if (format.code != fse->code) 1912 return -EINVAL; 1913 1914 format.code = fse->code; 1915 format.width = -1; 1916 format.height = -1; 1917 preview_try_format(prev, sd_state, fse->pad, &format, fse->which); 1918 fse->max_width = format.width; 1919 fse->max_height = format.height; 1920 1921 return 0; 1922} 1923 1924/* 1925 * preview_get_selection - Retrieve a selection rectangle on a pad 1926 * @sd: ISP preview V4L2 subdevice 1927 * @cfg: V4L2 subdev pad configuration 1928 * @sel: Selection rectangle 1929 * 1930 * The only supported rectangles are the crop rectangles on the sink pad. 1931 * 1932 * Return 0 on success or a negative error code otherwise. 1933 */ 1934static int preview_get_selection(struct v4l2_subdev *sd, 1935 struct v4l2_subdev_state *sd_state, 1936 struct v4l2_subdev_selection *sel) 1937{ 1938 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 1939 struct v4l2_mbus_framefmt *format; 1940 1941 if (sel->pad != PREV_PAD_SINK) 1942 return -EINVAL; 1943 1944 switch (sel->target) { 1945 case V4L2_SEL_TGT_CROP_BOUNDS: 1946 sel->r.left = 0; 1947 sel->r.top = 0; 1948 sel->r.width = INT_MAX; 1949 sel->r.height = INT_MAX; 1950 1951 format = __preview_get_format(prev, sd_state, PREV_PAD_SINK, 1952 sel->which); 1953 preview_try_crop(prev, format, &sel->r); 1954 break; 1955 1956 case V4L2_SEL_TGT_CROP: 1957 sel->r = *__preview_get_crop(prev, sd_state, sel->which); 1958 break; 1959 1960 default: 1961 return -EINVAL; 1962 } 1963 1964 return 0; 1965} 1966 1967/* 1968 * preview_set_selection - Set a selection rectangle on a pad 1969 * @sd: ISP preview V4L2 subdevice 1970 * @cfg: V4L2 subdev pad configuration 1971 * @sel: Selection rectangle 1972 * 1973 * The only supported rectangle is the actual crop rectangle on the sink pad. 1974 * 1975 * Return 0 on success or a negative error code otherwise. 1976 */ 1977static int preview_set_selection(struct v4l2_subdev *sd, 1978 struct v4l2_subdev_state *sd_state, 1979 struct v4l2_subdev_selection *sel) 1980{ 1981 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 1982 struct v4l2_mbus_framefmt *format; 1983 1984 if (sel->target != V4L2_SEL_TGT_CROP || 1985 sel->pad != PREV_PAD_SINK) 1986 return -EINVAL; 1987 1988 /* The crop rectangle can't be changed while streaming. */ 1989 if (prev->state != ISP_PIPELINE_STREAM_STOPPED) 1990 return -EBUSY; 1991 1992 /* Modifying the crop rectangle always changes the format on the source 1993 * pad. If the KEEP_CONFIG flag is set, just return the current crop 1994 * rectangle. 1995 */ 1996 if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { 1997 sel->r = *__preview_get_crop(prev, sd_state, sel->which); 1998 return 0; 1999 } 2000 2001 format = __preview_get_format(prev, sd_state, PREV_PAD_SINK, 2002 sel->which); 2003 preview_try_crop(prev, format, &sel->r); 2004 *__preview_get_crop(prev, sd_state, sel->which) = sel->r; 2005 2006 /* Update the source format. */ 2007 format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE, 2008 sel->which); 2009 preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format, 2010 sel->which); 2011 2012 return 0; 2013} 2014 2015/* 2016 * preview_get_format - Handle get format by pads subdev method 2017 * @sd : pointer to v4l2 subdev structure 2018 * @cfg: V4L2 subdev pad configuration 2019 * @fmt: pointer to v4l2 subdev format structure 2020 * return -EINVAL or zero on success 2021 */ 2022static int preview_get_format(struct v4l2_subdev *sd, 2023 struct v4l2_subdev_state *sd_state, 2024 struct v4l2_subdev_format *fmt) 2025{ 2026 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 2027 struct v4l2_mbus_framefmt *format; 2028 2029 format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which); 2030 if (format == NULL) 2031 return -EINVAL; 2032 2033 fmt->format = *format; 2034 return 0; 2035} 2036 2037/* 2038 * preview_set_format - Handle set format by pads subdev method 2039 * @sd : pointer to v4l2 subdev structure 2040 * @cfg: V4L2 subdev pad configuration 2041 * @fmt: pointer to v4l2 subdev format structure 2042 * return -EINVAL or zero on success 2043 */ 2044static int preview_set_format(struct v4l2_subdev *sd, 2045 struct v4l2_subdev_state *sd_state, 2046 struct v4l2_subdev_format *fmt) 2047{ 2048 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 2049 struct v4l2_mbus_framefmt *format; 2050 struct v4l2_rect *crop; 2051 2052 format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which); 2053 if (format == NULL) 2054 return -EINVAL; 2055 2056 preview_try_format(prev, sd_state, fmt->pad, &fmt->format, fmt->which); 2057 *format = fmt->format; 2058 2059 /* Propagate the format from sink to source */ 2060 if (fmt->pad == PREV_PAD_SINK) { 2061 /* Reset the crop rectangle. */ 2062 crop = __preview_get_crop(prev, sd_state, fmt->which); 2063 crop->left = 0; 2064 crop->top = 0; 2065 crop->width = fmt->format.width; 2066 crop->height = fmt->format.height; 2067 2068 preview_try_crop(prev, &fmt->format, crop); 2069 2070 /* Update the source format. */ 2071 format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE, 2072 fmt->which); 2073 preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format, 2074 fmt->which); 2075 } 2076 2077 return 0; 2078} 2079 2080/* 2081 * preview_init_formats - Initialize formats on all pads 2082 * @sd: ISP preview V4L2 subdevice 2083 * @fh: V4L2 subdev file handle 2084 * 2085 * Initialize all pad formats with default values. If fh is not NULL, try 2086 * formats are initialized on the file handle. Otherwise active formats are 2087 * initialized on the device. 2088 */ 2089static int preview_init_formats(struct v4l2_subdev *sd, 2090 struct v4l2_subdev_fh *fh) 2091{ 2092 struct v4l2_subdev_format format; 2093 2094 memset(&format, 0, sizeof(format)); 2095 format.pad = PREV_PAD_SINK; 2096 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 2097 format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 2098 format.format.width = 4096; 2099 format.format.height = 4096; 2100 preview_set_format(sd, fh ? fh->state : NULL, &format); 2101 2102 return 0; 2103} 2104 2105/* subdev core operations */ 2106static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = { 2107 .ioctl = preview_ioctl, 2108}; 2109 2110/* subdev video operations */ 2111static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = { 2112 .s_stream = preview_set_stream, 2113}; 2114 2115/* subdev pad operations */ 2116static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { 2117 .enum_mbus_code = preview_enum_mbus_code, 2118 .enum_frame_size = preview_enum_frame_size, 2119 .get_fmt = preview_get_format, 2120 .set_fmt = preview_set_format, 2121 .get_selection = preview_get_selection, 2122 .set_selection = preview_set_selection, 2123}; 2124 2125/* subdev operations */ 2126static const struct v4l2_subdev_ops preview_v4l2_ops = { 2127 .core = &preview_v4l2_core_ops, 2128 .video = &preview_v4l2_video_ops, 2129 .pad = &preview_v4l2_pad_ops, 2130}; 2131 2132/* subdev internal operations */ 2133static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = { 2134 .open = preview_init_formats, 2135}; 2136 2137/* ----------------------------------------------------------------------------- 2138 * Media entity operations 2139 */ 2140 2141/* 2142 * preview_link_setup - Setup previewer connections. 2143 * @entity : Pointer to media entity structure 2144 * @local : Pointer to local pad array 2145 * @remote : Pointer to remote pad array 2146 * @flags : Link flags 2147 * return -EINVAL or zero on success 2148 */ 2149static int preview_link_setup(struct media_entity *entity, 2150 const struct media_pad *local, 2151 const struct media_pad *remote, u32 flags) 2152{ 2153 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 2154 struct isp_prev_device *prev = v4l2_get_subdevdata(sd); 2155 unsigned int index = local->index; 2156 2157 /* FIXME: this is actually a hack! */ 2158 if (is_media_entity_v4l2_subdev(remote->entity)) 2159 index |= 2 << 16; 2160 2161 switch (index) { 2162 case PREV_PAD_SINK: 2163 /* read from memory */ 2164 if (flags & MEDIA_LNK_FL_ENABLED) { 2165 if (prev->input == PREVIEW_INPUT_CCDC) 2166 return -EBUSY; 2167 prev->input = PREVIEW_INPUT_MEMORY; 2168 } else { 2169 if (prev->input == PREVIEW_INPUT_MEMORY) 2170 prev->input = PREVIEW_INPUT_NONE; 2171 } 2172 break; 2173 2174 case PREV_PAD_SINK | 2 << 16: 2175 /* read from ccdc */ 2176 if (flags & MEDIA_LNK_FL_ENABLED) { 2177 if (prev->input == PREVIEW_INPUT_MEMORY) 2178 return -EBUSY; 2179 prev->input = PREVIEW_INPUT_CCDC; 2180 } else { 2181 if (prev->input == PREVIEW_INPUT_CCDC) 2182 prev->input = PREVIEW_INPUT_NONE; 2183 } 2184 break; 2185 2186 /* 2187 * The ISP core doesn't support pipelines with multiple video outputs. 2188 * Revisit this when it will be implemented, and return -EBUSY for now. 2189 */ 2190 2191 case PREV_PAD_SOURCE: 2192 /* write to memory */ 2193 if (flags & MEDIA_LNK_FL_ENABLED) { 2194 if (prev->output & ~PREVIEW_OUTPUT_MEMORY) 2195 return -EBUSY; 2196 prev->output |= PREVIEW_OUTPUT_MEMORY; 2197 } else { 2198 prev->output &= ~PREVIEW_OUTPUT_MEMORY; 2199 } 2200 break; 2201 2202 case PREV_PAD_SOURCE | 2 << 16: 2203 /* write to resizer */ 2204 if (flags & MEDIA_LNK_FL_ENABLED) { 2205 if (prev->output & ~PREVIEW_OUTPUT_RESIZER) 2206 return -EBUSY; 2207 prev->output |= PREVIEW_OUTPUT_RESIZER; 2208 } else { 2209 prev->output &= ~PREVIEW_OUTPUT_RESIZER; 2210 } 2211 break; 2212 2213 default: 2214 return -EINVAL; 2215 } 2216 2217 return 0; 2218} 2219 2220/* media operations */ 2221static const struct media_entity_operations preview_media_ops = { 2222 .link_setup = preview_link_setup, 2223 .link_validate = v4l2_subdev_link_validate, 2224}; 2225 2226void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) 2227{ 2228 v4l2_device_unregister_subdev(&prev->subdev); 2229 omap3isp_video_unregister(&prev->video_in); 2230 omap3isp_video_unregister(&prev->video_out); 2231} 2232 2233int omap3isp_preview_register_entities(struct isp_prev_device *prev, 2234 struct v4l2_device *vdev) 2235{ 2236 int ret; 2237 2238 /* Register the subdev and video nodes. */ 2239 prev->subdev.dev = vdev->mdev->dev; 2240 ret = v4l2_device_register_subdev(vdev, &prev->subdev); 2241 if (ret < 0) 2242 goto error; 2243 2244 ret = omap3isp_video_register(&prev->video_in, vdev); 2245 if (ret < 0) 2246 goto error; 2247 2248 ret = omap3isp_video_register(&prev->video_out, vdev); 2249 if (ret < 0) 2250 goto error; 2251 2252 return 0; 2253 2254error: 2255 omap3isp_preview_unregister_entities(prev); 2256 return ret; 2257} 2258 2259/* ----------------------------------------------------------------------------- 2260 * ISP previewer initialisation and cleanup 2261 */ 2262 2263/* 2264 * preview_init_entities - Initialize subdev and media entity. 2265 * @prev : Pointer to preview structure 2266 * return -ENOMEM or zero on success 2267 */ 2268static int preview_init_entities(struct isp_prev_device *prev) 2269{ 2270 struct v4l2_subdev *sd = &prev->subdev; 2271 struct media_pad *pads = prev->pads; 2272 struct media_entity *me = &sd->entity; 2273 int ret; 2274 2275 prev->input = PREVIEW_INPUT_NONE; 2276 2277 v4l2_subdev_init(sd, &preview_v4l2_ops); 2278 sd->internal_ops = &preview_v4l2_internal_ops; 2279 strscpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name)); 2280 sd->grp_id = 1 << 16; /* group ID for isp subdevs */ 2281 v4l2_set_subdevdata(sd, prev); 2282 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 2283 2284 v4l2_ctrl_handler_init(&prev->ctrls, 2); 2285 v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS, 2286 ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH, 2287 ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF); 2288 v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST, 2289 ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH, 2290 ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF); 2291 v4l2_ctrl_handler_setup(&prev->ctrls); 2292 sd->ctrl_handler = &prev->ctrls; 2293 2294 pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK 2295 | MEDIA_PAD_FL_MUST_CONNECT; 2296 pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 2297 2298 me->ops = &preview_media_ops; 2299 ret = media_entity_pads_init(me, PREV_PADS_NUM, pads); 2300 if (ret < 0) 2301 goto error_handler_free; 2302 2303 preview_init_formats(sd, NULL); 2304 2305 /* According to the OMAP34xx TRM, video buffers need to be aligned on a 2306 * 32 bytes boundary. However, an undocumented hardware bug requires a 2307 * 64 bytes boundary at the preview engine input. 2308 */ 2309 prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 2310 prev->video_in.ops = &preview_video_ops; 2311 prev->video_in.isp = to_isp_device(prev); 2312 prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; 2313 prev->video_in.bpl_alignment = 64; 2314 prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2315 prev->video_out.ops = &preview_video_ops; 2316 prev->video_out.isp = to_isp_device(prev); 2317 prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; 2318 prev->video_out.bpl_alignment = 32; 2319 2320 ret = omap3isp_video_init(&prev->video_in, "preview"); 2321 if (ret < 0) 2322 goto error_video_in; 2323 2324 ret = omap3isp_video_init(&prev->video_out, "preview"); 2325 if (ret < 0) 2326 goto error_video_out; 2327 2328 return 0; 2329 2330error_video_out: 2331 omap3isp_video_cleanup(&prev->video_in); 2332error_video_in: 2333 media_entity_cleanup(&prev->subdev.entity); 2334error_handler_free: 2335 v4l2_ctrl_handler_free(&prev->ctrls); 2336 return ret; 2337} 2338 2339/* 2340 * omap3isp_preview_init - Previewer initialization. 2341 * @isp : Pointer to ISP device 2342 * return -ENOMEM or zero on success 2343 */ 2344int omap3isp_preview_init(struct isp_device *isp) 2345{ 2346 struct isp_prev_device *prev = &isp->isp_prev; 2347 2348 init_waitqueue_head(&prev->wait); 2349 2350 preview_init_params(prev); 2351 2352 return preview_init_entities(prev); 2353} 2354 2355void omap3isp_preview_cleanup(struct isp_device *isp) 2356{ 2357 struct isp_prev_device *prev = &isp->isp_prev; 2358 2359 v4l2_ctrl_handler_free(&prev->ctrls); 2360 omap3isp_video_cleanup(&prev->video_in); 2361 omap3isp_video_cleanup(&prev->video_out); 2362 media_entity_cleanup(&prev->subdev.entity); 2363}