1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2012 Texas Instruments Inc
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation version 2.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 * Manjunath Hadli <manjunath.hadli@ti.com>
16 * Prabhakar Lad <prabhakar.lad@ti.com>
19 #include "dm365_ipipeif.h"
20 #include "vpfe_mc_capture.h"
22 static const unsigned int ipipeif_input_fmts[] = {
23 MEDIA_BUS_FMT_UYVY8_2X8,
24 MEDIA_BUS_FMT_SGRBG12_1X12,
26 MEDIA_BUS_FMT_UV8_1X8,
27 MEDIA_BUS_FMT_YDYUYDYV8_1X16,
28 MEDIA_BUS_FMT_SBGGR8_1X8,
31 static const unsigned int ipipeif_output_fmts[] = {
32 MEDIA_BUS_FMT_UYVY8_2X8,
33 MEDIA_BUS_FMT_SGRBG12_1X12,
35 MEDIA_BUS_FMT_UV8_1X8,
36 MEDIA_BUS_FMT_YDYUYDYV8_1X16,
37 MEDIA_BUS_FMT_SBGGR8_1X8,
38 MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
39 MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
43 ipipeif_get_pack_mode(u32 in_pix_fmt)
46 case MEDIA_BUS_FMT_SBGGR8_1X8:
47 case MEDIA_BUS_FMT_Y8_1X8:
48 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
49 case MEDIA_BUS_FMT_UV8_1X8:
50 return IPIPEIF_5_1_PACK_8_BIT;
52 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
53 return IPIPEIF_5_1_PACK_8_BIT_A_LAW;
55 case MEDIA_BUS_FMT_SGRBG12_1X12:
56 return IPIPEIF_5_1_PACK_16_BIT;
58 case MEDIA_BUS_FMT_SBGGR12_1X12:
59 return IPIPEIF_5_1_PACK_12_BIT;
62 return IPIPEIF_5_1_PACK_16_BIT;
66 static inline u32 ipipeif_read(void __iomem *addr, u32 offset)
68 return readl(addr + offset);
71 static inline void ipipeif_write(u32 val, void __iomem *addr, u32 offset)
73 writel(val, addr + offset);
76 static void ipipeif_config_dpc(void __iomem *addr, struct ipipeif_dpc *dpc)
81 val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT;
82 val |= dpc->thr & IPIPEIF_DPC2_THR_MASK;
84 ipipeif_write(val, addr, IPIPEIF_DPC2);
87 #define IPIPEIF_MODE_CONTINUOUS 0
88 #define IPIPEIF_MODE_ONE_SHOT 1
90 static int get_oneshot_mode(enum ipipeif_input_entity input)
92 if (input == IPIPEIF_INPUT_MEMORY)
93 return IPIPEIF_MODE_ONE_SHOT;
94 if (input == IPIPEIF_INPUT_ISIF)
95 return IPIPEIF_MODE_CONTINUOUS;
101 ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif)
103 struct v4l2_mbus_framefmt *informat;
105 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
106 if (ipipeif->input == IPIPEIF_INPUT_MEMORY &&
107 (informat->code == MEDIA_BUS_FMT_Y8_1X8 ||
108 informat->code == MEDIA_BUS_FMT_UV8_1X8))
111 return IPIPEIF_SRC1_PARALLEL_PORT;
115 ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif)
117 struct v4l2_mbus_framefmt *informat;
119 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
121 switch (informat->code) {
122 case MEDIA_BUS_FMT_SGRBG12_1X12:
123 return IPIPEIF_5_1_BITS11_0;
125 case MEDIA_BUS_FMT_Y8_1X8:
126 case MEDIA_BUS_FMT_UV8_1X8:
127 return IPIPEIF_5_1_BITS11_0;
130 return IPIPEIF_5_1_BITS7_0;
134 static enum ipipeif_input_source
135 ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif)
137 struct v4l2_mbus_framefmt *informat;
139 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
140 if (ipipeif->input == IPIPEIF_INPUT_ISIF)
143 if (informat->code == MEDIA_BUS_FMT_UYVY8_2X8)
144 return IPIPEIF_SDRAM_YUV;
146 return IPIPEIF_SDRAM_RAW;
149 void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif)
151 struct vpfe_video_device *video_in = &ipipeif->video_in;
153 if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
156 spin_lock(&video_in->dma_queue_lock);
157 vpfe_video_process_buffer_complete(video_in);
158 video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
159 vpfe_video_schedule_next_buffer(video_in);
160 spin_unlock(&video_in->dma_queue_lock);
163 int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev)
165 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
167 return ipipeif->config.decimation;
170 int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev)
172 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
174 return ipipeif->config.rsz;
177 #define RD_DATA_15_2 0x7
180 * ipipeif_hw_setup() - This function sets up IPIPEIF
181 * @sd: pointer to v4l2 subdev structure
182 * return -EINVAL or zero on success
184 static int ipipeif_hw_setup(struct v4l2_subdev *sd)
186 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
187 struct v4l2_mbus_framefmt *informat, *outformat;
188 struct ipipeif_params params = ipipeif->config;
189 enum ipipeif_input_source ipipeif_source;
191 void __iomem *ipipeif_base_addr;
198 ipipeif_base_addr = ipipeif->ipipeif_base_addr;
200 /* Enable clock to IPIPEIF and IPIPE */
201 vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
203 informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
204 outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE];
206 /* Combine all the fields to make CFG1 register of IPIPEIF */
207 tmp = val = get_oneshot_mode(ipipeif->input);
209 dev_err(&sd->devnode->dev, "ipipeif: links setup required");
212 val <<= ONESHOT_SHIFT;
214 ipipeif_source = ipipeif_get_source(ipipeif);
215 val |= ipipeif_source << INPSRC_SHIFT;
217 val |= params.clock_select << CLKSEL_SHIFT;
218 val |= params.avg_filter << AVGFILT_SHIFT;
219 val |= params.decimation << DECIM_SHIFT;
221 pack_mode = ipipeif_get_pack_mode(informat->code);
222 val |= pack_mode << PACK8IN_SHIFT;
224 source1 = ipipeif_get_cfg_src1(ipipeif);
225 val |= source1 << INPSRC1_SHIFT;
227 data_shift = ipipeif_get_data_shift(ipipeif);
228 if (ipipeif_source != IPIPEIF_SDRAM_YUV)
229 val |= data_shift << DATASFT_SHIFT;
231 val &= ~(RD_DATA_15_2 << DATASFT_SHIFT);
233 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1);
235 switch (ipipeif_source) {
237 ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
240 case IPIPEIF_SDRAM_RAW:
241 case IPIPEIF_CCDC_DARKFM:
242 ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
244 case IPIPEIF_SDRAM_YUV:
245 val |= data_shift << DATASFT_SHIFT;
246 ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN);
247 ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR);
248 ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM);
249 ipipeif_write(informat->height,
250 ipipeif_base_addr, IPIPEIF_VNUM);
257 /*check if decimation is enable or not */
258 if (params.decimation)
259 ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ);
261 /* Setup sync alignment and initial rsz position */
262 val = params.if_5_1.align_sync & 1;
263 val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT;
264 val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK;
265 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ);
266 isif_port_if = informat->code;
268 if (isif_port_if == MEDIA_BUS_FMT_Y8_1X8)
269 isif_port_if = MEDIA_BUS_FMT_YUYV8_1X16;
270 else if (isif_port_if == MEDIA_BUS_FMT_UV8_1X8)
271 isif_port_if = MEDIA_BUS_FMT_SGRBG12_1X12;
273 /* Enable DPCM decompression */
274 switch (ipipeif_source) {
275 case IPIPEIF_SDRAM_RAW:
277 if (outformat->code == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) {
279 val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) <<
280 IPIPEIF_DPCM_BITS_SHIFT;
281 val |= (ipipeif->dpcm_predictor & 1) <<
282 IPIPEIF_DPCM_PRED_SHIFT;
284 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM);
287 ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc);
289 ipipeif_write(params.if_5_1.clip,
290 ipipeif_base_addr, IPIPEIF_OCLIP);
292 /* fall through for SDRAM YUV mode */
294 val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2);
295 switch (isif_port_if) {
296 case MEDIA_BUS_FMT_YUYV8_1X16:
297 case MEDIA_BUS_FMT_UYVY8_2X8:
298 case MEDIA_BUS_FMT_Y8_1X8:
299 clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
300 set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
301 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
305 clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
306 clear_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
307 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
312 case IPIPEIF_SDRAM_YUV:
313 /* Set clock divider */
314 if (params.clock_select == IPIPEIF_SDRAM_CLK) {
315 val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV);
316 val |= (params.if_5_1.clk_div.m - 1) <<
317 IPIPEIF_CLKDIV_M_SHIFT;
318 val |= (params.if_5_1.clk_div.n - 1);
319 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV);
324 case IPIPEIF_CCDC_DARKFM:
326 ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc);
328 /* Set DF gain & threshold control */
330 if (params.if_5_1.df_gain_en) {
331 val = params.if_5_1.df_gain_thr &
332 IPIPEIF_DF_GAIN_THR_MASK;
333 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH);
334 val = (params.if_5_1.df_gain_en & 1) <<
335 IPIPEIF_DF_GAIN_EN_SHIFT;
336 val |= params.if_5_1.df_gain &
337 IPIPEIF_DF_GAIN_MASK;
339 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL);
341 val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT;
342 val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT;
344 switch (isif_port_if) {
345 case MEDIA_BUS_FMT_YUYV8_1X16:
346 case MEDIA_BUS_FMT_YUYV10_1X20:
347 clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
348 set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
351 case MEDIA_BUS_FMT_YUYV8_2X8:
352 case MEDIA_BUS_FMT_UYVY8_2X8:
353 case MEDIA_BUS_FMT_Y8_1X8:
354 case MEDIA_BUS_FMT_YUYV10_2X10:
355 set_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val);
356 set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val);
357 val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT;
362 ipipeif_write(params.if_5_1.clip, ipipeif_base_addr,
365 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
376 ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config)
378 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
379 struct device *dev = ipipeif->subdev.v4l2_dev->dev;
382 dev_err(dev, "Invalid configuration pointer\n");
386 ipipeif->config.clock_select = config->clock_select;
387 ipipeif->config.ppln = config->ppln;
388 ipipeif->config.lpfr = config->lpfr;
389 ipipeif->config.rsz = config->rsz;
390 ipipeif->config.decimation = config->decimation;
391 if (ipipeif->config.decimation &&
392 (ipipeif->config.rsz < IPIPEIF_RSZ_MIN ||
393 ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) {
394 dev_err(dev, "rsz range is %d to %d\n",
395 IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
399 ipipeif->config.avg_filter = config->avg_filter;
401 ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr;
402 ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain;
403 ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en;
405 ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start;
406 ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync;
407 ipipeif->config.if_5_1.clip = config->if_5_1.clip;
409 ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en;
410 ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr;
412 ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m;
413 ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n;
419 ipipeif_get_config(struct v4l2_subdev *sd, void *arg)
421 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
422 struct ipipeif_params *config = arg;
423 struct device *dev = ipipeif->subdev.v4l2_dev->dev;
426 dev_err(dev, "Invalid configuration pointer\n");
430 config->clock_select = ipipeif->config.clock_select;
431 config->ppln = ipipeif->config.ppln;
432 config->lpfr = ipipeif->config.lpfr;
433 config->rsz = ipipeif->config.rsz;
434 config->decimation = ipipeif->config.decimation;
435 config->avg_filter = ipipeif->config.avg_filter;
437 config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr;
438 config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain;
439 config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en;
441 config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start;
442 config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync;
443 config->if_5_1.clip = ipipeif->config.if_5_1.clip;
445 config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en;
446 config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr;
448 config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m;
449 config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n;
455 * ipipeif_ioctl() - Handle ipipeif module private ioctl's
456 * @sd: pointer to v4l2 subdev structure
457 * @cmd: configuration command
458 * @arg: configuration argument
460 static long ipipeif_ioctl(struct v4l2_subdev *sd,
461 unsigned int cmd, void *arg)
463 struct ipipeif_params *config = arg;
464 int ret = -ENOIOCTLCMD;
467 case VIDIOC_VPFE_IPIPEIF_S_CONFIG:
468 ret = ipipeif_set_config(sd, config);
471 case VIDIOC_VPFE_IPIPEIF_G_CONFIG:
472 ret = ipipeif_get_config(sd, arg);
479 * ipipeif_s_ctrl() - Handle set control subdev method
480 * @ctrl: pointer to v4l2 control structure
482 static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl)
484 struct vpfe_ipipeif_device *ipipeif =
485 container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls);
488 case VPFE_CID_DPCM_PREDICTOR:
489 ipipeif->dpcm_predictor = ctrl->val;
493 ipipeif->gain = ctrl->val;
503 #define ENABLE_IPIPEIF 0x1
505 void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev)
507 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
508 void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
511 if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
515 val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE);
518 ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE);
522 * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev
523 * @sd: pointer to v4l2 subdev structure
524 * @enable: 1 == Enable, 0 == Disable
526 static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
528 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
529 struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
535 ret = ipipeif_hw_setup(sd);
537 vpfe_ipipeif_enable(vpfe_dev);
543 * ipipeif_enum_mbus_code() - Handle pixel format enumeration
544 * @sd: pointer to v4l2 subdev structure
545 * @cfg: V4L2 subdev pad config
546 * @code: pointer to v4l2_subdev_mbus_code_enum structure
547 * return -EINVAL or zero on success
549 static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
550 struct v4l2_subdev_pad_config *cfg,
551 struct v4l2_subdev_mbus_code_enum *code)
554 case IPIPEIF_PAD_SINK:
555 if (code->index >= ARRAY_SIZE(ipipeif_input_fmts))
558 code->code = ipipeif_input_fmts[code->index];
561 case IPIPEIF_PAD_SOURCE:
562 if (code->index >= ARRAY_SIZE(ipipeif_output_fmts))
565 code->code = ipipeif_output_fmts[code->index];
576 * ipipeif_get_format() - Handle get format by pads subdev method
577 * @sd: pointer to v4l2 subdev structure
578 * @cfg: V4L2 subdev pad config
579 * @fmt: pointer to v4l2 subdev format structure
582 ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
583 struct v4l2_subdev_format *fmt)
585 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
587 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
588 fmt->format = ipipeif->formats[fmt->pad];
590 fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad));
595 #define MIN_OUT_WIDTH 32
596 #define MIN_OUT_HEIGHT 32
599 * ipipeif_try_format() - Handle try format by pad subdev method
600 * @ipipeif: VPFE ipipeif device.
601 * @cfg: V4L2 subdev pad config
603 * @fmt: pointer to v4l2 format structure.
604 * @which : wanted subdev format
607 ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
608 struct v4l2_subdev_pad_config *cfg, unsigned int pad,
609 struct v4l2_mbus_framefmt *fmt,
610 enum v4l2_subdev_format_whence which)
612 unsigned int max_out_height;
613 unsigned int max_out_width;
616 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
617 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
619 if (pad == IPIPEIF_PAD_SINK) {
620 for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++)
621 if (fmt->code == ipipeif_input_fmts[i])
624 /* If not found, use SBGGR10 as default */
625 if (i >= ARRAY_SIZE(ipipeif_input_fmts))
626 fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12;
627 } else if (pad == IPIPEIF_PAD_SOURCE) {
628 for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++)
629 if (fmt->code == ipipeif_output_fmts[i])
632 /* If not found, use UYVY as default */
633 if (i >= ARRAY_SIZE(ipipeif_output_fmts))
634 fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
637 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
638 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
642 ipipeif_enum_frame_size(struct v4l2_subdev *sd,
643 struct v4l2_subdev_pad_config *cfg,
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, cfg, fse->pad, &format, fse->which);
656 fse->min_width = format.width;
657 fse->min_height = format.height;
659 if (format.code != fse->code)
662 format.code = fse->code;
665 ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
666 fse->max_width = format.width;
667 fse->max_height = format.height;
673 * __ipipeif_get_format() - helper function for getting ipipeif format
674 * @ipipeif: pointer to ipipeif private structure.
675 * @cfg: V4L2 subdev pad config
677 * @which: wanted subdev format.
680 static struct v4l2_mbus_framefmt *
681 __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif,
682 struct v4l2_subdev_pad_config *cfg, unsigned int pad,
683 enum v4l2_subdev_format_whence which)
685 if (which == V4L2_SUBDEV_FORMAT_TRY)
686 return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad);
688 return &ipipeif->formats[pad];
692 * ipipeif_set_format() - Handle set format by pads subdev method
693 * @sd: pointer to v4l2 subdev structure
694 * @cfg: V4L2 subdev pad config
695 * @fmt: pointer to v4l2 subdev format structure
696 * return -EINVAL or zero on success
699 ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
700 struct v4l2_subdev_format *fmt)
702 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
703 struct v4l2_mbus_framefmt *format;
705 format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
709 ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which);
710 *format = fmt->format;
712 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
715 if (fmt->pad == IPIPEIF_PAD_SINK &&
716 ipipeif->input != IPIPEIF_INPUT_NONE)
717 ipipeif->formats[fmt->pad] = fmt->format;
718 else if (fmt->pad == IPIPEIF_PAD_SOURCE &&
719 ipipeif->output != IPIPEIF_OUTPUT_NONE)
720 ipipeif->formats[fmt->pad] = fmt->format;
727 static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif)
732 const struct ipipeif_params ipipeif_defaults = {
733 .clock_select = IPIPEIF_SDRAM_CLK,
735 .lpfr = HEIGHT_I + 10,
736 .rsz = 16, /* resize ratio 16/rsz */
737 .decimation = IPIPEIF_DECIMATION_OFF,
738 .avg_filter = IPIPEIF_AVG_OFF,
741 .m = 1, /* clock = sdram clock * (m/n) */
747 memcpy(&ipipeif->config, &ipipeif_defaults,
748 sizeof(struct ipipeif_params));
752 * ipipeif_init_formats() - Initialize formats on all pads
753 * @sd: VPFE ipipeif V4L2 subdevice
754 * @fh: V4L2 subdev file handle
756 * Initialize all pad formats with default values. Try formats are initialized
757 * on the file handle.
760 ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
762 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
763 struct v4l2_subdev_format format;
765 memset(&format, 0, sizeof(format));
766 format.pad = IPIPEIF_PAD_SINK;
767 format.which = V4L2_SUBDEV_FORMAT_TRY;
768 format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
769 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
770 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
771 ipipeif_set_format(sd, fh->pad, &format);
773 memset(&format, 0, sizeof(format));
774 format.pad = IPIPEIF_PAD_SOURCE;
775 format.which = V4L2_SUBDEV_FORMAT_TRY;
776 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
777 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
778 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
779 ipipeif_set_format(sd, fh->pad, &format);
781 ipipeif_set_default_config(ipipeif);
787 * ipipeif_video_in_queue() - ipipeif video in queue
788 * @vpfe_dev: vpfe device pointer
789 * @addr: buffer address
792 ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
794 struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
795 void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
799 if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
802 switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) {
803 case MEDIA_BUS_FMT_Y8_1X8:
804 case MEDIA_BUS_FMT_UV8_1X8:
805 case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
806 adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width;
810 adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1;
814 /* adjust the line len to be a multiple of 32 */
817 val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK;
818 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS);
820 /* lower sixteen bit */
821 val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK;
822 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL);
824 /* upper next seven bit */
825 val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK;
826 ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU);
831 /* subdev core operations */
832 static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = {
833 .ioctl = ipipeif_ioctl,
836 static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = {
837 .s_ctrl = ipipeif_s_ctrl,
840 static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = {
841 .ops = &ipipeif_ctrl_ops,
842 .id = VPFE_CID_DPCM_PREDICTOR,
843 .name = "DPCM Predictor",
844 .type = V4L2_CTRL_TYPE_INTEGER,
851 /* subdev file operations */
852 static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = {
853 .open = ipipeif_init_formats,
856 /* subdev video operations */
857 static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = {
858 .s_stream = ipipeif_set_stream,
861 /* subdev pad operations */
862 static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = {
863 .enum_mbus_code = ipipeif_enum_mbus_code,
864 .enum_frame_size = ipipeif_enum_frame_size,
865 .get_fmt = ipipeif_get_format,
866 .set_fmt = ipipeif_set_format,
869 /* subdev operations */
870 static const struct v4l2_subdev_ops ipipeif_v4l2_ops = {
871 .core = &ipipeif_v4l2_core_ops,
872 .video = &ipipeif_v4l2_video_ops,
873 .pad = &ipipeif_v4l2_pad_ops,
876 static const struct vpfe_video_operations video_in_ops = {
877 .queue = ipipeif_video_in_queue,
881 ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
882 const struct media_pad *remote, u32 flags)
884 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
885 struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
886 struct vpfe_device *vpfe = to_vpfe_device(ipipeif);
887 unsigned int index = local->index;
889 /* FIXME: this is actually a hack! */
890 if (is_media_entity_v4l2_subdev(remote->entity))
894 case IPIPEIF_PAD_SINK:
895 /* Single shot mode */
896 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
897 ipipeif->input = IPIPEIF_INPUT_NONE;
900 ipipeif->input = IPIPEIF_INPUT_MEMORY;
903 case IPIPEIF_PAD_SINK | 2 << 16:
905 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
906 ipipeif->input = IPIPEIF_INPUT_NONE;
909 if (ipipeif->input != IPIPEIF_INPUT_NONE)
912 ipipeif->input = IPIPEIF_INPUT_ISIF;
915 case IPIPEIF_PAD_SOURCE | 2 << 16:
916 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
917 ipipeif->output = IPIPEIF_OUTPUT_NONE;
920 if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity)
921 /* connencted to ipipe */
922 ipipeif->output = IPIPEIF_OUTPUT_IPIPE;
923 else if (remote->entity == &vpfe->vpfe_resizer.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_create_pad_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 strscpy(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_pads_init(me, IPIPEIF_NUM_PADS, pads);
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));