]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/staging/media/davinci_vpfe/dm365_isif.c
Merge tag 'please-pull-fixmcelog' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / media / davinci_vpfe / dm365_isif.c
1 /*
2 * Copyright (C) 2012 Texas Instruments Inc
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Contributors:
18 * Manjunath Hadli <manjunath.hadli@ti.com>
19 * Prabhakar Lad <prabhakar.lad@ti.com>
20 */
21
22 #include <linux/delay.h>
23 #include "dm365_isif.h"
24 #include "vpfe_mc_capture.h"
25
26 #define MAX_WIDTH 4096
27 #define MAX_HEIGHT 4096
28
29 static const unsigned int isif_fmts[] = {
30 MEDIA_BUS_FMT_YUYV8_2X8,
31 MEDIA_BUS_FMT_UYVY8_2X8,
32 MEDIA_BUS_FMT_YUYV8_1X16,
33 MEDIA_BUS_FMT_YUYV10_1X20,
34 MEDIA_BUS_FMT_SGRBG12_1X12,
35 MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
36 MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
37 };
38
39 #define ISIF_COLPTN_R_Ye 0x0
40 #define ISIF_COLPTN_Gr_Cy 0x1
41 #define ISIF_COLPTN_Gb_G 0x2
42 #define ISIF_COLPTN_B_Mg 0x3
43
44 #define ISIF_CCOLP_CP01_0 0
45 #define ISIF_CCOLP_CP03_2 2
46 #define ISIF_CCOLP_CP05_4 4
47 #define ISIF_CCOLP_CP07_6 6
48 #define ISIF_CCOLP_CP11_0 8
49 #define ISIF_CCOLP_CP13_2 10
50 #define ISIF_CCOLP_CP15_4 12
51 #define ISIF_CCOLP_CP17_6 14
52
53 static const u32 isif_sgrbg_pattern =
54 ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP01_0 |
55 ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP03_2 |
56 ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP05_4 |
57 ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP07_6 |
58 ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP11_0 |
59 ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP13_2 |
60 ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP15_4 |
61 ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP17_6;
62
63 static const u32 isif_srggb_pattern =
64 ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP01_0 |
65 ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP03_2 |
66 ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP05_4 |
67 ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP07_6 |
68 ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP11_0 |
69 ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP13_2 |
70 ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP15_4 |
71 ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP17_6;
72
73 static inline u32 isif_read(void __iomem *base_addr, u32 offset)
74 {
75 return readl(base_addr + offset);
76 }
77
78 static inline void isif_write(void __iomem *base_addr, u32 val, u32 offset)
79 {
80 writel(val, base_addr + offset);
81 }
82
83 static inline u32 isif_merge(void __iomem *base_addr, u32 mask, u32 val,
84 u32 offset)
85 {
86 u32 new_val = (isif_read(base_addr, offset) & ~mask) | (val & mask);
87
88 isif_write(base_addr, new_val, offset);
89
90 return new_val;
91 }
92
93 static void isif_enable_output_to_sdram(struct vpfe_isif_device *isif, int en)
94 {
95 isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_WEN_MASK,
96 en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
97 }
98
99 static inline void
100 isif_regw_lin_tbl(struct vpfe_isif_device *isif, u32 val, u32 offset, int i)
101 {
102 if (!i)
103 writel(val, isif->isif_cfg.linear_tbl0_addr + offset);
104 else
105 writel(val, isif->isif_cfg.linear_tbl1_addr + offset);
106 }
107
108 static void isif_disable_all_modules(struct vpfe_isif_device *isif)
109 {
110 /* disable BC */
111 isif_write(isif->isif_cfg.base_addr, 0, CLAMPCFG);
112 /* disable vdfc */
113 isif_write(isif->isif_cfg.base_addr, 0, DFCCTL);
114 /* disable CSC */
115 isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
116 /* disable linearization */
117 isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
118 }
119
120 static void isif_enable(struct vpfe_isif_device *isif, int en)
121 {
122 if (!en)
123 /* Before disable isif, disable all ISIF modules */
124 isif_disable_all_modules(isif);
125
126 /*
127 * wait for next VD. Assume lowest scan rate is 12 Hz. So
128 * 100 msec delay is good enough
129 */
130 msleep(100);
131 isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_VDHDEN_MASK,
132 en, SYNCEN);
133 }
134
135 /*
136 * ISIF helper functions
137 */
138
139 #define DM365_ISIF_MDFS_OFFSET 15
140 #define DM365_ISIF_MDFS_MASK 0x1
141
142 /* get field id in isif hardware */
143 enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev)
144 {
145 struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
146 u32 field_status;
147
148 field_status = isif_read(isif->isif_cfg.base_addr, MODESET);
149 field_status = (field_status >> DM365_ISIF_MDFS_OFFSET) &
150 DM365_ISIF_MDFS_MASK;
151 return field_status;
152 }
153
154 static int
155 isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt)
156 {
157 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
158 if (pixfmt == V4L2_PIX_FMT_SBGGR16)
159 isif->isif_cfg.data_pack = ISIF_PACK_16BIT;
160 else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) ||
161 (pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8))
162 isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
163 else
164 return -EINVAL;
165
166 isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
167 isif->isif_cfg.bayer.v4l2_pix_fmt = pixfmt;
168 } else {
169 if (pixfmt == V4L2_PIX_FMT_YUYV)
170 isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_YCBYCR;
171 else if (pixfmt == V4L2_PIX_FMT_UYVY)
172 isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
173 else
174 return -EINVAL;
175
176 isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
177 isif->isif_cfg.ycbcr.v4l2_pix_fmt = pixfmt;
178 }
179
180 return 0;
181 }
182
183 static int
184 isif_set_frame_format(struct vpfe_isif_device *isif,
185 enum isif_frmfmt frm_fmt)
186 {
187 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
188 isif->isif_cfg.bayer.frm_fmt = frm_fmt;
189 else
190 isif->isif_cfg.ycbcr.frm_fmt = frm_fmt;
191
192 return 0;
193 }
194
195 static int isif_set_image_window(struct vpfe_isif_device *isif)
196 {
197 struct v4l2_rect *win = &isif->crop;
198
199 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
200 isif->isif_cfg.bayer.win.top = win->top;
201 isif->isif_cfg.bayer.win.left = win->left;
202 isif->isif_cfg.bayer.win.width = win->width;
203 isif->isif_cfg.bayer.win.height = win->height;
204 return 0;
205 }
206 isif->isif_cfg.ycbcr.win.top = win->top;
207 isif->isif_cfg.ycbcr.win.left = win->left;
208 isif->isif_cfg.ycbcr.win.width = win->width;
209 isif->isif_cfg.ycbcr.win.height = win->height;
210
211 return 0;
212 }
213
214 static int
215 isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type)
216 {
217 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
218 isif->isif_cfg.bayer.buf_type = buf_type;
219 else
220 isif->isif_cfg.ycbcr.buf_type = buf_type;
221
222 return 0;
223 }
224
225 /* configure format in isif hardware */
226 static int
227 isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad)
228 {
229 struct vpfe_isif_device *vpfe_isif = &vpfe_dev->vpfe_isif;
230 enum isif_frmfmt frm_fmt = ISIF_FRMFMT_INTERLACED;
231 struct v4l2_pix_format format;
232 int ret = 0;
233
234 v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_isif.formats[pad]);
235 mbus_to_pix(&vpfe_dev->vpfe_isif.formats[pad], &format);
236
237 if (isif_set_pixel_format(vpfe_isif, format.pixelformat) < 0) {
238 v4l2_err(&vpfe_dev->v4l2_dev,
239 "Failed to set pixel format in isif\n");
240 return -EINVAL;
241 }
242
243 /* call for s_crop will override these values */
244 vpfe_isif->crop.left = 0;
245 vpfe_isif->crop.top = 0;
246 vpfe_isif->crop.width = format.width;
247 vpfe_isif->crop.height = format.height;
248
249 /* configure the image window */
250 isif_set_image_window(vpfe_isif);
251
252 switch (vpfe_dev->vpfe_isif.formats[pad].field) {
253 case V4L2_FIELD_INTERLACED:
254 /* do nothing, since it is default */
255 ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_INTERLEAVED);
256 break;
257
258 case V4L2_FIELD_NONE:
259 frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
260 /* buffer type only applicable for interlaced scan */
261 break;
262
263 case V4L2_FIELD_SEQ_TB:
264 ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_SEPARATED);
265 break;
266
267 default:
268 return -EINVAL;
269 }
270
271 /* set the frame format */
272 if (!ret)
273 ret = isif_set_frame_format(vpfe_isif, frm_fmt);
274
275 return ret;
276 }
277
278 /*
279 * isif_try_format() - Try video format on a pad
280 * @isif: VPFE isif device
281 * @fh: V4L2 subdev file handle
282 * @fmt: pointer to v4l2 subdev format structure
283 */
284 static void
285 isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh,
286 struct v4l2_subdev_format *fmt)
287 {
288 unsigned int width = fmt->format.width;
289 unsigned int height = fmt->format.height;
290 unsigned int i;
291
292 for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) {
293 if (fmt->format.code == isif_fmts[i])
294 break;
295 }
296
297 /* If not found, use YUYV8_2x8 as default */
298 if (i >= ARRAY_SIZE(isif_fmts))
299 fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
300
301 /* Clamp the size. */
302 fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
303 fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT);
304
305 /* The data formatter truncates the number of horizontal output
306 * pixels to a multiple of 16. To avoid clipping data, allow
307 * callers to request an output size bigger than the input size
308 * up to the nearest multiple of 16.
309 */
310 if (fmt->pad == ISIF_PAD_SOURCE)
311 fmt->format.width &= ~15;
312 }
313
314 /*
315 * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr
316 * @isif: Pointer to isif subdevice.
317 */
318 void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif)
319 {
320 struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
321 struct vpfe_video_device *video = &isif->video_out;
322 enum v4l2_field field;
323 int fid;
324
325 if (!video->started)
326 return;
327
328 field = video->fmt.fmt.pix.field;
329
330 if (field == V4L2_FIELD_NONE) {
331 /* handle progressive frame capture */
332 if (video->cur_frm != video->next_frm)
333 vpfe_video_process_buffer_complete(video);
334 return;
335 }
336
337 /* interlaced or TB capture check which field we
338 * are in hardware
339 */
340 fid = vpfe_isif_get_fid(vpfe_dev);
341
342 /* switch the software maintained field id */
343 video->field_id ^= 1;
344 if (fid == video->field_id) {
345 /* we are in-sync here,continue */
346 if (fid == 0) {
347 /*
348 * One frame is just being captured. If the
349 * next frame is available, release the current
350 * frame and move on
351 */
352 if (video->cur_frm != video->next_frm)
353 vpfe_video_process_buffer_complete(video);
354 /*
355 * based on whether the two fields are stored
356 * interleavely or separately in memory,
357 * reconfigure the ISIF memory address
358 */
359 if (field == V4L2_FIELD_SEQ_TB)
360 vpfe_video_schedule_bottom_field(video);
361 return;
362 }
363 /*
364 * if one field is just being captured configure
365 * the next frame get the next frame from the
366 * empty queue if no frame is available hold on
367 * to the current buffer
368 */
369 spin_lock(&video->dma_queue_lock);
370 if (!list_empty(&video->dma_queue) &&
371 video->cur_frm == video->next_frm)
372 vpfe_video_schedule_next_buffer(video);
373 spin_unlock(&video->dma_queue_lock);
374 } else if (fid == 0) {
375 /*
376 * out of sync. Recover from any hardware out-of-sync.
377 * May loose one frame
378 */
379 video->field_id = fid;
380 }
381 }
382
383 /*
384 * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr
385 * @isif: Pointer to isif subdevice.
386 */
387 void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif)
388 {
389 struct vpfe_video_device *video = &isif->video_out;
390
391 if (!video->started)
392 return;
393
394 spin_lock(&video->dma_queue_lock);
395 if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
396 !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm)
397 vpfe_video_schedule_next_buffer(video);
398
399 spin_unlock(&video->dma_queue_lock);
400 }
401
402 /*
403 * VPFE video operations
404 */
405
406 static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
407 {
408 struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
409
410 isif_write(isif->isif_cfg.base_addr, (addr >> 21) &
411 ISIF_CADU_BITS, CADU);
412 isif_write(isif->isif_cfg.base_addr, (addr >> 5) &
413 ISIF_CADL_BITS, CADL);
414
415 return 0;
416 }
417
418 static const struct vpfe_video_operations isif_video_ops = {
419 .queue = isif_video_queue,
420 };
421
422 /*
423 * V4L2 subdev operations
424 */
425
426 /* Parameter operations */
427 static int isif_get_params(struct v4l2_subdev *sd, void *params)
428 {
429 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
430
431 /* only raw module parameters can be set through the IOCTL */
432 if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
433 return -EINVAL;
434 memcpy(params, &isif->isif_cfg.bayer.config_params,
435 sizeof(isif->isif_cfg.bayer.config_params));
436 return 0;
437 }
438
439 static int isif_validate_df_csc_params(struct vpfe_isif_df_csc *df_csc)
440 {
441 struct vpfe_isif_color_space_conv *csc;
442 int err = -EINVAL;
443 int i;
444
445 if (!df_csc->df_or_csc) {
446 /* csc configuration */
447 csc = &df_csc->csc;
448 if (csc->en) {
449 for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++)
450 if (csc->coeff[i].integer >
451 ISIF_CSC_COEF_INTEG_MASK ||
452 csc->coeff[i].decimal >
453 ISIF_CSC_COEF_DECIMAL_MASK) {
454 pr_err("Invalid CSC coefficients\n");
455 return err;
456 }
457 }
458 }
459 if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) {
460 pr_err("Invalid df_csc start pix value\n");
461 return err;
462 }
463
464 if (df_csc->num_pixels > ISIF_DF_NUMPIX) {
465 pr_err("Invalid df_csc num pixels value\n");
466 return err;
467 }
468
469 if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) {
470 pr_err("Invalid df_csc start_line value\n");
471 return err;
472 }
473
474 if (df_csc->num_lines > ISIF_DF_NUMLINES) {
475 pr_err("Invalid df_csc num_lines value\n");
476 return err;
477 }
478
479 return 0;
480 }
481
482 #define DM365_ISIF_MAX_VDFLSFT 4
483 #define DM365_ISIF_MAX_VDFSLV 4095
484 #define DM365_ISIF_MAX_DFCMEM0 0x1fff
485 #define DM365_ISIF_MAX_DFCMEM1 0x1fff
486
487 static int isif_validate_dfc_params(struct vpfe_isif_dfc *dfc)
488 {
489 int err = -EINVAL;
490 int i;
491
492 if (!dfc->en)
493 return 0;
494
495 if (dfc->corr_whole_line > 1) {
496 pr_err("Invalid corr_whole_line value\n");
497 return err;
498 }
499
500 if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) {
501 pr_err("Invalid def_level_shift value\n");
502 return err;
503 }
504
505 if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) {
506 pr_err("Invalid def_sat_level value\n");
507 return err;
508 }
509
510 if (!dfc->num_vdefects ||
511 dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) {
512 pr_err("Invalid num_vdefects value\n");
513 return err;
514 }
515
516 for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) {
517 if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) {
518 pr_err("Invalid pos_vert value\n");
519 return err;
520 }
521 if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) {
522 pr_err("Invalid pos_horz value\n");
523 return err;
524 }
525 }
526
527 return 0;
528 }
529
530 #define DM365_ISIF_MAX_CLVRV 0xfff
531 #define DM365_ISIF_MAX_CLDC 0x1fff
532 #define DM365_ISIF_MAX_CLHSH 0x1fff
533 #define DM365_ISIF_MAX_CLHSV 0x1fff
534 #define DM365_ISIF_MAX_CLVSH 0x1fff
535 #define DM365_ISIF_MAX_CLVSV 0x1fff
536 #define DM365_ISIF_MAX_HEIGHT_BLACK_REGION 0x1fff
537
538 static int isif_validate_bclamp_params(struct vpfe_isif_black_clamp *bclamp)
539 {
540 int err = -EINVAL;
541
542 if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) {
543 pr_err("Invalid bclamp dc_offset value\n");
544 return err;
545 }
546 if (!bclamp->en)
547 return 0;
548 if (bclamp->horz.clamp_pix_limit > 1) {
549 pr_err("Invalid bclamp horz clamp_pix_limit value\n");
550 return err;
551 }
552 if (bclamp->horz.win_count_calc < 1 ||
553 bclamp->horz.win_count_calc > 32) {
554 pr_err("Invalid bclamp horz win_count_calc value\n");
555 return err;
556 }
557 if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) {
558 pr_err("Invalid bclamp win_start_v_calc value\n");
559 return err;
560 }
561
562 if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) {
563 pr_err("Invalid bclamp win_start_v_calc value\n");
564 return err;
565 }
566 if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) {
567 pr_err("Invalid bclamp reset_clamp_val value\n");
568 return err;
569 }
570 if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) {
571 pr_err("Invalid bclamp ob_v_sz_calc value\n");
572 return err;
573 }
574 if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) {
575 pr_err("Invalid bclamp ob_start_h value\n");
576 return err;
577 }
578 if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) {
579 pr_err("Invalid bclamp ob_start_h value\n");
580 return err;
581 }
582 return 0;
583 }
584
585 static int
586 isif_validate_raw_params(struct vpfe_isif_raw_config *params)
587 {
588 int ret;
589
590 ret = isif_validate_df_csc_params(&params->df_csc);
591 if (ret)
592 return ret;
593 ret = isif_validate_dfc_params(&params->dfc);
594 if (ret)
595 return ret;
596 ret = isif_validate_bclamp_params(&params->bclamp);
597 return ret;
598 }
599
600 static int isif_set_params(struct v4l2_subdev *sd, void *params)
601 {
602 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
603 struct vpfe_isif_raw_config isif_raw_params;
604 int ret = -EINVAL;
605
606 /* only raw module parameters can be set through the IOCTL */
607 if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
608 return ret;
609
610 memcpy(&isif_raw_params, params, sizeof(isif_raw_params));
611 if (!isif_validate_raw_params(&isif_raw_params)) {
612 memcpy(&isif->isif_cfg.bayer.config_params, &isif_raw_params,
613 sizeof(isif_raw_params));
614 ret = 0;
615 }
616 return ret;
617 }
618 /*
619 * isif_ioctl() - isif module private ioctl's
620 * @sd: VPFE isif V4L2 subdevice
621 * @cmd: ioctl command
622 * @arg: ioctl argument
623 *
624 * Return 0 on success or a negative error code otherwise.
625 */
626 static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
627 {
628 int ret;
629
630 switch (cmd) {
631 case VIDIOC_VPFE_ISIF_S_RAW_PARAMS:
632 ret = isif_set_params(sd, arg);
633 break;
634
635 case VIDIOC_VPFE_ISIF_G_RAW_PARAMS:
636 ret = isif_get_params(sd, arg);
637 break;
638
639 default:
640 ret = -ENOIOCTLCMD;
641 }
642 return ret;
643 }
644
645 static void isif_config_gain_offset(struct vpfe_isif_device *isif)
646 {
647 struct vpfe_isif_gain_offsets_adj *gain_off_ptr =
648 &isif->isif_cfg.bayer.config_params.gain_offset;
649 void __iomem *base = isif->isif_cfg.base_addr;
650 u32 val;
651
652 val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) |
653 ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) |
654 ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) |
655 ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) |
656 ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) |
657 ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT);
658 isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
659
660 isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN);
661 isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN);
662 isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN);
663 isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN);
664 isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK,
665 COFSTA);
666
667 }
668
669 static void isif_config_bclamp(struct vpfe_isif_device *isif,
670 struct vpfe_isif_black_clamp *bc)
671 {
672 u32 val;
673
674 /**
675 * DC Offset is always added to image data irrespective of bc enable
676 * status
677 */
678 val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK;
679 isif_write(isif->isif_cfg.base_addr, val, CLDCOFST);
680
681 if (!bc->en)
682 return;
683
684 val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) <<
685 ISIF_BC_MODE_COLOR_SHIFT;
686
687 /* Enable BC and horizontal clamp calculation paramaters */
688 val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) <<
689 ISIF_HORZ_BC_MODE_SHIFT);
690
691 isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG);
692
693 if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) {
694 /*
695 * Window count for calculation
696 * Base window selection
697 * pixel limit
698 * Horizontal size of window
699 * vertical size of the window
700 * Horizontal start position of the window
701 * Vertical start position of the window
702 */
703 val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) |
704 ((bc->horz.base_win_sel_calc & 1) <<
705 ISIF_HORZ_BC_WIN_SEL_SHIFT) |
706 ((bc->horz.clamp_pix_limit & 1) <<
707 ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
708 ((bc->horz.win_h_sz_calc &
709 ISIF_HORZ_BC_WIN_H_SIZE_MASK) <<
710 ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
711 ((bc->horz.win_v_sz_calc &
712 ISIF_HORZ_BC_WIN_V_SIZE_MASK) <<
713 ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
714
715 isif_write(isif->isif_cfg.base_addr, val, CLHWIN0);
716
717 val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK;
718 isif_write(isif->isif_cfg.base_addr, val, CLHWIN1);
719
720 val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK;
721 isif_write(isif->isif_cfg.base_addr, val, CLHWIN2);
722 }
723
724 /* vertical clamp calculation paramaters */
725 /* OB H Valid */
726 val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK;
727
728 /* Reset clamp value sel for previous line */
729 val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) <<
730 ISIF_VERT_BC_RST_VAL_SEL_SHIFT;
731
732 /* Line average coefficient */
733 val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT;
734 isif_write(isif->isif_cfg.base_addr, val, CLVWIN0);
735
736 /* Configured reset value */
737 if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) {
738 val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK;
739 isif_write(isif->isif_cfg.base_addr, val, CLVRV);
740 }
741
742 /* Optical Black horizontal start position */
743 val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK;
744 isif_write(isif->isif_cfg.base_addr, val, CLVWIN1);
745
746 /* Optical Black vertical start position */
747 val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK;
748 isif_write(isif->isif_cfg.base_addr, val, CLVWIN2);
749
750 val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK;
751 isif_write(isif->isif_cfg.base_addr, val, CLVWIN3);
752
753 /* Vertical start position for BC subtraction */
754 val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK;
755 isif_write(isif->isif_cfg.base_addr, val, CLSV);
756 }
757
758 /* This function will configure the window size to be capture in ISIF reg */
759 static void
760 isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win,
761 enum isif_frmfmt frm_fmt, int ppc, int mode)
762 {
763 int horz_nr_pixels;
764 int vert_nr_lines;
765 int horz_start;
766 int vert_start;
767 int mid_img;
768
769 /*
770 * ppc - per pixel count. indicates how many pixels per cell
771 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
772 * raw capture this is 1
773 */
774 horz_start = image_win->left << (ppc - 1);
775 horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
776
777 /* Writing the horizontal info into the registers */
778 isif_write(isif->isif_cfg.base_addr,
779 horz_start & START_PX_HOR_MASK, SPH);
780 isif_write(isif->isif_cfg.base_addr,
781 horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
782 vert_start = image_win->top;
783
784 if (frm_fmt == ISIF_FRMFMT_INTERLACED) {
785 vert_nr_lines = (image_win->height >> 1) - 1;
786 vert_start >>= 1;
787 /* To account for VD since line 0 doesn't have any data */
788 vert_start += 1;
789 } else {
790 /* To account for VD since line 0 doesn't have any data */
791 vert_start += 1;
792 vert_nr_lines = image_win->height - 1;
793 /* configure VDINT0 and VDINT1 */
794 mid_img = vert_start + (image_win->height / 2);
795 isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1);
796 }
797
798 if (!mode)
799 isif_write(isif->isif_cfg.base_addr, 0, VDINT0);
800 else
801 isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0);
802 isif_write(isif->isif_cfg.base_addr,
803 vert_start & START_VER_ONE_MASK, SLV0);
804 isif_write(isif->isif_cfg.base_addr,
805 vert_start & START_VER_TWO_MASK, SLV1);
806 isif_write(isif->isif_cfg.base_addr,
807 vert_nr_lines & NUM_LINES_VER, LNV);
808 }
809
810 #define DM365_ISIF_DFCMWR_MEMORY_WRITE 1
811 #define DM365_ISIF_DFCMRD_MEMORY_READ 0x2
812
813 static void
814 isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
815 {
816 #define DFC_WRITE_WAIT_COUNT 1000
817 u32 count = DFC_WRITE_WAIT_COUNT;
818 u32 val;
819 int i;
820
821 if (!vdfc->en)
822 return;
823
824 /* Correction mode */
825 val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) <<
826 ISIF_VDFC_CORR_MOD_SHIFT;
827
828 /* Correct whole line or partial */
829 if (vdfc->corr_whole_line)
830 val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
831
832 /* level shift value */
833 val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) <<
834 ISIF_VDFC_LEVEL_SHFT_SHIFT;
835
836 isif_write(isif->isif_cfg.base_addr, val, DFCCTL);
837
838 /* Defect saturation level */
839 val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK;
840 isif_write(isif->isif_cfg.base_addr, val, VDFSATLV);
841
842 isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert &
843 ISIF_VDFC_POS_MASK, DFCMEM0);
844 isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz &
845 ISIF_VDFC_POS_MASK, DFCMEM1);
846 if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
847 vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
848 isif_write(isif->isif_cfg.base_addr,
849 vdfc->table[0].level_at_pos, DFCMEM2);
850 isif_write(isif->isif_cfg.base_addr,
851 vdfc->table[0].level_up_pixels, DFCMEM3);
852 isif_write(isif->isif_cfg.base_addr,
853 vdfc->table[0].level_low_pixels, DFCMEM4);
854 }
855
856 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
857 /* set DFCMARST and set DFCMWR */
858 val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT;
859 val |= 1;
860 isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
861
862 while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01))
863 count--;
864
865 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
866 if (!count) {
867 pr_debug("defect table write timeout !!\n");
868 return;
869 }
870
871 for (i = 1; i < vdfc->num_vdefects; i++) {
872 isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert &
873 ISIF_VDFC_POS_MASK, DFCMEM0);
874
875 isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz &
876 ISIF_VDFC_POS_MASK, DFCMEM1);
877
878 if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
879 vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
880 isif_write(isif->isif_cfg.base_addr,
881 vdfc->table[i].level_at_pos, DFCMEM2);
882 isif_write(isif->isif_cfg.base_addr,
883 vdfc->table[i].level_up_pixels, DFCMEM3);
884 isif_write(isif->isif_cfg.base_addr,
885 vdfc->table[i].level_low_pixels, DFCMEM4);
886 }
887 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
888 /* clear DFCMARST and set DFCMWR */
889 val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT);
890 val |= 1;
891 isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
892
893 count = DFC_WRITE_WAIT_COUNT;
894 while (count && (isif_read(isif->isif_cfg.base_addr,
895 DFCMEMCTL) & 0x01))
896 count--;
897
898 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
899 if (!count) {
900 pr_debug("defect table write timeout !!\n");
901 return;
902 }
903 }
904 if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) {
905 /* Extra cycle needed */
906 isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0);
907 isif_write(isif->isif_cfg.base_addr,
908 DM365_ISIF_MAX_DFCMEM1, DFCMEM1);
909 isif_write(isif->isif_cfg.base_addr,
910 DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL);
911 }
912 /* enable VDFC */
913 isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
914 (1 << ISIF_VDFC_EN_SHIFT), DFCCTL);
915
916 isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
917 (0 << ISIF_VDFC_EN_SHIFT), DFCCTL);
918
919 isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL);
920 for (i = 0; i < vdfc->num_vdefects; i++) {
921 count = DFC_WRITE_WAIT_COUNT;
922 while (count &&
923 (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2))
924 count--;
925 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
926 if (!count) {
927 pr_debug("defect table write timeout !!\n");
928 return;
929 }
930 isif_write(isif->isif_cfg.base_addr,
931 DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL);
932 }
933 }
934
935 static void
936 isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc)
937 {
938 u32 val1;
939 u32 val2;
940 u32 i;
941
942 if (!df_csc->csc.en) {
943 isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
944 return;
945 }
946 /* initialize all bits to 0 */
947 val1 = 0;
948 for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) {
949 if ((i % 2) == 0) {
950 /* CSCM - LSB */
951 val1 = ((df_csc->csc.coeff[i].integer &
952 ISIF_CSC_COEF_INTEG_MASK) <<
953 ISIF_CSC_COEF_INTEG_SHIFT) |
954 ((df_csc->csc.coeff[i].decimal &
955 ISIF_CSC_COEF_DECIMAL_MASK));
956 } else {
957
958 /* CSCM - MSB */
959 val2 = ((df_csc->csc.coeff[i].integer &
960 ISIF_CSC_COEF_INTEG_MASK) <<
961 ISIF_CSC_COEF_INTEG_SHIFT) |
962 ((df_csc->csc.coeff[i].decimal &
963 ISIF_CSC_COEF_DECIMAL_MASK));
964 val2 <<= ISIF_CSCM_MSB_SHIFT;
965 val2 |= val1;
966 isif_write(isif->isif_cfg.base_addr, val2,
967 (CSCM0 + ((i-1) << 1)));
968 }
969 }
970 /* program the active area */
971 isif_write(isif->isif_cfg.base_addr, df_csc->start_pix &
972 ISIF_DF_CSC_SPH_MASK, FMTSPH);
973 /*
974 * one extra pixel as required for CSC. Actually number of
975 * pixel - 1 should be configured in this register. So we
976 * need to subtract 1 before writing to FMTSPH, but we will
977 * not do this since csc requires one extra pixel
978 */
979 isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels &
980 ISIF_DF_CSC_SPH_MASK, FMTLNH);
981 isif_write(isif->isif_cfg.base_addr, df_csc->start_line &
982 ISIF_DF_CSC_SPH_MASK, FMTSLV);
983 /*
984 * one extra line as required for CSC. See reason documented for
985 * num_pixels
986 */
987 isif_write(isif->isif_cfg.base_addr, df_csc->num_lines &
988 ISIF_DF_CSC_SPH_MASK, FMTLNV);
989 /* Enable CSC */
990 isif_write(isif->isif_cfg.base_addr, 1, CSCCTL);
991 }
992
993 static void
994 isif_config_linearization(struct vpfe_isif_device *isif,
995 struct vpfe_isif_linearize *linearize)
996 {
997 u32 val;
998 u32 i;
999
1000 if (!linearize->en) {
1001 isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
1002 return;
1003 }
1004 /* shift value for correction */
1005 val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) <<
1006 ISIF_LIN_CORRSFT_SHIFT;
1007 /* enable */
1008 val |= 1;
1009 isif_write(isif->isif_cfg.base_addr, val, LINCFG0);
1010 /* Scale factor */
1011 val = (linearize->scale_fact.integer & 1) <<
1012 ISIF_LIN_SCALE_FACT_INTEG_SHIFT;
1013 val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK;
1014 isif_write(isif->isif_cfg.base_addr, val, LINCFG1);
1015
1016 for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) {
1017 val = linearize->table[i] & ISIF_LIN_ENTRY_MASK;
1018 if (i%2)
1019 isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1);
1020 else
1021 isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0);
1022 }
1023 }
1024
1025 static void
1026 isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul)
1027 {
1028 u32 val;
1029
1030 /* Horizontal pattern */
1031 val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT;
1032 val |= cul->hcpat_odd;
1033 isif_write(isif->isif_cfg.base_addr, val, CULH);
1034 /* vertical pattern */
1035 isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV);
1036 /* LPF */
1037 isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT,
1038 cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
1039 }
1040
1041 static int isif_get_pix_fmt(u32 mbus_code)
1042 {
1043 switch (mbus_code) {
1044 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
1045 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
1046 case MEDIA_BUS_FMT_SGRBG12_1X12:
1047 return ISIF_PIXFMT_RAW;
1048
1049 case MEDIA_BUS_FMT_YUYV8_2X8:
1050 case MEDIA_BUS_FMT_UYVY8_2X8:
1051 case MEDIA_BUS_FMT_YUYV10_2X10:
1052 case MEDIA_BUS_FMT_Y8_1X8:
1053 return ISIF_PIXFMT_YCBCR_8BIT;
1054
1055 case MEDIA_BUS_FMT_YUYV8_1X16:
1056 case MEDIA_BUS_FMT_YUYV10_1X20:
1057 return ISIF_PIXFMT_YCBCR_16BIT;
1058
1059 default:
1060 break;
1061 }
1062 return -EINVAL;
1063 }
1064
1065 #define ISIF_INTERLACE_INVERSE_MODE 0x4b6d
1066 #define ISIF_INTERLACE_NON_INVERSE_MODE 0x0b6d
1067 #define ISIF_PROGRESSIVE_INVERSE_MODE 0x4000
1068 #define ISIF_PROGRESSIVE_NON_INVERSE_MODE 0x0000
1069
1070 static int isif_config_raw(struct v4l2_subdev *sd, int mode)
1071 {
1072 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1073 struct isif_params_raw *params = &isif->isif_cfg.bayer;
1074 struct vpfe_isif_raw_config *module_params =
1075 &isif->isif_cfg.bayer.config_params;
1076 struct v4l2_mbus_framefmt *format;
1077 int pix_fmt;
1078 u32 val;
1079
1080 format = &isif->formats[ISIF_PAD_SINK];
1081
1082 /* In case of user has set BT656IF earlier, it should be reset
1083 * when configuring for raw input.
1084 */
1085 isif_write(isif->isif_cfg.base_addr, 0, REC656IF);
1086 /* Configure CCDCFG register
1087 * Set CCD Not to swap input since input is RAW data
1088 * Set FID detection function to Latch at V-Sync
1089 * Set WENLOG - isif valid area
1090 * Set TRGSEL
1091 * Set EXTRG
1092 * Packed to 8 or 16 bits
1093 */
1094 val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
1095 ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
1096 ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack &
1097 ISIF_DATA_PACK_MASK);
1098 isif_write(isif->isif_cfg.base_addr, val, CCDCFG);
1099
1100 pix_fmt = isif_get_pix_fmt(format->code);
1101 if (pix_fmt < 0) {
1102 pr_debug("Invalid pix_fmt(input mode)\n");
1103 return -EINVAL;
1104 }
1105 /*
1106 * Configure the vertical sync polarity(MODESET.VDPOL)
1107 * Configure the horizontal sync polarity (MODESET.HDPOL)
1108 * Configure frame id polarity (MODESET.FLDPOL)
1109 * Configure data polarity
1110 * Configure External WEN Selection
1111 * Configure frame format(progressive or interlace)
1112 * Configure pixel format (Input mode)
1113 * Configure the data shift
1114 */
1115 val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) <<
1116 ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) <<
1117 ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) <<
1118 ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL &
1119 ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE &
1120 ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt &
1121 ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt &
1122 ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT);
1123
1124 /* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is
1125 * supported. shift appropriately depending on
1126 * different MBUS fmt's added
1127 */
1128 if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
1129 val |= ((VPFE_ISIF_NO_SHIFT &
1130 ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT);
1131
1132 isif_write(isif->isif_cfg.base_addr, val, MODESET);
1133 /*
1134 * Configure GAMMAWD register
1135 * CFA pattern setting
1136 */
1137 val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) <<
1138 ISIF_GAMMAWD_CFA_SHIFT;
1139 /* Gamma msb */
1140 if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8)
1141 val = val | ISIF_ALAW_ENABLE;
1142
1143 val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) <<
1144 ISIF_ALAW_GAMA_WD_SHIFT);
1145
1146 isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD);
1147 /* Configure DPCM compression settings */
1148 if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
1149 val = 1 << ISIF_DPCM_EN_SHIFT;
1150 val |= (params->dpcm_predictor &
1151 ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT;
1152 }
1153 isif_write(isif->isif_cfg.base_addr, val, MISC);
1154 /* Configure Gain & Offset */
1155 isif_config_gain_offset(isif);
1156 /* Configure Color pattern */
1157 if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
1158 val = isif_sgrbg_pattern;
1159 else
1160 /* default set to rggb */
1161 val = isif_srggb_pattern;
1162
1163 isif_write(isif->isif_cfg.base_addr, val, CCOLP);
1164
1165 /* Configure HSIZE register */
1166 val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) <<
1167 ISIF_HSIZE_FLIP_SHIFT;
1168
1169 /* calculate line offset in 32 bytes based on pack value */
1170 if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT)
1171 val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK;
1172 else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT)
1173 val |= ((((params->win.width + (params->win.width >> 2)) +
1174 31) >> 5) & ISIF_LINEOFST_MASK);
1175 else
1176 val |= (((params->win.width * 2) + 31) >> 5) &
1177 ISIF_LINEOFST_MASK;
1178 isif_write(isif->isif_cfg.base_addr, val, HSIZE);
1179 /* Configure SDOFST register */
1180 if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) {
1181 if (params->image_invert_en)
1182 /* For interlace inverse mode */
1183 isif_write(isif->isif_cfg.base_addr,
1184 ISIF_INTERLACE_INVERSE_MODE, SDOFST);
1185 else
1186 /* For interlace non inverse mode */
1187 isif_write(isif->isif_cfg.base_addr,
1188 ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST);
1189 } else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) {
1190 if (params->image_invert_en)
1191 isif_write(isif->isif_cfg.base_addr,
1192 ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST);
1193 else
1194 /* For progessive non inverse mode */
1195 isif_write(isif->isif_cfg.base_addr,
1196 ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST);
1197 }
1198 /* Configure video window */
1199 isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1200 /* Configure Black Clamp */
1201 isif_config_bclamp(isif, &module_params->bclamp);
1202 /* Configure Vertical Defection Pixel Correction */
1203 isif_config_dfc(isif, &module_params->dfc);
1204 if (!module_params->df_csc.df_or_csc)
1205 /* Configure Color Space Conversion */
1206 isif_config_csc(isif, &module_params->df_csc);
1207
1208 isif_config_linearization(isif, &module_params->linearize);
1209 /* Configure Culling */
1210 isif_config_culling(isif, &module_params->culling);
1211 /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */
1212 val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK;
1213 isif_write(isif->isif_cfg.base_addr, val, DATAHOFST);
1214
1215 val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK;
1216 isif_write(isif->isif_cfg.base_addr, val, DATAVOFST);
1217
1218 return 0;
1219 }
1220
1221 #define DM365_ISIF_HSIZE_MASK 0xffffffe0
1222 #define DM365_ISIF_SDOFST_2_LINES 0x00000249
1223
1224 /* This function will configure ISIF for YCbCr parameters. */
1225 static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
1226 {
1227 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1228 struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr;
1229 struct v4l2_mbus_framefmt *format;
1230 int pix_fmt;
1231 u32 modeset;
1232 u32 ccdcfg;
1233
1234 format = &isif->formats[ISIF_PAD_SINK];
1235 /*
1236 * first reset the ISIF
1237 * all registers have default values after reset
1238 * This is important since we assume default values to be set in
1239 * a lot of registers that we didn't touch
1240 */
1241 /* start with all bits zero */
1242 ccdcfg = modeset = 0;
1243 pix_fmt = isif_get_pix_fmt(format->code);
1244 if (pix_fmt < 0) {
1245 pr_debug("Invalid pix_fmt(input mode)\n");
1246 return -EINVAL;
1247 }
1248 /* configure pixel format or input mode */
1249 modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) <<
1250 ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) <<
1251 ISIF_FRM_FMT_SHIFT) | (((params->fid_pol &
1252 ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) |
1253 (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) |
1254 (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT));
1255 /* pack the data to 8-bit CCDCCFG */
1256 switch (format->code) {
1257 case MEDIA_BUS_FMT_YUYV8_2X8:
1258 case MEDIA_BUS_FMT_UYVY8_2X8:
1259 if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1260 pr_debug("Invalid pix_fmt(input mode)\n");
1261 return -EINVAL;
1262 }
1263 modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) <<
1264 ISIF_VD_POL_SHIFT);
1265 isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1266 ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR;
1267 break;
1268
1269 case MEDIA_BUS_FMT_YUYV10_2X10:
1270 if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1271 pr_debug("Invalid pix_fmt(input mode)\n");
1272 return -EINVAL;
1273 }
1274 /* setup BT.656, embedded sync */
1275 isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1276 /* enable 10 bit mode in ccdcfg */
1277 ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR |
1278 ISIF_BW656_ENABLE;
1279 break;
1280
1281 case MEDIA_BUS_FMT_YUYV10_1X20:
1282 if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1283 pr_debug("Invalid pix_fmt(input mode)\n");
1284 return -EINVAL;
1285 }
1286 isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1287 break;
1288
1289 case MEDIA_BUS_FMT_Y8_1X8:
1290 ccdcfg |= ISIF_PACK_8BIT;
1291 ccdcfg |= ISIF_YCINSWP_YCBCR;
1292 if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1293 pr_debug("Invalid pix_fmt(input mode)\n");
1294 return -EINVAL;
1295 }
1296 break;
1297
1298 case MEDIA_BUS_FMT_YUYV8_1X16:
1299 if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1300 pr_debug("Invalid pix_fmt(input mode)\n");
1301 return -EINVAL;
1302 }
1303 break;
1304
1305 default:
1306 /* should never come here */
1307 pr_debug("Invalid interface type\n");
1308 return -EINVAL;
1309 }
1310 isif_write(isif->isif_cfg.base_addr, modeset, MODESET);
1311 /* Set up pix order */
1312 ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) <<
1313 ISIF_PIX_ORDER_SHIFT;
1314 isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG);
1315 /* configure video window */
1316 if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 ||
1317 format->code == MEDIA_BUS_FMT_YUYV8_1X16)
1318 isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1319 else
1320 isif_setwin(isif, &params->win, params->frm_fmt, 2, mode);
1321
1322 /*
1323 * configure the horizontal line offset
1324 * this is done by rounding up width to a multiple of 16 pixels
1325 * and multiply by two to account for y:cb:cr 4:2:2 data
1326 */
1327 isif_write(isif->isif_cfg.base_addr,
1328 ((((params->win.width * 2) + 31) &
1329 DM365_ISIF_HSIZE_MASK) >> 5), HSIZE);
1330
1331 /* configure the memory line offset */
1332 if (params->frm_fmt == ISIF_FRMFMT_INTERLACED &&
1333 params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED)
1334 /* two fields are interleaved in memory */
1335 isif_write(isif->isif_cfg.base_addr,
1336 DM365_ISIF_SDOFST_2_LINES, SDOFST);
1337 return 0;
1338 }
1339
1340 static int isif_configure(struct v4l2_subdev *sd, int mode)
1341 {
1342 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1343 struct v4l2_mbus_framefmt *format;
1344
1345 format = &isif->formats[ISIF_PAD_SINK];
1346
1347 switch (format->code) {
1348 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
1349 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
1350 case MEDIA_BUS_FMT_SGRBG12_1X12:
1351 return isif_config_raw(sd, mode);
1352
1353 case MEDIA_BUS_FMT_YUYV8_2X8:
1354 case MEDIA_BUS_FMT_UYVY8_2X8:
1355 case MEDIA_BUS_FMT_YUYV10_2X10:
1356 case MEDIA_BUS_FMT_Y8_1X8:
1357 case MEDIA_BUS_FMT_YUYV8_1X16:
1358 case MEDIA_BUS_FMT_YUYV10_1X20:
1359 return isif_config_ycbcr(sd, mode);
1360
1361 default:
1362 break;
1363 }
1364 return -EINVAL;
1365 }
1366
1367 /*
1368 * isif_set_stream() - Enable/Disable streaming on the ISIF module
1369 * @sd: VPFE ISIF V4L2 subdevice
1370 * @enable: Enable/disable stream
1371 */
1372 static int isif_set_stream(struct v4l2_subdev *sd, int enable)
1373 {
1374 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1375 int ret;
1376
1377 if (enable) {
1378 ret = isif_configure(sd,
1379 (isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1);
1380 if (ret)
1381 return ret;
1382 if (isif->output == ISIF_OUTPUT_MEMORY)
1383 isif_enable_output_to_sdram(isif, 1);
1384 isif_enable(isif, 1);
1385 } else {
1386 isif_enable(isif, 0);
1387 isif_enable_output_to_sdram(isif, 0);
1388 }
1389
1390 return 0;
1391 }
1392
1393 /*
1394 * __isif_get_format() - helper function for getting isif format
1395 * @isif: pointer to isif private structure.
1396 * @pad: pad number.
1397 * @fh: V4L2 subdev file handle.
1398 * @which: wanted subdev format.
1399 */
1400 static struct v4l2_mbus_framefmt *
1401 __isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh,
1402 unsigned int pad, enum v4l2_subdev_format_whence which)
1403 {
1404 if (which == V4L2_SUBDEV_FORMAT_TRY) {
1405 struct v4l2_subdev_format fmt;
1406
1407 fmt.pad = pad;
1408 fmt.which = which;
1409
1410 return v4l2_subdev_get_try_format(fh, pad);
1411 }
1412 return &isif->formats[pad];
1413 }
1414
1415 /*
1416 * isif_set_format() - set format on pad
1417 * @sd : VPFE ISIF device
1418 * @fh : V4L2 subdev file handle
1419 * @fmt : pointer to v4l2 subdev format structure
1420 *
1421 * Return 0 on success or -EINVAL if format or pad is invalid
1422 */
1423 static int
1424 isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1425 struct v4l2_subdev_format *fmt)
1426 {
1427 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1428 struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1429 struct v4l2_mbus_framefmt *format;
1430
1431 format = __isif_get_format(isif, fh, fmt->pad, fmt->which);
1432 if (format == NULL)
1433 return -EINVAL;
1434
1435 isif_try_format(isif, fh, fmt);
1436 memcpy(format, &fmt->format, sizeof(*format));
1437
1438 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1439 return 0;
1440
1441 if (fmt->pad == ISIF_PAD_SOURCE)
1442 return isif_config_format(vpfe_dev, fmt->pad);
1443
1444 return 0;
1445 }
1446
1447 /*
1448 * isif_get_format() - Retrieve the video format on a pad
1449 * @sd: VPFE ISIF V4L2 subdevice
1450 * @fh: V4L2 subdev file handle
1451 * @fmt: pointer to v4l2 subdev format structure
1452 *
1453 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
1454 * to the format type.
1455 */
1456 static int
1457 isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1458 struct v4l2_subdev_format *fmt)
1459 {
1460 struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1461 struct v4l2_mbus_framefmt *format;
1462
1463 format = __isif_get_format(vpfe_isif, fh, fmt->pad, fmt->which);
1464 if (format == NULL)
1465 return -EINVAL;
1466
1467 memcpy(&fmt->format, format, sizeof(fmt->format));
1468
1469 return 0;
1470 }
1471
1472 /*
1473 * isif_enum_frame_size() - enum frame sizes on pads
1474 * @sd: VPFE isif V4L2 subdevice
1475 * @fh: V4L2 subdev file handle
1476 * @code: pointer to v4l2_subdev_frame_size_enum structure
1477 */
1478 static int
1479 isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1480 struct v4l2_subdev_frame_size_enum *fse)
1481 {
1482 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1483 struct v4l2_subdev_format format;
1484
1485 if (fse->index != 0)
1486 return -EINVAL;
1487
1488 format.pad = fse->pad;
1489 format.format.code = fse->code;
1490 format.format.width = 1;
1491 format.format.height = 1;
1492 format.which = V4L2_SUBDEV_FORMAT_TRY;
1493 isif_try_format(isif, fh, &format);
1494 fse->min_width = format.format.width;
1495 fse->min_height = format.format.height;
1496
1497 if (format.format.code != fse->code)
1498 return -EINVAL;
1499
1500 format.pad = fse->pad;
1501 format.format.code = fse->code;
1502 format.format.width = -1;
1503 format.format.height = -1;
1504 format.which = V4L2_SUBDEV_FORMAT_TRY;
1505 isif_try_format(isif, fh, &format);
1506 fse->max_width = format.format.width;
1507 fse->max_height = format.format.height;
1508
1509 return 0;
1510 }
1511
1512 /*
1513 * isif_enum_mbus_code() - enum mbus codes for pads
1514 * @sd: VPFE isif V4L2 subdevice
1515 * @fh: V4L2 subdev file handle
1516 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1517 */
1518 static int
1519 isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1520 struct v4l2_subdev_mbus_code_enum *code)
1521 {
1522 switch (code->pad) {
1523 case ISIF_PAD_SINK:
1524 case ISIF_PAD_SOURCE:
1525 if (code->index >= ARRAY_SIZE(isif_fmts))
1526 return -EINVAL;
1527 code->code = isif_fmts[code->index];
1528 break;
1529
1530 default:
1531 return -EINVAL;
1532 }
1533
1534 return 0;
1535 }
1536
1537 /*
1538 * isif_pad_set_selection() - set crop rectangle on pad
1539 * @sd: VPFE isif V4L2 subdevice
1540 * @fh: V4L2 subdev file handle
1541 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1542 *
1543 * Return 0 on success, -EINVAL if pad is invalid
1544 */
1545 static int
1546 isif_pad_set_selection(struct v4l2_subdev *sd,
1547 struct v4l2_subdev_fh *fh,
1548 struct v4l2_subdev_selection *sel)
1549 {
1550 struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1551 struct v4l2_mbus_framefmt *format;
1552
1553 /* check whether it's a valid pad and target */
1554 if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
1555 return -EINVAL;
1556
1557 format = __isif_get_format(vpfe_isif, fh, sel->pad, sel->which);
1558 if (format == NULL)
1559 return -EINVAL;
1560
1561 /* check wether crop rect is within limits */
1562 if (sel->r.top < 0 || sel->r.left < 0 ||
1563 (sel->r.left + sel->r.width >
1564 vpfe_isif->formats[ISIF_PAD_SINK].width) ||
1565 (sel->r.top + sel->r.height >
1566 vpfe_isif->formats[ISIF_PAD_SINK].height)) {
1567 sel->r.left = 0;
1568 sel->r.top = 0;
1569 sel->r.width = format->width;
1570 sel->r.height = format->height;
1571 }
1572 /* adjust the width to 16 pixel boundary */
1573 sel->r.width = ((sel->r.width + 15) & ~0xf);
1574 vpfe_isif->crop = sel->r;
1575 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1576 isif_set_image_window(vpfe_isif);
1577 } else {
1578 struct v4l2_rect *rect;
1579
1580 rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK);
1581 memcpy(rect, &vpfe_isif->crop, sizeof(*rect));
1582 }
1583 return 0;
1584 }
1585
1586 /*
1587 * isif_pad_get_selection() - get crop rectangle on pad
1588 * @sd: VPFE isif V4L2 subdevice
1589 * @fh: V4L2 subdev file handle
1590 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1591 *
1592 * Return 0 on success, -EINVAL if pad is invalid
1593 */
1594 static int
1595 isif_pad_get_selection(struct v4l2_subdev *sd,
1596 struct v4l2_subdev_fh *fh,
1597 struct v4l2_subdev_selection *sel)
1598 {
1599 struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1600
1601 /* check whether it's a valid pad and target */
1602 if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
1603 return -EINVAL;
1604
1605 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
1606 struct v4l2_rect *rect;
1607
1608 rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK);
1609 memcpy(&sel->r, rect, sizeof(*rect));
1610 } else {
1611 sel->r = vpfe_isif->crop;
1612 }
1613
1614 return 0;
1615 }
1616
1617 /*
1618 * isif_init_formats() - Initialize formats on all pads
1619 * @sd: VPFE isif V4L2 subdevice
1620 * @fh: V4L2 subdev file handle
1621 *
1622 * Initialize all pad formats with default values. If fh is not NULL, try
1623 * formats are initialized on the file handle. Otherwise active formats are
1624 * initialized on the device.
1625 */
1626 static int
1627 isif_init_formats(struct v4l2_subdev *sd,
1628 struct v4l2_subdev_fh *fh)
1629 {
1630 struct v4l2_subdev_format format;
1631 struct v4l2_subdev_selection sel;
1632
1633 memset(&format, 0, sizeof(format));
1634 format.pad = ISIF_PAD_SINK;
1635 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1636 format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
1637 format.format.width = MAX_WIDTH;
1638 format.format.height = MAX_HEIGHT;
1639 isif_set_format(sd, fh, &format);
1640
1641 memset(&format, 0, sizeof(format));
1642 format.pad = ISIF_PAD_SOURCE;
1643 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1644 format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
1645 format.format.width = MAX_WIDTH;
1646 format.format.height = MAX_HEIGHT;
1647 isif_set_format(sd, fh, &format);
1648
1649 memset(&sel, 0, sizeof(sel));
1650 sel.pad = ISIF_PAD_SINK;
1651 sel.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1652 sel.target = V4L2_SEL_TGT_CROP;
1653 sel.r.width = MAX_WIDTH;
1654 sel.r.height = MAX_HEIGHT;
1655 isif_pad_set_selection(sd, fh, &sel);
1656
1657 return 0;
1658 }
1659
1660 /* subdev core operations */
1661 static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = {
1662 .ioctl = isif_ioctl,
1663 };
1664
1665 /* subdev file operations */
1666 static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = {
1667 .open = isif_init_formats,
1668 };
1669
1670 /* subdev video operations */
1671 static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = {
1672 .s_stream = isif_set_stream,
1673 };
1674
1675 /* subdev pad operations */
1676 static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = {
1677 .enum_mbus_code = isif_enum_mbus_code,
1678 .enum_frame_size = isif_enum_frame_size,
1679 .get_fmt = isif_get_format,
1680 .set_fmt = isif_set_format,
1681 .set_selection = isif_pad_set_selection,
1682 .get_selection = isif_pad_get_selection,
1683 };
1684
1685 /* subdev operations */
1686 static const struct v4l2_subdev_ops isif_v4l2_ops = {
1687 .core = &isif_v4l2_core_ops,
1688 .video = &isif_v4l2_video_ops,
1689 .pad = &isif_v4l2_pad_ops,
1690 };
1691
1692 /*
1693 * Media entity operations
1694 */
1695
1696 /*
1697 * isif_link_setup() - Setup isif connections
1698 * @entity: isif media entity
1699 * @local: Pad at the local end of the link
1700 * @remote: Pad at the remote end of the link
1701 * @flags: Link flags
1702 *
1703 * return -EINVAL or zero on success
1704 */
1705 static int
1706 isif_link_setup(struct media_entity *entity, const struct media_pad *local,
1707 const struct media_pad *remote, u32 flags)
1708 {
1709 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1710 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1711
1712 switch (local->index | media_entity_type(remote->entity)) {
1713 case ISIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1714 /* read from decoder/sensor */
1715 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1716 isif->input = ISIF_INPUT_NONE;
1717 break;
1718 }
1719 if (isif->input != ISIF_INPUT_NONE)
1720 return -EBUSY;
1721 isif->input = ISIF_INPUT_PARALLEL;
1722 break;
1723
1724 case ISIF_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1725 /* write to memory */
1726 if (flags & MEDIA_LNK_FL_ENABLED)
1727 isif->output = ISIF_OUTPUT_MEMORY;
1728 else
1729 isif->output = ISIF_OUTPUT_NONE;
1730 break;
1731
1732 case ISIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
1733 if (flags & MEDIA_LNK_FL_ENABLED)
1734 isif->output = ISIF_OUTPUT_IPIPEIF;
1735 else
1736 isif->output = ISIF_OUTPUT_NONE;
1737 break;
1738
1739 default:
1740 return -EINVAL;
1741 }
1742
1743 return 0;
1744 }
1745 static const struct media_entity_operations isif_media_ops = {
1746 .link_setup = isif_link_setup,
1747 };
1748
1749 /*
1750 * vpfe_isif_unregister_entities() - isif unregister entity
1751 * @isif - pointer to isif subdevice structure.
1752 */
1753 void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
1754 {
1755 vpfe_video_unregister(&isif->video_out);
1756 /* unregister subdev */
1757 v4l2_device_unregister_subdev(&isif->subdev);
1758 /* cleanup entity */
1759 media_entity_cleanup(&isif->subdev.entity);
1760 }
1761
1762 static void isif_restore_defaults(struct vpfe_isif_device *isif)
1763 {
1764 enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
1765 int i;
1766
1767 memset(&isif->isif_cfg.bayer.config_params, 0,
1768 sizeof(struct vpfe_isif_raw_config));
1769
1770 isif->isif_cfg.bayer.config_params.linearize.corr_shft =
1771 VPFE_ISIF_NO_SHIFT;
1772 isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1;
1773 isif->isif_cfg.bayer.config_params.culling.hcpat_odd =
1774 ISIF_CULLING_HCAPT_ODD;
1775 isif->isif_cfg.bayer.config_params.culling.hcpat_even =
1776 ISIF_CULLING_HCAPT_EVEN;
1777 isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT;
1778 /* Enable clock to ISIF, IPIPEIF and BL */
1779 vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
1780 vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
1781 vpss_enable_clock(VPSS_BL_CLOCK, 1);
1782
1783 /* set all registers to default value */
1784 for (i = 0; i <= 0x1f8; i += 4)
1785 isif_write(isif->isif_cfg.base_addr, 0, i);
1786 /* no culling support */
1787 isif_write(isif->isif_cfg.base_addr, 0xffff, CULH);
1788 isif_write(isif->isif_cfg.base_addr, 0xff, CULV);
1789
1790 /* Set default offset and gain */
1791 isif_config_gain_offset(isif);
1792 vpss_select_ccdc_source(source);
1793 }
1794
1795 /*
1796 * vpfe_isif_register_entities() - isif register entity
1797 * @isif - pointer to isif subdevice structure.
1798 * @vdev: pointer to v4l2 device structure.
1799 */
1800 int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
1801 struct v4l2_device *vdev)
1802 {
1803 struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1804 unsigned int flags;
1805 int ret;
1806
1807 /* Register the subdev */
1808 ret = v4l2_device_register_subdev(vdev, &isif->subdev);
1809 if (ret < 0)
1810 return ret;
1811
1812 isif_restore_defaults(isif);
1813 ret = vpfe_video_register(&isif->video_out, vdev);
1814 if (ret) {
1815 pr_err("Failed to register isif video out device\n");
1816 goto out_video_register;
1817 }
1818 isif->video_out.vpfe_dev = vpfe_dev;
1819 flags = 0;
1820 /* connect isif to video node */
1821 ret = media_entity_create_link(&isif->subdev.entity, 1,
1822 &isif->video_out.video_dev.entity,
1823 0, flags);
1824 if (ret < 0)
1825 goto out_create_link;
1826 return 0;
1827 out_create_link:
1828 vpfe_video_unregister(&isif->video_out);
1829 out_video_register:
1830 v4l2_device_unregister_subdev(&isif->subdev);
1831 return ret;
1832 }
1833
1834 /* -------------------------------------------------------------------
1835 * V4L2 subdev control operations
1836 */
1837
1838 static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl)
1839 {
1840 struct vpfe_isif_device *isif =
1841 container_of(ctrl->handler, struct vpfe_isif_device, ctrls);
1842 struct isif_oper_config *config = &isif->isif_cfg;
1843
1844 switch (ctrl->id) {
1845 case VPFE_CID_DPCM_PREDICTOR:
1846 config->bayer.dpcm_predictor = ctrl->val;
1847 break;
1848
1849 case VPFE_ISIF_CID_CRGAIN:
1850 config->isif_gain_params.cr_gain = ctrl->val;
1851 break;
1852
1853 case VPFE_ISIF_CID_CGRGAIN:
1854 config->isif_gain_params.cgr_gain = ctrl->val;
1855 break;
1856
1857 case VPFE_ISIF_CID_CGBGAIN:
1858 config->isif_gain_params.cgb_gain = ctrl->val;
1859 break;
1860
1861 case VPFE_ISIF_CID_CBGAIN:
1862 config->isif_gain_params.cb_gain = ctrl->val;
1863 break;
1864
1865 case VPFE_ISIF_CID_GAIN_OFFSET:
1866 config->isif_gain_params.offset = ctrl->val;
1867 break;
1868
1869 default:
1870 return -EINVAL;
1871 }
1872 return 0;
1873 }
1874
1875 static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = {
1876 .s_ctrl = vpfe_isif_s_ctrl,
1877 };
1878
1879 static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = {
1880 .ops = &vpfe_isif_ctrl_ops,
1881 .id = VPFE_CID_DPCM_PREDICTOR,
1882 .name = "DPCM Predictor",
1883 .type = V4L2_CTRL_TYPE_INTEGER,
1884 .min = 0,
1885 .max = 1,
1886 .step = 1,
1887 .def = 0,
1888 };
1889
1890 static const struct v4l2_ctrl_config vpfe_isif_crgain = {
1891 .ops = &vpfe_isif_ctrl_ops,
1892 .id = VPFE_ISIF_CID_CRGAIN,
1893 .name = "CRGAIN",
1894 .type = V4L2_CTRL_TYPE_INTEGER,
1895 .min = 0,
1896 .max = (1 << 12) - 1,
1897 .step = 1,
1898 .def = 0,
1899 };
1900
1901 static const struct v4l2_ctrl_config vpfe_isif_cgrgain = {
1902 .ops = &vpfe_isif_ctrl_ops,
1903 .id = VPFE_ISIF_CID_CGRGAIN,
1904 .name = "CGRGAIN",
1905 .type = V4L2_CTRL_TYPE_INTEGER,
1906 .min = 0,
1907 .max = (1 << 12) - 1,
1908 .step = 1,
1909 .def = 0,
1910 };
1911
1912 static const struct v4l2_ctrl_config vpfe_isif_cgbgain = {
1913 .ops = &vpfe_isif_ctrl_ops,
1914 .id = VPFE_ISIF_CID_CGBGAIN,
1915 .name = "CGBGAIN",
1916 .type = V4L2_CTRL_TYPE_INTEGER,
1917 .min = 0,
1918 .max = (1 << 12) - 1,
1919 .step = 1,
1920 .def = 0,
1921 };
1922
1923 static const struct v4l2_ctrl_config vpfe_isif_cbgain = {
1924 .ops = &vpfe_isif_ctrl_ops,
1925 .id = VPFE_ISIF_CID_CBGAIN,
1926 .name = "CBGAIN",
1927 .type = V4L2_CTRL_TYPE_INTEGER,
1928 .min = 0,
1929 .max = (1 << 12) - 1,
1930 .step = 1,
1931 .def = 0,
1932 };
1933
1934 static const struct v4l2_ctrl_config vpfe_isif_gain_offset = {
1935 .ops = &vpfe_isif_ctrl_ops,
1936 .id = VPFE_ISIF_CID_GAIN_OFFSET,
1937 .name = "Gain Offset",
1938 .type = V4L2_CTRL_TYPE_INTEGER,
1939 .min = 0,
1940 .max = (1 << 12) - 1,
1941 .step = 1,
1942 .def = 0,
1943 };
1944
1945 static void isif_remove(struct vpfe_isif_device *isif,
1946 struct platform_device *pdev)
1947 {
1948 struct resource *res;
1949 int i = 0;
1950
1951 iounmap(isif->isif_cfg.base_addr);
1952 iounmap(isif->isif_cfg.linear_tbl0_addr);
1953 iounmap(isif->isif_cfg.linear_tbl1_addr);
1954
1955 while (i < 3) {
1956 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1957 if (res)
1958 release_mem_region(res->start,
1959 resource_size(res));
1960 i++;
1961 }
1962 }
1963
1964 static void isif_config_defaults(struct vpfe_isif_device *isif)
1965 {
1966 isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY;
1967 isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT;
1968 isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED;
1969 isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE;
1970 isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE;
1971 isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE;
1972 isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
1973 isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED;
1974
1975 isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8;
1976 isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
1977 isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
1978 isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE;
1979 isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE;
1980 isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE;
1981 isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC;
1982 isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11;
1983 isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
1984 }
1985 /*
1986 * vpfe_isif_init() - Initialize V4L2 subdev and media entity
1987 * @isif: VPFE isif module
1988 * @pdev: Pointer to platform device structure.
1989 * Return 0 on success and a negative error code on failure.
1990 */
1991 int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
1992 {
1993 struct v4l2_subdev *sd = &isif->subdev;
1994 struct media_pad *pads = &isif->pads[0];
1995 struct media_entity *me = &sd->entity;
1996 static resource_size_t res_len;
1997 struct resource *res;
1998 void __iomem *addr;
1999 int status;
2000 int i = 0;
2001
2002 /* Get the ISIF base address, linearization table0 and table1 addr. */
2003 while (i < 3) {
2004 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2005 if (!res) {
2006 status = -ENOENT;
2007 goto fail_nobase_res;
2008 }
2009 res_len = resource_size(res);
2010 res = request_mem_region(res->start, res_len, res->name);
2011 if (!res) {
2012 status = -EBUSY;
2013 goto fail_nobase_res;
2014 }
2015 addr = ioremap_nocache(res->start, res_len);
2016 if (!addr) {
2017 status = -EBUSY;
2018 goto fail_base_iomap;
2019 }
2020 switch (i) {
2021 case 0:
2022 /* ISIF base address */
2023 isif->isif_cfg.base_addr = addr;
2024 break;
2025 case 1:
2026 /* ISIF linear tbl0 address */
2027 isif->isif_cfg.linear_tbl0_addr = addr;
2028 break;
2029 default:
2030 /* ISIF linear tbl0 address */
2031 isif->isif_cfg.linear_tbl1_addr = addr;
2032 break;
2033 }
2034 i++;
2035 }
2036 davinci_cfg_reg(DM365_VIN_CAM_WEN);
2037 davinci_cfg_reg(DM365_VIN_CAM_VD);
2038 davinci_cfg_reg(DM365_VIN_CAM_HD);
2039 davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
2040 davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
2041
2042 /* queue ops */
2043 isif->video_out.ops = &isif_video_ops;
2044 v4l2_subdev_init(sd, &isif_v4l2_ops);
2045 sd->internal_ops = &isif_v4l2_internal_ops;
2046 strlcpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
2047 sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
2048 v4l2_set_subdevdata(sd, isif);
2049 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
2050 pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2051 pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
2052
2053 isif->input = ISIF_INPUT_NONE;
2054 isif->output = ISIF_OUTPUT_NONE;
2055 me->ops = &isif_media_ops;
2056 status = media_entity_init(me, ISIF_PADS_NUM, pads, 0);
2057 if (status)
2058 goto isif_fail;
2059 isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2060 status = vpfe_video_init(&isif->video_out, "ISIF");
2061 if (status) {
2062 pr_err("Failed to init isif-out video device\n");
2063 goto isif_fail;
2064 }
2065 v4l2_ctrl_handler_init(&isif->ctrls, 6);
2066 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL);
2067 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL);
2068 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL);
2069 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL);
2070 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL);
2071 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL);
2072
2073 v4l2_ctrl_handler_setup(&isif->ctrls);
2074 sd->ctrl_handler = &isif->ctrls;
2075 isif_config_defaults(isif);
2076 return 0;
2077 fail_base_iomap:
2078 release_mem_region(res->start, res_len);
2079 i--;
2080 fail_nobase_res:
2081 if (isif->isif_cfg.base_addr)
2082 iounmap(isif->isif_cfg.base_addr);
2083 if (isif->isif_cfg.linear_tbl0_addr)
2084 iounmap(isif->isif_cfg.linear_tbl0_addr);
2085
2086 while (i >= 0) {
2087 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2088 release_mem_region(res->start, res_len);
2089 i--;
2090 }
2091 return status;
2092 isif_fail:
2093 v4l2_ctrl_handler_free(&isif->ctrls);
2094 isif_remove(isif, pdev);
2095 return status;
2096 }
2097
2098 /*
2099 * vpfe_isif_cleanup - isif module cleanup
2100 * @isif: pointer to isif subdevice
2101 * @dev: pointer to platform device structure
2102 */
2103 void
2104 vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev)
2105 {
2106 isif_remove(isif, pdev);
2107 }