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 MEDIA_BUS_FMT_UYVY8_2X8
,
27 MEDIA_BUS_FMT_SGRBG12_1X12
,
29 MEDIA_BUS_FMT_UV8_1X8
,
30 MEDIA_BUS_FMT_YDYUYDYV8_1X16
,
31 MEDIA_BUS_FMT_SBGGR8_1X8
,
34 static const unsigned int ipipeif_output_fmts
[] = {
35 MEDIA_BUS_FMT_UYVY8_2X8
,
36 MEDIA_BUS_FMT_SGRBG12_1X12
,
38 MEDIA_BUS_FMT_UV8_1X8
,
39 MEDIA_BUS_FMT_YDYUYDYV8_1X16
,
40 MEDIA_BUS_FMT_SBGGR8_1X8
,
41 MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
,
42 MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8
,
46 ipipeif_get_pack_mode(u32 in_pix_fmt
)
49 case MEDIA_BUS_FMT_SBGGR8_1X8
:
50 case MEDIA_BUS_FMT_Y8_1X8
:
51 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
:
52 case MEDIA_BUS_FMT_UV8_1X8
:
53 return IPIPEIF_5_1_PACK_8_BIT
;
55 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8
:
56 return IPIPEIF_5_1_PACK_8_BIT_A_LAW
;
58 case MEDIA_BUS_FMT_SGRBG12_1X12
:
59 return IPIPEIF_5_1_PACK_16_BIT
;
61 case MEDIA_BUS_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
== MEDIA_BUS_FMT_Y8_1X8
||
111 informat
->code
== MEDIA_BUS_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 MEDIA_BUS_FMT_SGRBG12_1X12
:
126 return IPIPEIF_5_1_BITS11_0
;
128 case MEDIA_BUS_FMT_Y8_1X8
:
129 case MEDIA_BUS_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
== MEDIA_BUS_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
;
194 void *ipipeif_base_addr
;
201 ipipeif_base_addr
= ipipeif
->ipipeif_base_addr
;
203 /* Enable clock to IPIPEIF and IPIPE */
204 vpss_enable_clock(VPSS_IPIPEIF_CLOCK
, 1);
206 informat
= &ipipeif
->formats
[IPIPEIF_PAD_SINK
];
207 outformat
= &ipipeif
->formats
[IPIPEIF_PAD_SOURCE
];
209 /* Combine all the fields to make CFG1 register of IPIPEIF */
210 tmp
= val
= get_oneshot_mode(ipipeif
->input
);
212 dev_err(&sd
->devnode
->dev
, "ipipeif: links setup required");
215 val
<<= ONESHOT_SHIFT
;
217 ipipeif_source
= ipipeif_get_source(ipipeif
);
218 val
|= ipipeif_source
<< INPSRC_SHIFT
;
220 val
|= params
.clock_select
<< CLKSEL_SHIFT
;
221 val
|= params
.avg_filter
<< AVGFILT_SHIFT
;
222 val
|= params
.decimation
<< DECIM_SHIFT
;
224 pack_mode
= ipipeif_get_pack_mode(informat
->code
);
225 val
|= pack_mode
<< PACK8IN_SHIFT
;
227 source1
= ipipeif_get_cfg_src1(ipipeif
);
228 val
|= source1
<< INPSRC1_SHIFT
;
230 data_shift
= ipipeif_get_data_shift(ipipeif
);
231 if (ipipeif_source
!= IPIPEIF_SDRAM_YUV
)
232 val
|= data_shift
<< DATASFT_SHIFT
;
234 val
&= ~(RD_DATA_15_2
<< DATASFT_SHIFT
);
236 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_CFG1
);
238 switch (ipipeif_source
) {
240 ipipeif_write(ipipeif
->gain
, ipipeif_base_addr
, IPIPEIF_GAIN
);
243 case IPIPEIF_SDRAM_RAW
:
244 case IPIPEIF_CCDC_DARKFM
:
245 ipipeif_write(ipipeif
->gain
, ipipeif_base_addr
, IPIPEIF_GAIN
);
247 case IPIPEIF_SDRAM_YUV
:
248 val
|= data_shift
<< DATASFT_SHIFT
;
249 ipipeif_write(params
.ppln
, ipipeif_base_addr
, IPIPEIF_PPLN
);
250 ipipeif_write(params
.lpfr
, ipipeif_base_addr
, IPIPEIF_LPFR
);
251 ipipeif_write(informat
->width
, ipipeif_base_addr
, IPIPEIF_HNUM
);
252 ipipeif_write(informat
->height
,
253 ipipeif_base_addr
, IPIPEIF_VNUM
);
260 /*check if decimation is enable or not */
261 if (params
.decimation
)
262 ipipeif_write(params
.rsz
, ipipeif_base_addr
, IPIPEIF_RSZ
);
264 /* Setup sync alignment and initial rsz position */
265 val
= params
.if_5_1
.align_sync
& 1;
266 val
<<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT
;
267 val
|= params
.if_5_1
.rsz_start
& IPIPEIF_INIRSZ_MASK
;
268 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_INIRSZ
);
269 isif_port_if
= informat
->code
;
271 if (isif_port_if
== MEDIA_BUS_FMT_Y8_1X8
)
272 isif_port_if
= MEDIA_BUS_FMT_YUYV8_1X16
;
273 else if (isif_port_if
== MEDIA_BUS_FMT_UV8_1X8
)
274 isif_port_if
= MEDIA_BUS_FMT_SGRBG12_1X12
;
276 /* Enable DPCM decompression */
277 switch (ipipeif_source
) {
278 case IPIPEIF_SDRAM_RAW
:
280 if (outformat
->code
== MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
) {
282 val
|= (IPIPEIF_DPCM_8BIT_10BIT
& 1) <<
283 IPIPEIF_DPCM_BITS_SHIFT
;
284 val
|= (ipipeif
->dpcm_predictor
& 1) <<
285 IPIPEIF_DPCM_PRED_SHIFT
;
287 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_DPCM
);
290 ipipeif_config_dpc(ipipeif_base_addr
, ¶ms
.if_5_1
.dpc
);
292 ipipeif_write(params
.if_5_1
.clip
,
293 ipipeif_base_addr
, IPIPEIF_OCLIP
);
295 /* fall through for SDRAM YUV mode */
297 val
= ipipeif_read(ipipeif_base_addr
, IPIPEIF_CFG2
);
298 switch (isif_port_if
) {
299 case MEDIA_BUS_FMT_YUYV8_1X16
:
300 case MEDIA_BUS_FMT_UYVY8_2X8
:
301 case MEDIA_BUS_FMT_Y8_1X8
:
302 RESETBIT(val
, IPIPEIF_CFG2_YUV8_SHIFT
);
303 SETBIT(val
, IPIPEIF_CFG2_YUV16_SHIFT
);
304 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_CFG2
);
308 RESETBIT(val
, IPIPEIF_CFG2_YUV8_SHIFT
);
309 RESETBIT(val
, IPIPEIF_CFG2_YUV16_SHIFT
);
310 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_CFG2
);
314 case IPIPEIF_SDRAM_YUV
:
315 /* Set clock divider */
316 if (params
.clock_select
== IPIPEIF_SDRAM_CLK
) {
317 val
= ipipeif_read(ipipeif_base_addr
, IPIPEIF_CLKDIV
);
318 val
|= (params
.if_5_1
.clk_div
.m
- 1) <<
319 IPIPEIF_CLKDIV_M_SHIFT
;
320 val
|= (params
.if_5_1
.clk_div
.n
- 1);
321 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_CLKDIV
);
326 case IPIPEIF_CCDC_DARKFM
:
328 ipipeif_config_dpc(ipipeif_base_addr
, ¶ms
.if_5_1
.dpc
);
330 /* Set DF gain & threshold control */
332 if (params
.if_5_1
.df_gain_en
) {
333 val
= params
.if_5_1
.df_gain_thr
&
334 IPIPEIF_DF_GAIN_THR_MASK
;
335 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_DFSGTH
);
336 val
= (params
.if_5_1
.df_gain_en
& 1) <<
337 IPIPEIF_DF_GAIN_EN_SHIFT
;
338 val
|= params
.if_5_1
.df_gain
&
339 IPIPEIF_DF_GAIN_MASK
;
341 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_DFSGVL
);
343 val
= VPFE_PINPOL_POSITIVE
<< IPIPEIF_CFG2_HDPOL_SHIFT
;
344 val
|= VPFE_PINPOL_POSITIVE
<< IPIPEIF_CFG2_VDPOL_SHIFT
;
346 switch (isif_port_if
) {
347 case MEDIA_BUS_FMT_YUYV8_1X16
:
348 case MEDIA_BUS_FMT_YUYV10_1X20
:
349 RESETBIT(val
, IPIPEIF_CFG2_YUV8_SHIFT
);
350 SETBIT(val
, IPIPEIF_CFG2_YUV16_SHIFT
);
353 case MEDIA_BUS_FMT_YUYV8_2X8
:
354 case MEDIA_BUS_FMT_UYVY8_2X8
:
355 case MEDIA_BUS_FMT_Y8_1X8
:
356 case MEDIA_BUS_FMT_YUYV10_2X10
:
357 SETBIT(val
, IPIPEIF_CFG2_YUV8_SHIFT
);
358 SETBIT(val
, IPIPEIF_CFG2_YUV16_SHIFT
);
359 val
|= IPIPEIF_CBCR_Y
<< IPIPEIF_CFG2_YUV8P_SHIFT
;
364 ipipeif_write(params
.if_5_1
.clip
, ipipeif_base_addr
,
367 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_CFG2
);
378 ipipeif_set_config(struct v4l2_subdev
*sd
, struct ipipeif_params
*config
)
380 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
381 struct device
*dev
= ipipeif
->subdev
.v4l2_dev
->dev
;
384 dev_err(dev
, "Invalid configuration pointer\n");
388 ipipeif
->config
.clock_select
= config
->clock_select
;
389 ipipeif
->config
.ppln
= config
->ppln
;
390 ipipeif
->config
.lpfr
= config
->lpfr
;
391 ipipeif
->config
.rsz
= config
->rsz
;
392 ipipeif
->config
.decimation
= config
->decimation
;
393 if (ipipeif
->config
.decimation
&&
394 (ipipeif
->config
.rsz
< IPIPEIF_RSZ_MIN
||
395 ipipeif
->config
.rsz
> IPIPEIF_RSZ_MAX
)) {
396 dev_err(dev
, "rsz range is %d to %d\n",
397 IPIPEIF_RSZ_MIN
, IPIPEIF_RSZ_MAX
);
401 ipipeif
->config
.avg_filter
= config
->avg_filter
;
403 ipipeif
->config
.if_5_1
.df_gain_thr
= config
->if_5_1
.df_gain_thr
;
404 ipipeif
->config
.if_5_1
.df_gain
= config
->if_5_1
.df_gain
;
405 ipipeif
->config
.if_5_1
.df_gain_en
= config
->if_5_1
.df_gain_en
;
407 ipipeif
->config
.if_5_1
.rsz_start
= config
->if_5_1
.rsz_start
;
408 ipipeif
->config
.if_5_1
.align_sync
= config
->if_5_1
.align_sync
;
409 ipipeif
->config
.if_5_1
.clip
= config
->if_5_1
.clip
;
411 ipipeif
->config
.if_5_1
.dpc
.en
= config
->if_5_1
.dpc
.en
;
412 ipipeif
->config
.if_5_1
.dpc
.thr
= config
->if_5_1
.dpc
.thr
;
414 ipipeif
->config
.if_5_1
.clk_div
.m
= config
->if_5_1
.clk_div
.m
;
415 ipipeif
->config
.if_5_1
.clk_div
.n
= config
->if_5_1
.clk_div
.n
;
421 ipipeif_get_config(struct v4l2_subdev
*sd
, void __user
*arg
)
423 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
424 struct ipipeif_params
*config
= arg
;
425 struct device
*dev
= ipipeif
->subdev
.v4l2_dev
->dev
;
428 dev_err(dev
, "Invalid configuration pointer\n");
432 config
->clock_select
= ipipeif
->config
.clock_select
;
433 config
->ppln
= ipipeif
->config
.ppln
;
434 config
->lpfr
= ipipeif
->config
.lpfr
;
435 config
->rsz
= ipipeif
->config
.rsz
;
436 config
->decimation
= ipipeif
->config
.decimation
;
437 config
->avg_filter
= ipipeif
->config
.avg_filter
;
439 config
->if_5_1
.df_gain_thr
= ipipeif
->config
.if_5_1
.df_gain_thr
;
440 config
->if_5_1
.df_gain
= ipipeif
->config
.if_5_1
.df_gain
;
441 config
->if_5_1
.df_gain_en
= ipipeif
->config
.if_5_1
.df_gain_en
;
443 config
->if_5_1
.rsz_start
= ipipeif
->config
.if_5_1
.rsz_start
;
444 config
->if_5_1
.align_sync
= ipipeif
->config
.if_5_1
.align_sync
;
445 config
->if_5_1
.clip
= ipipeif
->config
.if_5_1
.clip
;
447 config
->if_5_1
.dpc
.en
= ipipeif
->config
.if_5_1
.dpc
.en
;
448 config
->if_5_1
.dpc
.thr
= ipipeif
->config
.if_5_1
.dpc
.thr
;
450 config
->if_5_1
.clk_div
.m
= ipipeif
->config
.if_5_1
.clk_div
.m
;
451 config
->if_5_1
.clk_div
.n
= ipipeif
->config
.if_5_1
.clk_div
.n
;
457 * ipipeif_ioctl() - Handle ipipeif module private ioctl's
458 * @sd: pointer to v4l2 subdev structure
459 * @cmd: configuration command
460 * @arg: configuration argument
462 static long ipipeif_ioctl(struct v4l2_subdev
*sd
,
463 unsigned int cmd
, void *arg
)
465 struct ipipeif_params
*config
= arg
;
466 int ret
= -ENOIOCTLCMD
;
469 case VIDIOC_VPFE_IPIPEIF_S_CONFIG
:
470 ret
= ipipeif_set_config(sd
, config
);
473 case VIDIOC_VPFE_IPIPEIF_G_CONFIG
:
474 ret
= ipipeif_get_config(sd
, arg
);
481 * ipipeif_s_ctrl() - Handle set control subdev method
482 * @ctrl: pointer to v4l2 control structure
484 static int ipipeif_s_ctrl(struct v4l2_ctrl
*ctrl
)
486 struct vpfe_ipipeif_device
*ipipeif
=
487 container_of(ctrl
->handler
, struct vpfe_ipipeif_device
, ctrls
);
490 case VPFE_CID_DPCM_PREDICTOR
:
491 ipipeif
->dpcm_predictor
= ctrl
->val
;
495 ipipeif
->gain
= ctrl
->val
;
505 #define ENABLE_IPIPEIF 0x1
507 void vpfe_ipipeif_enable(struct vpfe_device
*vpfe_dev
)
509 struct vpfe_ipipeif_device
*ipipeif
= &vpfe_dev
->vpfe_ipipeif
;
510 void *ipipeif_base_addr
= ipipeif
->ipipeif_base_addr
;
513 if (ipipeif
->input
!= IPIPEIF_INPUT_MEMORY
)
517 val
= ipipeif_read(ipipeif_base_addr
, IPIPEIF_ENABLE
);
520 ipipeif_write(ENABLE_IPIPEIF
, ipipeif_base_addr
, IPIPEIF_ENABLE
);
524 * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev
525 * @sd: pointer to v4l2 subdev structure
526 * @enable: 1 == Enable, 0 == Disable
528 static int ipipeif_set_stream(struct v4l2_subdev
*sd
, int enable
)
530 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
531 struct vpfe_device
*vpfe_dev
= to_vpfe_device(ipipeif
);
537 ret
= ipipeif_hw_setup(sd
);
539 vpfe_ipipeif_enable(vpfe_dev
);
545 * ipipeif_enum_mbus_code() - Handle pixel format enumeration
546 * @sd: pointer to v4l2 subdev structure
547 * @cfg: V4L2 subdev pad config
548 * @code: pointer to v4l2_subdev_mbus_code_enum structure
549 * return -EINVAL or zero on success
551 static int ipipeif_enum_mbus_code(struct v4l2_subdev
*sd
,
552 struct v4l2_subdev_pad_config
*cfg
,
553 struct v4l2_subdev_mbus_code_enum
*code
)
556 case IPIPEIF_PAD_SINK
:
557 if (code
->index
>= ARRAY_SIZE(ipipeif_input_fmts
))
560 code
->code
= ipipeif_input_fmts
[code
->index
];
563 case IPIPEIF_PAD_SOURCE
:
564 if (code
->index
>= ARRAY_SIZE(ipipeif_output_fmts
))
567 code
->code
= ipipeif_output_fmts
[code
->index
];
578 * ipipeif_get_format() - Handle get format by pads subdev method
579 * @sd: pointer to v4l2 subdev structure
580 * @cfg: V4L2 subdev pad config
581 * @fmt: pointer to v4l2 subdev format structure
584 ipipeif_get_format(struct v4l2_subdev
*sd
, struct v4l2_subdev_pad_config
*cfg
,
585 struct v4l2_subdev_format
*fmt
)
587 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
589 if (fmt
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
)
590 fmt
->format
= ipipeif
->formats
[fmt
->pad
];
592 fmt
->format
= *(v4l2_subdev_get_try_format(sd
, cfg
, fmt
->pad
));
597 #define MIN_OUT_WIDTH 32
598 #define MIN_OUT_HEIGHT 32
601 * ipipeif_try_format() - Handle try format by pad subdev method
602 * @ipipeif: VPFE ipipeif device.
603 * @cfg: V4L2 subdev pad config
605 * @fmt: pointer to v4l2 format structure.
606 * @which : wanted subdev format
609 ipipeif_try_format(struct vpfe_ipipeif_device
*ipipeif
,
610 struct v4l2_subdev_pad_config
*cfg
, unsigned int pad
,
611 struct v4l2_mbus_framefmt
*fmt
,
612 enum v4l2_subdev_format_whence which
)
614 unsigned int max_out_height
;
615 unsigned int max_out_width
;
618 max_out_width
= IPIPE_MAX_OUTPUT_WIDTH_A
;
619 max_out_height
= IPIPE_MAX_OUTPUT_HEIGHT_A
;
621 if (pad
== IPIPEIF_PAD_SINK
) {
622 for (i
= 0; i
< ARRAY_SIZE(ipipeif_input_fmts
); i
++)
623 if (fmt
->code
== ipipeif_input_fmts
[i
])
626 /* If not found, use SBGGR10 as default */
627 if (i
>= ARRAY_SIZE(ipipeif_input_fmts
))
628 fmt
->code
= MEDIA_BUS_FMT_SGRBG12_1X12
;
629 } else if (pad
== IPIPEIF_PAD_SOURCE
) {
630 for (i
= 0; i
< ARRAY_SIZE(ipipeif_output_fmts
); i
++)
631 if (fmt
->code
== ipipeif_output_fmts
[i
])
634 /* If not found, use UYVY as default */
635 if (i
>= ARRAY_SIZE(ipipeif_output_fmts
))
636 fmt
->code
= MEDIA_BUS_FMT_UYVY8_2X8
;
639 fmt
->width
= clamp_t(u32
, fmt
->width
, MIN_OUT_HEIGHT
, max_out_width
);
640 fmt
->height
= clamp_t(u32
, fmt
->height
, MIN_OUT_WIDTH
, max_out_height
);
644 ipipeif_enum_frame_size(struct v4l2_subdev
*sd
, struct v4l2_subdev_pad_config
*cfg
,
645 struct v4l2_subdev_frame_size_enum
*fse
)
647 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
648 struct v4l2_mbus_framefmt format
;
653 format
.code
= fse
->code
;
656 ipipeif_try_format(ipipeif
, cfg
, fse
->pad
, &format
, fse
->which
);
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
, cfg
, fse
->pad
, &format
, fse
->which
);
667 fse
->max_width
= format
.width
;
668 fse
->max_height
= format
.height
;
674 * __ipipeif_get_format() - helper function for getting ipipeif format
675 * @ipipeif: pointer to ipipeif private structure.
676 * @cfg: V4L2 subdev pad config
678 * @which: wanted subdev format.
681 static struct v4l2_mbus_framefmt
*
682 __ipipeif_get_format(struct vpfe_ipipeif_device
*ipipeif
,
683 struct v4l2_subdev_pad_config
*cfg
, unsigned int pad
,
684 enum v4l2_subdev_format_whence which
)
686 if (which
== V4L2_SUBDEV_FORMAT_TRY
)
687 return v4l2_subdev_get_try_format(&ipipeif
->subdev
, cfg
, pad
);
689 return &ipipeif
->formats
[pad
];
693 * ipipeif_set_format() - Handle set format by pads subdev method
694 * @sd: pointer to v4l2 subdev structure
695 * @cfg: V4L2 subdev pad config
696 * @fmt: pointer to v4l2 subdev format structure
697 * return -EINVAL or zero on success
700 ipipeif_set_format(struct v4l2_subdev
*sd
, struct v4l2_subdev_pad_config
*cfg
,
701 struct v4l2_subdev_format
*fmt
)
703 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
704 struct v4l2_mbus_framefmt
*format
;
706 format
= __ipipeif_get_format(ipipeif
, cfg
, fmt
->pad
, fmt
->which
);
710 ipipeif_try_format(ipipeif
, cfg
, fmt
->pad
, &fmt
->format
, fmt
->which
);
711 *format
= fmt
->format
;
713 if (fmt
->which
== V4L2_SUBDEV_FORMAT_TRY
)
716 if (fmt
->pad
== IPIPEIF_PAD_SINK
&&
717 ipipeif
->input
!= IPIPEIF_INPUT_NONE
)
718 ipipeif
->formats
[fmt
->pad
] = fmt
->format
;
719 else if (fmt
->pad
== IPIPEIF_PAD_SOURCE
&&
720 ipipeif
->output
!= IPIPEIF_OUTPUT_NONE
)
721 ipipeif
->formats
[fmt
->pad
] = fmt
->format
;
728 static void ipipeif_set_default_config(struct vpfe_ipipeif_device
*ipipeif
)
733 const struct ipipeif_params ipipeif_defaults
= {
734 .clock_select
= IPIPEIF_SDRAM_CLK
,
736 .lpfr
= HEIGHT_I
+ 10,
737 .rsz
= 16, /* resize ratio 16/rsz */
738 .decimation
= IPIPEIF_DECIMATION_OFF
,
739 .avg_filter
= IPIPEIF_AVG_OFF
,
742 .m
= 1, /* clock = sdram clock * (m/n) */
748 memcpy(&ipipeif
->config
, &ipipeif_defaults
,
749 sizeof(struct ipipeif_params
));
753 * ipipeif_init_formats() - Initialize formats on all pads
754 * @sd: VPFE ipipeif V4L2 subdevice
755 * @fh: V4L2 subdev file handle
757 * Initialize all pad formats with default values. Try formats are initialized
758 * on the file handle.
761 ipipeif_init_formats(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
763 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
764 struct v4l2_subdev_format format
;
766 memset(&format
, 0, sizeof(format
));
767 format
.pad
= IPIPEIF_PAD_SINK
;
768 format
.which
= V4L2_SUBDEV_FORMAT_TRY
;
769 format
.format
.code
= MEDIA_BUS_FMT_SGRBG12_1X12
;
770 format
.format
.width
= IPIPE_MAX_OUTPUT_WIDTH_A
;
771 format
.format
.height
= IPIPE_MAX_OUTPUT_HEIGHT_A
;
772 ipipeif_set_format(sd
, fh
->pad
, &format
);
774 memset(&format
, 0, sizeof(format
));
775 format
.pad
= IPIPEIF_PAD_SOURCE
;
776 format
.which
= V4L2_SUBDEV_FORMAT_TRY
;
777 format
.format
.code
= MEDIA_BUS_FMT_UYVY8_2X8
;
778 format
.format
.width
= IPIPE_MAX_OUTPUT_WIDTH_A
;
779 format
.format
.height
= IPIPE_MAX_OUTPUT_HEIGHT_A
;
780 ipipeif_set_format(sd
, fh
->pad
, &format
);
782 ipipeif_set_default_config(ipipeif
);
788 * ipipeif_video_in_queue() - ipipeif video in queue
789 * @vpfe_dev: vpfe device pointer
790 * @addr: buffer address
793 ipipeif_video_in_queue(struct vpfe_device
*vpfe_dev
, unsigned long addr
)
795 struct vpfe_ipipeif_device
*ipipeif
= &vpfe_dev
->vpfe_ipipeif
;
796 void *ipipeif_base_addr
= ipipeif
->ipipeif_base_addr
;
800 if (ipipeif
->input
!= IPIPEIF_INPUT_MEMORY
)
803 switch (ipipeif
->formats
[IPIPEIF_PAD_SINK
].code
) {
804 case MEDIA_BUS_FMT_Y8_1X8
:
805 case MEDIA_BUS_FMT_UV8_1X8
:
806 case MEDIA_BUS_FMT_YDYUYDYV8_1X16
:
807 adofs
= ipipeif
->formats
[IPIPEIF_PAD_SINK
].width
;
811 adofs
= ipipeif
->formats
[IPIPEIF_PAD_SINK
].width
<< 1;
815 /* adjust the line len to be a multiple of 32 */
818 val
= (adofs
>> 5) & IPIPEIF_ADOFS_LSB_MASK
;
819 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_ADOFS
);
821 /* lower sixteen bit */
822 val
= (addr
>> IPIPEIF_ADDRL_SHIFT
) & IPIPEIF_ADDRL_MASK
;
823 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_ADDRL
);
825 /* upper next seven bit */
826 val
= (addr
>> IPIPEIF_ADDRU_SHIFT
) & IPIPEIF_ADDRU_MASK
;
827 ipipeif_write(val
, ipipeif_base_addr
, IPIPEIF_ADDRU
);
832 /* subdev core operations */
833 static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops
= {
834 .ioctl
= ipipeif_ioctl
,
837 static const struct v4l2_ctrl_ops ipipeif_ctrl_ops
= {
838 .s_ctrl
= ipipeif_s_ctrl
,
841 static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred
= {
842 .ops
= &ipipeif_ctrl_ops
,
843 .id
= VPFE_CID_DPCM_PREDICTOR
,
844 .name
= "DPCM Predictor",
845 .type
= V4L2_CTRL_TYPE_INTEGER
,
852 /* subdev file operations */
853 static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops
= {
854 .open
= ipipeif_init_formats
,
857 /* subdev video operations */
858 static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops
= {
859 .s_stream
= ipipeif_set_stream
,
862 /* subdev pad operations */
863 static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops
= {
864 .enum_mbus_code
= ipipeif_enum_mbus_code
,
865 .enum_frame_size
= ipipeif_enum_frame_size
,
866 .get_fmt
= ipipeif_get_format
,
867 .set_fmt
= ipipeif_set_format
,
870 /* subdev operations */
871 static const struct v4l2_subdev_ops ipipeif_v4l2_ops
= {
872 .core
= &ipipeif_v4l2_core_ops
,
873 .video
= &ipipeif_v4l2_video_ops
,
874 .pad
= &ipipeif_v4l2_pad_ops
,
877 static const struct vpfe_video_operations video_in_ops
= {
878 .queue
= ipipeif_video_in_queue
,
882 ipipeif_link_setup(struct media_entity
*entity
, const struct media_pad
*local
,
883 const struct media_pad
*remote
, u32 flags
)
885 struct v4l2_subdev
*sd
= media_entity_to_v4l2_subdev(entity
);
886 struct vpfe_ipipeif_device
*ipipeif
= v4l2_get_subdevdata(sd
);
887 struct vpfe_device
*vpfe
= to_vpfe_device(ipipeif
);
888 int index
= local
->index
;
890 /* FIXME: this is actually a hack! */
891 if (is_media_entity_v4l2_subdev(remote
->entity
))
895 case IPIPEIF_PAD_SINK
:
896 /* Single shot mode */
897 if (!(flags
& MEDIA_LNK_FL_ENABLED
)) {
898 ipipeif
->input
= IPIPEIF_INPUT_NONE
;
901 ipipeif
->input
= IPIPEIF_INPUT_MEMORY
;
904 case IPIPEIF_PAD_SINK
| 2 << 16:
906 if (!(flags
& MEDIA_LNK_FL_ENABLED
)) {
907 ipipeif
->input
= IPIPEIF_INPUT_NONE
;
910 if (ipipeif
->input
!= IPIPEIF_INPUT_NONE
)
913 ipipeif
->input
= IPIPEIF_INPUT_ISIF
;
916 case IPIPEIF_PAD_SOURCE
| 2 << 16:
917 if (!(flags
& MEDIA_LNK_FL_ENABLED
)) {
918 ipipeif
->output
= IPIPEIF_OUTPUT_NONE
;
921 if (remote
->entity
== &vpfe
->vpfe_ipipe
.subdev
.entity
)
922 /* connencted to ipipe */
923 ipipeif
->output
= IPIPEIF_OUTPUT_IPIPE
;
924 else if (remote
->entity
== &vpfe
->vpfe_resizer
.
925 crop_resizer
.subdev
.entity
)
926 /* connected to resizer */
927 ipipeif
->output
= IPIPEIF_OUTPUT_RESIZER
;
939 static const struct media_entity_operations ipipeif_media_ops
= {
940 .link_setup
= ipipeif_link_setup
,
944 * vpfe_ipipeif_unregister_entities() - Unregister entity
945 * @ipipeif - pointer to ipipeif subdevice structure.
947 void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device
*ipipeif
)
949 /* unregister video device */
950 vpfe_video_unregister(&ipipeif
->video_in
);
952 /* unregister subdev */
953 v4l2_device_unregister_subdev(&ipipeif
->subdev
);
955 media_entity_cleanup(&ipipeif
->subdev
.entity
);
959 vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device
*ipipeif
,
960 struct v4l2_device
*vdev
)
962 struct vpfe_device
*vpfe_dev
= to_vpfe_device(ipipeif
);
966 /* Register the subdev */
967 ret
= v4l2_device_register_subdev(vdev
, &ipipeif
->subdev
);
971 ret
= vpfe_video_register(&ipipeif
->video_in
, vdev
);
973 pr_err("Failed to register ipipeif video-in device\n");
976 ipipeif
->video_in
.vpfe_dev
= vpfe_dev
;
979 ret
= media_create_pad_link(&ipipeif
->video_in
.video_dev
.entity
, 0,
980 &ipipeif
->subdev
.entity
, 0, flags
);
986 v4l2_device_unregister_subdev(&ipipeif
->subdev
);
991 #define IPIPEIF_GAIN_HIGH 0x3ff
992 #define IPIPEIF_DEFAULT_GAIN 0x200
994 int vpfe_ipipeif_init(struct vpfe_ipipeif_device
*ipipeif
,
995 struct platform_device
*pdev
)
997 struct v4l2_subdev
*sd
= &ipipeif
->subdev
;
998 struct media_pad
*pads
= &ipipeif
->pads
[0];
999 struct media_entity
*me
= &sd
->entity
;
1000 static resource_size_t res_len
;
1001 struct resource
*res
;
1004 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 3);
1008 res_len
= resource_size(res
);
1009 res
= request_mem_region(res
->start
, res_len
, res
->name
);
1013 ipipeif
->ipipeif_base_addr
= ioremap_nocache(res
->start
, res_len
);
1014 if (!ipipeif
->ipipeif_base_addr
) {
1019 v4l2_subdev_init(sd
, &ipipeif_v4l2_ops
);
1021 sd
->internal_ops
= &ipipeif_v4l2_internal_ops
;
1022 strlcpy(sd
->name
, "DAVINCI IPIPEIF", sizeof(sd
->name
));
1023 sd
->grp_id
= 1 << 16; /* group ID for davinci subdevs */
1025 v4l2_set_subdevdata(sd
, ipipeif
);
1027 sd
->flags
|= V4L2_SUBDEV_FL_HAS_EVENTS
| V4L2_SUBDEV_FL_HAS_DEVNODE
;
1028 pads
[IPIPEIF_PAD_SINK
].flags
= MEDIA_PAD_FL_SINK
;
1029 pads
[IPIPEIF_PAD_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
1030 ipipeif
->input
= IPIPEIF_INPUT_NONE
;
1031 ipipeif
->output
= IPIPEIF_OUTPUT_NONE
;
1032 me
->ops
= &ipipeif_media_ops
;
1034 ret
= media_entity_init(me
, IPIPEIF_NUM_PADS
, pads
);
1038 v4l2_ctrl_handler_init(&ipipeif
->ctrls
, 2);
1039 v4l2_ctrl_new_std(&ipipeif
->ctrls
, &ipipeif_ctrl_ops
,
1041 IPIPEIF_GAIN_HIGH
, 1, IPIPEIF_DEFAULT_GAIN
);
1042 v4l2_ctrl_new_custom(&ipipeif
->ctrls
, &vpfe_ipipeif_dpcm_pred
, NULL
);
1043 v4l2_ctrl_handler_setup(&ipipeif
->ctrls
);
1044 sd
->ctrl_handler
= &ipipeif
->ctrls
;
1046 ipipeif
->video_in
.ops
= &video_in_ops
;
1047 ipipeif
->video_in
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
1048 ret
= vpfe_video_init(&ipipeif
->video_in
, "IPIPEIF");
1050 pr_err("Failed to init IPIPEIF video-in device\n");
1053 ipipeif_set_default_config(ipipeif
);
1056 release_mem_region(res
->start
, res_len
);
1061 vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device
*ipipeif
,
1062 struct platform_device
*pdev
)
1064 struct resource
*res
;
1066 v4l2_ctrl_handler_free(&ipipeif
->ctrls
);
1067 iounmap(ipipeif
->ipipeif_base_addr
);
1068 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 3);
1070 release_mem_region(res
->start
, resource_size(res
));