2 * TI OMAP4 ISS V4L2 Driver - ISP RESIZER module
4 * Copyright (C) 2012 Texas Instruments, Inc.
6 * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include <linux/module.h>
15 #include <linux/uaccess.h>
16 #include <linux/delay.h>
17 #include <linux/device.h>
18 #include <linux/dma-mapping.h>
20 #include <linux/sched.h>
24 #include "iss_resizer.h"
26 static const unsigned int resizer_fmts
[] = {
27 MEDIA_BUS_FMT_UYVY8_1X16
,
28 MEDIA_BUS_FMT_YUYV8_1X16
,
32 * resizer_print_status - Print current RESIZER Module register values.
33 * @resizer: Pointer to ISS ISP RESIZER device.
35 * Also prints other debug information stored in the RESIZER module.
37 #define RSZ_PRINT_REGISTER(iss, name)\
38 dev_dbg(iss->dev, "###RSZ " #name "=0x%08x\n", \
39 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_##name))
41 #define RZA_PRINT_REGISTER(iss, name)\
42 dev_dbg(iss->dev, "###RZA " #name "=0x%08x\n", \
43 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_##name))
45 static void resizer_print_status(struct iss_resizer_device
*resizer
)
47 struct iss_device
*iss
= to_iss_device(resizer
);
49 dev_dbg(iss
->dev
, "-------------RESIZER Register dump-------------\n");
51 RSZ_PRINT_REGISTER(iss
, SYSCONFIG
);
52 RSZ_PRINT_REGISTER(iss
, IN_FIFO_CTRL
);
53 RSZ_PRINT_REGISTER(iss
, FRACDIV
);
54 RSZ_PRINT_REGISTER(iss
, SRC_EN
);
55 RSZ_PRINT_REGISTER(iss
, SRC_MODE
);
56 RSZ_PRINT_REGISTER(iss
, SRC_FMT0
);
57 RSZ_PRINT_REGISTER(iss
, SRC_FMT1
);
58 RSZ_PRINT_REGISTER(iss
, SRC_VPS
);
59 RSZ_PRINT_REGISTER(iss
, SRC_VSZ
);
60 RSZ_PRINT_REGISTER(iss
, SRC_HPS
);
61 RSZ_PRINT_REGISTER(iss
, SRC_HSZ
);
62 RSZ_PRINT_REGISTER(iss
, DMA_RZA
);
63 RSZ_PRINT_REGISTER(iss
, DMA_RZB
);
64 RSZ_PRINT_REGISTER(iss
, DMA_STA
);
65 RSZ_PRINT_REGISTER(iss
, GCK_MMR
);
66 RSZ_PRINT_REGISTER(iss
, GCK_SDR
);
67 RSZ_PRINT_REGISTER(iss
, IRQ_RZA
);
68 RSZ_PRINT_REGISTER(iss
, IRQ_RZB
);
69 RSZ_PRINT_REGISTER(iss
, YUV_Y_MIN
);
70 RSZ_PRINT_REGISTER(iss
, YUV_Y_MAX
);
71 RSZ_PRINT_REGISTER(iss
, YUV_C_MIN
);
72 RSZ_PRINT_REGISTER(iss
, YUV_C_MAX
);
73 RSZ_PRINT_REGISTER(iss
, SEQ
);
75 RZA_PRINT_REGISTER(iss
, EN
);
76 RZA_PRINT_REGISTER(iss
, MODE
);
77 RZA_PRINT_REGISTER(iss
, 420);
78 RZA_PRINT_REGISTER(iss
, I_VPS
);
79 RZA_PRINT_REGISTER(iss
, I_HPS
);
80 RZA_PRINT_REGISTER(iss
, O_VSZ
);
81 RZA_PRINT_REGISTER(iss
, O_HSZ
);
82 RZA_PRINT_REGISTER(iss
, V_PHS_Y
);
83 RZA_PRINT_REGISTER(iss
, V_PHS_C
);
84 RZA_PRINT_REGISTER(iss
, V_DIF
);
85 RZA_PRINT_REGISTER(iss
, V_TYP
);
86 RZA_PRINT_REGISTER(iss
, V_LPF
);
87 RZA_PRINT_REGISTER(iss
, H_PHS
);
88 RZA_PRINT_REGISTER(iss
, H_DIF
);
89 RZA_PRINT_REGISTER(iss
, H_TYP
);
90 RZA_PRINT_REGISTER(iss
, H_LPF
);
91 RZA_PRINT_REGISTER(iss
, DWN_EN
);
92 RZA_PRINT_REGISTER(iss
, SDR_Y_BAD_H
);
93 RZA_PRINT_REGISTER(iss
, SDR_Y_BAD_L
);
94 RZA_PRINT_REGISTER(iss
, SDR_Y_SAD_H
);
95 RZA_PRINT_REGISTER(iss
, SDR_Y_SAD_L
);
96 RZA_PRINT_REGISTER(iss
, SDR_Y_OFT
);
97 RZA_PRINT_REGISTER(iss
, SDR_Y_PTR_S
);
98 RZA_PRINT_REGISTER(iss
, SDR_Y_PTR_E
);
99 RZA_PRINT_REGISTER(iss
, SDR_C_BAD_H
);
100 RZA_PRINT_REGISTER(iss
, SDR_C_BAD_L
);
101 RZA_PRINT_REGISTER(iss
, SDR_C_SAD_H
);
102 RZA_PRINT_REGISTER(iss
, SDR_C_SAD_L
);
103 RZA_PRINT_REGISTER(iss
, SDR_C_OFT
);
104 RZA_PRINT_REGISTER(iss
, SDR_C_PTR_S
);
105 RZA_PRINT_REGISTER(iss
, SDR_C_PTR_E
);
107 dev_dbg(iss
->dev
, "-----------------------------------------------\n");
111 * resizer_enable - Enable/Disable RESIZER.
112 * @enable: enable flag
115 static void resizer_enable(struct iss_resizer_device
*resizer
, u8 enable
)
117 struct iss_device
*iss
= to_iss_device(resizer
);
119 iss_reg_update(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_EN
,
120 RSZ_SRC_EN_SRC_EN
, enable
? RSZ_SRC_EN_SRC_EN
: 0);
122 /* TODO: Enable RSZB */
123 iss_reg_update(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_EN
, RSZ_EN_EN
,
124 enable
? RSZ_EN_EN
: 0);
127 /* -----------------------------------------------------------------------------
128 * Format- and pipeline-related configuration helpers
132 * resizer_set_outaddr - Set memory address to save output image
133 * @resizer: Pointer to ISP RESIZER device.
134 * @addr: 32-bit memory address aligned on 32 byte boundary.
136 * Sets the memory address where the output will be saved.
138 static void resizer_set_outaddr(struct iss_resizer_device
*resizer
, u32 addr
)
140 struct iss_device
*iss
= to_iss_device(resizer
);
141 struct v4l2_mbus_framefmt
*informat
, *outformat
;
143 informat
= &resizer
->formats
[RESIZER_PAD_SINK
];
144 outformat
= &resizer
->formats
[RESIZER_PAD_SOURCE_MEM
];
146 /* Save address split in Base Address H & L */
147 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_BAD_H
,
148 (addr
>> 16) & 0xffff);
149 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_BAD_L
,
153 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_SAD_H
,
154 (addr
>> 16) & 0xffff);
155 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_SAD_L
,
158 /* Program UV buffer address... Hardcoded to be contiguous! */
159 if ((informat
->code
== MEDIA_BUS_FMT_UYVY8_1X16
) &&
160 (outformat
->code
== MEDIA_BUS_FMT_YUYV8_1_5X8
)) {
161 u32 c_addr
= addr
+ resizer
->video_out
.bpl_value
164 /* Ensure Y_BAD_L[6:0] = C_BAD_L[6:0]*/
165 if ((c_addr
^ addr
) & 0x7f) {
168 c_addr
|= addr
& 0x7f;
171 /* Save address split in Base Address H & L */
172 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_BAD_H
,
173 (c_addr
>> 16) & 0xffff);
174 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_BAD_L
,
178 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_SAD_H
,
179 (c_addr
>> 16) & 0xffff);
180 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_SAD_L
,
185 static void resizer_configure(struct iss_resizer_device
*resizer
)
187 struct iss_device
*iss
= to_iss_device(resizer
);
188 struct v4l2_mbus_framefmt
*informat
, *outformat
;
190 informat
= &resizer
->formats
[RESIZER_PAD_SINK
];
191 outformat
= &resizer
->formats
[RESIZER_PAD_SOURCE_MEM
];
193 /* Disable pass-through more. Despite its name, the BYPASS bit controls
194 * pass-through mode, not bypass mode.
196 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_FMT0
,
197 RSZ_SRC_FMT0_BYPASS
);
199 /* Select RSZ input */
200 iss_reg_update(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_FMT0
,
202 resizer
->input
== RESIZER_INPUT_IPIPEIF
?
203 RSZ_SRC_FMT0_SEL
: 0);
205 /* RSZ ignores WEN signal from IPIPE/IPIPEIF */
206 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_MODE
,
209 /* Set Resizer in free-running mode */
210 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_MODE
,
214 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_MODE
,
217 /* Set size related things now */
218 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_VPS
, 0);
219 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_HPS
, 0);
220 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_VSZ
,
221 informat
->height
- 2);
222 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SRC_HSZ
,
223 informat
->width
- 1);
225 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_I_VPS
, 0);
226 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_I_HPS
, 0);
228 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_O_VSZ
,
229 outformat
->height
- 2);
230 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_O_HSZ
,
231 outformat
->width
- 1);
233 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_V_DIF
, 0x100);
234 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_H_DIF
, 0x100);
236 /* Buffer output settings */
237 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_PTR_S
, 0);
238 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_PTR_E
,
239 outformat
->height
- 1);
241 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_Y_OFT
,
242 resizer
->video_out
.bpl_value
);
244 /* UYVY -> NV12 conversion */
245 if ((informat
->code
== MEDIA_BUS_FMT_UYVY8_1X16
) &&
246 (outformat
->code
== MEDIA_BUS_FMT_YUYV8_1_5X8
)) {
247 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_420
,
248 RSZ_420_CEN
| RSZ_420_YEN
);
250 /* UV Buffer output settings */
251 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_PTR_S
,
253 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_PTR_E
,
254 outformat
->height
- 1);
256 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_SDR_C_OFT
,
257 resizer
->video_out
.bpl_value
);
259 iss_reg_write(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RZA_420
, 0);
263 /* -----------------------------------------------------------------------------
267 static void resizer_isr_buffer(struct iss_resizer_device
*resizer
)
269 struct iss_buffer
*buffer
;
271 /* The whole resizer needs to be stopped. Disabling RZA only produces
272 * input FIFO overflows, most probably when the next frame is received.
274 resizer_enable(resizer
, 0);
276 buffer
= omap4iss_video_buffer_next(&resizer
->video_out
);
280 resizer_set_outaddr(resizer
, buffer
->iss_addr
);
282 resizer_enable(resizer
, 1);
286 * omap4iss_resizer_isr - Configure resizer during interframe time.
287 * @resizer: Pointer to ISP RESIZER device.
288 * @events: RESIZER events
290 void omap4iss_resizer_isr(struct iss_resizer_device
*resizer
, u32 events
)
292 struct iss_device
*iss
= to_iss_device(resizer
);
293 struct iss_pipeline
*pipe
=
294 to_iss_pipeline(&resizer
->subdev
.entity
);
296 if (events
& (ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR
|
297 ISP5_IRQ_RSZ_FIFO_OVF
)) {
298 dev_dbg(iss
->dev
, "RSZ Err: FIFO_IN_BLK:%d, FIFO_OVF:%d\n",
299 events
& ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR
? 1 : 0,
300 events
& ISP5_IRQ_RSZ_FIFO_OVF
? 1 : 0);
301 omap4iss_pipeline_cancel_stream(pipe
);
304 if (omap4iss_module_sync_is_stopping(&resizer
->wait
,
308 if (events
& ISP5_IRQ_RSZ_INT_DMA
)
309 resizer_isr_buffer(resizer
);
312 /* -----------------------------------------------------------------------------
313 * ISS video operations
316 static int resizer_video_queue(struct iss_video
*video
,
317 struct iss_buffer
*buffer
)
319 struct iss_resizer_device
*resizer
= container_of(video
,
320 struct iss_resizer_device
, video_out
);
322 if (!(resizer
->output
& RESIZER_OUTPUT_MEMORY
))
325 resizer_set_outaddr(resizer
, buffer
->iss_addr
);
328 * If streaming was enabled before there was a buffer queued
329 * or underrun happened in the ISR, the hardware was not enabled
330 * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set.
333 if (video
->dmaqueue_flags
& ISS_VIDEO_DMAQUEUE_UNDERRUN
) {
334 resizer_enable(resizer
, 1);
335 iss_video_dmaqueue_flags_clr(video
);
341 static const struct iss_video_operations resizer_video_ops
= {
342 .queue
= resizer_video_queue
,
345 /* -----------------------------------------------------------------------------
346 * V4L2 subdev operations
350 * resizer_set_stream - Enable/Disable streaming on the RESIZER module
351 * @sd: ISP RESIZER V4L2 subdevice
352 * @enable: Enable/disable stream
354 static int resizer_set_stream(struct v4l2_subdev
*sd
, int enable
)
356 struct iss_resizer_device
*resizer
= v4l2_get_subdevdata(sd
);
357 struct iss_device
*iss
= to_iss_device(resizer
);
358 struct iss_video
*video_out
= &resizer
->video_out
;
361 if (resizer
->state
== ISS_PIPELINE_STREAM_STOPPED
) {
362 if (enable
== ISS_PIPELINE_STREAM_STOPPED
)
365 omap4iss_isp_subclk_enable(iss
, OMAP4_ISS_ISP_SUBCLK_RSZ
);
367 iss_reg_set(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_GCK_MMR
,
369 iss_reg_set(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_GCK_SDR
,
372 /* FIXME: Enable RSZB also */
373 iss_reg_set(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SYSCONFIG
,
374 RSZ_SYSCONFIG_RSZA_CLK_EN
);
378 case ISS_PIPELINE_STREAM_CONTINUOUS
:
380 resizer_configure(resizer
);
381 resizer_print_status(resizer
);
384 * When outputting to memory with no buffer available, let the
385 * buffer queue handler start the hardware. A DMA queue flag
386 * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
387 * a buffer available.
389 if (resizer
->output
& RESIZER_OUTPUT_MEMORY
&&
390 !(video_out
->dmaqueue_flags
& ISS_VIDEO_DMAQUEUE_QUEUED
))
393 atomic_set(&resizer
->stopping
, 0);
394 resizer_enable(resizer
, 1);
395 iss_video_dmaqueue_flags_clr(video_out
);
398 case ISS_PIPELINE_STREAM_STOPPED
:
399 if (resizer
->state
== ISS_PIPELINE_STREAM_STOPPED
)
401 if (omap4iss_module_sync_idle(&sd
->entity
, &resizer
->wait
,
405 resizer_enable(resizer
, 0);
406 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_SYSCONFIG
,
407 RSZ_SYSCONFIG_RSZA_CLK_EN
);
408 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_GCK_SDR
,
410 iss_reg_clr(iss
, OMAP4_ISS_MEM_ISP_RESIZER
, RSZ_GCK_MMR
,
412 omap4iss_isp_subclk_disable(iss
, OMAP4_ISS_ISP_SUBCLK_RSZ
);
413 iss_video_dmaqueue_flags_clr(video_out
);
417 resizer
->state
= enable
;
421 static struct v4l2_mbus_framefmt
*
422 __resizer_get_format(struct iss_resizer_device
*resizer
,
423 struct v4l2_subdev_pad_config
*cfg
, unsigned int pad
,
424 enum v4l2_subdev_format_whence which
)
426 if (which
== V4L2_SUBDEV_FORMAT_TRY
)
427 return v4l2_subdev_get_try_format(&resizer
->subdev
, cfg
, pad
);
428 return &resizer
->formats
[pad
];
432 * resizer_try_format - Try video format on a pad
433 * @resizer: ISS RESIZER device
434 * @cfg: V4L2 subdev pad config
439 resizer_try_format(struct iss_resizer_device
*resizer
,
440 struct v4l2_subdev_pad_config
*cfg
, unsigned int pad
,
441 struct v4l2_mbus_framefmt
*fmt
,
442 enum v4l2_subdev_format_whence which
)
445 struct v4l2_mbus_framefmt
*format
;
446 unsigned int width
= fmt
->width
;
447 unsigned int height
= fmt
->height
;
451 case RESIZER_PAD_SINK
:
452 for (i
= 0; i
< ARRAY_SIZE(resizer_fmts
); i
++) {
453 if (fmt
->code
== resizer_fmts
[i
])
457 /* If not found, use UYVY as default */
458 if (i
>= ARRAY_SIZE(resizer_fmts
))
459 fmt
->code
= MEDIA_BUS_FMT_UYVY8_1X16
;
461 /* Clamp the input size. */
462 fmt
->width
= clamp_t(u32
, width
, 1, 8192);
463 fmt
->height
= clamp_t(u32
, height
, 1, 8192);
466 case RESIZER_PAD_SOURCE_MEM
:
467 pixelcode
= fmt
->code
;
468 format
= __resizer_get_format(resizer
, cfg
, RESIZER_PAD_SINK
,
470 memcpy(fmt
, format
, sizeof(*fmt
));
472 if ((pixelcode
== MEDIA_BUS_FMT_YUYV8_1_5X8
) &&
473 (fmt
->code
== MEDIA_BUS_FMT_UYVY8_1X16
))
474 fmt
->code
= pixelcode
;
476 /* The data formatter truncates the number of horizontal output
477 * pixels to a multiple of 16. To avoid clipping data, allow
478 * callers to request an output size bigger than the input size
479 * up to the nearest multiple of 16.
481 fmt
->width
= clamp_t(u32
, width
, 32, (fmt
->width
+ 15) & ~15);
483 fmt
->height
= clamp_t(u32
, height
, 32, fmt
->height
);
487 fmt
->colorspace
= V4L2_COLORSPACE_JPEG
;
488 fmt
->field
= V4L2_FIELD_NONE
;
492 * resizer_enum_mbus_code - Handle pixel format enumeration
493 * @sd : pointer to v4l2 subdev structure
494 * @cfg: V4L2 subdev pad config
495 * @code : pointer to v4l2_subdev_mbus_code_enum structure
496 * return -EINVAL or zero on success
498 static int resizer_enum_mbus_code(struct v4l2_subdev
*sd
,
499 struct v4l2_subdev_pad_config
*cfg
,
500 struct v4l2_subdev_mbus_code_enum
*code
)
502 struct iss_resizer_device
*resizer
= v4l2_get_subdevdata(sd
);
503 struct v4l2_mbus_framefmt
*format
;
506 case RESIZER_PAD_SINK
:
507 if (code
->index
>= ARRAY_SIZE(resizer_fmts
))
510 code
->code
= resizer_fmts
[code
->index
];
513 case RESIZER_PAD_SOURCE_MEM
:
514 format
= __resizer_get_format(resizer
, cfg
, RESIZER_PAD_SINK
,
517 if (code
->index
== 0) {
518 code
->code
= format
->code
;
522 switch (format
->code
) {
523 case MEDIA_BUS_FMT_UYVY8_1X16
:
524 if (code
->index
== 1)
525 code
->code
= MEDIA_BUS_FMT_YUYV8_1_5X8
;
530 if (code
->index
!= 0)
543 static int resizer_enum_frame_size(struct v4l2_subdev
*sd
,
544 struct v4l2_subdev_pad_config
*cfg
,
545 struct v4l2_subdev_frame_size_enum
*fse
)
547 struct iss_resizer_device
*resizer
= v4l2_get_subdevdata(sd
);
548 struct v4l2_mbus_framefmt format
;
553 format
.code
= fse
->code
;
556 resizer_try_format(resizer
, cfg
, fse
->pad
, &format
, fse
->which
);
557 fse
->min_width
= format
.width
;
558 fse
->min_height
= format
.height
;
560 if (format
.code
!= fse
->code
)
563 format
.code
= fse
->code
;
566 resizer_try_format(resizer
, cfg
, fse
->pad
, &format
, fse
->which
);
567 fse
->max_width
= format
.width
;
568 fse
->max_height
= format
.height
;
574 * resizer_get_format - Retrieve the video format on a pad
575 * @sd : ISP RESIZER V4L2 subdevice
576 * @cfg: V4L2 subdev pad config
579 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
580 * to the format type.
582 static int resizer_get_format(struct v4l2_subdev
*sd
,
583 struct v4l2_subdev_pad_config
*cfg
,
584 struct v4l2_subdev_format
*fmt
)
586 struct iss_resizer_device
*resizer
= v4l2_get_subdevdata(sd
);
587 struct v4l2_mbus_framefmt
*format
;
589 format
= __resizer_get_format(resizer
, cfg
, fmt
->pad
, fmt
->which
);
593 fmt
->format
= *format
;
598 * resizer_set_format - Set the video format on a pad
599 * @sd : ISP RESIZER V4L2 subdevice
600 * @cfg: V4L2 subdev pad config
603 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
604 * to the format type.
606 static int resizer_set_format(struct v4l2_subdev
*sd
,
607 struct v4l2_subdev_pad_config
*cfg
,
608 struct v4l2_subdev_format
*fmt
)
610 struct iss_resizer_device
*resizer
= v4l2_get_subdevdata(sd
);
611 struct v4l2_mbus_framefmt
*format
;
613 format
= __resizer_get_format(resizer
, cfg
, fmt
->pad
, fmt
->which
);
617 resizer_try_format(resizer
, cfg
, fmt
->pad
, &fmt
->format
, fmt
->which
);
618 *format
= fmt
->format
;
620 /* Propagate the format from sink to source */
621 if (fmt
->pad
== RESIZER_PAD_SINK
) {
622 format
= __resizer_get_format(resizer
, cfg
,
623 RESIZER_PAD_SOURCE_MEM
,
625 *format
= fmt
->format
;
626 resizer_try_format(resizer
, cfg
, RESIZER_PAD_SOURCE_MEM
, format
,
633 static int resizer_link_validate(struct v4l2_subdev
*sd
,
634 struct media_link
*link
,
635 struct v4l2_subdev_format
*source_fmt
,
636 struct v4l2_subdev_format
*sink_fmt
)
638 /* Check if the two ends match */
639 if (source_fmt
->format
.width
!= sink_fmt
->format
.width
||
640 source_fmt
->format
.height
!= sink_fmt
->format
.height
)
643 if (source_fmt
->format
.code
!= sink_fmt
->format
.code
)
650 * resizer_init_formats - Initialize formats on all pads
651 * @sd: ISP RESIZER V4L2 subdevice
652 * @fh: V4L2 subdev file handle
654 * Initialize all pad formats with default values. If fh is not NULL, try
655 * formats are initialized on the file handle. Otherwise active formats are
656 * initialized on the device.
658 static int resizer_init_formats(struct v4l2_subdev
*sd
,
659 struct v4l2_subdev_fh
*fh
)
661 struct v4l2_subdev_format format
;
663 memset(&format
, 0, sizeof(format
));
664 format
.pad
= RESIZER_PAD_SINK
;
665 format
.which
= fh
? V4L2_SUBDEV_FORMAT_TRY
: V4L2_SUBDEV_FORMAT_ACTIVE
;
666 format
.format
.code
= MEDIA_BUS_FMT_UYVY8_1X16
;
667 format
.format
.width
= 4096;
668 format
.format
.height
= 4096;
669 resizer_set_format(sd
, fh
? fh
->pad
: NULL
, &format
);
674 /* V4L2 subdev video operations */
675 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops
= {
676 .s_stream
= resizer_set_stream
,
679 /* V4L2 subdev pad operations */
680 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops
= {
681 .enum_mbus_code
= resizer_enum_mbus_code
,
682 .enum_frame_size
= resizer_enum_frame_size
,
683 .get_fmt
= resizer_get_format
,
684 .set_fmt
= resizer_set_format
,
685 .link_validate
= resizer_link_validate
,
688 /* V4L2 subdev operations */
689 static const struct v4l2_subdev_ops resizer_v4l2_ops
= {
690 .video
= &resizer_v4l2_video_ops
,
691 .pad
= &resizer_v4l2_pad_ops
,
694 /* V4L2 subdev internal operations */
695 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops
= {
696 .open
= resizer_init_formats
,
699 /* -----------------------------------------------------------------------------
700 * Media entity operations
704 * resizer_link_setup - Setup RESIZER connections
705 * @entity: RESIZER media entity
706 * @local: Pad at the local end of the link
707 * @remote: Pad at the remote end of the link
710 * return -EINVAL or zero on success
712 static int resizer_link_setup(struct media_entity
*entity
,
713 const struct media_pad
*local
,
714 const struct media_pad
*remote
, u32 flags
)
716 struct v4l2_subdev
*sd
= media_entity_to_v4l2_subdev(entity
);
717 struct iss_resizer_device
*resizer
= v4l2_get_subdevdata(sd
);
718 struct iss_device
*iss
= to_iss_device(resizer
);
720 switch (local
->index
| media_entity_type(remote
->entity
)) {
721 case RESIZER_PAD_SINK
| MEDIA_ENT_T_V4L2_SUBDEV
:
722 /* Read from IPIPE or IPIPEIF. */
723 if (!(flags
& MEDIA_LNK_FL_ENABLED
)) {
724 resizer
->input
= RESIZER_INPUT_NONE
;
728 if (resizer
->input
!= RESIZER_INPUT_NONE
)
731 if (remote
->entity
== &iss
->ipipeif
.subdev
.entity
)
732 resizer
->input
= RESIZER_INPUT_IPIPEIF
;
733 else if (remote
->entity
== &iss
->ipipe
.subdev
.entity
)
734 resizer
->input
= RESIZER_INPUT_IPIPE
;
738 case RESIZER_PAD_SOURCE_MEM
| MEDIA_ENT_T_DEVNODE
:
739 /* Write to memory */
740 if (flags
& MEDIA_LNK_FL_ENABLED
) {
741 if (resizer
->output
& ~RESIZER_OUTPUT_MEMORY
)
743 resizer
->output
|= RESIZER_OUTPUT_MEMORY
;
745 resizer
->output
&= ~RESIZER_OUTPUT_MEMORY
;
756 /* media operations */
757 static const struct media_entity_operations resizer_media_ops
= {
758 .link_setup
= resizer_link_setup
,
759 .link_validate
= v4l2_subdev_link_validate
,
763 * resizer_init_entities - Initialize V4L2 subdev and media entity
764 * @resizer: ISS ISP RESIZER module
766 * Return 0 on success and a negative error code on failure.
768 static int resizer_init_entities(struct iss_resizer_device
*resizer
)
770 struct v4l2_subdev
*sd
= &resizer
->subdev
;
771 struct media_pad
*pads
= resizer
->pads
;
772 struct media_entity
*me
= &sd
->entity
;
775 resizer
->input
= RESIZER_INPUT_NONE
;
777 v4l2_subdev_init(sd
, &resizer_v4l2_ops
);
778 sd
->internal_ops
= &resizer_v4l2_internal_ops
;
779 strlcpy(sd
->name
, "OMAP4 ISS ISP resizer", sizeof(sd
->name
));
780 sd
->grp_id
= 1 << 16; /* group ID for iss subdevs */
781 v4l2_set_subdevdata(sd
, resizer
);
782 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
784 pads
[RESIZER_PAD_SINK
].flags
= MEDIA_PAD_FL_SINK
;
785 pads
[RESIZER_PAD_SOURCE_MEM
].flags
= MEDIA_PAD_FL_SOURCE
;
787 me
->ops
= &resizer_media_ops
;
788 ret
= media_entity_init(me
, RESIZER_PADS_NUM
, pads
);
792 resizer_init_formats(sd
, NULL
);
794 resizer
->video_out
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
795 resizer
->video_out
.ops
= &resizer_video_ops
;
796 resizer
->video_out
.iss
= to_iss_device(resizer
);
797 resizer
->video_out
.capture_mem
= PAGE_ALIGN(4096 * 4096) * 3;
798 resizer
->video_out
.bpl_alignment
= 32;
799 resizer
->video_out
.bpl_zero_padding
= 1;
800 resizer
->video_out
.bpl_max
= 0x1ffe0;
802 ret
= omap4iss_video_init(&resizer
->video_out
, "ISP resizer a");
806 /* Connect the RESIZER subdev to the video node. */
807 ret
= media_create_pad_link(&resizer
->subdev
.entity
,
808 RESIZER_PAD_SOURCE_MEM
,
809 &resizer
->video_out
.video
.entity
, 0, 0);
816 void omap4iss_resizer_unregister_entities(struct iss_resizer_device
*resizer
)
818 v4l2_device_unregister_subdev(&resizer
->subdev
);
819 omap4iss_video_unregister(&resizer
->video_out
);
822 int omap4iss_resizer_register_entities(struct iss_resizer_device
*resizer
,
823 struct v4l2_device
*vdev
)
827 /* Register the subdev and video node. */
828 ret
= v4l2_device_register_subdev(vdev
, &resizer
->subdev
);
832 ret
= omap4iss_video_register(&resizer
->video_out
, vdev
);
839 omap4iss_resizer_unregister_entities(resizer
);
843 /* -----------------------------------------------------------------------------
844 * ISP RESIZER initialisation and cleanup
848 * omap4iss_resizer_init - RESIZER module initialization.
849 * @iss: Device pointer specific to the OMAP4 ISS.
851 * TODO: Get the initialisation values from platform data.
853 * Return 0 on success or a negative error code otherwise.
855 int omap4iss_resizer_init(struct iss_device
*iss
)
857 struct iss_resizer_device
*resizer
= &iss
->resizer
;
859 resizer
->state
= ISS_PIPELINE_STREAM_STOPPED
;
860 init_waitqueue_head(&resizer
->wait
);
862 return resizer_init_entities(resizer
);
866 * omap4iss_resizer_cleanup - RESIZER module cleanup.
867 * @iss: Device pointer specific to the OMAP4 ISS.
869 void omap4iss_resizer_cleanup(struct iss_device
*iss
)
871 struct iss_resizer_device
*resizer
= &iss
->resizer
;
873 media_entity_cleanup(&resizer
->subdev
.entity
);