blob: ae9202ded59fa59a38be084ede2cfc93f10e3703 [file] [log] [blame]
Manjunath Hadli6a630532012-11-28 02:09:35 -03001/*
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
Hans Verkuile0a97342013-12-20 09:04:44 -030022#include <linux/delay.h>
Manjunath Hadli6a630532012-11-28 02:09:35 -030023#include "dm365_isif.h"
24#include "vpfe_mc_capture.h"
25
26#define MAX_WIDTH 4096
27#define MAX_HEIGHT 4096
28
29static const unsigned int isif_fmts[] = {
Boris BREZILLON3336f072014-11-10 14:28:33 -030030 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,
Manjunath Hadli6a630532012-11-28 02:09:35 -030037};
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
53static 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
63static 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
Tapasweni Pathak2129e172014-10-08 09:12:17 +053073static inline u32 isif_read(void __iomem *base_addr, u32 offset)
Manjunath Hadli6a630532012-11-28 02:09:35 -030074{
75 return readl(base_addr + offset);
76}
77
Tapasweni Pathak2129e172014-10-08 09:12:17 +053078static inline void isif_write(void __iomem *base_addr, u32 val, u32 offset)
Manjunath Hadli6a630532012-11-28 02:09:35 -030079{
80 writel(val, base_addr + offset);
81}
82
Tapasweni Pathak2129e172014-10-08 09:12:17 +053083static inline u32 isif_merge(void __iomem *base_addr, u32 mask, u32 val,
Manjunath Hadli6a630532012-11-28 02:09:35 -030084 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
93static 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
99static inline void
100isif_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
108static 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
120static 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 */
143enum 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
154static int
155isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt)
156{
Boris BREZILLON3336f072014-11-10 14:28:33 -0300157 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
Manjunath Hadli6a630532012-11-28 02:09:35 -0300158 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
183static int
184isif_set_frame_format(struct vpfe_isif_device *isif,
185 enum isif_frmfmt frm_fmt)
186{
Boris BREZILLON3336f072014-11-10 14:28:33 -0300187 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
Manjunath Hadli6a630532012-11-28 02:09:35 -0300188 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
195static int isif_set_image_window(struct vpfe_isif_device *isif)
196{
197 struct v4l2_rect *win = &isif->crop;
198
Boris BREZILLON3336f072014-11-10 14:28:33 -0300199 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
Manjunath Hadli6a630532012-11-28 02:09:35 -0300200 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
214static int
215isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type)
216{
Boris BREZILLON3336f072014-11-10 14:28:33 -0300217 if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
Manjunath Hadli6a630532012-11-28 02:09:35 -0300218 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 */
226static int
227isif_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
Hans Verkuilf7234132015-03-04 01:47:54 -0800281 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -0300282 * @fmt: pointer to v4l2 subdev format structure
283 */
284static void
Thaissa Falbo8e8919f2016-02-15 04:10:11 -0200285isif_try_format(struct vpfe_isif_device *isif,
286 struct v4l2_subdev_pad_config *cfg,
Manjunath Hadli6a630532012-11-28 02:09:35 -0300287 struct v4l2_subdev_format *fmt)
288{
289 unsigned int width = fmt->format.width;
290 unsigned int height = fmt->format.height;
291 unsigned int i;
292
293 for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) {
294 if (fmt->format.code == isif_fmts[i])
295 break;
296 }
297
298 /* If not found, use YUYV8_2x8 as default */
299 if (i >= ARRAY_SIZE(isif_fmts))
Boris BREZILLON3336f072014-11-10 14:28:33 -0300300 fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
Manjunath Hadli6a630532012-11-28 02:09:35 -0300301
302 /* Clamp the size. */
303 fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
304 fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT);
305
306 /* The data formatter truncates the number of horizontal output
307 * pixels to a multiple of 16. To avoid clipping data, allow
308 * callers to request an output size bigger than the input size
309 * up to the nearest multiple of 16.
310 */
311 if (fmt->pad == ISIF_PAD_SOURCE)
312 fmt->format.width &= ~15;
313}
314
315/*
316 * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr
317 * @isif: Pointer to isif subdevice.
318 */
319void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif)
320{
321 struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
322 struct vpfe_video_device *video = &isif->video_out;
323 enum v4l2_field field;
324 int fid;
325
326 if (!video->started)
327 return;
328
329 field = video->fmt.fmt.pix.field;
330
331 if (field == V4L2_FIELD_NONE) {
332 /* handle progressive frame capture */
333 if (video->cur_frm != video->next_frm)
334 vpfe_video_process_buffer_complete(video);
335 return;
336 }
337
338 /* interlaced or TB capture check which field we
339 * are in hardware
340 */
341 fid = vpfe_isif_get_fid(vpfe_dev);
342
343 /* switch the software maintained field id */
344 video->field_id ^= 1;
345 if (fid == video->field_id) {
346 /* we are in-sync here,continue */
347 if (fid == 0) {
348 /*
349 * One frame is just being captured. If the
350 * next frame is available, release the current
351 * frame and move on
352 */
353 if (video->cur_frm != video->next_frm)
354 vpfe_video_process_buffer_complete(video);
355 /*
356 * based on whether the two fields are stored
357 * interleavely or separately in memory,
358 * reconfigure the ISIF memory address
359 */
360 if (field == V4L2_FIELD_SEQ_TB)
361 vpfe_video_schedule_bottom_field(video);
362 return;
363 }
364 /*
365 * if one field is just being captured configure
366 * the next frame get the next frame from the
367 * empty queue if no frame is available hold on
368 * to the current buffer
369 */
370 spin_lock(&video->dma_queue_lock);
371 if (!list_empty(&video->dma_queue) &&
372 video->cur_frm == video->next_frm)
373 vpfe_video_schedule_next_buffer(video);
374 spin_unlock(&video->dma_queue_lock);
375 } else if (fid == 0) {
376 /*
377 * out of sync. Recover from any hardware out-of-sync.
378 * May loose one frame
379 */
380 video->field_id = fid;
381 }
382}
383
384/*
385 * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr
386 * @isif: Pointer to isif subdevice.
387 */
388void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif)
389{
390 struct vpfe_video_device *video = &isif->video_out;
391
392 if (!video->started)
393 return;
394
395 spin_lock(&video->dma_queue_lock);
396 if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
397 !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm)
398 vpfe_video_schedule_next_buffer(video);
399
400 spin_unlock(&video->dma_queue_lock);
401}
402
403/*
404 * VPFE video operations
405 */
406
407static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
408{
409 struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
410
411 isif_write(isif->isif_cfg.base_addr, (addr >> 21) &
412 ISIF_CADU_BITS, CADU);
413 isif_write(isif->isif_cfg.base_addr, (addr >> 5) &
414 ISIF_CADL_BITS, CADL);
415
416 return 0;
417}
418
419static const struct vpfe_video_operations isif_video_ops = {
420 .queue = isif_video_queue,
421};
422
423/*
424 * V4L2 subdev operations
425 */
426
427/* Parameter operations */
428static int isif_get_params(struct v4l2_subdev *sd, void *params)
429{
430 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
431
432 /* only raw module parameters can be set through the IOCTL */
Boris BREZILLON3336f072014-11-10 14:28:33 -0300433 if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
Manjunath Hadli6a630532012-11-28 02:09:35 -0300434 return -EINVAL;
435 memcpy(params, &isif->isif_cfg.bayer.config_params,
436 sizeof(isif->isif_cfg.bayer.config_params));
437 return 0;
438}
439
440static int isif_validate_df_csc_params(struct vpfe_isif_df_csc *df_csc)
441{
442 struct vpfe_isif_color_space_conv *csc;
443 int err = -EINVAL;
Manjunath Hadli6a630532012-11-28 02:09:35 -0300444 int i;
445
446 if (!df_csc->df_or_csc) {
447 /* csc configuration */
448 csc = &df_csc->csc;
449 if (csc->en) {
Manjunath Hadli6a630532012-11-28 02:09:35 -0300450 for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++)
451 if (csc->coeff[i].integer >
452 ISIF_CSC_COEF_INTEG_MASK ||
453 csc->coeff[i].decimal >
454 ISIF_CSC_COEF_DECIMAL_MASK) {
455 pr_err("Invalid CSC coefficients\n");
456 return err;
457 }
458 }
459 }
460 if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) {
461 pr_err("Invalid df_csc start pix value\n");
462 return err;
463 }
464
465 if (df_csc->num_pixels > ISIF_DF_NUMPIX) {
466 pr_err("Invalid df_csc num pixels value\n");
467 return err;
468 }
469
470 if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) {
471 pr_err("Invalid df_csc start_line value\n");
472 return err;
473 }
474
475 if (df_csc->num_lines > ISIF_DF_NUMLINES) {
476 pr_err("Invalid df_csc num_lines value\n");
477 return err;
478 }
479
480 return 0;
481}
482
483#define DM365_ISIF_MAX_VDFLSFT 4
484#define DM365_ISIF_MAX_VDFSLV 4095
485#define DM365_ISIF_MAX_DFCMEM0 0x1fff
486#define DM365_ISIF_MAX_DFCMEM1 0x1fff
487
488static int isif_validate_dfc_params(struct vpfe_isif_dfc *dfc)
489{
490 int err = -EINVAL;
491 int i;
492
493 if (!dfc->en)
494 return 0;
495
496 if (dfc->corr_whole_line > 1) {
497 pr_err("Invalid corr_whole_line value\n");
498 return err;
499 }
500
501 if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) {
502 pr_err("Invalid def_level_shift value\n");
503 return err;
504 }
505
506 if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) {
507 pr_err("Invalid def_sat_level value\n");
508 return err;
509 }
510
511 if (!dfc->num_vdefects ||
512 dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) {
513 pr_err("Invalid num_vdefects value\n");
514 return err;
515 }
516
517 for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) {
518 if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) {
519 pr_err("Invalid pos_vert value\n");
520 return err;
521 }
522 if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) {
523 pr_err("Invalid pos_horz value\n");
524 return err;
525 }
526 }
527
528 return 0;
529}
530
531#define DM365_ISIF_MAX_CLVRV 0xfff
532#define DM365_ISIF_MAX_CLDC 0x1fff
533#define DM365_ISIF_MAX_CLHSH 0x1fff
534#define DM365_ISIF_MAX_CLHSV 0x1fff
535#define DM365_ISIF_MAX_CLVSH 0x1fff
536#define DM365_ISIF_MAX_CLVSV 0x1fff
537#define DM365_ISIF_MAX_HEIGHT_BLACK_REGION 0x1fff
538
539static int isif_validate_bclamp_params(struct vpfe_isif_black_clamp *bclamp)
540{
541 int err = -EINVAL;
542
543 if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) {
544 pr_err("Invalid bclamp dc_offset value\n");
545 return err;
546 }
547 if (!bclamp->en)
548 return 0;
549 if (bclamp->horz.clamp_pix_limit > 1) {
550 pr_err("Invalid bclamp horz clamp_pix_limit value\n");
551 return err;
552 }
553 if (bclamp->horz.win_count_calc < 1 ||
554 bclamp->horz.win_count_calc > 32) {
555 pr_err("Invalid bclamp horz win_count_calc value\n");
556 return err;
557 }
558 if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) {
559 pr_err("Invalid bclamp win_start_v_calc value\n");
560 return err;
561 }
562
563 if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) {
564 pr_err("Invalid bclamp win_start_v_calc value\n");
565 return err;
566 }
567 if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) {
568 pr_err("Invalid bclamp reset_clamp_val value\n");
569 return err;
570 }
571 if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) {
572 pr_err("Invalid bclamp ob_v_sz_calc value\n");
573 return err;
574 }
575 if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) {
576 pr_err("Invalid bclamp ob_start_h value\n");
577 return err;
578 }
579 if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) {
580 pr_err("Invalid bclamp ob_start_h value\n");
581 return err;
582 }
583 return 0;
584}
585
586static int
587isif_validate_raw_params(struct vpfe_isif_raw_config *params)
588{
589 int ret;
590
591 ret = isif_validate_df_csc_params(&params->df_csc);
592 if (ret)
593 return ret;
594 ret = isif_validate_dfc_params(&params->dfc);
595 if (ret)
596 return ret;
597 ret = isif_validate_bclamp_params(&params->bclamp);
598 return ret;
599}
600
601static int isif_set_params(struct v4l2_subdev *sd, void *params)
602{
603 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
604 struct vpfe_isif_raw_config isif_raw_params;
605 int ret = -EINVAL;
606
607 /* only raw module parameters can be set through the IOCTL */
Boris BREZILLON3336f072014-11-10 14:28:33 -0300608 if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
Manjunath Hadli6a630532012-11-28 02:09:35 -0300609 return ret;
610
611 memcpy(&isif_raw_params, params, sizeof(isif_raw_params));
612 if (!isif_validate_raw_params(&isif_raw_params)) {
613 memcpy(&isif->isif_cfg.bayer.config_params, &isif_raw_params,
614 sizeof(isif_raw_params));
615 ret = 0;
616 }
617 return ret;
618}
619/*
620 * isif_ioctl() - isif module private ioctl's
621 * @sd: VPFE isif V4L2 subdevice
622 * @cmd: ioctl command
623 * @arg: ioctl argument
624 *
625 * Return 0 on success or a negative error code otherwise.
626 */
627static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
628{
Manjunath Hadli6a630532012-11-28 02:09:35 -0300629 switch (cmd) {
630 case VIDIOC_VPFE_ISIF_S_RAW_PARAMS:
Thaissa Falboc3397c12016-02-18 19:17:54 -0200631 return isif_set_params(sd, arg);
Manjunath Hadli6a630532012-11-28 02:09:35 -0300632
633 case VIDIOC_VPFE_ISIF_G_RAW_PARAMS:
Thaissa Falboc3397c12016-02-18 19:17:54 -0200634 return isif_get_params(sd, arg);
Manjunath Hadli6a630532012-11-28 02:09:35 -0300635
636 default:
Thaissa Falboc3397c12016-02-18 19:17:54 -0200637 return -ENOIOCTLCMD;
Manjunath Hadli6a630532012-11-28 02:09:35 -0300638 }
Manjunath Hadli6a630532012-11-28 02:09:35 -0300639}
640
641static void isif_config_gain_offset(struct vpfe_isif_device *isif)
642{
643 struct vpfe_isif_gain_offsets_adj *gain_off_ptr =
644 &isif->isif_cfg.bayer.config_params.gain_offset;
Tapasweni Pathak2129e172014-10-08 09:12:17 +0530645 void __iomem *base = isif->isif_cfg.base_addr;
Manjunath Hadli6a630532012-11-28 02:09:35 -0300646 u32 val;
647
648 val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) |
649 ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) |
650 ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) |
651 ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) |
652 ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) |
653 ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT);
654 isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
655
656 isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN);
657 isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN);
658 isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN);
659 isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN);
660 isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK,
661 COFSTA);
662
663}
664
665static void isif_config_bclamp(struct vpfe_isif_device *isif,
666 struct vpfe_isif_black_clamp *bc)
667{
668 u32 val;
669
670 /**
671 * DC Offset is always added to image data irrespective of bc enable
672 * status
673 */
674 val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK;
675 isif_write(isif->isif_cfg.base_addr, val, CLDCOFST);
676
677 if (!bc->en)
678 return;
679
680 val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) <<
681 ISIF_BC_MODE_COLOR_SHIFT;
682
Masanari Iida2f9e96c2013-03-26 11:23:28 -0300683 /* Enable BC and horizontal clamp calculation paramaters */
Manjunath Hadli6a630532012-11-28 02:09:35 -0300684 val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) <<
685 ISIF_HORZ_BC_MODE_SHIFT);
686
687 isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG);
688
689 if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) {
690 /*
691 * Window count for calculation
692 * Base window selection
693 * pixel limit
694 * Horizontal size of window
695 * vertical size of the window
696 * Horizontal start position of the window
697 * Vertical start position of the window
698 */
699 val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) |
700 ((bc->horz.base_win_sel_calc & 1) <<
701 ISIF_HORZ_BC_WIN_SEL_SHIFT) |
702 ((bc->horz.clamp_pix_limit & 1) <<
703 ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
704 ((bc->horz.win_h_sz_calc &
705 ISIF_HORZ_BC_WIN_H_SIZE_MASK) <<
706 ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
707 ((bc->horz.win_v_sz_calc &
708 ISIF_HORZ_BC_WIN_V_SIZE_MASK) <<
709 ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
710
711 isif_write(isif->isif_cfg.base_addr, val, CLHWIN0);
712
713 val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK;
714 isif_write(isif->isif_cfg.base_addr, val, CLHWIN1);
715
716 val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK;
717 isif_write(isif->isif_cfg.base_addr, val, CLHWIN2);
718 }
719
Masanari Iida2f9e96c2013-03-26 11:23:28 -0300720 /* vertical clamp calculation paramaters */
Manjunath Hadli6a630532012-11-28 02:09:35 -0300721 /* OB H Valid */
722 val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK;
723
724 /* Reset clamp value sel for previous line */
725 val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) <<
726 ISIF_VERT_BC_RST_VAL_SEL_SHIFT;
727
728 /* Line average coefficient */
729 val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT;
730 isif_write(isif->isif_cfg.base_addr, val, CLVWIN0);
731
732 /* Configured reset value */
733 if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) {
734 val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK;
735 isif_write(isif->isif_cfg.base_addr, val, CLVRV);
736 }
737
738 /* Optical Black horizontal start position */
739 val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK;
740 isif_write(isif->isif_cfg.base_addr, val, CLVWIN1);
741
742 /* Optical Black vertical start position */
743 val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK;
744 isif_write(isif->isif_cfg.base_addr, val, CLVWIN2);
745
746 val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK;
747 isif_write(isif->isif_cfg.base_addr, val, CLVWIN3);
748
749 /* Vertical start position for BC subtraction */
750 val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK;
751 isif_write(isif->isif_cfg.base_addr, val, CLSV);
752}
753
754/* This function will configure the window size to be capture in ISIF reg */
755static void
756isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win,
757 enum isif_frmfmt frm_fmt, int ppc, int mode)
758{
759 int horz_nr_pixels;
760 int vert_nr_lines;
761 int horz_start;
762 int vert_start;
763 int mid_img;
764
765 /*
766 * ppc - per pixel count. indicates how many pixels per cell
767 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
768 * raw capture this is 1
769 */
770 horz_start = image_win->left << (ppc - 1);
771 horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
772
773 /* Writing the horizontal info into the registers */
774 isif_write(isif->isif_cfg.base_addr,
775 horz_start & START_PX_HOR_MASK, SPH);
776 isif_write(isif->isif_cfg.base_addr,
777 horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
778 vert_start = image_win->top;
779
780 if (frm_fmt == ISIF_FRMFMT_INTERLACED) {
781 vert_nr_lines = (image_win->height >> 1) - 1;
782 vert_start >>= 1;
783 /* To account for VD since line 0 doesn't have any data */
784 vert_start += 1;
785 } else {
786 /* To account for VD since line 0 doesn't have any data */
787 vert_start += 1;
788 vert_nr_lines = image_win->height - 1;
789 /* configure VDINT0 and VDINT1 */
790 mid_img = vert_start + (image_win->height / 2);
791 isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1);
792 }
793
794 if (!mode)
795 isif_write(isif->isif_cfg.base_addr, 0, VDINT0);
796 else
797 isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0);
798 isif_write(isif->isif_cfg.base_addr,
799 vert_start & START_VER_ONE_MASK, SLV0);
800 isif_write(isif->isif_cfg.base_addr,
801 vert_start & START_VER_TWO_MASK, SLV1);
802 isif_write(isif->isif_cfg.base_addr,
803 vert_nr_lines & NUM_LINES_VER, LNV);
804}
805
806#define DM365_ISIF_DFCMWR_MEMORY_WRITE 1
807#define DM365_ISIF_DFCMRD_MEMORY_READ 0x2
808
809static void
810isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
811{
812#define DFC_WRITE_WAIT_COUNT 1000
813 u32 count = DFC_WRITE_WAIT_COUNT;
814 u32 val;
815 int i;
816
817 if (!vdfc->en)
818 return;
819
820 /* Correction mode */
821 val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) <<
822 ISIF_VDFC_CORR_MOD_SHIFT;
823
824 /* Correct whole line or partial */
825 if (vdfc->corr_whole_line)
826 val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
827
828 /* level shift value */
829 val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) <<
830 ISIF_VDFC_LEVEL_SHFT_SHIFT;
831
832 isif_write(isif->isif_cfg.base_addr, val, DFCCTL);
833
834 /* Defect saturation level */
835 val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK;
836 isif_write(isif->isif_cfg.base_addr, val, VDFSATLV);
837
838 isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert &
839 ISIF_VDFC_POS_MASK, DFCMEM0);
840 isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz &
841 ISIF_VDFC_POS_MASK, DFCMEM1);
842 if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
843 vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
844 isif_write(isif->isif_cfg.base_addr,
845 vdfc->table[0].level_at_pos, DFCMEM2);
846 isif_write(isif->isif_cfg.base_addr,
847 vdfc->table[0].level_up_pixels, DFCMEM3);
848 isif_write(isif->isif_cfg.base_addr,
849 vdfc->table[0].level_low_pixels, DFCMEM4);
850 }
851
852 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
853 /* set DFCMARST and set DFCMWR */
854 val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT;
855 val |= 1;
856 isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
857
858 while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01))
859 count--;
860
861 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
862 if (!count) {
863 pr_debug("defect table write timeout !!\n");
864 return;
865 }
866
867 for (i = 1; i < vdfc->num_vdefects; i++) {
868 isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert &
869 ISIF_VDFC_POS_MASK, DFCMEM0);
870
871 isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz &
872 ISIF_VDFC_POS_MASK, DFCMEM1);
873
874 if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
875 vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
876 isif_write(isif->isif_cfg.base_addr,
877 vdfc->table[i].level_at_pos, DFCMEM2);
878 isif_write(isif->isif_cfg.base_addr,
879 vdfc->table[i].level_up_pixels, DFCMEM3);
880 isif_write(isif->isif_cfg.base_addr,
881 vdfc->table[i].level_low_pixels, DFCMEM4);
882 }
883 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
884 /* clear DFCMARST and set DFCMWR */
885 val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT);
886 val |= 1;
887 isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
888
889 count = DFC_WRITE_WAIT_COUNT;
890 while (count && (isif_read(isif->isif_cfg.base_addr,
891 DFCMEMCTL) & 0x01))
892 count--;
893
894 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
895 if (!count) {
896 pr_debug("defect table write timeout !!\n");
897 return;
898 }
899 }
900 if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) {
901 /* Extra cycle needed */
902 isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0);
903 isif_write(isif->isif_cfg.base_addr,
904 DM365_ISIF_MAX_DFCMEM1, DFCMEM1);
905 isif_write(isif->isif_cfg.base_addr,
906 DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL);
907 }
908 /* enable VDFC */
909 isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
910 (1 << ISIF_VDFC_EN_SHIFT), DFCCTL);
911
912 isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
913 (0 << ISIF_VDFC_EN_SHIFT), DFCCTL);
914
915 isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL);
Lisa Nguyenc3249812013-10-28 18:23:34 -0300916 for (i = 0; i < vdfc->num_vdefects; i++) {
Manjunath Hadli6a630532012-11-28 02:09:35 -0300917 count = DFC_WRITE_WAIT_COUNT;
918 while (count &&
919 (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2))
920 count--;
921 val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
922 if (!count) {
923 pr_debug("defect table write timeout !!\n");
924 return;
925 }
926 isif_write(isif->isif_cfg.base_addr,
927 DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL);
928 }
929}
930
931static void
932isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc)
933{
934 u32 val1;
935 u32 val2;
936 u32 i;
937
938 if (!df_csc->csc.en) {
939 isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
940 return;
941 }
942 /* initialize all bits to 0 */
943 val1 = 0;
944 for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) {
945 if ((i % 2) == 0) {
946 /* CSCM - LSB */
947 val1 = ((df_csc->csc.coeff[i].integer &
948 ISIF_CSC_COEF_INTEG_MASK) <<
949 ISIF_CSC_COEF_INTEG_SHIFT) |
950 ((df_csc->csc.coeff[i].decimal &
951 ISIF_CSC_COEF_DECIMAL_MASK));
952 } else {
953
954 /* CSCM - MSB */
955 val2 = ((df_csc->csc.coeff[i].integer &
956 ISIF_CSC_COEF_INTEG_MASK) <<
957 ISIF_CSC_COEF_INTEG_SHIFT) |
958 ((df_csc->csc.coeff[i].decimal &
959 ISIF_CSC_COEF_DECIMAL_MASK));
960 val2 <<= ISIF_CSCM_MSB_SHIFT;
961 val2 |= val1;
962 isif_write(isif->isif_cfg.base_addr, val2,
963 (CSCM0 + ((i-1) << 1)));
964 }
965 }
966 /* program the active area */
967 isif_write(isif->isif_cfg.base_addr, df_csc->start_pix &
968 ISIF_DF_CSC_SPH_MASK, FMTSPH);
969 /*
970 * one extra pixel as required for CSC. Actually number of
971 * pixel - 1 should be configured in this register. So we
972 * need to subtract 1 before writing to FMTSPH, but we will
973 * not do this since csc requires one extra pixel
974 */
975 isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels &
976 ISIF_DF_CSC_SPH_MASK, FMTLNH);
977 isif_write(isif->isif_cfg.base_addr, df_csc->start_line &
978 ISIF_DF_CSC_SPH_MASK, FMTSLV);
979 /*
980 * one extra line as required for CSC. See reason documented for
981 * num_pixels
982 */
983 isif_write(isif->isif_cfg.base_addr, df_csc->num_lines &
984 ISIF_DF_CSC_SPH_MASK, FMTLNV);
985 /* Enable CSC */
986 isif_write(isif->isif_cfg.base_addr, 1, CSCCTL);
987}
988
989static void
990isif_config_linearization(struct vpfe_isif_device *isif,
991 struct vpfe_isif_linearize *linearize)
992{
993 u32 val;
994 u32 i;
995
996 if (!linearize->en) {
997 isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
998 return;
999 }
1000 /* shift value for correction */
1001 val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) <<
1002 ISIF_LIN_CORRSFT_SHIFT;
1003 /* enable */
1004 val |= 1;
1005 isif_write(isif->isif_cfg.base_addr, val, LINCFG0);
1006 /* Scale factor */
1007 val = (linearize->scale_fact.integer & 1) <<
1008 ISIF_LIN_SCALE_FACT_INTEG_SHIFT;
1009 val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK;
1010 isif_write(isif->isif_cfg.base_addr, val, LINCFG1);
1011
1012 for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) {
1013 val = linearize->table[i] & ISIF_LIN_ENTRY_MASK;
1014 if (i%2)
1015 isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1);
1016 else
1017 isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0);
1018 }
1019}
1020
1021static void
1022isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul)
1023{
1024 u32 val;
1025
1026 /* Horizontal pattern */
1027 val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT;
1028 val |= cul->hcpat_odd;
1029 isif_write(isif->isif_cfg.base_addr, val, CULH);
1030 /* vertical pattern */
1031 isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV);
1032 /* LPF */
1033 isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT,
1034 cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
1035}
1036
1037static int isif_get_pix_fmt(u32 mbus_code)
1038{
1039 switch (mbus_code) {
Boris BREZILLON3336f072014-11-10 14:28:33 -03001040 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
1041 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
1042 case MEDIA_BUS_FMT_SGRBG12_1X12:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001043 return ISIF_PIXFMT_RAW;
1044
Boris BREZILLON3336f072014-11-10 14:28:33 -03001045 case MEDIA_BUS_FMT_YUYV8_2X8:
1046 case MEDIA_BUS_FMT_UYVY8_2X8:
1047 case MEDIA_BUS_FMT_YUYV10_2X10:
1048 case MEDIA_BUS_FMT_Y8_1X8:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001049 return ISIF_PIXFMT_YCBCR_8BIT;
1050
Boris BREZILLON3336f072014-11-10 14:28:33 -03001051 case MEDIA_BUS_FMT_YUYV8_1X16:
1052 case MEDIA_BUS_FMT_YUYV10_1X20:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001053 return ISIF_PIXFMT_YCBCR_16BIT;
1054
1055 default:
1056 break;
1057 }
1058 return -EINVAL;
1059}
1060
1061#define ISIF_INTERLACE_INVERSE_MODE 0x4b6d
1062#define ISIF_INTERLACE_NON_INVERSE_MODE 0x0b6d
1063#define ISIF_PROGRESSIVE_INVERSE_MODE 0x4000
1064#define ISIF_PROGRESSIVE_NON_INVERSE_MODE 0x0000
1065
1066static int isif_config_raw(struct v4l2_subdev *sd, int mode)
1067{
1068 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1069 struct isif_params_raw *params = &isif->isif_cfg.bayer;
1070 struct vpfe_isif_raw_config *module_params =
1071 &isif->isif_cfg.bayer.config_params;
1072 struct v4l2_mbus_framefmt *format;
1073 int pix_fmt;
1074 u32 val;
1075
1076 format = &isif->formats[ISIF_PAD_SINK];
1077
1078 /* In case of user has set BT656IF earlier, it should be reset
1079 * when configuring for raw input.
1080 */
1081 isif_write(isif->isif_cfg.base_addr, 0, REC656IF);
1082 /* Configure CCDCFG register
1083 * Set CCD Not to swap input since input is RAW data
1084 * Set FID detection function to Latch at V-Sync
1085 * Set WENLOG - isif valid area
1086 * Set TRGSEL
1087 * Set EXTRG
1088 * Packed to 8 or 16 bits
1089 */
1090 val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
1091 ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
1092 ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack &
1093 ISIF_DATA_PACK_MASK);
1094 isif_write(isif->isif_cfg.base_addr, val, CCDCFG);
1095
1096 pix_fmt = isif_get_pix_fmt(format->code);
1097 if (pix_fmt < 0) {
1098 pr_debug("Invalid pix_fmt(input mode)\n");
1099 return -EINVAL;
1100 }
1101 /*
1102 * Configure the vertical sync polarity(MODESET.VDPOL)
1103 * Configure the horizontal sync polarity (MODESET.HDPOL)
1104 * Configure frame id polarity (MODESET.FLDPOL)
1105 * Configure data polarity
1106 * Configure External WEN Selection
1107 * Configure frame format(progressive or interlace)
1108 * Configure pixel format (Input mode)
1109 * Configure the data shift
1110 */
1111 val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) <<
1112 ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) <<
1113 ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) <<
1114 ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL &
1115 ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE &
1116 ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt &
1117 ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt &
1118 ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT);
1119
Boris BREZILLON3336f072014-11-10 14:28:33 -03001120 /* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is
Manjunath Hadli6a630532012-11-28 02:09:35 -03001121 * supported. shift appropriately depending on
1122 * different MBUS fmt's added
1123 */
Boris BREZILLON3336f072014-11-10 14:28:33 -03001124 if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001125 val |= ((VPFE_ISIF_NO_SHIFT &
1126 ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT);
1127
1128 isif_write(isif->isif_cfg.base_addr, val, MODESET);
1129 /*
1130 * Configure GAMMAWD register
1131 * CFA pattern setting
1132 */
1133 val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) <<
1134 ISIF_GAMMAWD_CFA_SHIFT;
1135 /* Gamma msb */
1136 if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8)
1137 val = val | ISIF_ALAW_ENABLE;
1138
1139 val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) <<
1140 ISIF_ALAW_GAMA_WD_SHIFT);
1141
1142 isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD);
1143 /* Configure DPCM compression settings */
1144 if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
1145 val = 1 << ISIF_DPCM_EN_SHIFT;
1146 val |= (params->dpcm_predictor &
1147 ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT;
1148 }
1149 isif_write(isif->isif_cfg.base_addr, val, MISC);
1150 /* Configure Gain & Offset */
1151 isif_config_gain_offset(isif);
1152 /* Configure Color pattern */
Boris BREZILLON3336f072014-11-10 14:28:33 -03001153 if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001154 val = isif_sgrbg_pattern;
1155 else
1156 /* default set to rggb */
1157 val = isif_srggb_pattern;
1158
1159 isif_write(isif->isif_cfg.base_addr, val, CCOLP);
1160
1161 /* Configure HSIZE register */
1162 val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) <<
1163 ISIF_HSIZE_FLIP_SHIFT;
1164
1165 /* calculate line offset in 32 bytes based on pack value */
1166 if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT)
1167 val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK;
1168 else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT)
1169 val |= ((((params->win.width + (params->win.width >> 2)) +
1170 31) >> 5) & ISIF_LINEOFST_MASK);
1171 else
1172 val |= (((params->win.width * 2) + 31) >> 5) &
1173 ISIF_LINEOFST_MASK;
1174 isif_write(isif->isif_cfg.base_addr, val, HSIZE);
1175 /* Configure SDOFST register */
1176 if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) {
1177 if (params->image_invert_en)
1178 /* For interlace inverse mode */
1179 isif_write(isif->isif_cfg.base_addr,
1180 ISIF_INTERLACE_INVERSE_MODE, SDOFST);
1181 else
1182 /* For interlace non inverse mode */
1183 isif_write(isif->isif_cfg.base_addr,
1184 ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST);
1185 } else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) {
1186 if (params->image_invert_en)
1187 isif_write(isif->isif_cfg.base_addr,
1188 ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST);
1189 else
1190 /* For progessive non inverse mode */
1191 isif_write(isif->isif_cfg.base_addr,
1192 ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST);
1193 }
1194 /* Configure video window */
1195 isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1196 /* Configure Black Clamp */
1197 isif_config_bclamp(isif, &module_params->bclamp);
1198 /* Configure Vertical Defection Pixel Correction */
1199 isif_config_dfc(isif, &module_params->dfc);
1200 if (!module_params->df_csc.df_or_csc)
1201 /* Configure Color Space Conversion */
1202 isif_config_csc(isif, &module_params->df_csc);
1203
1204 isif_config_linearization(isif, &module_params->linearize);
1205 /* Configure Culling */
1206 isif_config_culling(isif, &module_params->culling);
1207 /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */
1208 val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK;
1209 isif_write(isif->isif_cfg.base_addr, val, DATAHOFST);
1210
1211 val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK;
1212 isif_write(isif->isif_cfg.base_addr, val, DATAVOFST);
1213
1214 return 0;
1215}
1216
1217#define DM365_ISIF_HSIZE_MASK 0xffffffe0
1218#define DM365_ISIF_SDOFST_2_LINES 0x00000249
1219
1220/* This function will configure ISIF for YCbCr parameters. */
1221static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
1222{
1223 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1224 struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr;
1225 struct v4l2_mbus_framefmt *format;
1226 int pix_fmt;
1227 u32 modeset;
1228 u32 ccdcfg;
1229
1230 format = &isif->formats[ISIF_PAD_SINK];
1231 /*
1232 * first reset the ISIF
1233 * all registers have default values after reset
1234 * This is important since we assume default values to be set in
1235 * a lot of registers that we didn't touch
1236 */
1237 /* start with all bits zero */
Bhumika Goyal12f2a7b2016-02-13 11:49:35 +05301238 ccdcfg = 0;
1239 modeset = 0;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001240 pix_fmt = isif_get_pix_fmt(format->code);
1241 if (pix_fmt < 0) {
1242 pr_debug("Invalid pix_fmt(input mode)\n");
1243 return -EINVAL;
1244 }
1245 /* configure pixel format or input mode */
1246 modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) <<
1247 ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) <<
1248 ISIF_FRM_FMT_SHIFT) | (((params->fid_pol &
1249 ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) |
1250 (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) |
1251 (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT));
1252 /* pack the data to 8-bit CCDCCFG */
1253 switch (format->code) {
Boris BREZILLON3336f072014-11-10 14:28:33 -03001254 case MEDIA_BUS_FMT_YUYV8_2X8:
1255 case MEDIA_BUS_FMT_UYVY8_2X8:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001256 if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1257 pr_debug("Invalid pix_fmt(input mode)\n");
1258 return -EINVAL;
1259 }
1260 modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) <<
1261 ISIF_VD_POL_SHIFT);
1262 isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1263 ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR;
1264 break;
1265
Boris BREZILLON3336f072014-11-10 14:28:33 -03001266 case MEDIA_BUS_FMT_YUYV10_2X10:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001267 if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1268 pr_debug("Invalid pix_fmt(input mode)\n");
1269 return -EINVAL;
1270 }
1271 /* setup BT.656, embedded sync */
1272 isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1273 /* enable 10 bit mode in ccdcfg */
1274 ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR |
1275 ISIF_BW656_ENABLE;
1276 break;
1277
Boris BREZILLON3336f072014-11-10 14:28:33 -03001278 case MEDIA_BUS_FMT_YUYV10_1X20:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001279 if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1280 pr_debug("Invalid pix_fmt(input mode)\n");
1281 return -EINVAL;
1282 }
1283 isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1284 break;
1285
Boris BREZILLON3336f072014-11-10 14:28:33 -03001286 case MEDIA_BUS_FMT_Y8_1X8:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001287 ccdcfg |= ISIF_PACK_8BIT;
1288 ccdcfg |= ISIF_YCINSWP_YCBCR;
1289 if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1290 pr_debug("Invalid pix_fmt(input mode)\n");
1291 return -EINVAL;
1292 }
1293 break;
1294
Boris BREZILLON3336f072014-11-10 14:28:33 -03001295 case MEDIA_BUS_FMT_YUYV8_1X16:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001296 if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1297 pr_debug("Invalid pix_fmt(input mode)\n");
1298 return -EINVAL;
1299 }
1300 break;
1301
1302 default:
1303 /* should never come here */
1304 pr_debug("Invalid interface type\n");
1305 return -EINVAL;
1306 }
1307 isif_write(isif->isif_cfg.base_addr, modeset, MODESET);
1308 /* Set up pix order */
1309 ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) <<
1310 ISIF_PIX_ORDER_SHIFT;
1311 isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG);
1312 /* configure video window */
Boris BREZILLON3336f072014-11-10 14:28:33 -03001313 if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 ||
1314 format->code == MEDIA_BUS_FMT_YUYV8_1X16)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001315 isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1316 else
1317 isif_setwin(isif, &params->win, params->frm_fmt, 2, mode);
1318
1319 /*
1320 * configure the horizontal line offset
1321 * this is done by rounding up width to a multiple of 16 pixels
1322 * and multiply by two to account for y:cb:cr 4:2:2 data
1323 */
1324 isif_write(isif->isif_cfg.base_addr,
1325 ((((params->win.width * 2) + 31) &
1326 DM365_ISIF_HSIZE_MASK) >> 5), HSIZE);
1327
1328 /* configure the memory line offset */
1329 if (params->frm_fmt == ISIF_FRMFMT_INTERLACED &&
1330 params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED)
1331 /* two fields are interleaved in memory */
1332 isif_write(isif->isif_cfg.base_addr,
1333 DM365_ISIF_SDOFST_2_LINES, SDOFST);
1334 return 0;
1335}
1336
1337static int isif_configure(struct v4l2_subdev *sd, int mode)
1338{
1339 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1340 struct v4l2_mbus_framefmt *format;
1341
1342 format = &isif->formats[ISIF_PAD_SINK];
1343
1344 switch (format->code) {
Boris BREZILLON3336f072014-11-10 14:28:33 -03001345 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
1346 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
1347 case MEDIA_BUS_FMT_SGRBG12_1X12:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001348 return isif_config_raw(sd, mode);
1349
Boris BREZILLON3336f072014-11-10 14:28:33 -03001350 case MEDIA_BUS_FMT_YUYV8_2X8:
1351 case MEDIA_BUS_FMT_UYVY8_2X8:
1352 case MEDIA_BUS_FMT_YUYV10_2X10:
1353 case MEDIA_BUS_FMT_Y8_1X8:
1354 case MEDIA_BUS_FMT_YUYV8_1X16:
1355 case MEDIA_BUS_FMT_YUYV10_1X20:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001356 return isif_config_ycbcr(sd, mode);
1357
1358 default:
1359 break;
1360 }
1361 return -EINVAL;
1362}
1363
1364/*
1365 * isif_set_stream() - Enable/Disable streaming on the ISIF module
1366 * @sd: VPFE ISIF V4L2 subdevice
1367 * @enable: Enable/disable stream
1368 */
1369static int isif_set_stream(struct v4l2_subdev *sd, int enable)
1370{
1371 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1372 int ret;
1373
1374 if (enable) {
1375 ret = isif_configure(sd,
1376 (isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1);
1377 if (ret)
1378 return ret;
1379 if (isif->output == ISIF_OUTPUT_MEMORY)
1380 isif_enable_output_to_sdram(isif, 1);
1381 isif_enable(isif, 1);
1382 } else {
1383 isif_enable(isif, 0);
1384 isif_enable_output_to_sdram(isif, 0);
1385 }
1386
1387 return 0;
1388}
1389
1390/*
1391 * __isif_get_format() - helper function for getting isif format
1392 * @isif: pointer to isif private structure.
1393 * @pad: pad number.
Hans Verkuilf7234132015-03-04 01:47:54 -08001394 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -03001395 * @which: wanted subdev format.
1396 */
1397static struct v4l2_mbus_framefmt *
Thaissa Falbo8e8919f2016-02-15 04:10:11 -02001398__isif_get_format(struct vpfe_isif_device *isif,
1399 struct v4l2_subdev_pad_config *cfg, unsigned int pad,
1400 enum v4l2_subdev_format_whence which)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001401{
1402 if (which == V4L2_SUBDEV_FORMAT_TRY) {
1403 struct v4l2_subdev_format fmt;
1404
1405 fmt.pad = pad;
1406 fmt.which = which;
1407
Hans Verkuilf7234132015-03-04 01:47:54 -08001408 return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001409 }
1410 return &isif->formats[pad];
1411}
1412
1413/*
Hans Verkuilf7234132015-03-04 01:47:54 -08001414 * isif_set_format() - set format on pad
1415 * @sd : VPFE ISIF device
1416 * @cfg : V4L2 subdev pad config
1417 * @fmt : pointer to v4l2 subdev format structure
1418 *
1419 * Return 0 on success or -EINVAL if format or pad is invalid
1420 */
Manjunath Hadli6a630532012-11-28 02:09:35 -03001421static int
Hans Verkuilf7234132015-03-04 01:47:54 -08001422isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
Manjunath Hadli6a630532012-11-28 02:09:35 -03001423 struct v4l2_subdev_format *fmt)
1424{
1425 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1426 struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1427 struct v4l2_mbus_framefmt *format;
1428
Hans Verkuilf7234132015-03-04 01:47:54 -08001429 format = __isif_get_format(isif, cfg, fmt->pad, fmt->which);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001430 if (format == NULL)
1431 return -EINVAL;
1432
Hans Verkuilf7234132015-03-04 01:47:54 -08001433 isif_try_format(isif, cfg, fmt);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001434 memcpy(format, &fmt->format, sizeof(*format));
1435
1436 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1437 return 0;
1438
1439 if (fmt->pad == ISIF_PAD_SOURCE)
1440 return isif_config_format(vpfe_dev, fmt->pad);
1441
1442 return 0;
1443}
1444
1445/*
1446 * isif_get_format() - Retrieve the video format on a pad
1447 * @sd: VPFE ISIF V4L2 subdevice
Hans Verkuilf7234132015-03-04 01:47:54 -08001448 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -03001449 * @fmt: pointer to v4l2 subdev format structure
1450 *
1451 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
1452 * to the format type.
1453 */
1454static int
Hans Verkuilf7234132015-03-04 01:47:54 -08001455isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
Manjunath Hadli6a630532012-11-28 02:09:35 -03001456 struct v4l2_subdev_format *fmt)
1457{
1458 struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1459 struct v4l2_mbus_framefmt *format;
1460
Hans Verkuilf7234132015-03-04 01:47:54 -08001461 format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001462 if (format == NULL)
1463 return -EINVAL;
1464
1465 memcpy(&fmt->format, format, sizeof(fmt->format));
1466
1467 return 0;
1468}
1469
1470/*
1471 * isif_enum_frame_size() - enum frame sizes on pads
1472 * @sd: VPFE isif V4L2 subdevice
Hans Verkuilf7234132015-03-04 01:47:54 -08001473 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -03001474 * @code: pointer to v4l2_subdev_frame_size_enum structure
1475 */
1476static int
Hans Verkuilf7234132015-03-04 01:47:54 -08001477isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
Manjunath Hadli6a630532012-11-28 02:09:35 -03001478 struct v4l2_subdev_frame_size_enum *fse)
1479{
1480 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1481 struct v4l2_subdev_format format;
1482
1483 if (fse->index != 0)
1484 return -EINVAL;
1485
1486 format.pad = fse->pad;
1487 format.format.code = fse->code;
1488 format.format.width = 1;
1489 format.format.height = 1;
Hans Verkuil5778e742015-03-04 01:47:58 -08001490 format.which = fse->which;
Hans Verkuilf7234132015-03-04 01:47:54 -08001491 isif_try_format(isif, cfg, &format);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001492 fse->min_width = format.format.width;
1493 fse->min_height = format.format.height;
1494
1495 if (format.format.code != fse->code)
1496 return -EINVAL;
1497
1498 format.pad = fse->pad;
1499 format.format.code = fse->code;
1500 format.format.width = -1;
1501 format.format.height = -1;
Hans Verkuil5778e742015-03-04 01:47:58 -08001502 format.which = fse->which;
Hans Verkuilf7234132015-03-04 01:47:54 -08001503 isif_try_format(isif, cfg, &format);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001504 fse->max_width = format.format.width;
1505 fse->max_height = format.format.height;
1506
1507 return 0;
1508}
1509
1510/*
1511 * isif_enum_mbus_code() - enum mbus codes for pads
1512 * @sd: VPFE isif V4L2 subdevice
Hans Verkuilf7234132015-03-04 01:47:54 -08001513 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -03001514 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1515 */
1516static int
Hans Verkuilf7234132015-03-04 01:47:54 -08001517isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
Manjunath Hadli6a630532012-11-28 02:09:35 -03001518 struct v4l2_subdev_mbus_code_enum *code)
1519{
1520 switch (code->pad) {
1521 case ISIF_PAD_SINK:
1522 case ISIF_PAD_SOURCE:
1523 if (code->index >= ARRAY_SIZE(isif_fmts))
1524 return -EINVAL;
1525 code->code = isif_fmts[code->index];
1526 break;
1527
1528 default:
1529 return -EINVAL;
1530 }
1531
1532 return 0;
1533}
1534
1535/*
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001536 * isif_pad_set_selection() - set crop rectangle on pad
Manjunath Hadli6a630532012-11-28 02:09:35 -03001537 * @sd: VPFE isif V4L2 subdevice
Hans Verkuilf7234132015-03-04 01:47:54 -08001538 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -03001539 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1540 *
1541 * Return 0 on success, -EINVAL if pad is invalid
1542 */
1543static int
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001544isif_pad_set_selection(struct v4l2_subdev *sd,
Hans Verkuilf7234132015-03-04 01:47:54 -08001545 struct v4l2_subdev_pad_config *cfg,
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001546 struct v4l2_subdev_selection *sel)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001547{
1548 struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1549 struct v4l2_mbus_framefmt *format;
1550
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001551 /* check whether it's a valid pad and target */
1552 if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001553 return -EINVAL;
1554
Hans Verkuilf7234132015-03-04 01:47:54 -08001555 format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001556 if (format == NULL)
1557 return -EINVAL;
1558
1559 /* check wether crop rect is within limits */
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001560 if (sel->r.top < 0 || sel->r.left < 0 ||
1561 (sel->r.left + sel->r.width >
Manjunath Hadli6a630532012-11-28 02:09:35 -03001562 vpfe_isif->formats[ISIF_PAD_SINK].width) ||
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001563 (sel->r.top + sel->r.height >
Manjunath Hadli6a630532012-11-28 02:09:35 -03001564 vpfe_isif->formats[ISIF_PAD_SINK].height)) {
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001565 sel->r.left = 0;
1566 sel->r.top = 0;
1567 sel->r.width = format->width;
1568 sel->r.height = format->height;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001569 }
Masanari Iida2f9e96c2013-03-26 11:23:28 -03001570 /* adjust the width to 16 pixel boundary */
Janani Ravichandran3a35be22016-02-11 17:52:30 -05001571 sel->r.width = (sel->r.width + 15) & ~0xf;
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001572 vpfe_isif->crop = sel->r;
1573 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
Manjunath Hadli6a630532012-11-28 02:09:35 -03001574 isif_set_image_window(vpfe_isif);
1575 } else {
1576 struct v4l2_rect *rect;
1577
Hans Verkuilf7234132015-03-04 01:47:54 -08001578 rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001579 memcpy(rect, &vpfe_isif->crop, sizeof(*rect));
1580 }
1581 return 0;
1582}
1583
1584/*
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001585 * isif_pad_get_selection() - get crop rectangle on pad
Manjunath Hadli6a630532012-11-28 02:09:35 -03001586 * @sd: VPFE isif V4L2 subdevice
Hans Verkuilf7234132015-03-04 01:47:54 -08001587 * @cfg: V4L2 subdev pad config
Manjunath Hadli6a630532012-11-28 02:09:35 -03001588 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1589 *
1590 * Return 0 on success, -EINVAL if pad is invalid
1591 */
1592static int
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001593isif_pad_get_selection(struct v4l2_subdev *sd,
Hans Verkuilf7234132015-03-04 01:47:54 -08001594 struct v4l2_subdev_pad_config *cfg,
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001595 struct v4l2_subdev_selection *sel)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001596{
1597 struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1598
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001599 /* check whether it's a valid pad and target */
1600 if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
Manjunath Hadli6a630532012-11-28 02:09:35 -03001601 return -EINVAL;
1602
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001603 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
Manjunath Hadli6a630532012-11-28 02:09:35 -03001604 struct v4l2_rect *rect;
anuvazhayilaf3491b2014-10-29 02:34:56 +05301605
Hans Verkuilf7234132015-03-04 01:47:54 -08001606 rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK);
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001607 memcpy(&sel->r, rect, sizeof(*rect));
Manjunath Hadli6a630532012-11-28 02:09:35 -03001608 } else {
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001609 sel->r = vpfe_isif->crop;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001610 }
1611
1612 return 0;
1613}
1614
1615/*
1616 * isif_init_formats() - Initialize formats on all pads
1617 * @sd: VPFE isif V4L2 subdevice
1618 * @fh: V4L2 subdev file handle
1619 *
Hans Verkuilf7234132015-03-04 01:47:54 -08001620 * Initialize all pad formats with default values. Try formats are initialized
1621 * on the file handle.
Manjunath Hadli6a630532012-11-28 02:09:35 -03001622 */
1623static int
1624isif_init_formats(struct v4l2_subdev *sd,
1625 struct v4l2_subdev_fh *fh)
1626{
1627 struct v4l2_subdev_format format;
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001628 struct v4l2_subdev_selection sel;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001629
1630 memset(&format, 0, sizeof(format));
1631 format.pad = ISIF_PAD_SINK;
Hans Verkuilf7234132015-03-04 01:47:54 -08001632 format.which = V4L2_SUBDEV_FORMAT_TRY;
Boris BREZILLON3336f072014-11-10 14:28:33 -03001633 format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001634 format.format.width = MAX_WIDTH;
1635 format.format.height = MAX_HEIGHT;
Hans Verkuilf7234132015-03-04 01:47:54 -08001636 isif_set_format(sd, fh->pad, &format);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001637
1638 memset(&format, 0, sizeof(format));
1639 format.pad = ISIF_PAD_SOURCE;
Hans Verkuilf7234132015-03-04 01:47:54 -08001640 format.which = V4L2_SUBDEV_FORMAT_TRY;
Boris BREZILLON3336f072014-11-10 14:28:33 -03001641 format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001642 format.format.width = MAX_WIDTH;
1643 format.format.height = MAX_HEIGHT;
Hans Verkuilf7234132015-03-04 01:47:54 -08001644 isif_set_format(sd, fh->pad, &format);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001645
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001646 memset(&sel, 0, sizeof(sel));
1647 sel.pad = ISIF_PAD_SINK;
Hans Verkuilf7234132015-03-04 01:47:54 -08001648 sel.which = V4L2_SUBDEV_FORMAT_TRY;
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001649 sel.target = V4L2_SEL_TGT_CROP;
1650 sel.r.width = MAX_WIDTH;
1651 sel.r.height = MAX_HEIGHT;
Hans Verkuilf7234132015-03-04 01:47:54 -08001652 isif_pad_set_selection(sd, fh->pad, &sel);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001653
1654 return 0;
1655}
1656
1657/* subdev core operations */
1658static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = {
1659 .ioctl = isif_ioctl,
1660};
1661
1662/* subdev file operations */
1663static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = {
1664 .open = isif_init_formats,
1665};
1666
1667/* subdev video operations */
1668static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = {
1669 .s_stream = isif_set_stream,
1670};
1671
1672/* subdev pad operations */
1673static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = {
1674 .enum_mbus_code = isif_enum_mbus_code,
1675 .enum_frame_size = isif_enum_frame_size,
1676 .get_fmt = isif_get_format,
1677 .set_fmt = isif_set_format,
Hans Verkuil1a023fe2014-12-04 06:54:52 -03001678 .set_selection = isif_pad_set_selection,
1679 .get_selection = isif_pad_get_selection,
Manjunath Hadli6a630532012-11-28 02:09:35 -03001680};
1681
1682/* subdev operations */
1683static const struct v4l2_subdev_ops isif_v4l2_ops = {
1684 .core = &isif_v4l2_core_ops,
1685 .video = &isif_v4l2_video_ops,
1686 .pad = &isif_v4l2_pad_ops,
1687};
1688
1689/*
1690 * Media entity operations
1691 */
1692
1693/*
1694 * isif_link_setup() - Setup isif connections
1695 * @entity: isif media entity
1696 * @local: Pad at the local end of the link
1697 * @remote: Pad at the remote end of the link
1698 * @flags: Link flags
1699 *
1700 * return -EINVAL or zero on success
1701 */
1702static int
1703isif_link_setup(struct media_entity *entity, const struct media_pad *local,
1704 const struct media_pad *remote, u32 flags)
1705{
1706 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1707 struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
Mauro Carvalho Chehab829de292015-12-11 12:23:23 -02001708 unsigned int index = local->index;
Manjunath Hadli6a630532012-11-28 02:09:35 -03001709
Mauro Carvalho Chehab59ecd592015-05-07 22:12:33 -03001710 /* FIXME: this is actually a hack! */
1711 if (is_media_entity_v4l2_subdev(remote->entity))
1712 index |= 2 << 16;
1713
1714 switch (index) {
1715 case ISIF_PAD_SINK | 2 << 16:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001716 /* read from decoder/sensor */
1717 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1718 isif->input = ISIF_INPUT_NONE;
1719 break;
1720 }
1721 if (isif->input != ISIF_INPUT_NONE)
1722 return -EBUSY;
1723 isif->input = ISIF_INPUT_PARALLEL;
1724 break;
1725
Mauro Carvalho Chehab59ecd592015-05-07 22:12:33 -03001726 case ISIF_PAD_SOURCE:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001727 /* write to memory */
1728 if (flags & MEDIA_LNK_FL_ENABLED)
1729 isif->output = ISIF_OUTPUT_MEMORY;
1730 else
1731 isif->output = ISIF_OUTPUT_NONE;
1732 break;
1733
Mauro Carvalho Chehab59ecd592015-05-07 22:12:33 -03001734 case ISIF_PAD_SOURCE | 2 << 16:
Manjunath Hadli6a630532012-11-28 02:09:35 -03001735 if (flags & MEDIA_LNK_FL_ENABLED)
1736 isif->output = ISIF_OUTPUT_IPIPEIF;
1737 else
1738 isif->output = ISIF_OUTPUT_NONE;
1739 break;
1740
1741 default:
1742 return -EINVAL;
1743 }
1744
1745 return 0;
1746}
1747static const struct media_entity_operations isif_media_ops = {
1748 .link_setup = isif_link_setup,
1749};
1750
1751/*
1752 * vpfe_isif_unregister_entities() - isif unregister entity
1753 * @isif - pointer to isif subdevice structure.
1754 */
1755void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
1756{
1757 vpfe_video_unregister(&isif->video_out);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001758 /* unregister subdev */
1759 v4l2_device_unregister_subdev(&isif->subdev);
Sakari Ailus7bb151b2013-06-11 06:50:49 -03001760 /* cleanup entity */
1761 media_entity_cleanup(&isif->subdev.entity);
Manjunath Hadli6a630532012-11-28 02:09:35 -03001762}
1763
1764static void isif_restore_defaults(struct vpfe_isif_device *isif)
1765{
1766 enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
1767 int i;
1768
1769 memset(&isif->isif_cfg.bayer.config_params, 0,
1770 sizeof(struct vpfe_isif_raw_config));
1771
1772 isif->isif_cfg.bayer.config_params.linearize.corr_shft =
1773 VPFE_ISIF_NO_SHIFT;
1774 isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1;
1775 isif->isif_cfg.bayer.config_params.culling.hcpat_odd =
1776 ISIF_CULLING_HCAPT_ODD;
1777 isif->isif_cfg.bayer.config_params.culling.hcpat_even =
1778 ISIF_CULLING_HCAPT_EVEN;
1779 isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT;
1780 /* Enable clock to ISIF, IPIPEIF and BL */
1781 vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
1782 vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
1783 vpss_enable_clock(VPSS_BL_CLOCK, 1);
1784
1785 /* set all registers to default value */
1786 for (i = 0; i <= 0x1f8; i += 4)
1787 isif_write(isif->isif_cfg.base_addr, 0, i);
1788 /* no culling support */
1789 isif_write(isif->isif_cfg.base_addr, 0xffff, CULH);
1790 isif_write(isif->isif_cfg.base_addr, 0xff, CULV);
1791
1792 /* Set default offset and gain */
1793 isif_config_gain_offset(isif);
1794 vpss_select_ccdc_source(source);
1795}
1796
1797/*
1798 * vpfe_isif_register_entities() - isif register entity
1799 * @isif - pointer to isif subdevice structure.
1800 * @vdev: pointer to v4l2 device structure.
1801 */
1802int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
1803 struct v4l2_device *vdev)
1804{
1805 struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1806 unsigned int flags;
1807 int ret;
1808
1809 /* Register the subdev */
1810 ret = v4l2_device_register_subdev(vdev, &isif->subdev);
1811 if (ret < 0)
1812 return ret;
1813
1814 isif_restore_defaults(isif);
1815 ret = vpfe_video_register(&isif->video_out, vdev);
1816 if (ret) {
1817 pr_err("Failed to register isif video out device\n");
1818 goto out_video_register;
1819 }
1820 isif->video_out.vpfe_dev = vpfe_dev;
1821 flags = 0;
1822 /* connect isif to video node */
Mauro Carvalho Chehab8df00a12015-08-07 08:14:38 -03001823 ret = media_create_pad_link(&isif->subdev.entity, 1,
Manjunath Hadli6a630532012-11-28 02:09:35 -03001824 &isif->video_out.video_dev.entity,
1825 0, flags);
1826 if (ret < 0)
1827 goto out_create_link;
1828 return 0;
1829out_create_link:
1830 vpfe_video_unregister(&isif->video_out);
1831out_video_register:
1832 v4l2_device_unregister_subdev(&isif->subdev);
1833 return ret;
1834}
1835
1836/* -------------------------------------------------------------------
1837 * V4L2 subdev control operations
1838 */
1839
1840static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl)
1841{
1842 struct vpfe_isif_device *isif =
1843 container_of(ctrl->handler, struct vpfe_isif_device, ctrls);
1844 struct isif_oper_config *config = &isif->isif_cfg;
1845
1846 switch (ctrl->id) {
1847 case VPFE_CID_DPCM_PREDICTOR:
1848 config->bayer.dpcm_predictor = ctrl->val;
1849 break;
1850
1851 case VPFE_ISIF_CID_CRGAIN:
1852 config->isif_gain_params.cr_gain = ctrl->val;
1853 break;
1854
1855 case VPFE_ISIF_CID_CGRGAIN:
1856 config->isif_gain_params.cgr_gain = ctrl->val;
1857 break;
1858
1859 case VPFE_ISIF_CID_CGBGAIN:
1860 config->isif_gain_params.cgb_gain = ctrl->val;
1861 break;
1862
1863 case VPFE_ISIF_CID_CBGAIN:
1864 config->isif_gain_params.cb_gain = ctrl->val;
1865 break;
1866
1867 case VPFE_ISIF_CID_GAIN_OFFSET:
1868 config->isif_gain_params.offset = ctrl->val;
1869 break;
1870
1871 default:
1872 return -EINVAL;
1873 }
1874 return 0;
1875}
1876
1877static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = {
1878 .s_ctrl = vpfe_isif_s_ctrl,
1879};
1880
1881static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = {
1882 .ops = &vpfe_isif_ctrl_ops,
1883 .id = VPFE_CID_DPCM_PREDICTOR,
1884 .name = "DPCM Predictor",
1885 .type = V4L2_CTRL_TYPE_INTEGER,
1886 .min = 0,
1887 .max = 1,
1888 .step = 1,
1889 .def = 0,
1890};
1891
1892static const struct v4l2_ctrl_config vpfe_isif_crgain = {
1893 .ops = &vpfe_isif_ctrl_ops,
1894 .id = VPFE_ISIF_CID_CRGAIN,
1895 .name = "CRGAIN",
1896 .type = V4L2_CTRL_TYPE_INTEGER,
1897 .min = 0,
1898 .max = (1 << 12) - 1,
1899 .step = 1,
1900 .def = 0,
1901};
1902
1903static const struct v4l2_ctrl_config vpfe_isif_cgrgain = {
1904 .ops = &vpfe_isif_ctrl_ops,
1905 .id = VPFE_ISIF_CID_CGRGAIN,
1906 .name = "CGRGAIN",
1907 .type = V4L2_CTRL_TYPE_INTEGER,
1908 .min = 0,
1909 .max = (1 << 12) - 1,
1910 .step = 1,
1911 .def = 0,
1912};
1913
1914static const struct v4l2_ctrl_config vpfe_isif_cgbgain = {
1915 .ops = &vpfe_isif_ctrl_ops,
1916 .id = VPFE_ISIF_CID_CGBGAIN,
1917 .name = "CGBGAIN",
1918 .type = V4L2_CTRL_TYPE_INTEGER,
1919 .min = 0,
1920 .max = (1 << 12) - 1,
1921 .step = 1,
1922 .def = 0,
1923};
1924
1925static const struct v4l2_ctrl_config vpfe_isif_cbgain = {
1926 .ops = &vpfe_isif_ctrl_ops,
1927 .id = VPFE_ISIF_CID_CBGAIN,
1928 .name = "CBGAIN",
1929 .type = V4L2_CTRL_TYPE_INTEGER,
1930 .min = 0,
1931 .max = (1 << 12) - 1,
1932 .step = 1,
1933 .def = 0,
1934};
1935
1936static const struct v4l2_ctrl_config vpfe_isif_gain_offset = {
1937 .ops = &vpfe_isif_ctrl_ops,
1938 .id = VPFE_ISIF_CID_GAIN_OFFSET,
1939 .name = "Gain Offset",
1940 .type = V4L2_CTRL_TYPE_INTEGER,
1941 .min = 0,
1942 .max = (1 << 12) - 1,
1943 .step = 1,
1944 .def = 0,
1945};
1946
1947static void isif_remove(struct vpfe_isif_device *isif,
1948 struct platform_device *pdev)
1949{
1950 struct resource *res;
1951 int i = 0;
1952
1953 iounmap(isif->isif_cfg.base_addr);
1954 iounmap(isif->isif_cfg.linear_tbl0_addr);
1955 iounmap(isif->isif_cfg.linear_tbl1_addr);
1956
1957 while (i < 3) {
1958 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1959 if (res)
1960 release_mem_region(res->start,
Silviu-Mihai Popescu69aa6f42013-03-18 15:06:20 -03001961 resource_size(res));
Manjunath Hadli6a630532012-11-28 02:09:35 -03001962 i++;
1963 }
1964}
1965
1966static void isif_config_defaults(struct vpfe_isif_device *isif)
1967{
1968 isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY;
1969 isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT;
1970 isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED;
1971 isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE;
1972 isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE;
1973 isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE;
1974 isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
1975 isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED;
1976
1977 isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8;
1978 isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
1979 isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
1980 isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE;
1981 isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE;
1982 isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE;
1983 isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC;
1984 isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11;
1985 isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
1986}
1987/*
1988 * vpfe_isif_init() - Initialize V4L2 subdev and media entity
1989 * @isif: VPFE isif module
1990 * @pdev: Pointer to platform device structure.
1991 * Return 0 on success and a negative error code on failure.
1992 */
1993int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
1994{
1995 struct v4l2_subdev *sd = &isif->subdev;
1996 struct media_pad *pads = &isif->pads[0];
1997 struct media_entity *me = &sd->entity;
1998 static resource_size_t res_len;
1999 struct resource *res;
Tapasweni Pathak2129e172014-10-08 09:12:17 +05302000 void __iomem *addr;
Manjunath Hadli6a630532012-11-28 02:09:35 -03002001 int status;
2002 int i = 0;
2003
2004 /* Get the ISIF base address, linearization table0 and table1 addr. */
2005 while (i < 3) {
2006 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2007 if (!res) {
2008 status = -ENOENT;
2009 goto fail_nobase_res;
2010 }
Silviu-Mihai Popescu69aa6f42013-03-18 15:06:20 -03002011 res_len = resource_size(res);
Manjunath Hadli6a630532012-11-28 02:09:35 -03002012 res = request_mem_region(res->start, res_len, res->name);
2013 if (!res) {
2014 status = -EBUSY;
2015 goto fail_nobase_res;
2016 }
2017 addr = ioremap_nocache(res->start, res_len);
2018 if (!addr) {
2019 status = -EBUSY;
2020 goto fail_base_iomap;
2021 }
2022 switch (i) {
2023 case 0:
2024 /* ISIF base address */
2025 isif->isif_cfg.base_addr = addr;
2026 break;
2027 case 1:
2028 /* ISIF linear tbl0 address */
2029 isif->isif_cfg.linear_tbl0_addr = addr;
2030 break;
2031 default:
2032 /* ISIF linear tbl0 address */
2033 isif->isif_cfg.linear_tbl1_addr = addr;
2034 break;
2035 }
2036 i++;
2037 }
2038 davinci_cfg_reg(DM365_VIN_CAM_WEN);
2039 davinci_cfg_reg(DM365_VIN_CAM_VD);
2040 davinci_cfg_reg(DM365_VIN_CAM_HD);
2041 davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
2042 davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
2043
2044 /* queue ops */
2045 isif->video_out.ops = &isif_video_ops;
2046 v4l2_subdev_init(sd, &isif_v4l2_ops);
2047 sd->internal_ops = &isif_v4l2_internal_ops;
2048 strlcpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
2049 sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
2050 v4l2_set_subdevdata(sd, isif);
2051 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
2052 pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2053 pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
2054
2055 isif->input = ISIF_INPUT_NONE;
2056 isif->output = ISIF_OUTPUT_NONE;
2057 me->ops = &isif_media_ops;
Mauro Carvalho Chehabab22e772015-12-11 07:44:40 -02002058 status = media_entity_pads_init(me, ISIF_PADS_NUM, pads);
Manjunath Hadli6a630532012-11-28 02:09:35 -03002059 if (status)
2060 goto isif_fail;
2061 isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2062 status = vpfe_video_init(&isif->video_out, "ISIF");
2063 if (status) {
2064 pr_err("Failed to init isif-out video device\n");
2065 goto isif_fail;
2066 }
2067 v4l2_ctrl_handler_init(&isif->ctrls, 6);
2068 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL);
2069 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL);
2070 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL);
2071 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL);
2072 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL);
2073 v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL);
2074
2075 v4l2_ctrl_handler_setup(&isif->ctrls);
2076 sd->ctrl_handler = &isif->ctrls;
2077 isif_config_defaults(isif);
2078 return 0;
2079fail_base_iomap:
2080 release_mem_region(res->start, res_len);
2081 i--;
2082fail_nobase_res:
2083 if (isif->isif_cfg.base_addr)
2084 iounmap(isif->isif_cfg.base_addr);
2085 if (isif->isif_cfg.linear_tbl0_addr)
2086 iounmap(isif->isif_cfg.linear_tbl0_addr);
2087
2088 while (i >= 0) {
2089 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2090 release_mem_region(res->start, res_len);
2091 i--;
2092 }
2093 return status;
2094isif_fail:
2095 v4l2_ctrl_handler_free(&isif->ctrls);
2096 isif_remove(isif, pdev);
2097 return status;
2098}
2099
2100/*
2101 * vpfe_isif_cleanup - isif module cleanup
2102 * @isif: pointer to isif subdevice
2103 * @dev: pointer to platform device structure
2104 */
2105void
2106vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev)
2107{
2108 isif_remove(isif, pdev);
2109}