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