4 * TI OMAP3 ISP driver - Preview module
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27 #include <linux/device.h>
29 #include <linux/module.h>
30 #include <linux/mutex.h>
31 #include <linux/uaccess.h>
35 #include "isppreview.h"
37 /* Default values in Office Fluorescent Light for RGBtoRGB Blending */
38 static struct omap3isp_prev_rgbtorgb flr_rgb2rgb
= {
39 { /* RGB-RGB Matrix */
40 {0x01E2, 0x0F30, 0x0FEE},
41 {0x0F9B, 0x01AC, 0x0FB9},
42 {0x0FE0, 0x0EC0, 0x0260}
44 {0x0000, 0x0000, 0x0000}
47 /* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
48 static struct omap3isp_prev_csc flr_prev_csc
= {
49 { /* CSC Coef Matrix */
57 /* Default values in Office Fluorescent Light for CFA Gradient*/
58 #define FLR_CFA_GRADTHRS_HORZ 0x28
59 #define FLR_CFA_GRADTHRS_VERT 0x28
61 /* Default values in Office Fluorescent Light for Chroma Suppression*/
62 #define FLR_CSUP_GAIN 0x0D
63 #define FLR_CSUP_THRES 0xEB
65 /* Default values in Office Fluorescent Light for Noise Filter*/
66 #define FLR_NF_STRGTH 0x03
68 /* Default values for White Balance */
69 #define FLR_WBAL_DGAIN 0x100
70 #define FLR_WBAL_COEF 0x20
72 /* Default values in Office Fluorescent Light for Black Adjustment*/
73 #define FLR_BLKADJ_BLUE 0x0
74 #define FLR_BLKADJ_GREEN 0x0
75 #define FLR_BLKADJ_RED 0x0
77 #define DEF_DETECT_CORRECT_VAL 0xe
80 * Margins and image size limits.
82 * The preview engine crops several rows and columns internally depending on
83 * which filters are enabled. To avoid format changes when the filters are
84 * enabled or disabled (which would prevent them from being turned on or off
85 * during streaming), the driver assumes all the filters are enabled when
86 * computing sink crop and source format limits.
88 * If a filter is disabled, additional cropping is automatically added at the
89 * preview engine input by the driver to avoid overflow at line and frame end.
90 * This is completely transparent for applications.
92 * Median filter 4 pixels
94 * Faulty pixels correction 4 pixels, 4 lines
95 * CFA filter 4 pixels, 4 lines in Bayer mode
96 * 2 lines in other modes
97 * Color suppression 2 pixels
99 * -------------------------------------------------------------
100 * Maximum total 14 pixels, 8 lines
102 * The color suppression and luma enhancement filters are applied after bayer to
103 * YUV conversion. They thus can crop one pixel on the left and one pixel on the
104 * right side of the image without changing the color pattern. When both those
105 * filters are disabled, the driver must crop the two pixels on the same side of
106 * the image to avoid changing the bayer pattern. The left margin is thus set to
107 * 8 pixels and the right margin to 6 pixels.
110 #define PREV_MARGIN_LEFT 8
111 #define PREV_MARGIN_RIGHT 6
112 #define PREV_MARGIN_TOP 4
113 #define PREV_MARGIN_BOTTOM 4
115 #define PREV_MIN_IN_WIDTH 64
116 #define PREV_MIN_IN_HEIGHT 8
117 #define PREV_MAX_IN_HEIGHT 16384
119 #define PREV_MIN_OUT_WIDTH 0
120 #define PREV_MIN_OUT_HEIGHT 0
121 #define PREV_MAX_OUT_WIDTH_REV_1 1280
122 #define PREV_MAX_OUT_WIDTH_REV_2 3300
123 #define PREV_MAX_OUT_WIDTH_REV_15 4096
126 * Coeficient Tables for the submodules in Preview.
127 * Array is initialised with the values from.the tables text file.
131 * CFA Filter Coefficient Table
134 static u32 cfa_coef_table
[] = {
135 #include "cfa_coef_table.h"
139 * Default Gamma Correction Table - All components
141 static u32 gamma_table
[] = {
142 #include "gamma_table.h"
146 * Noise Filter Threshold table
148 static u32 noise_filter_table
[] = {
149 #include "noise_filter_table.h"
153 * Luminance Enhancement Table
155 static u32 luma_enhance_table
[] = {
156 #include "luma_enhance_table.h"
160 * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
161 * @enable: 1 - Reverse the A-Law done in CCDC.
164 preview_enable_invalaw(struct isp_prev_device
*prev
, u8 enable
)
166 struct isp_device
*isp
= to_isp_device(prev
);
169 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
170 ISPPRV_PCR_WIDTH
| ISPPRV_PCR_INVALAW
);
172 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
173 ISPPRV_PCR_WIDTH
| ISPPRV_PCR_INVALAW
);
177 * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture.
179 * @enable: 1 - Enable, 0 - Disable
181 * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
182 * The process is applied for each captured frame.
185 preview_enable_drkframe_capture(struct isp_prev_device
*prev
, u8 enable
)
187 struct isp_device
*isp
= to_isp_device(prev
);
190 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
193 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
198 * preview_enable_drkframe - Enable/Disable of the darkframe subtract.
199 * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
200 * subtracted with the pixels in the current frame.
202 * The process is applied for each captured frame.
205 preview_enable_drkframe(struct isp_prev_device
*prev
, u8 enable
)
207 struct isp_device
*isp
= to_isp_device(prev
);
210 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
213 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
218 * preview_config_drkf_shadcomp - Configures shift value in shading comp.
219 * @scomp_shtval: 3bit value of shift used in shading compensation.
222 preview_config_drkf_shadcomp(struct isp_prev_device
*prev
,
223 const void *scomp_shtval
)
225 struct isp_device
*isp
= to_isp_device(prev
);
226 const u32
*shtval
= scomp_shtval
;
228 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
229 ISPPRV_PCR_SCOMP_SFT_MASK
,
230 *shtval
<< ISPPRV_PCR_SCOMP_SFT_SHIFT
);
234 * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
235 * @enable: 1 - Enables Horizontal Median Filter.
238 preview_enable_hmed(struct isp_prev_device
*prev
, u8 enable
)
240 struct isp_device
*isp
= to_isp_device(prev
);
243 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
246 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
251 * preview_config_hmed - Configures the Horizontal Median Filter.
252 * @prev_hmed: Structure containing the odd and even distance between the
253 * pixels in the image along with the filter threshold.
256 preview_config_hmed(struct isp_prev_device
*prev
, const void *prev_hmed
)
258 struct isp_device
*isp
= to_isp_device(prev
);
259 const struct omap3isp_prev_hmed
*hmed
= prev_hmed
;
261 isp_reg_writel(isp
, (hmed
->odddist
== 1 ? 0 : ISPPRV_HMED_ODDDIST
) |
262 (hmed
->evendist
== 1 ? 0 : ISPPRV_HMED_EVENDIST
) |
263 (hmed
->thres
<< ISPPRV_HMED_THRESHOLD_SHIFT
),
264 OMAP3_ISP_IOMEM_PREV
, ISPPRV_HMED
);
268 * preview_config_noisefilter - Configures the Noise Filter.
269 * @prev_nf: Structure containing the noisefilter table, strength to be used
270 * for the noise filter and the defect correction enable flag.
273 preview_config_noisefilter(struct isp_prev_device
*prev
, const void *prev_nf
)
275 struct isp_device
*isp
= to_isp_device(prev
);
276 const struct omap3isp_prev_nf
*nf
= prev_nf
;
279 isp_reg_writel(isp
, nf
->spread
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_NF
);
280 isp_reg_writel(isp
, ISPPRV_NF_TABLE_ADDR
,
281 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_ADDR
);
282 for (i
= 0; i
< OMAP3ISP_PREV_NF_TBL_SIZE
; i
++) {
283 isp_reg_writel(isp
, nf
->table
[i
],
284 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_DATA
);
289 * preview_config_dcor - Configures the defect correction
290 * @prev_dcor: Structure containing the defect correct thresholds
293 preview_config_dcor(struct isp_prev_device
*prev
, const void *prev_dcor
)
295 struct isp_device
*isp
= to_isp_device(prev
);
296 const struct omap3isp_prev_dcor
*dcor
= prev_dcor
;
298 isp_reg_writel(isp
, dcor
->detect_correct
[0],
299 OMAP3_ISP_IOMEM_PREV
, ISPPRV_CDC_THR0
);
300 isp_reg_writel(isp
, dcor
->detect_correct
[1],
301 OMAP3_ISP_IOMEM_PREV
, ISPPRV_CDC_THR1
);
302 isp_reg_writel(isp
, dcor
->detect_correct
[2],
303 OMAP3_ISP_IOMEM_PREV
, ISPPRV_CDC_THR2
);
304 isp_reg_writel(isp
, dcor
->detect_correct
[3],
305 OMAP3_ISP_IOMEM_PREV
, ISPPRV_CDC_THR3
);
306 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
308 dcor
->couplet_mode_en
? ISPPRV_PCR_DCCOUP
: 0);
312 * preview_config_cfa - Configures the CFA Interpolation parameters.
313 * @prev_cfa: Structure containing the CFA interpolation table, CFA format
314 * in the image, vertical and horizontal gradient threshold.
317 preview_config_cfa(struct isp_prev_device
*prev
, const void *prev_cfa
)
319 struct isp_device
*isp
= to_isp_device(prev
);
320 const struct omap3isp_prev_cfa
*cfa
= prev_cfa
;
323 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
324 ISPPRV_PCR_CFAFMT_MASK
,
325 cfa
->format
<< ISPPRV_PCR_CFAFMT_SHIFT
);
328 (cfa
->gradthrs_vert
<< ISPPRV_CFA_GRADTH_VER_SHIFT
) |
329 (cfa
->gradthrs_horz
<< ISPPRV_CFA_GRADTH_HOR_SHIFT
),
330 OMAP3_ISP_IOMEM_PREV
, ISPPRV_CFA
);
332 isp_reg_writel(isp
, ISPPRV_CFA_TABLE_ADDR
,
333 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_ADDR
);
335 for (i
= 0; i
< OMAP3ISP_PREV_CFA_TBL_SIZE
; i
++) {
336 isp_reg_writel(isp
, cfa
->table
[i
],
337 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_DATA
);
342 * preview_config_gammacorrn - Configures the Gamma Correction table values
343 * @gtable: Structure containing the table for red, blue, green gamma table.
346 preview_config_gammacorrn(struct isp_prev_device
*prev
, const void *gtable
)
348 struct isp_device
*isp
= to_isp_device(prev
);
349 const struct omap3isp_prev_gtables
*gt
= gtable
;
352 isp_reg_writel(isp
, ISPPRV_REDGAMMA_TABLE_ADDR
,
353 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_ADDR
);
354 for (i
= 0; i
< OMAP3ISP_PREV_GAMMA_TBL_SIZE
; i
++)
355 isp_reg_writel(isp
, gt
->red
[i
], OMAP3_ISP_IOMEM_PREV
,
356 ISPPRV_SET_TBL_DATA
);
358 isp_reg_writel(isp
, ISPPRV_GREENGAMMA_TABLE_ADDR
,
359 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_ADDR
);
360 for (i
= 0; i
< OMAP3ISP_PREV_GAMMA_TBL_SIZE
; i
++)
361 isp_reg_writel(isp
, gt
->green
[i
], OMAP3_ISP_IOMEM_PREV
,
362 ISPPRV_SET_TBL_DATA
);
364 isp_reg_writel(isp
, ISPPRV_BLUEGAMMA_TABLE_ADDR
,
365 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_ADDR
);
366 for (i
= 0; i
< OMAP3ISP_PREV_GAMMA_TBL_SIZE
; i
++)
367 isp_reg_writel(isp
, gt
->blue
[i
], OMAP3_ISP_IOMEM_PREV
,
368 ISPPRV_SET_TBL_DATA
);
372 * preview_config_luma_enhancement - Sets the Luminance Enhancement table.
373 * @ytable: Structure containing the table for Luminance Enhancement table.
376 preview_config_luma_enhancement(struct isp_prev_device
*prev
,
379 struct isp_device
*isp
= to_isp_device(prev
);
380 const struct omap3isp_prev_luma
*yt
= ytable
;
383 isp_reg_writel(isp
, ISPPRV_YENH_TABLE_ADDR
,
384 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_ADDR
);
385 for (i
= 0; i
< OMAP3ISP_PREV_YENH_TBL_SIZE
; i
++) {
386 isp_reg_writel(isp
, yt
->table
[i
],
387 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SET_TBL_DATA
);
392 * preview_config_chroma_suppression - Configures the Chroma Suppression.
393 * @csup: Structure containing the threshold value for suppression
394 * and the hypass filter enable flag.
397 preview_config_chroma_suppression(struct isp_prev_device
*prev
,
400 struct isp_device
*isp
= to_isp_device(prev
);
401 const struct omap3isp_prev_csup
*cs
= csup
;
404 cs
->gain
| (cs
->thres
<< ISPPRV_CSUP_THRES_SHIFT
) |
405 (cs
->hypf_en
<< ISPPRV_CSUP_HPYF_SHIFT
),
406 OMAP3_ISP_IOMEM_PREV
, ISPPRV_CSUP
);
410 * preview_enable_noisefilter - Enables/Disables the Noise Filter.
411 * @enable: 1 - Enables the Noise Filter.
414 preview_enable_noisefilter(struct isp_prev_device
*prev
, u8 enable
)
416 struct isp_device
*isp
= to_isp_device(prev
);
419 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
422 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
427 * preview_enable_dcor - Enables/Disables the defect correction.
428 * @enable: 1 - Enables the defect correction.
431 preview_enable_dcor(struct isp_prev_device
*prev
, u8 enable
)
433 struct isp_device
*isp
= to_isp_device(prev
);
436 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
439 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
444 * preview_enable_gammabypass - Enables/Disables the GammaByPass
445 * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
446 * 0 - Goes through Gamma Correction. input and output is 10bit.
449 preview_enable_gammabypass(struct isp_prev_device
*prev
, u8 enable
)
451 struct isp_device
*isp
= to_isp_device(prev
);
454 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
455 ISPPRV_PCR_GAMMA_BYPASS
);
457 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
458 ISPPRV_PCR_GAMMA_BYPASS
);
462 * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
463 * @enable: 1 - Enable the Luminance Enhancement.
466 preview_enable_luma_enhancement(struct isp_prev_device
*prev
, u8 enable
)
468 struct isp_device
*isp
= to_isp_device(prev
);
471 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
474 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
479 * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
480 * @enable: 1 - Enable the Chrominance Suppression.
483 preview_enable_chroma_suppression(struct isp_prev_device
*prev
, u8 enable
)
485 struct isp_device
*isp
= to_isp_device(prev
);
488 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
491 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
496 * preview_config_whitebalance - Configures the White Balance parameters.
497 * @prev_wbal: Structure containing the digital gain and white balance
500 * Coefficient matrix always with default values.
503 preview_config_whitebalance(struct isp_prev_device
*prev
, const void *prev_wbal
)
505 struct isp_device
*isp
= to_isp_device(prev
);
506 const struct omap3isp_prev_wbal
*wbal
= prev_wbal
;
509 isp_reg_writel(isp
, wbal
->dgain
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_WB_DGAIN
);
511 val
= wbal
->coef0
<< ISPPRV_WBGAIN_COEF0_SHIFT
;
512 val
|= wbal
->coef1
<< ISPPRV_WBGAIN_COEF1_SHIFT
;
513 val
|= wbal
->coef2
<< ISPPRV_WBGAIN_COEF2_SHIFT
;
514 val
|= wbal
->coef3
<< ISPPRV_WBGAIN_COEF3_SHIFT
;
515 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_WBGAIN
);
518 ISPPRV_WBSEL_COEF0
<< ISPPRV_WBSEL_N0_0_SHIFT
|
519 ISPPRV_WBSEL_COEF1
<< ISPPRV_WBSEL_N0_1_SHIFT
|
520 ISPPRV_WBSEL_COEF0
<< ISPPRV_WBSEL_N0_2_SHIFT
|
521 ISPPRV_WBSEL_COEF1
<< ISPPRV_WBSEL_N0_3_SHIFT
|
522 ISPPRV_WBSEL_COEF2
<< ISPPRV_WBSEL_N1_0_SHIFT
|
523 ISPPRV_WBSEL_COEF3
<< ISPPRV_WBSEL_N1_1_SHIFT
|
524 ISPPRV_WBSEL_COEF2
<< ISPPRV_WBSEL_N1_2_SHIFT
|
525 ISPPRV_WBSEL_COEF3
<< ISPPRV_WBSEL_N1_3_SHIFT
|
526 ISPPRV_WBSEL_COEF0
<< ISPPRV_WBSEL_N2_0_SHIFT
|
527 ISPPRV_WBSEL_COEF1
<< ISPPRV_WBSEL_N2_1_SHIFT
|
528 ISPPRV_WBSEL_COEF0
<< ISPPRV_WBSEL_N2_2_SHIFT
|
529 ISPPRV_WBSEL_COEF1
<< ISPPRV_WBSEL_N2_3_SHIFT
|
530 ISPPRV_WBSEL_COEF2
<< ISPPRV_WBSEL_N3_0_SHIFT
|
531 ISPPRV_WBSEL_COEF3
<< ISPPRV_WBSEL_N3_1_SHIFT
|
532 ISPPRV_WBSEL_COEF2
<< ISPPRV_WBSEL_N3_2_SHIFT
|
533 ISPPRV_WBSEL_COEF3
<< ISPPRV_WBSEL_N3_3_SHIFT
,
534 OMAP3_ISP_IOMEM_PREV
, ISPPRV_WBSEL
);
538 * preview_config_blkadj - Configures the Black Adjustment parameters.
539 * @prev_blkadj: Structure containing the black adjustment towards red, green,
543 preview_config_blkadj(struct isp_prev_device
*prev
, const void *prev_blkadj
)
545 struct isp_device
*isp
= to_isp_device(prev
);
546 const struct omap3isp_prev_blkadj
*blkadj
= prev_blkadj
;
548 isp_reg_writel(isp
, (blkadj
->blue
<< ISPPRV_BLKADJOFF_B_SHIFT
) |
549 (blkadj
->green
<< ISPPRV_BLKADJOFF_G_SHIFT
) |
550 (blkadj
->red
<< ISPPRV_BLKADJOFF_R_SHIFT
),
551 OMAP3_ISP_IOMEM_PREV
, ISPPRV_BLKADJOFF
);
555 * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix.
556 * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
560 preview_config_rgb_blending(struct isp_prev_device
*prev
, const void *rgb2rgb
)
562 struct isp_device
*isp
= to_isp_device(prev
);
563 const struct omap3isp_prev_rgbtorgb
*rgbrgb
= rgb2rgb
;
566 val
= (rgbrgb
->matrix
[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT
;
567 val
|= (rgbrgb
->matrix
[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT
;
568 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_MAT1
);
570 val
= (rgbrgb
->matrix
[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT
;
571 val
|= (rgbrgb
->matrix
[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT
;
572 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_MAT2
);
574 val
= (rgbrgb
->matrix
[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT
;
575 val
|= (rgbrgb
->matrix
[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT
;
576 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_MAT3
);
578 val
= (rgbrgb
->matrix
[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT
;
579 val
|= (rgbrgb
->matrix
[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT
;
580 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_MAT4
);
582 val
= (rgbrgb
->matrix
[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT
;
583 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_MAT5
);
585 val
= (rgbrgb
->offset
[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT
;
586 val
|= (rgbrgb
->offset
[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT
;
587 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_OFF1
);
589 val
= (rgbrgb
->offset
[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT
;
590 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RGB_OFF2
);
594 * Configures the color space conversion (RGB toYCbYCr) matrix
595 * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
599 preview_config_csc(struct isp_prev_device
*prev
, const void *prev_csc
)
601 struct isp_device
*isp
= to_isp_device(prev
);
602 const struct omap3isp_prev_csc
*csc
= prev_csc
;
605 val
= (csc
->matrix
[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT
;
606 val
|= (csc
->matrix
[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT
;
607 val
|= (csc
->matrix
[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT
;
608 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_CSC0
);
610 val
= (csc
->matrix
[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT
;
611 val
|= (csc
->matrix
[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT
;
612 val
|= (csc
->matrix
[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT
;
613 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_CSC1
);
615 val
= (csc
->matrix
[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT
;
616 val
|= (csc
->matrix
[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT
;
617 val
|= (csc
->matrix
[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT
;
618 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_CSC2
);
620 val
= (csc
->offset
[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT
;
621 val
|= (csc
->offset
[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT
;
622 val
|= (csc
->offset
[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT
;
623 isp_reg_writel(isp
, val
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_CSC_OFFSET
);
627 * preview_update_contrast - Updates the contrast.
628 * @contrast: Pointer to hold the current programmed contrast value.
630 * Value should be programmed before enabling the module.
633 preview_update_contrast(struct isp_prev_device
*prev
, u8 contrast
)
635 struct prev_params
*params
;
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];
642 if (params
->contrast
!= (contrast
* ISPPRV_CONTRAST_UNITS
)) {
643 params
->contrast
= contrast
* ISPPRV_CONTRAST_UNITS
;
644 params
->update
|= OMAP3ISP_PREV_CONTRAST
;
646 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
650 * preview_config_contrast - Configures the Contrast.
651 * @params: Contrast value (u8 pointer, U8Q0 format).
653 * Value should be programmed before enabling the module.
656 preview_config_contrast(struct isp_prev_device
*prev
, const void *params
)
658 struct isp_device
*isp
= to_isp_device(prev
);
660 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_CNT_BRT
,
661 0xff << ISPPRV_CNT_BRT_CNT_SHIFT
,
662 *(u8
*)params
<< ISPPRV_CNT_BRT_CNT_SHIFT
);
666 * preview_update_brightness - Updates the brightness in preview module.
667 * @brightness: Pointer to hold the current programmed brightness value.
671 preview_update_brightness(struct isp_prev_device
*prev
, u8 brightness
)
673 struct prev_params
*params
;
676 spin_lock_irqsave(&prev
->params
.lock
, flags
);
677 params
= (prev
->params
.active
& OMAP3ISP_PREV_BRIGHTNESS
)
678 ? &prev
->params
.params
[0] : &prev
->params
.params
[1];
680 if (params
->brightness
!= (brightness
* ISPPRV_BRIGHT_UNITS
)) {
681 params
->brightness
= brightness
* ISPPRV_BRIGHT_UNITS
;
682 params
->update
|= OMAP3ISP_PREV_BRIGHTNESS
;
684 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
688 * preview_config_brightness - Configures the brightness.
689 * @params: Brightness value (u8 pointer, U8Q0 format).
692 preview_config_brightness(struct isp_prev_device
*prev
, const void *params
)
694 struct isp_device
*isp
= to_isp_device(prev
);
696 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_CNT_BRT
,
697 0xff << ISPPRV_CNT_BRT_BRT_SHIFT
,
698 *(u8
*)params
<< ISPPRV_CNT_BRT_BRT_SHIFT
);
702 * preview_config_yc_range - Configures the max and min Y and C values.
703 * @yclimit: Structure containing the range of Y and C values.
706 preview_config_yc_range(struct isp_prev_device
*prev
, const void *yclimit
)
708 struct isp_device
*isp
= to_isp_device(prev
);
709 const struct omap3isp_prev_yclimit
*yc
= yclimit
;
712 yc
->maxC
<< ISPPRV_SETUP_YC_MAXC_SHIFT
|
713 yc
->maxY
<< ISPPRV_SETUP_YC_MAXY_SHIFT
|
714 yc
->minC
<< ISPPRV_SETUP_YC_MINC_SHIFT
|
715 yc
->minY
<< ISPPRV_SETUP_YC_MINY_SHIFT
,
716 OMAP3_ISP_IOMEM_PREV
, ISPPRV_SETUP_YC
);
720 preview_params_lock(struct isp_prev_device
*prev
, u32 update
, bool shadow
)
722 u32 active
= prev
->params
.active
;
725 /* Mark all shadow parameters we are going to touch as busy. */
726 prev
->params
.params
[0].busy
|= ~active
& update
;
727 prev
->params
.params
[1].busy
|= active
& update
;
729 /* Mark all active parameters we are going to touch as busy. */
730 update
= (prev
->params
.params
[0].update
& active
)
731 | (prev
->params
.params
[1].update
& ~active
);
733 prev
->params
.params
[0].busy
|= active
& update
;
734 prev
->params
.params
[1].busy
|= ~active
& update
;
741 preview_params_unlock(struct isp_prev_device
*prev
, u32 update
, bool shadow
)
743 u32 active
= prev
->params
.active
;
746 /* Set the update flag for shadow parameters that have been
747 * updated and clear the busy flag for all shadow parameters.
749 prev
->params
.params
[0].update
|= (~active
& update
);
750 prev
->params
.params
[1].update
|= (active
& update
);
751 prev
->params
.params
[0].busy
&= active
;
752 prev
->params
.params
[1].busy
&= ~active
;
754 /* Clear the update flag for active parameters that have been
755 * applied and the busy flag for all active parameters.
757 prev
->params
.params
[0].update
&= ~(active
& update
);
758 prev
->params
.params
[1].update
&= ~(~active
& update
);
759 prev
->params
.params
[0].busy
&= ~active
;
760 prev
->params
.params
[1].busy
&= active
;
764 static void preview_params_switch(struct isp_prev_device
*prev
)
768 /* Switch active parameters with updated shadow parameters when the
769 * shadow parameter has been updated and neither the active not the
770 * shadow parameter is busy.
772 to_switch
= (prev
->params
.params
[0].update
& ~prev
->params
.active
)
773 | (prev
->params
.params
[1].update
& prev
->params
.active
);
774 to_switch
&= ~(prev
->params
.params
[0].busy
|
775 prev
->params
.params
[1].busy
);
779 prev
->params
.active
^= to_switch
;
781 /* Remove the update flag for the shadow copy of parameters we have
784 prev
->params
.params
[0].update
&= ~(~prev
->params
.active
& to_switch
);
785 prev
->params
.params
[1].update
&= ~(prev
->params
.active
& to_switch
);
788 /* preview parameters update structure */
789 struct preview_update
{
790 void (*config
)(struct isp_prev_device
*, const void *);
791 void (*enable
)(struct isp_prev_device
*, u8
);
792 unsigned int param_offset
;
793 unsigned int param_size
;
794 unsigned int config_offset
;
798 /* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
799 static const struct preview_update update_attrs
[] = {
800 /* OMAP3ISP_PREV_LUMAENH */ {
801 preview_config_luma_enhancement
,
802 preview_enable_luma_enhancement
,
803 offsetof(struct prev_params
, luma
),
804 FIELD_SIZEOF(struct prev_params
, luma
),
805 offsetof(struct omap3isp_prev_update_config
, luma
),
806 }, /* OMAP3ISP_PREV_INVALAW */ {
808 preview_enable_invalaw
,
809 }, /* OMAP3ISP_PREV_HRZ_MED */ {
812 offsetof(struct prev_params
, hmed
),
813 FIELD_SIZEOF(struct prev_params
, hmed
),
814 offsetof(struct omap3isp_prev_update_config
, hmed
),
815 }, /* OMAP3ISP_PREV_CFA */ {
818 offsetof(struct prev_params
, cfa
),
819 FIELD_SIZEOF(struct prev_params
, cfa
),
820 offsetof(struct omap3isp_prev_update_config
, cfa
),
821 }, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
822 preview_config_chroma_suppression
,
823 preview_enable_chroma_suppression
,
824 offsetof(struct prev_params
, csup
),
825 FIELD_SIZEOF(struct prev_params
, csup
),
826 offsetof(struct omap3isp_prev_update_config
, csup
),
827 }, /* OMAP3ISP_PREV_WB */ {
828 preview_config_whitebalance
,
830 offsetof(struct prev_params
, wbal
),
831 FIELD_SIZEOF(struct prev_params
, wbal
),
832 offsetof(struct omap3isp_prev_update_config
, wbal
),
833 }, /* OMAP3ISP_PREV_BLKADJ */ {
834 preview_config_blkadj
,
836 offsetof(struct prev_params
, blkadj
),
837 FIELD_SIZEOF(struct prev_params
, blkadj
),
838 offsetof(struct omap3isp_prev_update_config
, blkadj
),
839 }, /* OMAP3ISP_PREV_RGB2RGB */ {
840 preview_config_rgb_blending
,
842 offsetof(struct prev_params
, rgb2rgb
),
843 FIELD_SIZEOF(struct prev_params
, rgb2rgb
),
844 offsetof(struct omap3isp_prev_update_config
, rgb2rgb
),
845 }, /* OMAP3ISP_PREV_COLOR_CONV */ {
848 offsetof(struct prev_params
, csc
),
849 FIELD_SIZEOF(struct prev_params
, csc
),
850 offsetof(struct omap3isp_prev_update_config
, csc
),
851 }, /* OMAP3ISP_PREV_YC_LIMIT */ {
852 preview_config_yc_range
,
854 offsetof(struct prev_params
, yclimit
),
855 FIELD_SIZEOF(struct prev_params
, yclimit
),
856 offsetof(struct omap3isp_prev_update_config
, yclimit
),
857 }, /* OMAP3ISP_PREV_DEFECT_COR */ {
860 offsetof(struct prev_params
, dcor
),
861 FIELD_SIZEOF(struct prev_params
, dcor
),
862 offsetof(struct omap3isp_prev_update_config
, dcor
),
863 }, /* OMAP3ISP_PREV_GAMMABYPASS */ {
865 preview_enable_gammabypass
,
866 }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
868 preview_enable_drkframe_capture
,
869 }, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
871 preview_enable_drkframe
,
872 }, /* OMAP3ISP_PREV_LENS_SHADING */ {
873 preview_config_drkf_shadcomp
,
874 preview_enable_drkframe
,
875 }, /* OMAP3ISP_PREV_NF */ {
876 preview_config_noisefilter
,
877 preview_enable_noisefilter
,
878 offsetof(struct prev_params
, nf
),
879 FIELD_SIZEOF(struct prev_params
, nf
),
880 offsetof(struct omap3isp_prev_update_config
, nf
),
881 }, /* OMAP3ISP_PREV_GAMMA */ {
882 preview_config_gammacorrn
,
884 offsetof(struct prev_params
, gamma
),
885 FIELD_SIZEOF(struct prev_params
, gamma
),
886 offsetof(struct omap3isp_prev_update_config
, gamma
),
887 }, /* OMAP3ISP_PREV_CONTRAST */ {
888 preview_config_contrast
,
890 offsetof(struct prev_params
, contrast
),
892 }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
893 preview_config_brightness
,
895 offsetof(struct prev_params
, brightness
),
901 * preview_config - Copy and update local structure with userspace preview
903 * @prev: ISP preview engine
904 * @cfg: Configuration
906 * Return zero if success or -EFAULT if the configuration can't be copied from
909 static int preview_config(struct isp_prev_device
*prev
,
910 struct omap3isp_prev_update_config
*cfg
)
918 if (cfg
->update
== 0)
921 /* Mark the shadow parameters we're going to update as busy. */
922 spin_lock_irqsave(&prev
->params
.lock
, flags
);
923 preview_params_lock(prev
, cfg
->update
, true);
924 active
= prev
->params
.active
;
925 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
929 for (i
= 0; i
< ARRAY_SIZE(update_attrs
); i
++) {
930 const struct preview_update
*attr
= &update_attrs
[i
];
931 struct prev_params
*params
;
932 unsigned int bit
= 1 << i
;
934 if (attr
->skip
|| !(cfg
->update
& bit
))
937 params
= &prev
->params
.params
[!!(active
& bit
)];
939 if (cfg
->flag
& bit
) {
940 void __user
*from
= *(void * __user
*)
941 ((void *)cfg
+ attr
->config_offset
);
942 void *to
= (void *)params
+ attr
->param_offset
;
943 size_t size
= attr
->param_size
;
945 if (to
&& from
&& size
) {
946 if (copy_from_user(to
, from
, size
)) {
951 params
->features
|= bit
;
953 params
->features
&= ~bit
;
959 spin_lock_irqsave(&prev
->params
.lock
, flags
);
960 preview_params_unlock(prev
, update
, true);
961 preview_params_switch(prev
);
962 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
968 * preview_setup_hw - Setup preview registers and/or internal memory
969 * @prev: pointer to preview private structure
970 * @update: Bitmask of parameters to setup
971 * @active: Bitmask of parameters active in set 0
972 * Note: can be called from interrupt context
975 static void preview_setup_hw(struct isp_prev_device
*prev
, u32 update
,
984 features
= (prev
->params
.params
[0].features
& active
)
985 | (prev
->params
.params
[1].features
& ~active
);
987 for (i
= 0; i
< ARRAY_SIZE(update_attrs
); i
++) {
988 const struct preview_update
*attr
= &update_attrs
[i
];
989 struct prev_params
*params
;
990 unsigned int bit
= 1 << i
;
996 params
= &prev
->params
.params
[!(active
& bit
)];
998 if (params
->features
& bit
) {
1000 param_ptr
= (void *)params
+ attr
->param_offset
;
1001 attr
->config(prev
, param_ptr
);
1004 attr
->enable(prev
, 1);
1007 attr
->enable(prev
, 0);
1013 * preview_config_ycpos - Configure byte layout of YUV image.
1014 * @mode: Indicates the required byte layout.
1017 preview_config_ycpos(struct isp_prev_device
*prev
,
1018 enum v4l2_mbus_pixelcode pixelcode
)
1020 struct isp_device
*isp
= to_isp_device(prev
);
1021 enum preview_ycpos_mode mode
;
1023 switch (pixelcode
) {
1024 case V4L2_MBUS_FMT_YUYV8_1X16
:
1025 mode
= YCPOS_CrYCbY
;
1027 case V4L2_MBUS_FMT_UYVY8_1X16
:
1028 mode
= YCPOS_YCrYCb
;
1034 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1035 ISPPRV_PCR_YCPOS_CrYCbY
,
1036 mode
<< ISPPRV_PCR_YCPOS_SHIFT
);
1040 * preview_config_averager - Enable / disable / configure averager
1041 * @average: Average value to be configured.
1043 static void preview_config_averager(struct isp_prev_device
*prev
, u8 average
)
1045 struct isp_device
*isp
= to_isp_device(prev
);
1046 struct prev_params
*params
;
1049 params
= (prev
->params
.active
& OMAP3ISP_PREV_CFA
)
1050 ? &prev
->params
.params
[0] : &prev
->params
.params
[1];
1052 if (params
->cfa
.format
== OMAP3ISP_CFAFMT_BAYER
)
1053 reg
= ISPPRV_AVE_EVENDIST_2
<< ISPPRV_AVE_EVENDIST_SHIFT
|
1054 ISPPRV_AVE_ODDDIST_2
<< ISPPRV_AVE_ODDDIST_SHIFT
|
1056 else if (params
->cfa
.format
== OMAP3ISP_CFAFMT_RGBFOVEON
)
1057 reg
= ISPPRV_AVE_EVENDIST_3
<< ISPPRV_AVE_EVENDIST_SHIFT
|
1058 ISPPRV_AVE_ODDDIST_3
<< ISPPRV_AVE_ODDDIST_SHIFT
|
1060 isp_reg_writel(isp
, reg
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_AVE
);
1064 * preview_config_input_format - Configure the input format
1065 * @prev: The preview engine
1066 * @format: Format on the preview engine sink pad
1068 * Enable CFA interpolation for Bayer formats and disable it for greyscale
1071 static void preview_config_input_format(struct isp_prev_device
*prev
,
1072 const struct v4l2_mbus_framefmt
*format
)
1074 struct isp_device
*isp
= to_isp_device(prev
);
1076 if (format
->code
!= V4L2_MBUS_FMT_Y10_1X10
)
1077 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1080 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1085 * preview_config_input_size - Configure the input frame size
1087 * The preview engine crops several rows and columns internally depending on
1088 * which processing blocks are enabled. The driver assumes all those blocks are
1089 * enabled when reporting source pad formats to userspace. If this assumption is
1090 * not true, rows and columns must be manually cropped at the preview engine
1091 * input to avoid overflows at the end of lines and frames.
1093 * See the explanation at the PREV_MARGIN_* definitions for more details.
1095 static void preview_config_input_size(struct isp_prev_device
*prev
, u32 active
)
1097 const struct v4l2_mbus_framefmt
*format
= &prev
->formats
[PREV_PAD_SINK
];
1098 struct isp_device
*isp
= to_isp_device(prev
);
1099 unsigned int sph
= prev
->crop
.left
;
1100 unsigned int eph
= prev
->crop
.left
+ prev
->crop
.width
- 1;
1101 unsigned int slv
= prev
->crop
.top
;
1102 unsigned int elv
= prev
->crop
.top
+ prev
->crop
.height
- 1;
1105 if (format
->code
!= V4L2_MBUS_FMT_Y10_1X10
) {
1112 features
= (prev
->params
.params
[0].features
& active
)
1113 | (prev
->params
.params
[1].features
& ~active
);
1115 if (features
& (OMAP3ISP_PREV_DEFECT_COR
| OMAP3ISP_PREV_NF
)) {
1121 if (features
& OMAP3ISP_PREV_HRZ_MED
) {
1125 if (features
& (OMAP3ISP_PREV_CHROMA_SUPP
| OMAP3ISP_PREV_LUMAENH
))
1128 isp_reg_writel(isp
, (sph
<< ISPPRV_HORZ_INFO_SPH_SHIFT
) | eph
,
1129 OMAP3_ISP_IOMEM_PREV
, ISPPRV_HORZ_INFO
);
1130 isp_reg_writel(isp
, (slv
<< ISPPRV_VERT_INFO_SLV_SHIFT
) | elv
,
1131 OMAP3_ISP_IOMEM_PREV
, ISPPRV_VERT_INFO
);
1135 * preview_config_inlineoffset - Configures the Read address line offset.
1136 * @prev: Preview module
1137 * @offset: Line offset
1139 * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
1140 * However, a hardware bug requires the memory start address to be aligned on a
1141 * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
1145 preview_config_inlineoffset(struct isp_prev_device
*prev
, u32 offset
)
1147 struct isp_device
*isp
= to_isp_device(prev
);
1149 isp_reg_writel(isp
, offset
& 0xffff, OMAP3_ISP_IOMEM_PREV
,
1150 ISPPRV_RADR_OFFSET
);
1154 * preview_set_inaddr - Sets memory address of input frame.
1155 * @addr: 32bit memory address aligned on 32byte boundary.
1157 * Configures the memory address from which the input frame is to be read.
1159 static void preview_set_inaddr(struct isp_prev_device
*prev
, u32 addr
)
1161 struct isp_device
*isp
= to_isp_device(prev
);
1163 isp_reg_writel(isp
, addr
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_RSDR_ADDR
);
1167 * preview_config_outlineoffset - Configures the Write address line offset.
1168 * @offset: Line Offset for the preview output.
1170 * The offset must be a multiple of 32 bytes.
1172 static void preview_config_outlineoffset(struct isp_prev_device
*prev
,
1175 struct isp_device
*isp
= to_isp_device(prev
);
1177 isp_reg_writel(isp
, offset
& 0xffff, OMAP3_ISP_IOMEM_PREV
,
1178 ISPPRV_WADD_OFFSET
);
1182 * preview_set_outaddr - Sets the memory address to store output frame
1183 * @addr: 32bit memory address aligned on 32byte boundary.
1185 * Configures the memory address to which the output frame is written.
1187 static void preview_set_outaddr(struct isp_prev_device
*prev
, u32 addr
)
1189 struct isp_device
*isp
= to_isp_device(prev
);
1191 isp_reg_writel(isp
, addr
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_WSDR_ADDR
);
1194 static void preview_adjust_bandwidth(struct isp_prev_device
*prev
)
1196 struct isp_pipeline
*pipe
= to_isp_pipeline(&prev
->subdev
.entity
);
1197 struct isp_device
*isp
= to_isp_device(prev
);
1198 const struct v4l2_mbus_framefmt
*ifmt
= &prev
->formats
[PREV_PAD_SINK
];
1199 unsigned long l3_ick
= pipe
->l3_ick
;
1200 struct v4l2_fract
*timeperframe
;
1201 unsigned int cycles_per_frame
;
1202 unsigned int requests_per_frame
;
1203 unsigned int cycles_per_request
;
1204 unsigned int minimum
;
1205 unsigned int maximum
;
1208 if (prev
->input
!= PREVIEW_INPUT_MEMORY
) {
1209 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_SBL
, ISPSBL_SDR_REQ_EXP
,
1210 ISPSBL_SDR_REQ_PRV_EXP_MASK
);
1214 /* Compute the minimum number of cycles per request, based on the
1215 * pipeline maximum data rate. This is an absolute lower bound if we
1216 * don't want SBL overflows, so round the value up.
1218 cycles_per_request
= div_u64((u64
)l3_ick
/ 2 * 256 + pipe
->max_rate
- 1,
1220 minimum
= DIV_ROUND_UP(cycles_per_request
, 32);
1222 /* Compute the maximum number of cycles per request, based on the
1223 * requested frame rate. This is a soft upper bound to achieve a frame
1224 * rate equal or higher than the requested value, so round the value
1227 timeperframe
= &pipe
->max_timeperframe
;
1229 requests_per_frame
= DIV_ROUND_UP(ifmt
->width
* 2, 256) * ifmt
->height
;
1230 cycles_per_frame
= div_u64((u64
)l3_ick
* timeperframe
->numerator
,
1231 timeperframe
->denominator
);
1232 cycles_per_request
= cycles_per_frame
/ requests_per_frame
;
1234 maximum
= cycles_per_request
/ 32;
1236 value
= max(minimum
, maximum
);
1238 dev_dbg(isp
->dev
, "%s: cycles per request = %u\n", __func__
, value
);
1239 isp_reg_clr_set(isp
, OMAP3_ISP_IOMEM_SBL
, ISPSBL_SDR_REQ_EXP
,
1240 ISPSBL_SDR_REQ_PRV_EXP_MASK
,
1241 value
<< ISPSBL_SDR_REQ_PRV_EXP_SHIFT
);
1245 * omap3isp_preview_busy - Gets busy state of preview module.
1247 int omap3isp_preview_busy(struct isp_prev_device
*prev
)
1249 struct isp_device
*isp
= to_isp_device(prev
);
1251 return isp_reg_readl(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
)
1256 * omap3isp_preview_restore_context - Restores the values of preview registers
1258 void omap3isp_preview_restore_context(struct isp_device
*isp
)
1260 struct isp_prev_device
*prev
= &isp
->isp_prev
;
1261 const u32 update
= OMAP3ISP_PREV_FEATURES_END
- 1;
1263 prev
->params
.params
[0].update
= prev
->params
.active
& update
;
1264 prev
->params
.params
[1].update
= ~prev
->params
.active
& update
;
1266 preview_setup_hw(prev
, update
, prev
->params
.active
);
1268 prev
->params
.params
[0].update
= 0;
1269 prev
->params
.params
[1].update
= 0;
1273 * preview_print_status - Dump preview module registers to the kernel log
1275 #define PREV_PRINT_REGISTER(isp, name)\
1276 dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
1277 isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
1279 static void preview_print_status(struct isp_prev_device
*prev
)
1281 struct isp_device
*isp
= to_isp_device(prev
);
1283 dev_dbg(isp
->dev
, "-------------Preview Register dump----------\n");
1285 PREV_PRINT_REGISTER(isp
, PCR
);
1286 PREV_PRINT_REGISTER(isp
, HORZ_INFO
);
1287 PREV_PRINT_REGISTER(isp
, VERT_INFO
);
1288 PREV_PRINT_REGISTER(isp
, RSDR_ADDR
);
1289 PREV_PRINT_REGISTER(isp
, RADR_OFFSET
);
1290 PREV_PRINT_REGISTER(isp
, DSDR_ADDR
);
1291 PREV_PRINT_REGISTER(isp
, DRKF_OFFSET
);
1292 PREV_PRINT_REGISTER(isp
, WSDR_ADDR
);
1293 PREV_PRINT_REGISTER(isp
, WADD_OFFSET
);
1294 PREV_PRINT_REGISTER(isp
, AVE
);
1295 PREV_PRINT_REGISTER(isp
, HMED
);
1296 PREV_PRINT_REGISTER(isp
, NF
);
1297 PREV_PRINT_REGISTER(isp
, WB_DGAIN
);
1298 PREV_PRINT_REGISTER(isp
, WBGAIN
);
1299 PREV_PRINT_REGISTER(isp
, WBSEL
);
1300 PREV_PRINT_REGISTER(isp
, CFA
);
1301 PREV_PRINT_REGISTER(isp
, BLKADJOFF
);
1302 PREV_PRINT_REGISTER(isp
, RGB_MAT1
);
1303 PREV_PRINT_REGISTER(isp
, RGB_MAT2
);
1304 PREV_PRINT_REGISTER(isp
, RGB_MAT3
);
1305 PREV_PRINT_REGISTER(isp
, RGB_MAT4
);
1306 PREV_PRINT_REGISTER(isp
, RGB_MAT5
);
1307 PREV_PRINT_REGISTER(isp
, RGB_OFF1
);
1308 PREV_PRINT_REGISTER(isp
, RGB_OFF2
);
1309 PREV_PRINT_REGISTER(isp
, CSC0
);
1310 PREV_PRINT_REGISTER(isp
, CSC1
);
1311 PREV_PRINT_REGISTER(isp
, CSC2
);
1312 PREV_PRINT_REGISTER(isp
, CSC_OFFSET
);
1313 PREV_PRINT_REGISTER(isp
, CNT_BRT
);
1314 PREV_PRINT_REGISTER(isp
, CSUP
);
1315 PREV_PRINT_REGISTER(isp
, SETUP_YC
);
1316 PREV_PRINT_REGISTER(isp
, SET_TBL_ADDR
);
1317 PREV_PRINT_REGISTER(isp
, CDC_THR0
);
1318 PREV_PRINT_REGISTER(isp
, CDC_THR1
);
1319 PREV_PRINT_REGISTER(isp
, CDC_THR2
);
1320 PREV_PRINT_REGISTER(isp
, CDC_THR3
);
1322 dev_dbg(isp
->dev
, "--------------------------------------------\n");
1326 * preview_init_params - init image processing parameters.
1327 * @prev: pointer to previewer private structure
1329 static void preview_init_params(struct isp_prev_device
*prev
)
1331 struct prev_params
*params
;
1334 spin_lock_init(&prev
->params
.lock
);
1336 prev
->params
.active
= ~0;
1337 prev
->params
.params
[0].busy
= 0;
1338 prev
->params
.params
[0].update
= OMAP3ISP_PREV_FEATURES_END
- 1;
1339 prev
->params
.params
[1].busy
= 0;
1340 prev
->params
.params
[1].update
= 0;
1342 params
= &prev
->params
.params
[0];
1345 params
->contrast
= ISPPRV_CONTRAST_DEF
* ISPPRV_CONTRAST_UNITS
;
1346 params
->brightness
= ISPPRV_BRIGHT_DEF
* ISPPRV_BRIGHT_UNITS
;
1347 params
->cfa
.format
= OMAP3ISP_CFAFMT_BAYER
;
1348 memcpy(params
->cfa
.table
, cfa_coef_table
,
1349 sizeof(params
->cfa
.table
));
1350 params
->cfa
.gradthrs_horz
= FLR_CFA_GRADTHRS_HORZ
;
1351 params
->cfa
.gradthrs_vert
= FLR_CFA_GRADTHRS_VERT
;
1352 params
->csup
.gain
= FLR_CSUP_GAIN
;
1353 params
->csup
.thres
= FLR_CSUP_THRES
;
1354 params
->csup
.hypf_en
= 0;
1355 memcpy(params
->luma
.table
, luma_enhance_table
,
1356 sizeof(params
->luma
.table
));
1357 params
->nf
.spread
= FLR_NF_STRGTH
;
1358 memcpy(params
->nf
.table
, noise_filter_table
, sizeof(params
->nf
.table
));
1359 params
->dcor
.couplet_mode_en
= 1;
1360 for (i
= 0; i
< OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS
; i
++)
1361 params
->dcor
.detect_correct
[i
] = DEF_DETECT_CORRECT_VAL
;
1362 memcpy(params
->gamma
.blue
, gamma_table
, sizeof(params
->gamma
.blue
));
1363 memcpy(params
->gamma
.green
, gamma_table
, sizeof(params
->gamma
.green
));
1364 memcpy(params
->gamma
.red
, gamma_table
, sizeof(params
->gamma
.red
));
1365 params
->wbal
.dgain
= FLR_WBAL_DGAIN
;
1366 params
->wbal
.coef0
= FLR_WBAL_COEF
;
1367 params
->wbal
.coef1
= FLR_WBAL_COEF
;
1368 params
->wbal
.coef2
= FLR_WBAL_COEF
;
1369 params
->wbal
.coef3
= FLR_WBAL_COEF
;
1370 params
->blkadj
.red
= FLR_BLKADJ_RED
;
1371 params
->blkadj
.green
= FLR_BLKADJ_GREEN
;
1372 params
->blkadj
.blue
= FLR_BLKADJ_BLUE
;
1373 params
->rgb2rgb
= flr_rgb2rgb
;
1374 params
->csc
= flr_prev_csc
;
1375 params
->yclimit
.minC
= ISPPRV_YC_MIN
;
1376 params
->yclimit
.maxC
= ISPPRV_YC_MAX
;
1377 params
->yclimit
.minY
= ISPPRV_YC_MIN
;
1378 params
->yclimit
.maxY
= ISPPRV_YC_MAX
;
1380 params
->features
= OMAP3ISP_PREV_CFA
| OMAP3ISP_PREV_DEFECT_COR
1381 | OMAP3ISP_PREV_NF
| OMAP3ISP_PREV_GAMMA
1382 | OMAP3ISP_PREV_BLKADJ
| OMAP3ISP_PREV_YC_LIMIT
1383 | OMAP3ISP_PREV_RGB2RGB
| OMAP3ISP_PREV_COLOR_CONV
1384 | OMAP3ISP_PREV_WB
| OMAP3ISP_PREV_BRIGHTNESS
1385 | OMAP3ISP_PREV_CONTRAST
;
1389 * preview_max_out_width - Handle previewer hardware ouput limitations
1390 * @isp_revision : ISP revision
1391 * returns maximum width output for current isp revision
1393 static unsigned int preview_max_out_width(struct isp_prev_device
*prev
)
1395 struct isp_device
*isp
= to_isp_device(prev
);
1397 switch (isp
->revision
) {
1398 case ISP_REVISION_1_0
:
1399 return PREV_MAX_OUT_WIDTH_REV_1
;
1401 case ISP_REVISION_2_0
:
1403 return PREV_MAX_OUT_WIDTH_REV_2
;
1405 case ISP_REVISION_15_0
:
1406 return PREV_MAX_OUT_WIDTH_REV_15
;
1410 static void preview_configure(struct isp_prev_device
*prev
)
1412 struct isp_device
*isp
= to_isp_device(prev
);
1413 struct v4l2_mbus_framefmt
*format
;
1414 unsigned long flags
;
1418 spin_lock_irqsave(&prev
->params
.lock
, flags
);
1419 /* Mark all active parameters we are going to touch as busy. */
1420 update
= preview_params_lock(prev
, 0, false);
1421 active
= prev
->params
.active
;
1422 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
1424 preview_setup_hw(prev
, update
, active
);
1426 if (prev
->output
& PREVIEW_OUTPUT_MEMORY
)
1427 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1428 ISPPRV_PCR_SDRPORT
);
1430 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1431 ISPPRV_PCR_SDRPORT
);
1433 if (prev
->output
& PREVIEW_OUTPUT_RESIZER
)
1434 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1435 ISPPRV_PCR_RSZPORT
);
1437 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1438 ISPPRV_PCR_RSZPORT
);
1441 format
= &prev
->formats
[PREV_PAD_SINK
];
1443 preview_adjust_bandwidth(prev
);
1445 preview_config_input_format(prev
, format
);
1446 preview_config_input_size(prev
, active
);
1448 if (prev
->input
== PREVIEW_INPUT_CCDC
)
1449 preview_config_inlineoffset(prev
, 0);
1451 preview_config_inlineoffset(prev
,
1452 ALIGN(format
->width
, 0x20) * 2);
1454 /* PREV_PAD_SOURCE */
1455 format
= &prev
->formats
[PREV_PAD_SOURCE
];
1457 if (prev
->output
& PREVIEW_OUTPUT_MEMORY
)
1458 preview_config_outlineoffset(prev
,
1459 ALIGN(format
->width
, 0x10) * 2);
1461 preview_config_averager(prev
, 0);
1462 preview_config_ycpos(prev
, format
->code
);
1464 spin_lock_irqsave(&prev
->params
.lock
, flags
);
1465 preview_params_unlock(prev
, update
, false);
1466 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
1469 /* -----------------------------------------------------------------------------
1470 * Interrupt handling
1473 static void preview_enable_oneshot(struct isp_prev_device
*prev
)
1475 struct isp_device
*isp
= to_isp_device(prev
);
1477 /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
1478 * bit is set. As the preview engine is used in single-shot mode, we
1479 * need to set PCR.SOURCE before enabling the preview engine.
1481 if (prev
->input
== PREVIEW_INPUT_MEMORY
)
1482 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1485 isp_reg_set(isp
, OMAP3_ISP_IOMEM_PREV
, ISPPRV_PCR
,
1486 ISPPRV_PCR_EN
| ISPPRV_PCR_ONESHOT
);
1489 void omap3isp_preview_isr_frame_sync(struct isp_prev_device
*prev
)
1492 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
1493 * condition, the module was paused and now we have a buffer queued
1494 * on the output again. Restart the pipeline if running in continuous
1497 if (prev
->state
== ISP_PIPELINE_STREAM_CONTINUOUS
&&
1498 prev
->video_out
.dmaqueue_flags
& ISP_VIDEO_DMAQUEUE_QUEUED
) {
1499 preview_enable_oneshot(prev
);
1500 isp_video_dmaqueue_flags_clr(&prev
->video_out
);
1504 static void preview_isr_buffer(struct isp_prev_device
*prev
)
1506 struct isp_pipeline
*pipe
= to_isp_pipeline(&prev
->subdev
.entity
);
1507 struct isp_buffer
*buffer
;
1510 if (prev
->input
== PREVIEW_INPUT_MEMORY
) {
1511 buffer
= omap3isp_video_buffer_next(&prev
->video_in
);
1513 preview_set_inaddr(prev
, buffer
->isp_addr
);
1514 pipe
->state
|= ISP_PIPELINE_IDLE_INPUT
;
1517 if (prev
->output
& PREVIEW_OUTPUT_MEMORY
) {
1518 buffer
= omap3isp_video_buffer_next(&prev
->video_out
);
1519 if (buffer
!= NULL
) {
1520 preview_set_outaddr(prev
, buffer
->isp_addr
);
1523 pipe
->state
|= ISP_PIPELINE_IDLE_OUTPUT
;
1526 switch (prev
->state
) {
1527 case ISP_PIPELINE_STREAM_SINGLESHOT
:
1528 if (isp_pipeline_ready(pipe
))
1529 omap3isp_pipeline_set_stream(pipe
,
1530 ISP_PIPELINE_STREAM_SINGLESHOT
);
1533 case ISP_PIPELINE_STREAM_CONTINUOUS
:
1534 /* If an underrun occurs, the video queue operation handler will
1535 * restart the preview engine. Otherwise restart it immediately.
1538 preview_enable_oneshot(prev
);
1541 case ISP_PIPELINE_STREAM_STOPPED
:
1548 * omap3isp_preview_isr - ISP preview engine interrupt handler
1550 * Manage the preview engine video buffers and configure shadowed registers.
1552 void omap3isp_preview_isr(struct isp_prev_device
*prev
)
1554 unsigned long flags
;
1558 if (omap3isp_module_sync_is_stopping(&prev
->wait
, &prev
->stopping
))
1561 spin_lock_irqsave(&prev
->params
.lock
, flags
);
1562 preview_params_switch(prev
);
1563 update
= preview_params_lock(prev
, 0, false);
1564 active
= prev
->params
.active
;
1565 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
1567 preview_setup_hw(prev
, update
, active
);
1568 preview_config_input_size(prev
, active
);
1570 if (prev
->input
== PREVIEW_INPUT_MEMORY
||
1571 prev
->output
& PREVIEW_OUTPUT_MEMORY
)
1572 preview_isr_buffer(prev
);
1573 else if (prev
->state
== ISP_PIPELINE_STREAM_CONTINUOUS
)
1574 preview_enable_oneshot(prev
);
1576 spin_lock_irqsave(&prev
->params
.lock
, flags
);
1577 preview_params_unlock(prev
, update
, false);
1578 spin_unlock_irqrestore(&prev
->params
.lock
, flags
);
1581 /* -----------------------------------------------------------------------------
1582 * ISP video operations
1585 static int preview_video_queue(struct isp_video
*video
,
1586 struct isp_buffer
*buffer
)
1588 struct isp_prev_device
*prev
= &video
->isp
->isp_prev
;
1590 if (video
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
)
1591 preview_set_inaddr(prev
, buffer
->isp_addr
);
1593 if (video
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1594 preview_set_outaddr(prev
, buffer
->isp_addr
);
1599 static const struct isp_video_operations preview_video_ops
= {
1600 .queue
= preview_video_queue
,
1603 /* -----------------------------------------------------------------------------
1604 * V4L2 subdev operations
1608 * preview_s_ctrl - Handle set control subdev method
1609 * @ctrl: pointer to v4l2 control structure
1611 static int preview_s_ctrl(struct v4l2_ctrl
*ctrl
)
1613 struct isp_prev_device
*prev
=
1614 container_of(ctrl
->handler
, struct isp_prev_device
, ctrls
);
1617 case V4L2_CID_BRIGHTNESS
:
1618 preview_update_brightness(prev
, ctrl
->val
);
1620 case V4L2_CID_CONTRAST
:
1621 preview_update_contrast(prev
, ctrl
->val
);
1628 static const struct v4l2_ctrl_ops preview_ctrl_ops
= {
1629 .s_ctrl
= preview_s_ctrl
,
1633 * preview_ioctl - Handle preview module private ioctl's
1634 * @prev: pointer to preview context structure
1635 * @cmd: configuration command
1636 * @arg: configuration argument
1637 * return -EINVAL or zero on success
1639 static long preview_ioctl(struct v4l2_subdev
*sd
, unsigned int cmd
, void *arg
)
1641 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
1644 case VIDIOC_OMAP3ISP_PRV_CFG
:
1645 return preview_config(prev
, arg
);
1648 return -ENOIOCTLCMD
;
1653 * preview_set_stream - Enable/Disable streaming on preview subdev
1654 * @sd : pointer to v4l2 subdev structure
1655 * @enable: 1 == Enable, 0 == Disable
1656 * return -EINVAL or zero on success
1658 static int preview_set_stream(struct v4l2_subdev
*sd
, int enable
)
1660 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
1661 struct isp_video
*video_out
= &prev
->video_out
;
1662 struct isp_device
*isp
= to_isp_device(prev
);
1663 struct device
*dev
= to_device(prev
);
1665 if (prev
->state
== ISP_PIPELINE_STREAM_STOPPED
) {
1666 if (enable
== ISP_PIPELINE_STREAM_STOPPED
)
1669 omap3isp_subclk_enable(isp
, OMAP3_ISP_SUBCLK_PREVIEW
);
1670 preview_configure(prev
);
1671 atomic_set(&prev
->stopping
, 0);
1672 preview_print_status(prev
);
1676 case ISP_PIPELINE_STREAM_CONTINUOUS
:
1677 if (prev
->output
& PREVIEW_OUTPUT_MEMORY
)
1678 omap3isp_sbl_enable(isp
, OMAP3_ISP_SBL_PREVIEW_WRITE
);
1680 if (video_out
->dmaqueue_flags
& ISP_VIDEO_DMAQUEUE_QUEUED
||
1681 !(prev
->output
& PREVIEW_OUTPUT_MEMORY
))
1682 preview_enable_oneshot(prev
);
1684 isp_video_dmaqueue_flags_clr(video_out
);
1687 case ISP_PIPELINE_STREAM_SINGLESHOT
:
1688 if (prev
->input
== PREVIEW_INPUT_MEMORY
)
1689 omap3isp_sbl_enable(isp
, OMAP3_ISP_SBL_PREVIEW_READ
);
1690 if (prev
->output
& PREVIEW_OUTPUT_MEMORY
)
1691 omap3isp_sbl_enable(isp
, OMAP3_ISP_SBL_PREVIEW_WRITE
);
1693 preview_enable_oneshot(prev
);
1696 case ISP_PIPELINE_STREAM_STOPPED
:
1697 if (omap3isp_module_sync_idle(&sd
->entity
, &prev
->wait
,
1699 dev_dbg(dev
, "%s: stop timeout.\n", sd
->name
);
1700 omap3isp_sbl_disable(isp
, OMAP3_ISP_SBL_PREVIEW_READ
);
1701 omap3isp_sbl_disable(isp
, OMAP3_ISP_SBL_PREVIEW_WRITE
);
1702 omap3isp_subclk_disable(isp
, OMAP3_ISP_SUBCLK_PREVIEW
);
1703 isp_video_dmaqueue_flags_clr(video_out
);
1707 prev
->state
= enable
;
1711 static struct v4l2_mbus_framefmt
*
1712 __preview_get_format(struct isp_prev_device
*prev
, struct v4l2_subdev_fh
*fh
,
1713 unsigned int pad
, enum v4l2_subdev_format_whence which
)
1715 if (which
== V4L2_SUBDEV_FORMAT_TRY
)
1716 return v4l2_subdev_get_try_format(fh
, pad
);
1718 return &prev
->formats
[pad
];
1721 static struct v4l2_rect
*
1722 __preview_get_crop(struct isp_prev_device
*prev
, struct v4l2_subdev_fh
*fh
,
1723 enum v4l2_subdev_format_whence which
)
1725 if (which
== V4L2_SUBDEV_FORMAT_TRY
)
1726 return v4l2_subdev_get_try_crop(fh
, PREV_PAD_SINK
);
1731 /* previewer format descriptions */
1732 static const unsigned int preview_input_fmts
[] = {
1733 V4L2_MBUS_FMT_Y10_1X10
,
1734 V4L2_MBUS_FMT_SGRBG10_1X10
,
1735 V4L2_MBUS_FMT_SRGGB10_1X10
,
1736 V4L2_MBUS_FMT_SBGGR10_1X10
,
1737 V4L2_MBUS_FMT_SGBRG10_1X10
,
1740 static const unsigned int preview_output_fmts
[] = {
1741 V4L2_MBUS_FMT_UYVY8_1X16
,
1742 V4L2_MBUS_FMT_YUYV8_1X16
,
1746 * preview_try_format - Validate a format
1747 * @prev: ISP preview engine
1748 * @fh: V4L2 subdev file handle
1750 * @fmt: format to be validated
1751 * @which: try/active format selector
1753 * Validate and adjust the given format for the given pad based on the preview
1754 * engine limits and the format and crop rectangles on other pads.
1756 static void preview_try_format(struct isp_prev_device
*prev
,
1757 struct v4l2_subdev_fh
*fh
, unsigned int pad
,
1758 struct v4l2_mbus_framefmt
*fmt
,
1759 enum v4l2_subdev_format_whence which
)
1761 enum v4l2_mbus_pixelcode pixelcode
;
1762 struct v4l2_rect
*crop
;
1767 /* When reading data from the CCDC, the input size has already
1768 * been mangled by the CCDC output pad so it can be accepted
1771 * When reading data from memory, clamp the requested width and
1772 * height. The TRM doesn't specify a minimum input height, make
1773 * sure we got enough lines to enable the noise filter and color
1774 * filter array interpolation.
1776 if (prev
->input
== PREVIEW_INPUT_MEMORY
) {
1777 fmt
->width
= clamp_t(u32
, fmt
->width
, PREV_MIN_IN_WIDTH
,
1778 preview_max_out_width(prev
));
1779 fmt
->height
= clamp_t(u32
, fmt
->height
,
1781 PREV_MAX_IN_HEIGHT
);
1784 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
1786 for (i
= 0; i
< ARRAY_SIZE(preview_input_fmts
); i
++) {
1787 if (fmt
->code
== preview_input_fmts
[i
])
1791 /* If not found, use SGRBG10 as default */
1792 if (i
>= ARRAY_SIZE(preview_input_fmts
))
1793 fmt
->code
= V4L2_MBUS_FMT_SGRBG10_1X10
;
1796 case PREV_PAD_SOURCE
:
1797 pixelcode
= fmt
->code
;
1798 *fmt
= *__preview_get_format(prev
, fh
, PREV_PAD_SINK
, which
);
1800 switch (pixelcode
) {
1801 case V4L2_MBUS_FMT_YUYV8_1X16
:
1802 case V4L2_MBUS_FMT_UYVY8_1X16
:
1803 fmt
->code
= pixelcode
;
1807 fmt
->code
= V4L2_MBUS_FMT_YUYV8_1X16
;
1811 /* The preview module output size is configurable through the
1812 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
1813 * is not supported yet, hardcode the output size to the crop
1816 crop
= __preview_get_crop(prev
, fh
, which
);
1817 fmt
->width
= crop
->width
;
1818 fmt
->height
= crop
->height
;
1820 fmt
->colorspace
= V4L2_COLORSPACE_JPEG
;
1824 fmt
->field
= V4L2_FIELD_NONE
;
1828 * preview_try_crop - Validate a crop rectangle
1829 * @prev: ISP preview engine
1830 * @sink: format on the sink pad
1831 * @crop: crop rectangle to be validated
1833 * The preview engine crops lines and columns for its internal operation,
1834 * depending on which filters are enabled. Enforce minimum crop margins to
1835 * handle that transparently for userspace.
1837 * See the explanation at the PREV_MARGIN_* definitions for more details.
1839 static void preview_try_crop(struct isp_prev_device
*prev
,
1840 const struct v4l2_mbus_framefmt
*sink
,
1841 struct v4l2_rect
*crop
)
1843 unsigned int left
= PREV_MARGIN_LEFT
;
1844 unsigned int right
= sink
->width
- PREV_MARGIN_RIGHT
;
1845 unsigned int top
= PREV_MARGIN_TOP
;
1846 unsigned int bottom
= sink
->height
- PREV_MARGIN_BOTTOM
;
1848 /* When processing data on-the-fly from the CCDC, at least 2 pixels must
1849 * be cropped from the left and right sides of the image. As we don't
1850 * know which filters will be enabled, increase the left and right
1853 if (prev
->input
== PREVIEW_INPUT_CCDC
) {
1858 /* Restrict left/top to even values to keep the Bayer pattern. */
1862 crop
->left
= clamp_t(u32
, crop
->left
, left
, right
- PREV_MIN_OUT_WIDTH
);
1863 crop
->top
= clamp_t(u32
, crop
->top
, top
, bottom
- PREV_MIN_OUT_HEIGHT
);
1864 crop
->width
= clamp_t(u32
, crop
->width
, PREV_MIN_OUT_WIDTH
,
1865 right
- crop
->left
);
1866 crop
->height
= clamp_t(u32
, crop
->height
, PREV_MIN_OUT_HEIGHT
,
1867 bottom
- crop
->top
);
1871 * preview_enum_mbus_code - Handle pixel format enumeration
1872 * @sd : pointer to v4l2 subdev structure
1873 * @fh : V4L2 subdev file handle
1874 * @code : pointer to v4l2_subdev_mbus_code_enum structure
1875 * return -EINVAL or zero on success
1877 static int preview_enum_mbus_code(struct v4l2_subdev
*sd
,
1878 struct v4l2_subdev_fh
*fh
,
1879 struct v4l2_subdev_mbus_code_enum
*code
)
1881 switch (code
->pad
) {
1883 if (code
->index
>= ARRAY_SIZE(preview_input_fmts
))
1886 code
->code
= preview_input_fmts
[code
->index
];
1888 case PREV_PAD_SOURCE
:
1889 if (code
->index
>= ARRAY_SIZE(preview_output_fmts
))
1892 code
->code
= preview_output_fmts
[code
->index
];
1901 static int preview_enum_frame_size(struct v4l2_subdev
*sd
,
1902 struct v4l2_subdev_fh
*fh
,
1903 struct v4l2_subdev_frame_size_enum
*fse
)
1905 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
1906 struct v4l2_mbus_framefmt format
;
1908 if (fse
->index
!= 0)
1911 format
.code
= fse
->code
;
1914 preview_try_format(prev
, fh
, fse
->pad
, &format
, V4L2_SUBDEV_FORMAT_TRY
);
1915 fse
->min_width
= format
.width
;
1916 fse
->min_height
= format
.height
;
1918 if (format
.code
!= fse
->code
)
1921 format
.code
= fse
->code
;
1924 preview_try_format(prev
, fh
, fse
->pad
, &format
, V4L2_SUBDEV_FORMAT_TRY
);
1925 fse
->max_width
= format
.width
;
1926 fse
->max_height
= format
.height
;
1932 * preview_get_selection - Retrieve a selection rectangle on a pad
1933 * @sd: ISP preview V4L2 subdevice
1934 * @fh: V4L2 subdev file handle
1935 * @sel: Selection rectangle
1937 * The only supported rectangles are the crop rectangles on the sink pad.
1939 * Return 0 on success or a negative error code otherwise.
1941 static int preview_get_selection(struct v4l2_subdev
*sd
,
1942 struct v4l2_subdev_fh
*fh
,
1943 struct v4l2_subdev_selection
*sel
)
1945 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
1946 struct v4l2_mbus_framefmt
*format
;
1948 if (sel
->pad
!= PREV_PAD_SINK
)
1951 switch (sel
->target
) {
1952 case V4L2_SEL_TGT_CROP_BOUNDS
:
1955 sel
->r
.width
= INT_MAX
;
1956 sel
->r
.height
= INT_MAX
;
1958 format
= __preview_get_format(prev
, fh
, PREV_PAD_SINK
,
1960 preview_try_crop(prev
, format
, &sel
->r
);
1963 case V4L2_SEL_TGT_CROP
:
1964 sel
->r
= *__preview_get_crop(prev
, fh
, sel
->which
);
1975 * preview_set_selection - Set a selection rectangle on a pad
1976 * @sd: ISP preview V4L2 subdevice
1977 * @fh: V4L2 subdev file handle
1978 * @sel: Selection rectangle
1980 * The only supported rectangle is the actual crop rectangle on the sink pad.
1982 * Return 0 on success or a negative error code otherwise.
1984 static int preview_set_selection(struct v4l2_subdev
*sd
,
1985 struct v4l2_subdev_fh
*fh
,
1986 struct v4l2_subdev_selection
*sel
)
1988 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
1989 struct v4l2_mbus_framefmt
*format
;
1991 if (sel
->target
!= V4L2_SEL_TGT_CROP
||
1992 sel
->pad
!= PREV_PAD_SINK
)
1995 /* The crop rectangle can't be changed while streaming. */
1996 if (prev
->state
!= ISP_PIPELINE_STREAM_STOPPED
)
1999 /* Modifying the crop rectangle always changes the format on the source
2000 * pad. If the KEEP_CONFIG flag is set, just return the current crop
2003 if (sel
->flags
& V4L2_SEL_FLAG_KEEP_CONFIG
) {
2004 sel
->r
= *__preview_get_crop(prev
, fh
, sel
->which
);
2008 format
= __preview_get_format(prev
, fh
, PREV_PAD_SINK
, sel
->which
);
2009 preview_try_crop(prev
, format
, &sel
->r
);
2010 *__preview_get_crop(prev
, fh
, sel
->which
) = sel
->r
;
2012 /* Update the source format. */
2013 format
= __preview_get_format(prev
, fh
, PREV_PAD_SOURCE
, sel
->which
);
2014 preview_try_format(prev
, fh
, PREV_PAD_SOURCE
, format
, sel
->which
);
2020 * preview_get_format - Handle get format by pads subdev method
2021 * @sd : pointer to v4l2 subdev structure
2022 * @fh : V4L2 subdev file handle
2023 * @fmt: pointer to v4l2 subdev format structure
2024 * return -EINVAL or zero on success
2026 static int preview_get_format(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
,
2027 struct v4l2_subdev_format
*fmt
)
2029 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
2030 struct v4l2_mbus_framefmt
*format
;
2032 format
= __preview_get_format(prev
, fh
, fmt
->pad
, fmt
->which
);
2036 fmt
->format
= *format
;
2041 * preview_set_format - Handle set format by pads subdev method
2042 * @sd : pointer to v4l2 subdev structure
2043 * @fh : V4L2 subdev file handle
2044 * @fmt: pointer to v4l2 subdev format structure
2045 * return -EINVAL or zero on success
2047 static int preview_set_format(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
,
2048 struct v4l2_subdev_format
*fmt
)
2050 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
2051 struct v4l2_mbus_framefmt
*format
;
2052 struct v4l2_rect
*crop
;
2054 format
= __preview_get_format(prev
, fh
, fmt
->pad
, fmt
->which
);
2058 preview_try_format(prev
, fh
, fmt
->pad
, &fmt
->format
, fmt
->which
);
2059 *format
= fmt
->format
;
2061 /* Propagate the format from sink to source */
2062 if (fmt
->pad
== PREV_PAD_SINK
) {
2063 /* Reset the crop rectangle. */
2064 crop
= __preview_get_crop(prev
, fh
, fmt
->which
);
2067 crop
->width
= fmt
->format
.width
;
2068 crop
->height
= fmt
->format
.height
;
2070 preview_try_crop(prev
, &fmt
->format
, crop
);
2072 /* Update the source format. */
2073 format
= __preview_get_format(prev
, fh
, PREV_PAD_SOURCE
,
2075 preview_try_format(prev
, fh
, PREV_PAD_SOURCE
, format
,
2083 * preview_init_formats - Initialize formats on all pads
2084 * @sd: ISP preview V4L2 subdevice
2085 * @fh: V4L2 subdev file handle
2087 * Initialize all pad formats with default values. If fh is not NULL, try
2088 * formats are initialized on the file handle. Otherwise active formats are
2089 * initialized on the device.
2091 static int preview_init_formats(struct v4l2_subdev
*sd
,
2092 struct v4l2_subdev_fh
*fh
)
2094 struct v4l2_subdev_format format
;
2096 memset(&format
, 0, sizeof(format
));
2097 format
.pad
= PREV_PAD_SINK
;
2098 format
.which
= fh
? V4L2_SUBDEV_FORMAT_TRY
: V4L2_SUBDEV_FORMAT_ACTIVE
;
2099 format
.format
.code
= V4L2_MBUS_FMT_SGRBG10_1X10
;
2100 format
.format
.width
= 4096;
2101 format
.format
.height
= 4096;
2102 preview_set_format(sd
, fh
, &format
);
2107 /* subdev core operations */
2108 static const struct v4l2_subdev_core_ops preview_v4l2_core_ops
= {
2109 .ioctl
= preview_ioctl
,
2112 /* subdev video operations */
2113 static const struct v4l2_subdev_video_ops preview_v4l2_video_ops
= {
2114 .s_stream
= preview_set_stream
,
2117 /* subdev pad operations */
2118 static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops
= {
2119 .enum_mbus_code
= preview_enum_mbus_code
,
2120 .enum_frame_size
= preview_enum_frame_size
,
2121 .get_fmt
= preview_get_format
,
2122 .set_fmt
= preview_set_format
,
2123 .get_selection
= preview_get_selection
,
2124 .set_selection
= preview_set_selection
,
2127 /* subdev operations */
2128 static const struct v4l2_subdev_ops preview_v4l2_ops
= {
2129 .core
= &preview_v4l2_core_ops
,
2130 .video
= &preview_v4l2_video_ops
,
2131 .pad
= &preview_v4l2_pad_ops
,
2134 /* subdev internal operations */
2135 static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops
= {
2136 .open
= preview_init_formats
,
2139 /* -----------------------------------------------------------------------------
2140 * Media entity operations
2144 * preview_link_setup - Setup previewer connections.
2145 * @entity : Pointer to media entity structure
2146 * @local : Pointer to local pad array
2147 * @remote : Pointer to remote pad array
2148 * @flags : Link flags
2149 * return -EINVAL or zero on success
2151 static int preview_link_setup(struct media_entity
*entity
,
2152 const struct media_pad
*local
,
2153 const struct media_pad
*remote
, u32 flags
)
2155 struct v4l2_subdev
*sd
= media_entity_to_v4l2_subdev(entity
);
2156 struct isp_prev_device
*prev
= v4l2_get_subdevdata(sd
);
2158 switch (local
->index
| media_entity_type(remote
->entity
)) {
2159 case PREV_PAD_SINK
| MEDIA_ENT_T_DEVNODE
:
2160 /* read from memory */
2161 if (flags
& MEDIA_LNK_FL_ENABLED
) {
2162 if (prev
->input
== PREVIEW_INPUT_CCDC
)
2164 prev
->input
= PREVIEW_INPUT_MEMORY
;
2166 if (prev
->input
== PREVIEW_INPUT_MEMORY
)
2167 prev
->input
= PREVIEW_INPUT_NONE
;
2171 case PREV_PAD_SINK
| MEDIA_ENT_T_V4L2_SUBDEV
:
2172 /* read from ccdc */
2173 if (flags
& MEDIA_LNK_FL_ENABLED
) {
2174 if (prev
->input
== PREVIEW_INPUT_MEMORY
)
2176 prev
->input
= PREVIEW_INPUT_CCDC
;
2178 if (prev
->input
== PREVIEW_INPUT_CCDC
)
2179 prev
->input
= PREVIEW_INPUT_NONE
;
2184 * The ISP core doesn't support pipelines with multiple video outputs.
2185 * Revisit this when it will be implemented, and return -EBUSY for now.
2188 case PREV_PAD_SOURCE
| MEDIA_ENT_T_DEVNODE
:
2189 /* write to memory */
2190 if (flags
& MEDIA_LNK_FL_ENABLED
) {
2191 if (prev
->output
& ~PREVIEW_OUTPUT_MEMORY
)
2193 prev
->output
|= PREVIEW_OUTPUT_MEMORY
;
2195 prev
->output
&= ~PREVIEW_OUTPUT_MEMORY
;
2199 case PREV_PAD_SOURCE
| MEDIA_ENT_T_V4L2_SUBDEV
:
2200 /* write to resizer */
2201 if (flags
& MEDIA_LNK_FL_ENABLED
) {
2202 if (prev
->output
& ~PREVIEW_OUTPUT_RESIZER
)
2204 prev
->output
|= PREVIEW_OUTPUT_RESIZER
;
2206 prev
->output
&= ~PREVIEW_OUTPUT_RESIZER
;
2217 /* media operations */
2218 static const struct media_entity_operations preview_media_ops
= {
2219 .link_setup
= preview_link_setup
,
2220 .link_validate
= v4l2_subdev_link_validate
,
2223 void omap3isp_preview_unregister_entities(struct isp_prev_device
*prev
)
2225 v4l2_device_unregister_subdev(&prev
->subdev
);
2226 omap3isp_video_unregister(&prev
->video_in
);
2227 omap3isp_video_unregister(&prev
->video_out
);
2230 int omap3isp_preview_register_entities(struct isp_prev_device
*prev
,
2231 struct v4l2_device
*vdev
)
2235 /* Register the subdev and video nodes. */
2236 ret
= v4l2_device_register_subdev(vdev
, &prev
->subdev
);
2240 ret
= omap3isp_video_register(&prev
->video_in
, vdev
);
2244 ret
= omap3isp_video_register(&prev
->video_out
, vdev
);
2251 omap3isp_preview_unregister_entities(prev
);
2255 /* -----------------------------------------------------------------------------
2256 * ISP previewer initialisation and cleanup
2260 * preview_init_entities - Initialize subdev and media entity.
2261 * @prev : Pointer to preview structure
2262 * return -ENOMEM or zero on success
2264 static int preview_init_entities(struct isp_prev_device
*prev
)
2266 struct v4l2_subdev
*sd
= &prev
->subdev
;
2267 struct media_pad
*pads
= prev
->pads
;
2268 struct media_entity
*me
= &sd
->entity
;
2271 prev
->input
= PREVIEW_INPUT_NONE
;
2273 v4l2_subdev_init(sd
, &preview_v4l2_ops
);
2274 sd
->internal_ops
= &preview_v4l2_internal_ops
;
2275 strlcpy(sd
->name
, "OMAP3 ISP preview", sizeof(sd
->name
));
2276 sd
->grp_id
= 1 << 16; /* group ID for isp subdevs */
2277 v4l2_set_subdevdata(sd
, prev
);
2278 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
2280 v4l2_ctrl_handler_init(&prev
->ctrls
, 2);
2281 v4l2_ctrl_new_std(&prev
->ctrls
, &preview_ctrl_ops
, V4L2_CID_BRIGHTNESS
,
2282 ISPPRV_BRIGHT_LOW
, ISPPRV_BRIGHT_HIGH
,
2283 ISPPRV_BRIGHT_STEP
, ISPPRV_BRIGHT_DEF
);
2284 v4l2_ctrl_new_std(&prev
->ctrls
, &preview_ctrl_ops
, V4L2_CID_CONTRAST
,
2285 ISPPRV_CONTRAST_LOW
, ISPPRV_CONTRAST_HIGH
,
2286 ISPPRV_CONTRAST_STEP
, ISPPRV_CONTRAST_DEF
);
2287 v4l2_ctrl_handler_setup(&prev
->ctrls
);
2288 sd
->ctrl_handler
= &prev
->ctrls
;
2290 pads
[PREV_PAD_SINK
].flags
= MEDIA_PAD_FL_SINK
;
2291 pads
[PREV_PAD_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
2293 me
->ops
= &preview_media_ops
;
2294 ret
= media_entity_init(me
, PREV_PADS_NUM
, pads
, 0);
2298 preview_init_formats(sd
, NULL
);
2300 /* According to the OMAP34xx TRM, video buffers need to be aligned on a
2301 * 32 bytes boundary. However, an undocumented hardware bug requires a
2302 * 64 bytes boundary at the preview engine input.
2304 prev
->video_in
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
2305 prev
->video_in
.ops
= &preview_video_ops
;
2306 prev
->video_in
.isp
= to_isp_device(prev
);
2307 prev
->video_in
.capture_mem
= PAGE_ALIGN(4096 * 4096) * 2 * 3;
2308 prev
->video_in
.bpl_alignment
= 64;
2309 prev
->video_out
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
2310 prev
->video_out
.ops
= &preview_video_ops
;
2311 prev
->video_out
.isp
= to_isp_device(prev
);
2312 prev
->video_out
.capture_mem
= PAGE_ALIGN(4096 * 4096) * 2 * 3;
2313 prev
->video_out
.bpl_alignment
= 32;
2315 ret
= omap3isp_video_init(&prev
->video_in
, "preview");
2317 goto error_video_in
;
2319 ret
= omap3isp_video_init(&prev
->video_out
, "preview");
2321 goto error_video_out
;
2323 /* Connect the video nodes to the previewer subdev. */
2324 ret
= media_entity_create_link(&prev
->video_in
.video
.entity
, 0,
2325 &prev
->subdev
.entity
, PREV_PAD_SINK
, 0);
2329 ret
= media_entity_create_link(&prev
->subdev
.entity
, PREV_PAD_SOURCE
,
2330 &prev
->video_out
.video
.entity
, 0, 0);
2337 omap3isp_video_cleanup(&prev
->video_out
);
2339 omap3isp_video_cleanup(&prev
->video_in
);
2341 media_entity_cleanup(&prev
->subdev
.entity
);
2346 * omap3isp_preview_init - Previewer initialization.
2347 * @dev : Pointer to ISP device
2348 * return -ENOMEM or zero on success
2350 int omap3isp_preview_init(struct isp_device
*isp
)
2352 struct isp_prev_device
*prev
= &isp
->isp_prev
;
2354 init_waitqueue_head(&prev
->wait
);
2356 preview_init_params(prev
);
2358 return preview_init_entities(prev
);
2361 void omap3isp_preview_cleanup(struct isp_device
*isp
)
2363 struct isp_prev_device
*prev
= &isp
->isp_prev
;
2365 v4l2_ctrl_handler_free(&prev
->ctrls
);
2366 omap3isp_video_cleanup(&prev
->video_in
);
2367 omap3isp_video_cleanup(&prev
->video_out
);
2368 media_entity_cleanup(&prev
->subdev
.entity
);