2 * Copyright (C) 2012 Texas Instruments Inc
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.
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.
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
18 * Manjunath Hadli <manjunath.hadli@ti.com>
19 * Prabhakar Lad <prabhakar.lad@ti.com>
22 #include "dm365_ipipeif.h"
23 #include "vpfe_mc_capture.h"
25 static const unsigned int ipipeif_input_fmts[] = {
26 V4L2_MBUS_FMT_UYVY8_2X8,
27 V4L2_MBUS_FMT_SGRBG12_1X12,
29 V4L2_MBUS_FMT_UV8_1X8,
30 V4L2_MBUS_FMT_YDYUYDYV8_1X16,
31 V4L2_MBUS_FMT_SBGGR8_1X8,
34 static const unsigned int ipipeif_output_fmts[] = {
35 V4L2_MBUS_FMT_UYVY8_2X8,
36 V4L2_MBUS_FMT_SGRBG12_1X12,
38 V4L2_MBUS_FMT_UV8_1X8,
39 V4L2_MBUS_FMT_YDYUYDYV8_1X16,
40 V4L2_MBUS_FMT_SBGGR8_1X8,
41 V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
42 V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
46 ipipeif_get_pack_mode(enum v4l2_mbus_pixelcode in_pix_fmt)
49 case V4L2_MBUS_FMT_SBGGR8_1X8:
50 case V4L2_MBUS_FMT_Y8_1X8:
51 case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
52 case V4L2_MBUS_FMT_UV8_1X8:
53 return IPIPEIF_5_1_PACK_8_BIT;
55 case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
56 return IPIPEIF_5_1_PACK_8_BIT_A_LAW;
58 case V4L2_MBUS_FMT_SGRBG12_1X12:
59 return IPIPEIF_5_1_PACK_16_BIT;
61 case V4L2_MBUS_FMT_SBGGR12_1X12:
62 return IPIPEIF_5_1_PACK_12_BIT;
65 return IPIPEIF_5_1_PACK_16_BIT;
69 static inline u32 ipipeif_read(void *addr, u32 offset)
71 return readl(addr + offset);
74 static inline void ipipeif_write(u32 val, void *addr, u32 offset)
76 writel(val, addr + offset);
79 static void ipipeif_config_dpc(void *addr, struct ipipeif_dpc *dpc)
84 val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT;
85 val |= dpc->thr & IPIPEIF_DPC2_THR_MASK;
87 ipipeif_write(val, addr, IPIPEIF_DPC2);
90 #define IPIPEIF_MODE_CONTINUOUS 0
91 #define IPIPEIF_MODE_ONE_SHOT 1
93 static int get_oneshot_mode(enum ipipeif_input_entity input)
95 if (input == IPIPEIF_INPUT_MEMORY)
96 return IPIPEIF_MODE_ONE_SHOT;
97 else if (input == IPIPEIF_INPUT_ISIF)
98 return IPIPEIF_MODE_CONTINUOUS;
104 ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif)
106 struct v4l2_mbus_framefmt *informat;
108 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
109 if (ipipeif->input == IPIPEIF_INPUT_MEMORY &&
110 (informat->code == V4L2_MBUS_FMT_Y8_1X8 ||
111 informat->code == V4L2_MBUS_FMT_UV8_1X8))
114 return IPIPEIF_SRC1_PARALLEL_PORT;
118 ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif)
120 struct v4l2_mbus_framefmt *informat;
122 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
124 switch (informat->code) {
125 case V4L2_MBUS_FMT_SGRBG12_1X12:
126 return IPIPEIF_5_1_BITS11_0;
128 case V4L2_MBUS_FMT_Y8_1X8:
129 case V4L2_MBUS_FMT_UV8_1X8:
130 return IPIPEIF_5_1_BITS11_0;
133 return IPIPEIF_5_1_BITS7_0;
137 static enum ipipeif_input_source
138 ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif)
140 struct v4l2_mbus_framefmt *informat;
142 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
143 if (ipipeif->input == IPIPEIF_INPUT_ISIF)
146 if (informat->code == V4L2_MBUS_FMT_UYVY8_2X8)
147 return IPIPEIF_SDRAM_YUV;
149 return IPIPEIF_SDRAM_RAW;
152 void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif)
154 struct vpfe_video_device *video_in = &ipipeif->video_in;
156 if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
159 spin_lock(&video_in->dma_queue_lock);
160 vpfe_video_process_buffer_complete(video_in);
161 video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
162 vpfe_video_schedule_next_buffer(video_in);
163 spin_unlock(&video_in->dma_queue_lock);
166 int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev)
168 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
170 return ipipeif->config.decimation;
173 int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev)
175 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
177 return ipipeif->config.rsz;
180 #define RD_DATA_15_2 0x7
183 * ipipeif_hw_setup() - This function sets up IPIPEIF
184 * @sd: pointer to v4l2 subdev structure
185 * return -EINVAL or zero on success
187 static int ipipeif_hw_setup(struct v4l2_subdev *sd)
189 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
190 struct v4l2_mbus_framefmt *informat, *outformat;
191 struct ipipeif_params params = ipipeif->config;
192 enum ipipeif_input_source ipipeif_source;
193 enum v4l2_mbus_pixelcode isif_port_if;
194 void *ipipeif_base_addr;
200 ipipeif_base_addr = ipipeif->ipipeif_base_addr;
202 /* Enable clock to IPIPEIF and IPIPE */
203 vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
205 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
206 outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE];
208 /* Combine all the fields to make CFG1 register of IPIPEIF */
209 val = get_oneshot_mode(ipipeif->input);
211 pr_err("ipipeif: links setup required");
214 val = val << ONESHOT_SHIFT;
216 ipipeif_source = ipipeif_get_source(ipipeif);
217 val |= ipipeif_source << INPSRC_SHIFT;
219 val |= params.clock_select << CLKSEL_SHIFT;
220 val |= params.avg_filter << AVGFILT_SHIFT;
221 val |= params.decimation << DECIM_SHIFT;
223 pack_mode = ipipeif_get_pack_mode(informat->code);
224 val |= pack_mode << PACK8IN_SHIFT;
226 source1 = ipipeif_get_cfg_src1(ipipeif);
227 val |= source1 << INPSRC1_SHIFT;
229 data_shift = ipipeif_get_data_shift(ipipeif);
230 if (ipipeif_source != IPIPEIF_SDRAM_YUV)
231 val |= data_shift << DATASFT_SHIFT;
233 val &= ~(RD_DATA_15_2 << DATASFT_SHIFT);
235 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1);
237 switch (ipipeif_source) {
239 ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
242 case IPIPEIF_SDRAM_RAW:
243 case IPIPEIF_CCDC_DARKFM:
244 ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
246 case IPIPEIF_SDRAM_YUV:
247 val |= data_shift << DATASFT_SHIFT;
248 ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN);
249 ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR);
250 ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM);
251 ipipeif_write(informat->height,
252 ipipeif_base_addr, IPIPEIF_VNUM);
259 /*check if decimation is enable or not */
260 if (params.decimation)
261 ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ);
263 /* Setup sync alignment and initial rsz position */
264 val = params.if_5_1.align_sync & 1;
265 val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT;
266 val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK;
267 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ);
268 isif_port_if = informat->code;
270 if (isif_port_if == V4L2_MBUS_FMT_Y8_1X8)
271 isif_port_if = V4L2_MBUS_FMT_YUYV8_1X16;
272 else if (isif_port_if == V4L2_MBUS_FMT_UV8_1X8)
273 isif_port_if = V4L2_MBUS_FMT_SGRBG12_1X12;
275 /* Enable DPCM decompression */
276 switch (ipipeif_source) {
277 case IPIPEIF_SDRAM_RAW:
279 if (outformat->code == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) {
281 val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) <<
282 IPIPEIF_DPCM_BITS_SHIFT;
283 val |= (ipipeif->dpcm_predictor & 1) <<
284 IPIPEIF_DPCM_PRED_SHIFT;
286 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM);
289 ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc);
291 ipipeif_write(params.if_5_1.clip,
292 ipipeif_base_addr, IPIPEIF_OCLIP);
294 /* fall through for SDRAM YUV mode */
296 val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2);
297 switch (isif_port_if) {
298 case V4L2_MBUS_FMT_YUYV8_1X16:
299 case V4L2_MBUS_FMT_UYVY8_2X8:
300 case V4L2_MBUS_FMT_Y8_1X8:
301 RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
302 SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
303 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
307 RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
308 RESETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
309 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
313 case IPIPEIF_SDRAM_YUV:
314 /* Set clock divider */
315 if (params.clock_select == IPIPEIF_SDRAM_CLK) {
316 val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV);
317 val |= (params.if_5_1.clk_div.m - 1) <<
318 IPIPEIF_CLKDIV_M_SHIFT;
319 val |= (params.if_5_1.clk_div.n - 1);
320 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV);
325 case IPIPEIF_CCDC_DARKFM:
327 ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc);
329 /* Set DF gain & threshold control */
331 if (params.if_5_1.df_gain_en) {
332 val = params.if_5_1.df_gain_thr &
333 IPIPEIF_DF_GAIN_THR_MASK;
334 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH);
335 val = (params.if_5_1.df_gain_en & 1) <<
336 IPIPEIF_DF_GAIN_EN_SHIFT;
337 val |= params.if_5_1.df_gain &
338 IPIPEIF_DF_GAIN_MASK;
340 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL);
342 val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT;
343 val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT;
345 switch (isif_port_if) {
346 case V4L2_MBUS_FMT_YUYV8_1X16:
347 case V4L2_MBUS_FMT_YUYV10_1X20:
348 RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
349 SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
352 case V4L2_MBUS_FMT_YUYV8_2X8:
353 case V4L2_MBUS_FMT_UYVY8_2X8:
354 case V4L2_MBUS_FMT_Y8_1X8:
355 case V4L2_MBUS_FMT_YUYV10_2X10:
356 SETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
357 SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
358 val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT;
363 ipipeif_write(params.if_5_1.clip, ipipeif_base_addr,
366 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
377 ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config)
379 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
380 struct device *dev = ipipeif->subdev.v4l2_dev->dev;
383 dev_err(dev, "Invalid configuration pointer\n");
387 ipipeif->config.clock_select = config->clock_select;
388 ipipeif->config.ppln = config->ppln;
389 ipipeif->config.lpfr = config->lpfr;
390 ipipeif->config.rsz = config->rsz;
391 ipipeif->config.decimation = config->decimation;
392 if (ipipeif->config.decimation &&
393 (ipipeif->config.rsz < IPIPEIF_RSZ_MIN ||
394 ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) {
395 dev_err(dev, "rsz range is %d to %d\n",
396 IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
400 ipipeif->config.avg_filter = config->avg_filter;
402 ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr;
403 ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain;
404 ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en;
406 ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start;
407 ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync;
408 ipipeif->config.if_5_1.clip = config->if_5_1.clip;
410 ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en;
411 ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr;
413 ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m;
414 ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n;
420 ipipeif_get_config(struct v4l2_subdev *sd, void __user *arg)
422 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
423 struct ipipeif_params *config = (struct ipipeif_params *)arg;
424 struct device *dev = ipipeif->subdev.v4l2_dev->dev;
427 dev_err(dev, "Invalid configuration pointer\n");
431 config->clock_select = ipipeif->config.clock_select;
432 config->ppln = ipipeif->config.ppln;
433 config->lpfr = ipipeif->config.lpfr;
434 config->rsz = ipipeif->config.rsz;
435 config->decimation = ipipeif->config.decimation;
436 config->avg_filter = ipipeif->config.avg_filter;
438 config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr;
439 config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain;
440 config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en;
442 config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start;
443 config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync;
444 config->if_5_1.clip = ipipeif->config.if_5_1.clip;
446 config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en;
447 config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr;
449 config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m;
450 config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n;
456 * ipipeif_ioctl() - Handle ipipeif module private ioctl's
457 * @sd: pointer to v4l2 subdev structure
458 * @cmd: configuration command
459 * @arg: configuration argument
461 static long ipipeif_ioctl(struct v4l2_subdev *sd,
462 unsigned int cmd, void *arg)
464 struct ipipeif_params *config = (struct ipipeif_params *)arg;
465 int ret = -ENOIOCTLCMD;
468 case VIDIOC_VPFE_IPIPEIF_S_CONFIG:
469 ret = ipipeif_set_config(sd, config);
472 case VIDIOC_VPFE_IPIPEIF_G_CONFIG:
473 ret = ipipeif_get_config(sd, arg);
480 * ipipeif_s_ctrl() - Handle set control subdev method
481 * @ctrl: pointer to v4l2 control structure
483 static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl)
485 struct vpfe_ipipeif_device *ipipeif =
486 container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls);
489 case VPFE_CID_DPCM_PREDICTOR:
490 ipipeif->dpcm_predictor = ctrl->val;
494 ipipeif->gain = ctrl->val;
504 #define ENABLE_IPIPEIF 0x1
506 void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev)
508 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
509 void *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
512 if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
516 val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE);
519 ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE);
523 * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev
524 * @sd: pointer to v4l2 subdev structure
525 * @enable: 1 == Enable, 0 == Disable
527 static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
529 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
530 struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
536 ret = ipipeif_hw_setup(sd);
538 vpfe_ipipeif_enable(vpfe_dev);
544 * ipipeif_enum_mbus_code() - Handle pixel format enumeration
545 * @sd: pointer to v4l2 subdev structure
546 * @fh: V4L2 subdev file handle
547 * @code: pointer to v4l2_subdev_mbus_code_enum structure
548 * return -EINVAL or zero on success
550 static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
551 struct v4l2_subdev_fh *fh,
552 struct v4l2_subdev_mbus_code_enum *code)
555 case IPIPEIF_PAD_SINK:
556 if (code->index >= ARRAY_SIZE(ipipeif_input_fmts))
559 code->code = ipipeif_input_fmts[code->index];
562 case IPIPEIF_PAD_SOURCE:
563 if (code->index >= ARRAY_SIZE(ipipeif_output_fmts))
566 code->code = ipipeif_output_fmts[code->index];
577 * ipipeif_get_format() - Handle get format by pads subdev method
578 * @sd: pointer to v4l2 subdev structure
579 * @fh: V4L2 subdev file handle
580 * @fmt: pointer to v4l2 subdev format structure
583 ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
584 struct v4l2_subdev_format *fmt)
586 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
588 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
589 fmt->format = ipipeif->formats[fmt->pad];
591 fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad));
596 #define MIN_OUT_WIDTH 32
597 #define MIN_OUT_HEIGHT 32
600 * ipipeif_try_format() - Handle try format by pad subdev method
601 * @ipipeif: VPFE ipipeif device.
602 * @fh: V4L2 subdev file handle.
604 * @fmt: pointer to v4l2 format structure.
605 * @which : wanted subdev format
608 ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
609 struct v4l2_subdev_fh *fh, unsigned int pad,
610 struct v4l2_mbus_framefmt *fmt,
611 enum v4l2_subdev_format_whence which)
613 unsigned int max_out_height;
614 unsigned int max_out_width;
617 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
618 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
620 if (pad == IPIPEIF_PAD_SINK) {
621 for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++)
622 if (fmt->code == ipipeif_input_fmts[i])
625 /* If not found, use SBGGR10 as default */
626 if (i >= ARRAY_SIZE(ipipeif_input_fmts))
627 fmt->code = V4L2_MBUS_FMT_SGRBG12_1X12;
628 } else if (pad == IPIPEIF_PAD_SOURCE) {
629 for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++)
630 if (fmt->code == ipipeif_output_fmts[i])
633 /* If not found, use UYVY as default */
634 if (i >= ARRAY_SIZE(ipipeif_output_fmts))
635 fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
638 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
639 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
643 ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
644 struct v4l2_subdev_frame_size_enum *fse)
646 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
647 struct v4l2_mbus_framefmt format;
652 format.code = fse->code;
655 ipipeif_try_format(ipipeif, fh, fse->pad, &format,
656 V4L2_SUBDEV_FORMAT_TRY);
657 fse->min_width = format.width;
658 fse->min_height = format.height;
660 if (format.code != fse->code)
663 format.code = fse->code;
666 ipipeif_try_format(ipipeif, fh, fse->pad, &format,
667 V4L2_SUBDEV_FORMAT_TRY);
668 fse->max_width = format.width;
669 fse->max_height = format.height;
675 * __ipipeif_get_format() - helper function for getting ipipeif format
676 * @ipipeif: pointer to ipipeif private structure.
678 * @fh: V4L2 subdev file handle.
679 * @which: wanted subdev format.
682 static struct v4l2_mbus_framefmt *
683 __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif,
684 struct v4l2_subdev_fh *fh, unsigned int pad,
685 enum v4l2_subdev_format_whence which)
687 if (which == V4L2_SUBDEV_FORMAT_TRY)
688 return v4l2_subdev_get_try_format(fh, pad);
690 return &ipipeif->formats[pad];
694 * ipipeif_set_format() - Handle set format by pads subdev method
695 * @sd: pointer to v4l2 subdev structure
696 * @fh: V4L2 subdev file handle
697 * @fmt: pointer to v4l2 subdev format structure
698 * return -EINVAL or zero on success
701 ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
702 struct v4l2_subdev_format *fmt)
704 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
705 struct v4l2_mbus_framefmt *format;
707 format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which);
711 ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which);
712 *format = fmt->format;
714 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
717 if (fmt->pad == IPIPEIF_PAD_SINK &&
718 ipipeif->input != IPIPEIF_INPUT_NONE)
719 ipipeif->formats[fmt->pad] = fmt->format;
720 else if (fmt->pad == IPIPEIF_PAD_SOURCE &&
721 ipipeif->output != IPIPEIF_OUTPUT_NONE)
722 ipipeif->formats[fmt->pad] = fmt->format;
729 static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif)
734 const struct ipipeif_params ipipeif_defaults = {
735 .clock_select = IPIPEIF_SDRAM_CLK,
737 .lpfr = HEIGHT_I + 10,
738 .rsz = 16, /* resize ratio 16/rsz */
739 .decimation = IPIPEIF_DECIMATION_OFF,
740 .avg_filter = IPIPEIF_AVG_OFF,
743 .m = 1, /* clock = sdram clock * (m/n) */
749 memset(&ipipeif->config, 0, sizeof(struct ipipeif_params));
750 memcpy(&ipipeif->config, &ipipeif_defaults,
751 sizeof(struct ipipeif_params));
755 * ipipeif_init_formats() - Initialize formats on all pads
756 * @sd: VPFE ipipeif V4L2 subdevice
757 * @fh: V4L2 subdev file handle
759 * Initialize all pad formats with default values. If fh is not NULL, try
760 * formats are initialized on the file handle. Otherwise active formats are
761 * initialized on the device.
764 ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
766 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
767 struct v4l2_subdev_format format;
769 memset(&format, 0, sizeof(format));
770 format.pad = IPIPEIF_PAD_SINK;
771 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
772 format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
773 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
774 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
775 ipipeif_set_format(sd, fh, &format);
777 memset(&format, 0, sizeof(format));
778 format.pad = IPIPEIF_PAD_SOURCE;
779 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
780 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
781 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
782 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
783 ipipeif_set_format(sd, fh, &format);
785 ipipeif_set_default_config(ipipeif);
791 * ipipeif_video_in_queue() - ipipeif video in queue
792 * @vpfe_dev: vpfe device pointer
793 * @addr: buffer address
796 ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
798 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
799 void *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
803 if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
806 switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) {
807 case V4L2_MBUS_FMT_Y8_1X8:
808 case V4L2_MBUS_FMT_UV8_1X8:
809 case V4L2_MBUS_FMT_YDYUYDYV8_1X16:
810 adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width;
814 adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1;
818 /* adjust the line len to be a multiple of 32 */
821 val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK;
822 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS);
824 /* lower sixteen bit */
825 val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK;
826 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL);
828 /* upper next seven bit */
829 val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK;
830 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU);
835 /* subdev core operations */
836 static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = {
837 .ioctl = ipipeif_ioctl,
840 static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = {
841 .s_ctrl = ipipeif_s_ctrl,
844 static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = {
845 .ops = &ipipeif_ctrl_ops,
846 .id = VPFE_CID_DPCM_PREDICTOR,
847 .name = "DPCM Predictor",
848 .type = V4L2_CTRL_TYPE_INTEGER,
855 /* subdev file operations */
856 static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = {
857 .open = ipipeif_init_formats,
860 /* subdev video operations */
861 static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = {
862 .s_stream = ipipeif_set_stream,
865 /* subdev pad operations */
866 static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = {
867 .enum_mbus_code = ipipeif_enum_mbus_code,
868 .enum_frame_size = ipipeif_enum_frame_size,
869 .get_fmt = ipipeif_get_format,
870 .set_fmt = ipipeif_set_format,
873 /* subdev operations */
874 static const struct v4l2_subdev_ops ipipeif_v4l2_ops = {
875 .core = &ipipeif_v4l2_core_ops,
876 .video = &ipipeif_v4l2_video_ops,
877 .pad = &ipipeif_v4l2_pad_ops,
880 static const struct vpfe_video_operations video_in_ops = {
881 .queue = ipipeif_video_in_queue,
885 ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
886 const struct media_pad *remote, u32 flags)
888 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
889 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
890 struct vpfe_device *vpfe = to_vpfe_device(ipipeif);
892 switch (local->index | media_entity_type(remote->entity)) {
893 case IPIPEIF_PAD_SINK | MEDIA_ENT_T_DEVNODE:
894 /* Single shot mode */
895 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
896 ipipeif->input = IPIPEIF_INPUT_NONE;
899 ipipeif->input = IPIPEIF_INPUT_MEMORY;
902 case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
904 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
905 ipipeif->input = IPIPEIF_INPUT_NONE;
908 if (ipipeif->input != IPIPEIF_INPUT_NONE)
911 ipipeif->input = IPIPEIF_INPUT_ISIF;
914 case IPIPEIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
915 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
916 ipipeif->output = IPIPEIF_OUTPUT_NONE;
919 if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity)
920 /* connencted to ipipe */
921 ipipeif->output = IPIPEIF_OUTPUT_IPIPE;
922 else if (remote->entity == &vpfe->vpfe_resizer.
923 crop_resizer.subdev.entity)
924 /* connected to resizer */
925 ipipeif->output = IPIPEIF_OUTPUT_RESIZER;
937 static const struct media_entity_operations ipipeif_media_ops = {
938 .link_setup = ipipeif_link_setup,
942 * vpfe_ipipeif_unregister_entities() - Unregister entity
943 * @ipipeif - pointer to ipipeif subdevice structure.
945 void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif)
947 /* unregister video device */
948 vpfe_video_unregister(&ipipeif->video_in);
950 /* unregister subdev */
951 v4l2_device_unregister_subdev(&ipipeif->subdev);
953 media_entity_cleanup(&ipipeif->subdev.entity);
957 vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif,
958 struct v4l2_device *vdev)
960 struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
964 /* Register the subdev */
965 ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev);
969 ret = vpfe_video_register(&ipipeif->video_in, vdev);
971 pr_err("Failed to register ipipeif video-in device\n");
974 ipipeif->video_in.vpfe_dev = vpfe_dev;
977 ret = media_entity_create_link(&ipipeif->video_in.video_dev.entity, 0,
978 &ipipeif->subdev.entity, 0, flags);
984 v4l2_device_unregister_subdev(&ipipeif->subdev);
989 #define IPIPEIF_GAIN_HIGH 0x3ff
990 #define IPIPEIF_DEFAULT_GAIN 0x200
992 int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
993 struct platform_device *pdev)
995 struct v4l2_subdev *sd = &ipipeif->subdev;
996 struct media_pad *pads = &ipipeif->pads[0];
997 struct media_entity *me = &sd->entity;
998 static resource_size_t res_len;
999 struct resource *res;
1002 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1006 res_len = resource_size(res);
1007 res = request_mem_region(res->start, res_len, res->name);
1011 ipipeif->ipipeif_base_addr = ioremap_nocache(res->start, res_len);
1012 if (!ipipeif->ipipeif_base_addr) {
1017 v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
1019 sd->internal_ops = &ipipeif_v4l2_internal_ops;
1020 strlcpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name));
1021 sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
1023 v4l2_set_subdevdata(sd, ipipeif);
1025 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1026 pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1027 pads[IPIPEIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1028 ipipeif->input = IPIPEIF_INPUT_NONE;
1029 ipipeif->output = IPIPEIF_OUTPUT_NONE;
1030 me->ops = &ipipeif_media_ops;
1032 ret = media_entity_init(me, IPIPEIF_NUM_PADS, pads, 0);
1036 v4l2_ctrl_handler_init(&ipipeif->ctrls, 2);
1037 v4l2_ctrl_new_std(&ipipeif->ctrls, &ipipeif_ctrl_ops,
1039 IPIPEIF_GAIN_HIGH, 1, IPIPEIF_DEFAULT_GAIN);
1040 v4l2_ctrl_new_custom(&ipipeif->ctrls, &vpfe_ipipeif_dpcm_pred, NULL);
1041 v4l2_ctrl_handler_setup(&ipipeif->ctrls);
1042 sd->ctrl_handler = &ipipeif->ctrls;
1044 ipipeif->video_in.ops = &video_in_ops;
1045 ipipeif->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1046 ret = vpfe_video_init(&ipipeif->video_in, "IPIPEIF");
1048 pr_err("Failed to init IPIPEIF video-in device\n");
1051 ipipeif_set_default_config(ipipeif);
1054 release_mem_region(res->start, res_len);
1059 vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif,
1060 struct platform_device *pdev)
1062 struct resource *res;
1064 v4l2_ctrl_handler_free(&ipipeif->ctrls);
1065 iounmap(ipipeif->ipipeif_base_addr);
1066 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1068 release_mem_region(res->start, resource_size(res));