linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/8]  TV drivers for Samsung S5P platform (media part)
@ 2011-06-29 12:51 Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 1/8] v4l: add macro for 1080p59_54 preset Tomasz Stanislawski
                   ` (7 more replies)
  0 siblings, 8 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Hello,

I would like to present the 6th version of TV drivers for Samsung S5P platform.
The most recent changes are:

1. The patch for TV drivers was separated into three patches.
- one patch for HDMI and HDMIPHY driver
- two patches respectively for SDO and Mixer

2. Number of fixes after Hans Verkuil's review.
- code cleanup, fixed upside-down function order
- merged PAL standards for SDO driver
- added colorspace support
- fixed setting caps bits
- fixed return values on errors
- add usage of v4l2_fh framework
- reduced debugging control to simple on/off switch in Kconfig
- marked drivers as experimental due to usage of OVERLAY buffer
  for cropping configuration

3. New API features.
- support for VIDIOC_G_DV_PRESET
- support for VIDIOC_G_STD
- support for VIDIOC_G_OUTPUT
- support for PRIORITY api
- drivers passed v4l2-compliance tests

4. Other fixes
- fixed hang-up problem on pm_runtime resume caused by resetting mixer while
  its clock's parent was off. The problem is caused by incorrect clock
  modelling for Samsung S5P platform
- fixed calculations of multiplane related fields
- fix in v4l_fill_dv_preset_info function
- added new callbacks to v4l2_subdev: g_tvnorms_output, g_dv_preset,
  g_std_output

Updated RFC for TV driver:

==============
 Introduction
==============

The purpose of this RFC is to discuss the driver for a TV output interface
available in upcoming Samsung SoC. The HW is able to generate digital and
analog signals. Current version of the driver supports only digital output.

Internally the driver uses videobuf2 framework, and DMA-CONTIG memory allocator.

======================
 Hardware description
======================

The SoC contains a few HW sub-blocks:

1. Video Processor (VP). It is used for processing of NV12 data.  An image
stored in RAM is accessed by DMA. Pixels are cropped, scaled. Additionally,
post processing operations like brightness, sharpness and contrast adjustments
could be performed. The output in YCbCr444 format is send to Mixer.

2. Mixer (MXR). The piece of hardware responsible for mixing and blending
multiple data inputs before passing it to an output device.  The MXR is capable
of handling up to three image layers. One is the output of VP.  Other two are
images in RGB format (multiple variants are supported).  The layers are scaled,
cropped and blended with background color.  The blending factor, and layers'
priority are controlled by MXR's registers. The output is passed either to HDMI
or SDO.

3. HDMI. The piece of HW responsible for generation of HDMI packets. It takes
pixel data from mixer and transforms it into data frames. The output is send
to HDMIPHY interface.

4. HDMIPHY. Physical interface for HDMI. Its duties are sending HDMI packets to
HDMI connector. Basically, it contains a PLL that produces source clock for
Mixer, VP and HDMI during streaming.

5. SDO. Generation of TV analog signal. The alternative output for the Mixer.
It receives data and passes it to VideoDAC. The SDO is responsible for timing
generation of analog TV signal. It supports multiple standards.

6. VideoDAC. Modulator for TVOUT signal. Receives data from SDO. Converts
it to analog domain. Next, the signal is modulated to CVBS format, amplified
and sent to Composite Connector.

The diagram below depicts connection between all HW pieces.
                    +-----------+
NV12 data ---dma--->|   Video   |
                    | Processor |
                    +-----------+
                          |
                          V
                    +-----------+
RGB data  ---dma--->|           |
                    |   Mixer   |
RGB data  ---dma--->|           |
                    +-----------+
                          |
                          * dmux
                         /
                  +-----*   *------+
                  |                |
                  V                V
            +-----------+    +-----------+
            |    HDMI   |    |    SDO    |
            +-----------+    +-----------+
                  |                |
                  V                V
            +-----------+    +-----------+
            |  HDMIPHY  |    |  VideoDAC |
            +-----------+    +-----------+
                  |                |
                  V                V
                HDMI           Composite
             connector         connector


==================
 Driver interface
==================

The posted driver implements three V4L2 nodes. Every video node implements V4L2
output buffer. One of nodes corresponds to input of Video Processor. The other
two nodes correspond to RGB inputs of Mixer. All nodes share the same output.
It is one of the Mixer's outputs: SDO or HDMI. Changing output in one layer
using S_OUTPUT would change outputs of all other video nodes. The same thing
happens if one try to reconfigure output i.e. by calling S_DV_PRESET. However
it not possible to change or reconfigure the output while streaming. To sum up,
all features in posted version of driver goes as follows:

1. QUERYCAP
2. S_FMT, G_FMT - multiplanar API, single planar modes must be emulated
  a) node named video0 supports formats NV12, NV21, NV12T (tiled version of
NV12), NV12MT (multiplane version of NV12T).
  b) nodes named graph0 and graph1 support formats RGB565, ARGB1555, ARGB4444,
ARGB8888.
3. Buffer with USERPTR and MMAP memory.
4. Streaming and buffer control. (STREAMON, STREAMOFF, REQBUF, QBUF, DQBUF)
5. OUTPUT configurations and enumeration using VIDIOC_{ENUM/S/G}_OUTPUT.
6. DV preset control (SET, GET, ENUM). Currently modes 480P59_94, 720P59_94,
1080P30, 1080P59_94 and 1080P60 work.
7. Analog standards using VIDIOC_{S_/G_/ENUM}STD. Modes PAL_N, PAL_Nc, PAL_M,
   PAL_60, NTSC_443, PAL_BGHID, NTSC_M are supported.
8. Positioning layer's window on output display using S_CROP, G_GROP, CROPCAP.
9. Positioning and cropping data in buffer using S_CROP, G_GROP, CROPCAP with
buffer type OVERLAY *. This is temporary interface and it is going to be
substituted by SELECTION api.
10. Support for priority api: VIDIOC_{G/S}_PRIORITY

TODOs:
- add control of alpha blending / chroma keying via V4L2 controls
- add controls for luminance curve and sharpness in VP
- consider exporting all output functionalities to separate video node
- consider media controller framework

* The need of cropping in source buffers came from problem with MFC driver for
S5P. The MFC supports only width divisible by 64. If a width of a decoded movie
is not aligned do 64 then padding pixels are filled with zeros. This is an ugly
green color in YCbCr colorspace. Filling it with zeros by a CPU is a waste of
resources since an image can be cropped in VP. Is it possible to set crops for
user data for M2M devices. V4L2 lacks such functionality of non-M2M devices.
Therefore cropping in buffer V4L2_BUF_TYPE_VIDEO_OVERLAY was used as an work
around.

=====================
 Device Architecture
=====================

Three drivers are added in this patch.

1. HDMIPHY. It is an I2C driver for HDMIPHY interface. It exports following
callback by V4L2 subdevice:
- s_power: currently stub
- s_stream: configures and starts/stops HDMIPHY
- s_dv_preset: used to choose proper frequency of clock for other TV devices

2. HDMI. The auxiliary driver used to control HDMI interface. It exports its
subdev in its private data for use by other drivers. The following callbacks are
implemented:
- s_power: runs HDMI hardware, regulators and clocks.
- s_stream: runs HDMIPHY and starts generation of video frames.
- enum_dv_presets
- s_dv_preset
- g_dv_preset: returns current preset used by HDMI
- g_mbus_format: returns information on data format expected by on HDMI input
  The driver supports an interrupt. It is used to detect plug/unplug events in
kernel debugs.  The API for detection of such an events in V4L2 API is to be
defined.

3. SDO. The auxiliary driver used to control analog TV. It also exports its
subdev for other drivers. The following callbacks are implemented.
- s_power: runs TV hardware, regulators and clocks.
- s_stream: runs TV clock and starts generation of video signal.
- s_std_output: set configuration of TV standard from one of PAL/NTSC family
- g_std_output: get current configuration of TV standard
- g_tvnorms_output: used by Mixer to obtain tv standards supported by SDO
- g_mbus_format: returns information on data format expected by on SDO input

5. Mixer & Video Processor driver. It is called 's5p-mixer' because of
historical reasons. It was decided combine VP and MXR drivers into one because
of shared interrupt and very similar interface via V4L2 nodes. The driver is a
realization of many-to-many relation between multiple input layers and multiple
outputs. All shared resources are kept in struct mxr_device. It provides
utilities for management and synchronization of access to resources and
reference counting. The outputs are obtained from HDMI/SDO private data.  One
layer is a single video node. Simple inheritance is applied because there only
little difference between layer's types. Every layer type implements set of
ops. There are different ops for Mixer layers and other for VP layer.

The videobuf2 framework was used for the management of buffers and streaming.
All other V4L2 ioctls are processed in layers common interface. The DMA-COHERENT
was used as memory allocator for Mixer's buffers. It could be easily exchanged
with any other allocator integrated with videobuf2 framework.

===============
 Usage summary
===============

Follow steps below to display double-buffered animation on output.
In order to use other output please use VIDIOC_S_OUTPUT.

01. Open video node named graph0.
02. S_FMT(type = OUTPUT, pixelformat = V4L2_PIX_FMT_RGB*, width, height, ...)
03. REQ_BUFS(type = OUTPUT, memory = MMAP, count = 2)
04. MMAP(type = OUTPUT, index = 0)
05. MMAP(type = OUTPUT, index = 1)
06. Fill buffer 0 with data
07. QBUF(type = OUTPUT, index = 0)
08. STREAM_ON(type = OUTPUT)
09. Fill buffer 1 with data
10. QBUF(type = OUTPUT, index = 1)
11. DQBUF(type = OUTPUT)
12. QBUF(type = OUTPUT, index = 0)
13. DQBUF(type = OUTPUT)
14. Goto 09

===============
 Patch Summary
===============

Tomasz Stanislawski (8):
  v4l: add macro for 1080p59_54 preset
  v4l: add g_tvnorms_output callback to V4L2 subdev
  v4l: add g_dv_preset callback to V4L2 subdev
  v4l: add g_std_output callback to V4L2 subdev
  v4l: fix v4l_fill_dv_preset_info function
  v4l: s5p-tv: add drivers for HDMI on Samsung S5P platform
  v4l: s5p-tv: add SDO driver for Samsung S5P platform
  v4l: s5p-tv: add TV Mixer driver for Samsung S5P platform

 drivers/media/video/Kconfig                  |    2 +
 drivers/media/video/Makefile                 |    1 +
 drivers/media/video/s5p-tv/Kconfig           |   76 ++
 drivers/media/video/s5p-tv/Makefile          |   17 +
 drivers/media/video/s5p-tv/hdmi_drv.c        | 1043 ++++++++++++++++++++++++++
 drivers/media/video/s5p-tv/hdmiphy_drv.c     |  196 +++++
 drivers/media/video/s5p-tv/mixer.h           |  354 +++++++++
 drivers/media/video/s5p-tv/mixer_drv.c       |  487 ++++++++++++
 drivers/media/video/s5p-tv/mixer_grp_layer.c |  185 +++++
 drivers/media/video/s5p-tv/mixer_reg.c       |  541 +++++++++++++
 drivers/media/video/s5p-tv/mixer_video.c     | 1006 +++++++++++++++++++++++++
 drivers/media/video/s5p-tv/mixer_vp_layer.c  |  211 ++++++
 drivers/media/video/s5p-tv/regs-hdmi.h       |  141 ++++
 drivers/media/video/s5p-tv/regs-mixer.h      |  121 +++
 drivers/media/video/s5p-tv/regs-sdo.h        |   63 ++
 drivers/media/video/s5p-tv/regs-vp.h         |   88 +++
 drivers/media/video/s5p-tv/sdo_drv.c         |  479 ++++++++++++
 drivers/media/video/v4l2-common.c            |    3 +
 include/linux/videodev2.h                    |    1 +
 include/media/v4l2-subdev.h                  |   12 +
 20 files changed, 5027 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/s5p-tv/Kconfig
 create mode 100644 drivers/media/video/s5p-tv/Makefile
 create mode 100644 drivers/media/video/s5p-tv/hdmi_drv.c
 create mode 100644 drivers/media/video/s5p-tv/hdmiphy_drv.c
 create mode 100644 drivers/media/video/s5p-tv/mixer.h
 create mode 100644 drivers/media/video/s5p-tv/mixer_drv.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_grp_layer.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_reg.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_video.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_vp_layer.c
 create mode 100644 drivers/media/video/s5p-tv/regs-hdmi.h
 create mode 100644 drivers/media/video/s5p-tv/regs-mixer.h
 create mode 100644 drivers/media/video/s5p-tv/regs-sdo.h
 create mode 100644 drivers/media/video/s5p-tv/regs-vp.h
 create mode 100644 drivers/media/video/s5p-tv/sdo_drv.c

-- 
1.7.5.4

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-07-04 16:09   ` [RFC] DV timings spec fixes at V4L2 API - was: " Mauro Carvalho Chehab
  2011-06-29 12:51 ` [PATCH 2/8] v4l: add g_tvnorms_output callback to V4L2 subdev Tomasz Stanislawski
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

The 1080p59_94 is supported by latest Samsung SoC.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/video/v4l2-common.c |    1 +
 include/linux/videodev2.h         |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 06b9f9f..003e648 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -582,6 +582,7 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
 		{ 1920, 1080, "1080p@30" },	/* V4L2_DV_1080P30 */
 		{ 1920, 1080, "1080p@50" },	/* V4L2_DV_1080P50 */
 		{ 1920, 1080, "1080p@60" },	/* V4L2_DV_1080P60 */
+		{ 1920, 1080, "1080p@59.94" },	/* V4L2_DV_1080P59_94 */
 	};
 
 	if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 8a4c309..7c77c4e 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -872,6 +872,7 @@ struct v4l2_dv_enum_preset {
 #define		V4L2_DV_1080P30		16 /* SMPTE 296M */
 #define		V4L2_DV_1080P50		17 /* BT.1120 */
 #define		V4L2_DV_1080P60		18 /* BT.1120 */
+#define		V4L2_DV_1080P59_94	19
 
 /*
  *	D V 	B T	T I M I N G S
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 2/8] v4l: add g_tvnorms_output callback to V4L2 subdev
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 1/8] v4l: add macro for 1080p59_54 preset Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 3/8] v4l: add g_dv_preset " Tomasz Stanislawski
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Callback is used to acquire TV norms supported by a subdev.
It is used to avoid having standards in top-level driver.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 include/media/v4l2-subdev.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 1562c4f..476fcdd 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -225,6 +225,9 @@ struct v4l2_subdev_audio_ops {
    s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
 	video input devices.
 
+   g_tvnorms_output: get v4l2_std_id with all standards supported by video
+	OUTPUT device. This is ignored by video input devices.
+
    s_crystal_freq: sets the frequency of the crystal used to generate the
 	clocks in Hz. An extra flags field allows device specific configuration
 	regarding clock frequency dividers, etc. If not used, then set flags
@@ -261,6 +264,7 @@ struct v4l2_subdev_video_ops {
 	int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
 	int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
 	int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
+	int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
 	int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
 	int (*s_stream)(struct v4l2_subdev *sd, int enable);
 	int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 3/8] v4l: add g_dv_preset callback to V4L2 subdev
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 1/8] v4l: add macro for 1080p59_54 preset Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 2/8] v4l: add g_tvnorms_output callback to V4L2 subdev Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 4/8] v4l: add g_std_output " Tomasz Stanislawski
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Callback is used to acquire current digital video preset from a subdev.
It is used to avoid keeping dv preset in top-level driver.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 include/media/v4l2-subdev.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 476fcdd..af491a1 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -242,6 +242,8 @@ struct v4l2_subdev_audio_ops {
    s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to
 	s_std()
 
+   g_dv_preset: get current dv (Digital Video) preset in the sub device.
+
    query_dv_preset: query dv preset in the sub device. This is similar to
 	querystd()
 
@@ -282,6 +284,8 @@ struct v4l2_subdev_video_ops {
 			struct v4l2_dv_enum_preset *preset);
 	int (*s_dv_preset)(struct v4l2_subdev *sd,
 			struct v4l2_dv_preset *preset);
+	int (*g_dv_preset)(struct v4l2_subdev *sd,
+			struct v4l2_dv_preset *preset);
 	int (*query_dv_preset)(struct v4l2_subdev *sd,
 			struct v4l2_dv_preset *preset);
 	int (*s_dv_timings)(struct v4l2_subdev *sd,
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 4/8] v4l: add g_std_output callback to V4L2 subdev
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
                   ` (2 preceding siblings ...)
  2011-06-29 12:51 ` [PATCH 3/8] v4l: add g_dv_preset " Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 5/8] v4l: fix v4l_fill_dv_preset_info function Tomasz Stanislawski
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Callback is used to acquire current analog TV standard from a subdev.
It is used to avoid keeping current standard in top-level driver.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 include/media/v4l2-subdev.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index af491a1..fd9cdc6 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -225,6 +225,9 @@ struct v4l2_subdev_audio_ops {
    s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
 	video input devices.
 
+   g_std_output: get current standard for video OUTPUT devices. This is ignored
+	by video input devices.
+
    g_tvnorms_output: get v4l2_std_id with all standards supported by video
 	OUTPUT device. This is ignored by video input devices.
 
@@ -265,6 +268,7 @@ struct v4l2_subdev_video_ops {
 	int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
 	int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
 	int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
+	int (*g_std_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
 	int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
 	int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
 	int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5/8] v4l: fix v4l_fill_dv_preset_info function
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
                   ` (3 preceding siblings ...)
  2011-06-29 12:51 ` [PATCH 4/8] v4l: add g_std_output " Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-07-14 16:02   ` Mauro Carvalho Chehab
  2011-06-29 12:51 ` [PATCH 6/8] v4l: s5p-tv: add drivers for HDMI on Samsung S5P platform Tomasz Stanislawski
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

The function fills struct v4l2_dv_enum_preset with appropriate
preset parameters but it forgets to zero field named reserved.
This patch fixes this bug.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
---
 drivers/media/video/v4l2-common.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 003e648..e7c02e9 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -592,6 +592,8 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
 	info->width = dv_presets[preset].width;
 	info->height = dv_presets[preset].height;
 	strlcpy(info->name, dv_presets[preset].name, sizeof(info->name));
+	/* assure that reserved fields are zeroed */
+	memset(info->reserved, 0, sizeof(info->reserved));
 	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 6/8] v4l: s5p-tv: add drivers for HDMI on Samsung S5P platform
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
                   ` (4 preceding siblings ...)
  2011-06-29 12:51 ` [PATCH 5/8] v4l: fix v4l_fill_dv_preset_info function Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 7/8] v4l: s5p-tv: add SDO driver for " Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 8/8] v4l: s5p-tv: add TV Mixer " Tomasz Stanislawski
  7 siblings, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Add drivers for HDMI outputs on Samsung platforms from S5P family.
- HDMIPHY - auxiliary I2C driver need by HDMI driver
- HDMI    - generation and control of streaming by HDMI output

Drivers are using:
- v4l2 framework
- runtime PM

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/video/Kconfig              |    2 +
 drivers/media/video/Makefile             |    1 +
 drivers/media/video/s5p-tv/Kconfig       |   49 ++
 drivers/media/video/s5p-tv/Makefile      |   13 +
 drivers/media/video/s5p-tv/hdmi_drv.c    | 1043 ++++++++++++++++++++++++++++++
 drivers/media/video/s5p-tv/hdmiphy_drv.c |  196 ++++++
 drivers/media/video/s5p-tv/regs-hdmi.h   |  141 ++++
 7 files changed, 1445 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/s5p-tv/Kconfig
 create mode 100644 drivers/media/video/s5p-tv/Makefile
 create mode 100644 drivers/media/video/s5p-tv/hdmi_drv.c
 create mode 100644 drivers/media/video/s5p-tv/hdmiphy_drv.c
 create mode 100644 drivers/media/video/s5p-tv/regs-hdmi.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4847c2c..97a563f 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -954,6 +954,8 @@ config VIDEO_S5P_MIPI_CSIS
 	  To compile this driver as a module, choose M here: the
 	  module will be called s5p-csis.
 
+source "drivers/media/video/s5p-tv/Kconfig"
+
 #
 # USB Multimedia device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 89478f0..13c1082e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -169,6 +169,7 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP1)		+= omap1_camera.o
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) 	+= s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)	+= s5p-tv/
 
 obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
 
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
new file mode 100644
index 0000000..893be5b
--- /dev/null
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -0,0 +1,49 @@
+# drivers/media/video/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#	http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+config VIDEO_SAMSUNG_S5P_TV
+	bool "Samsung TV driver for S5P platform (experimental)"
+	depends on PLAT_S5P
+	depends on EXPERIMENTAL
+	default n
+	---help---
+	  Say Y here to enable selecting the TV output devices for
+	  Samsung S5P platform.
+
+if VIDEO_SAMSUNG_S5P_TV
+
+config VIDEO_SAMSUNG_S5P_HDMI
+	tristate "Samsung HDMI Driver"
+	depends on VIDEO_V4L2
+	depends on VIDEO_SAMSUNG_S5P_TV
+	select VIDEO_SAMSUNG_S5P_HDMIPHY
+	help
+	  Say Y here if you want support for the HDMI output
+	  interface in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an auxiliary driver, that exposes a V4L2
+	  subdev for use by other drivers. This driver requires
+	  hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+	bool "Enable debug for HDMI Driver"
+	depends on VIDEO_SAMSUNG_S5P_HDMI
+	default n
+	help
+	  Enables debugging for HDMI driver.
+
+config VIDEO_SAMSUNG_S5P_HDMIPHY
+	tristate "Samsung HDMIPHY Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+	depends on VIDEO_SAMSUNG_S5P_TV
+	help
+	  Say Y here if you want support for the physical HDMI
+	  interface in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an I2C driver, that exposes a V4L2
+	  subdev for use by other drivers.
+
+endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
new file mode 100644
index 0000000..1b07132
--- /dev/null
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -0,0 +1,13 @@
+# drivers/media/video/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#	http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
+s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
+s5p-hdmi-y += hdmi_drv.o
+
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
new file mode 100644
index 0000000..e40dd4d
--- /dev/null
+++ b/drivers/media/video/s5p-tv/hdmi_drv.c
@@ -0,0 +1,1043 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+
+#include "regs-hdmi.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+
+struct hdmi_resources {
+	struct clk *hdmi;
+	struct clk *sclk_hdmi;
+	struct clk *sclk_pixel;
+	struct clk *sclk_hdmiphy;
+	struct clk *hdmiphy;
+	struct regulator_bulk_data *regul_bulk;
+	int regul_count;
+};
+
+struct hdmi_device {
+	/** base address of HDMI registers */
+	void __iomem *regs;
+	/** HDMI interrupt */
+	unsigned int irq;
+	/** pointer to device parent */
+	struct device *dev;
+	/** subdev generated by HDMI device */
+	struct v4l2_subdev sd;
+	/** V4L2 device structure */
+	struct v4l2_device v4l2_dev;
+	/** subdev of HDMIPHY interface */
+	struct v4l2_subdev *phy_sd;
+	/** configuration of current graphic mode */
+	const struct hdmi_preset_conf *cur_conf;
+	/** current preset */
+	u32 cur_preset;
+	/** other resources */
+	struct hdmi_resources res;
+};
+
+struct hdmi_driver_data {
+	int hdmiphy_bus;
+};
+
+struct hdmi_tg_regs {
+	u8 cmd;
+	u8 h_fsz_l;
+	u8 h_fsz_h;
+	u8 hact_st_l;
+	u8 hact_st_h;
+	u8 hact_sz_l;
+	u8 hact_sz_h;
+	u8 v_fsz_l;
+	u8 v_fsz_h;
+	u8 vsync_l;
+	u8 vsync_h;
+	u8 vsync2_l;
+	u8 vsync2_h;
+	u8 vact_st_l;
+	u8 vact_st_h;
+	u8 vact_sz_l;
+	u8 vact_sz_h;
+	u8 field_chg_l;
+	u8 field_chg_h;
+	u8 vact_st2_l;
+	u8 vact_st2_h;
+	u8 vsync_top_hdmi_l;
+	u8 vsync_top_hdmi_h;
+	u8 vsync_bot_hdmi_l;
+	u8 vsync_bot_hdmi_h;
+	u8 field_top_hdmi_l;
+	u8 field_top_hdmi_h;
+	u8 field_bot_hdmi_l;
+	u8 field_bot_hdmi_h;
+};
+
+struct hdmi_core_regs {
+	u8 h_blank[2];
+	u8 v_blank[3];
+	u8 h_v_line[3];
+	u8 vsync_pol[1];
+	u8 int_pro_mode[1];
+	u8 v_blank_f[3];
+	u8 h_sync_gen[3];
+	u8 v_sync_gen1[3];
+	u8 v_sync_gen2[3];
+	u8 v_sync_gen3[3];
+};
+
+struct hdmi_preset_conf {
+	struct hdmi_core_regs core;
+	struct hdmi_tg_regs tg;
+	struct v4l2_mbus_framefmt mbus_fmt;
+};
+
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+	I2C_BOARD_INFO("hdmiphy", 0x38),
+};
+
+static struct hdmi_driver_data hdmi_driver_data[] = {
+	{ .hdmiphy_bus = 3 },
+	{ .hdmiphy_bus = 8 },
+};
+
+static struct platform_device_id hdmi_driver_types[] = {
+	{
+		.name		= "s5pv210-hdmi",
+		.driver_data	= (unsigned long)&hdmi_driver_data[0],
+	}, {
+		.name		= "exynos4-hdmi",
+		.driver_data	= (unsigned long)&hdmi_driver_data[1],
+	}, {
+		/* end node */
+	}
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct hdmi_device, sd);
+}
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+	writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+	u32 old = readl(hdev->regs + reg_id);
+	value = (value & mask) | (old & ~mask);
+	writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+	writeb(value, hdev->regs + reg_id);
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+	return readl(hdev->regs + reg_id);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+	struct hdmi_device *hdev = dev_data;
+	u32 intc_flag;
+
+	(void)irq;
+	intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+	/* clearing flags for HPD plug/unplug */
+	if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+		printk(KERN_INFO "unplugged\n");
+		hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+			HDMI_INTC_FLAG_HPD_UNPLUG);
+	}
+	if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+		printk(KERN_INFO "plugged\n");
+		hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+			HDMI_INTC_FLAG_HPD_PLUG);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+	/* enable HPD interrupts */
+	hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+		HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+	/* choose HDMI mode */
+	hdmi_write_mask(hdev, HDMI_MODE_SEL,
+		HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+	/* disable bluescreen */
+	hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+	/* choose bluescreen (fecal) color */
+	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+	/* enable AVI packet every vsync, fixes purple line problem */
+	hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
+	/* force YUV444, look to CEA-861-D, table 7 for more detail */
+	hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
+	hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+	const struct hdmi_preset_conf *conf)
+{
+	const struct hdmi_core_regs *core = &conf->core;
+	const struct hdmi_tg_regs *tg = &conf->tg;
+
+	/* setting core registers */
+	hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+	hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+	hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
+	hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
+	hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
+	hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
+	hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
+	hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
+	hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+	hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+	hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
+	hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
+	hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
+	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
+	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
+	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
+	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+	/* Timing generator registers */
+	hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+	hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+	hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+	hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+	hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+	hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+	hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+	hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+	hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+	hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+	hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+	hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+	hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+	hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+	hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+	hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+	hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+	hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+	hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+	hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+	hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+}
+
+static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+	struct device *dev = hdmi_dev->dev;
+	const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+	struct v4l2_dv_preset preset;
+	int ret;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	/* reset hdmiphy */
+	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+	mdelay(10);
+	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+	mdelay(10);
+
+	/* configure presets */
+	preset.preset = hdmi_dev->cur_preset;
+	ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+	if (ret) {
+		dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+		return ret;
+	}
+
+	/* resetting HDMI core */
+	hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+	mdelay(10);
+	hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+	mdelay(10);
+
+	hdmi_reg_init(hdmi_dev);
+
+	/* setting core registers */
+	hdmi_timing_apply(hdmi_dev, conf);
+
+	return 0;
+}
+
+static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+	dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+		readl(hdev->regs + reg_id))
+
+	dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_INTC_FLAG);
+	DUMPREG(HDMI_INTC_CON);
+	DUMPREG(HDMI_HPD_STATUS);
+	DUMPREG(HDMI_PHY_RSTOUT);
+	DUMPREG(HDMI_PHY_VPLL);
+	DUMPREG(HDMI_PHY_CMU);
+	DUMPREG(HDMI_CORE_RSTOUT);
+
+	dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_CON_0);
+	DUMPREG(HDMI_CON_1);
+	DUMPREG(HDMI_CON_2);
+	DUMPREG(HDMI_SYS_STATUS);
+	DUMPREG(HDMI_PHY_STATUS);
+	DUMPREG(HDMI_STATUS_EN);
+	DUMPREG(HDMI_HPD);
+	DUMPREG(HDMI_MODE_SEL);
+	DUMPREG(HDMI_HPD_GEN);
+	DUMPREG(HDMI_DC_CONTROL);
+	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+	dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_H_BLANK_0);
+	DUMPREG(HDMI_H_BLANK_1);
+	DUMPREG(HDMI_V_BLANK_0);
+	DUMPREG(HDMI_V_BLANK_1);
+	DUMPREG(HDMI_V_BLANK_2);
+	DUMPREG(HDMI_H_V_LINE_0);
+	DUMPREG(HDMI_H_V_LINE_1);
+	DUMPREG(HDMI_H_V_LINE_2);
+	DUMPREG(HDMI_VSYNC_POL);
+	DUMPREG(HDMI_INT_PRO_MODE);
+	DUMPREG(HDMI_V_BLANK_F_0);
+	DUMPREG(HDMI_V_BLANK_F_1);
+	DUMPREG(HDMI_V_BLANK_F_2);
+	DUMPREG(HDMI_H_SYNC_GEN_0);
+	DUMPREG(HDMI_H_SYNC_GEN_1);
+	DUMPREG(HDMI_H_SYNC_GEN_2);
+	DUMPREG(HDMI_V_SYNC_GEN_1_0);
+	DUMPREG(HDMI_V_SYNC_GEN_1_1);
+	DUMPREG(HDMI_V_SYNC_GEN_1_2);
+	DUMPREG(HDMI_V_SYNC_GEN_2_0);
+	DUMPREG(HDMI_V_SYNC_GEN_2_1);
+	DUMPREG(HDMI_V_SYNC_GEN_2_2);
+	DUMPREG(HDMI_V_SYNC_GEN_3_0);
+	DUMPREG(HDMI_V_SYNC_GEN_3_1);
+	DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+	dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_TG_CMD);
+	DUMPREG(HDMI_TG_H_FSZ_L);
+	DUMPREG(HDMI_TG_H_FSZ_H);
+	DUMPREG(HDMI_TG_HACT_ST_L);
+	DUMPREG(HDMI_TG_HACT_ST_H);
+	DUMPREG(HDMI_TG_HACT_SZ_L);
+	DUMPREG(HDMI_TG_HACT_SZ_H);
+	DUMPREG(HDMI_TG_V_FSZ_L);
+	DUMPREG(HDMI_TG_V_FSZ_H);
+	DUMPREG(HDMI_TG_VSYNC_L);
+	DUMPREG(HDMI_TG_VSYNC_H);
+	DUMPREG(HDMI_TG_VSYNC2_L);
+	DUMPREG(HDMI_TG_VSYNC2_H);
+	DUMPREG(HDMI_TG_VACT_ST_L);
+	DUMPREG(HDMI_TG_VACT_ST_H);
+	DUMPREG(HDMI_TG_VACT_SZ_L);
+	DUMPREG(HDMI_TG_VACT_SZ_H);
+	DUMPREG(HDMI_TG_FIELD_CHG_L);
+	DUMPREG(HDMI_TG_FIELD_CHG_H);
+	DUMPREG(HDMI_TG_VACT_ST2_L);
+	DUMPREG(HDMI_TG_VACT_ST2_H);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
+
+static const struct hdmi_preset_conf hdmi_conf_480p = {
+	.core = {
+		.h_blank = {0x8a, 0x00},
+		.v_blank = {0x0d, 0x6a, 0x01},
+		.h_v_line = {0x0d, 0xa2, 0x35},
+		.vsync_pol = {0x01},
+		.int_pro_mode = {0x00},
+		.v_blank_f = {0x00, 0x00, 0x00},
+		.h_sync_gen = {0x0e, 0x30, 0x11},
+		.v_sync_gen1 = {0x0f, 0x90, 0x00},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x5a, 0x03, /* h_fsz */
+		0x8a, 0x00, 0xd0, 0x02, /* hact */
+		0x0d, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0xe0, 0x01, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+	},
+	.mbus_fmt = {
+		.width = 720,
+		.height = 480,
+		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+		.field = V4L2_FIELD_NONE,
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+	.core = {
+		.h_blank = {0x72, 0x01},
+		.v_blank = {0xee, 0xf2, 0x00},
+		.h_v_line = {0xee, 0x22, 0x67},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+		.h_sync_gen = {0x6c, 0x50, 0x02},
+		.v_sync_gen1 = {0x0a, 0x50, 0x00},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x72, 0x06, /* h_fsz */
+		0x72, 0x01, 0x00, 0x05, /* hact */
+		0xee, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x1e, 0x00, 0xd0, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+	},
+	.mbus_fmt = {
+		.width = 1280,
+		.height = 720,
+		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+		.field = V4L2_FIELD_NONE,
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+	.core = {
+		.h_blank = {0xd0, 0x02},
+		.v_blank = {0x65, 0x6c, 0x01},
+		.h_v_line = {0x65, 0x04, 0xa5},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+		.h_sync_gen = {0x0e, 0xea, 0x08},
+		.v_sync_gen1 = {0x09, 0x40, 0x00},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x98, 0x08, /* h_fsz */
+		0x18, 0x01, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0x38, 0x04, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+	},
+	.mbus_fmt = {
+		.width = 1920,
+		.height = 1080,
+		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+		.field = V4L2_FIELD_NONE,
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+	.core = {
+		.h_blank = {0x18, 0x01},
+		.v_blank = {0x65, 0x6c, 0x01},
+		.h_v_line = {0x65, 0x84, 0x89},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+		.h_sync_gen = {0x56, 0x08, 0x02},
+		.v_sync_gen1 = {0x09, 0x40, 0x00},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x98, 0x08, /* h_fsz */
+		0x18, 0x01, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0x38, 0x04, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+	},
+	.mbus_fmt = {
+		.width = 1920,
+		.height = 1080,
+		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+		.field = V4L2_FIELD_NONE,
+	},
+};
+
+static const struct {
+	u32 preset;
+	const struct hdmi_preset_conf *conf;
+} hdmi_conf[] = {
+	{ V4L2_DV_480P59_94, &hdmi_conf_480p },
+	{ V4L2_DV_720P59_94, &hdmi_conf_720p60 },
+	{ V4L2_DV_1080P50, &hdmi_conf_1080p50 },
+	{ V4L2_DV_1080P30, &hdmi_conf_1080p60 },
+	{ V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+	{ V4L2_DV_1080P59_94, &hdmi_conf_1080p60 },
+};
+
+static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
+		if (hdmi_conf[i].preset == preset)
+			return  hdmi_conf[i].conf;
+	return NULL;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+	struct device *dev = hdev->dev;
+	struct hdmi_resources *res = &hdev->res;
+	int ret, tries;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+	if (ret)
+		return ret;
+
+	/* waiting for HDMIPHY's PLL to get to steady state */
+	for (tries = 100; tries; --tries) {
+		u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+		if (val & HDMI_PHY_STATUS_READY)
+			break;
+		mdelay(1);
+	}
+	/* steady state not achieved */
+	if (tries == 0) {
+		dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
+		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+		hdmi_dumpregs(hdev, "s_stream");
+		return -EIO;
+	}
+
+	/* hdmiphy clock is used for HDMI in streaming mode */
+	clk_disable(res->sclk_hdmi);
+	clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+	clk_enable(res->sclk_hdmi);
+
+	/* enable HDMI and timing generator */
+	hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+	hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+	hdmi_dumpregs(hdev, "streamon");
+	return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+	struct device *dev = hdev->dev;
+	struct hdmi_resources *res = &hdev->res;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+	hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
+
+	/* pixel(vpll) clock is used for HDMI in config mode */
+	clk_disable(res->sclk_hdmi);
+	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+	clk_enable(res->sclk_hdmi);
+
+	v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+
+	hdmi_dumpregs(hdev, "streamoff");
+	return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	struct device *dev = hdev->dev;
+
+	dev_dbg(dev, "%s(%d)\n", __func__, enable);
+	if (enable)
+		return hdmi_streamon(hdev);
+	return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+	/* turn HDMI power on */
+	regulator_bulk_enable(res->regul_count, res->regul_bulk);
+	/* power-on hdmi physical interface */
+	clk_enable(res->hdmiphy);
+	/* use VPP as parent clock; HDMIPHY is not working yet */
+	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+	/* turn clocks on */
+	clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_resource_poweroff(struct hdmi_resources *res)
+{
+	/* turn clocks off */
+	clk_disable(res->sclk_hdmi);
+	/* power-off hdmiphy */
+	clk_disable(res->hdmiphy);
+	/* turn HDMI power off */
+	regulator_bulk_disable(res->regul_count, res->regul_bulk);
+}
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(hdev->dev);
+	else
+		ret = pm_runtime_put_sync(hdev->dev);
+	/* only values < 0 indicate errors */
+	return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+	struct v4l2_dv_preset *preset)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	struct device *dev = hdev->dev;
+	const struct hdmi_preset_conf *conf;
+
+	conf = hdmi_preset2conf(preset->preset);
+	if (conf == NULL) {
+		dev_err(dev, "preset (%u) not supported\n", preset->preset);
+		return -EINVAL;
+	}
+	hdev->cur_conf = conf;
+	hdev->cur_preset = preset->preset;
+	return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+	struct v4l2_dv_preset *preset)
+{
+	memset(preset, 0, sizeof(*preset));
+	preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+	return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+	  struct v4l2_mbus_framefmt *fmt)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	struct device *dev = hdev->dev;
+
+	dev_dbg(dev, "%s\n", __func__);
+	if (!hdev->cur_conf)
+		return -EINVAL;
+	*fmt = hdev->cur_conf->mbus_fmt;
+	return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+	struct v4l2_dv_enum_preset *preset)
+{
+	if (preset->index >= ARRAY_SIZE(hdmi_conf))
+		return -EINVAL;
+	return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+	.s_power = hdmi_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+	.s_dv_preset = hdmi_s_dv_preset,
+	.g_dv_preset = hdmi_g_dv_preset,
+	.enum_dv_presets = hdmi_enum_dv_presets,
+	.g_mbus_fmt = hdmi_g_mbus_fmt,
+	.s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+	.core = &hdmi_sd_core_ops,
+	.video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+	dev_dbg(dev, "%s\n", __func__);
+	hdmi_resource_poweroff(&hdev->res);
+	return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	int ret = 0;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	hdmi_resource_poweron(&hdev->res);
+
+	ret = hdmi_conf_apply(hdev);
+	if (ret)
+		goto fail;
+
+	dev_dbg(dev, "poweron succeed\n");
+
+	return 0;
+
+fail:
+	hdmi_resource_poweroff(&hdev->res);
+	dev_err(dev, "poweron failed\n");
+
+	return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+	.runtime_suspend = hdmi_runtime_suspend,
+	.runtime_resume	 = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+	struct hdmi_resources *res = &hdev->res;
+
+	dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+	/* put clocks, power */
+	if (res->regul_count)
+		regulator_bulk_free(res->regul_count, res->regul_bulk);
+	/* kfree is NULL-safe */
+	kfree(res->regul_bulk);
+	if (!IS_ERR_OR_NULL(res->hdmiphy))
+		clk_put(res->hdmiphy);
+	if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+		clk_put(res->sclk_hdmiphy);
+	if (!IS_ERR_OR_NULL(res->sclk_pixel))
+		clk_put(res->sclk_pixel);
+	if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+		clk_put(res->sclk_hdmi);
+	if (!IS_ERR_OR_NULL(res->hdmi))
+		clk_put(res->hdmi);
+	memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+	struct device *dev = hdev->dev;
+	struct hdmi_resources *res = &hdev->res;
+	static char *supply[] = {
+		"hdmi-en",
+		"vdd",
+		"vdd_osc",
+		"vdd_pll",
+	};
+	int i, ret;
+
+	dev_dbg(dev, "HDMI resource init\n");
+
+	memset(res, 0, sizeof *res);
+	/* get clocks, power */
+
+	res->hdmi = clk_get(dev, "hdmi");
+	if (IS_ERR_OR_NULL(res->hdmi)) {
+		dev_err(dev, "failed to get clock 'hdmi'\n");
+		goto fail;
+	}
+	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+		dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+		goto fail;
+	}
+	res->sclk_pixel = clk_get(dev, "sclk_pixel");
+	if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+		dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+		goto fail;
+	}
+	res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+	if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+		dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+		goto fail;
+	}
+	res->hdmiphy = clk_get(dev, "hdmiphy");
+	if (IS_ERR_OR_NULL(res->hdmiphy)) {
+		dev_err(dev, "failed to get clock 'hdmiphy'\n");
+		goto fail;
+	}
+	res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
+		sizeof res->regul_bulk[0], GFP_KERNEL);
+	if (!res->regul_bulk) {
+		dev_err(dev, "failed to get memory for regulators\n");
+		goto fail;
+	}
+	for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+		res->regul_bulk[i].supply = supply[i];
+		res->regul_bulk[i].consumer = NULL;
+	}
+
+	ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+	if (ret) {
+		dev_err(dev, "failed to get regulators\n");
+		goto fail;
+	}
+	res->regul_count = ARRAY_SIZE(supply);
+
+	return 0;
+fail:
+	dev_err(dev, "HDMI resource init - failed\n");
+	hdmi_resources_cleanup(hdev);
+	return -ENODEV;
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct i2c_adapter *phy_adapter;
+	struct v4l2_subdev *sd;
+	struct hdmi_device *hdmi_dev = NULL;
+	struct hdmi_driver_data *drv_data;
+	int ret;
+
+	dev_dbg(dev, "probe start\n");
+
+	hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+	if (!hdmi_dev) {
+		dev_err(dev, "out of memory\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	hdmi_dev->dev = dev;
+
+	ret = hdmi_resources_init(hdmi_dev);
+	if (ret)
+		goto fail_hdev;
+
+	/* mapping HDMI registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(dev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail_init;
+	}
+
+	hdmi_dev->regs = ioremap(res->start, resource_size(res));
+	if (hdmi_dev->regs == NULL) {
+		dev_err(dev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail_hdev;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(dev, "get interrupt resource failed.\n");
+		ret = -ENXIO;
+		goto fail_regs;
+	}
+
+	ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
+	if (ret) {
+		dev_err(dev, "request interrupt failed.\n");
+		goto fail_regs;
+	}
+	hdmi_dev->irq = res->start;
+
+	/* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+	strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+		sizeof(hdmi_dev->v4l2_dev.name));
+	/* passing NULL owner prevents driver from erasing drvdata */
+	ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "could not register v4l2 device.\n");
+		goto fail_irq;
+	}
+
+	drv_data = (struct hdmi_driver_data *)
+		platform_get_device_id(pdev)->driver_data;
+	phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
+	if (phy_adapter == NULL) {
+		dev_err(dev, "adapter request failed\n");
+		ret = -ENXIO;
+		goto fail_vdev;
+	}
+
+	hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
+		phy_adapter, &hdmiphy_info, NULL);
+	/* on failure or not adapter is no longer useful */
+	i2c_put_adapter(phy_adapter);
+	if (hdmi_dev->phy_sd == NULL) {
+		dev_err(dev, "missing subdev for hdmiphy\n");
+		ret = -ENODEV;
+		goto fail_vdev;
+	}
+
+	clk_enable(hdmi_dev->res.hdmi);
+
+	pm_runtime_enable(dev);
+
+	sd = &hdmi_dev->sd;
+	v4l2_subdev_init(sd, &hdmi_sd_ops);
+	sd->owner = THIS_MODULE;
+
+	strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
+	hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+	/* FIXME: missing fail preset is not supported */
+	hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+
+	/* storing subdev for call that have only access to struct device */
+	dev_set_drvdata(dev, sd);
+
+	dev_info(dev, "probe sucessful\n");
+
+	return 0;
+
+fail_vdev:
+	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_irq:
+	free_irq(hdmi_dev->irq, hdmi_dev);
+
+fail_regs:
+	iounmap(hdmi_dev->regs);
+
+fail_init:
+	hdmi_resources_cleanup(hdmi_dev);
+
+fail_hdev:
+	kfree(hdmi_dev);
+
+fail:
+	dev_err(dev, "probe failed\n");
+	return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+	pm_runtime_disable(dev);
+	clk_disable(hdmi_dev->res.hdmi);
+	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+	disable_irq(hdmi_dev->irq);
+	free_irq(hdmi_dev->irq, hdmi_dev);
+	iounmap(hdmi_dev->regs);
+	hdmi_resources_cleanup(hdmi_dev);
+	kfree(hdmi_dev);
+	dev_info(dev, "remove sucessful\n");
+
+	return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+	.probe = hdmi_probe,
+	.remove = __devexit_p(hdmi_remove),
+	.id_table = hdmi_driver_types,
+	.driver = {
+		.name = "s5p-hdmi",
+		.owner = THIS_MODULE,
+		.pm = &hdmi_pm_ops,
+	}
+};
+
+/* D R I V E R   I N I T I A L I Z A T I O N */
+
+static int __init hdmi_init(void)
+{
+	int ret;
+	static const char banner[] __initdata = KERN_INFO \
+		"Samsung HDMI output driver, "
+		"(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+	printk(banner);
+
+	ret = platform_driver_register(&hdmi_driver);
+	if (ret)
+		printk(KERN_ERR "HDMI platform driver register failed\n");
+
+	return ret;
+}
+module_init(hdmi_init);
+
+static void __exit hdmi_exit(void)
+{
+	platform_driver_unregister(&hdmi_driver);
+}
+module_exit(hdmi_exit);
+
+
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
new file mode 100644
index 0000000..da5b684
--- /dev/null
+++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c
@@ -0,0 +1,196 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
+MODULE_LICENSE("GPL");
+
+struct hdmiphy_conf {
+	u32 preset;
+	const u8 *data;
+};
+
+static const u8 hdmiphy_conf27[32] = {
+	0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+	0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
+	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+	0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+	0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+	0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+	0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
+	0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
+	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
+	0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
+	0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
+	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+	0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf148_35[32] = {
+	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+	0x6D, 0x18, 0x00, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+	0x22, 0x40, 0xa5, 0x26, 0x02, 0x00, 0x00, 0x00,
+};
+
+static const struct hdmiphy_conf hdmiphy_conf[] = {
+	{ V4L2_DV_480P59_94, hdmiphy_conf27 },
+	{ V4L2_DV_1080P30, hdmiphy_conf74_175 },
+	{ V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+	{ V4L2_DV_720P60, hdmiphy_conf74_25 },
+	{ V4L2_DV_1080P50, hdmiphy_conf148_5 },
+	{ V4L2_DV_1080P60, hdmiphy_conf148_5 },
+	{ V4L2_DV_1080P59_94, hdmiphy_conf148_35},
+};
+
+const u8 *hdmiphy_preset2conf(u32 preset)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
+		if (hdmiphy_conf[i].preset == preset)
+			return hdmiphy_conf[i].data;
+	return NULL;
+}
+
+static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
+{
+	/* to be implemented */
+	return 0;
+}
+
+static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
+	struct v4l2_dv_preset *preset)
+{
+	const u8 *data;
+	u8 buffer[32];
+	int ret;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+
+	dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
+	data = hdmiphy_preset2conf(preset->preset);
+	if (!data) {
+		dev_err(dev, "format not supported\n");
+		return -EINVAL;
+	}
+
+	/* storing configuration to the device */
+	memcpy(buffer, data, 32);
+	ret = i2c_master_send(client, buffer, 32);
+	if (ret != 32) {
+		dev_err(dev, "failed to configure HDMIPHY via I2C\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+	u8 buffer[2];
+	int ret;
+
+	dev_info(dev, "s_stream(%d)\n", enable);
+	/* going to/from configuration from/to operation mode */
+	buffer[0] = 0x1f;
+	buffer[1] = enable ? 0x80 : 0x00;
+
+	ret = i2c_master_send(client, buffer, 2);
+	if (ret != 2) {
+		dev_err(dev, "stream (%d) failed\n", enable);
+		return -EIO;
+	}
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
+	.s_power =  hdmiphy_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
+	.s_dv_preset = hdmiphy_s_dv_preset,
+	.s_stream =  hdmiphy_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmiphy_ops = {
+	.core = &hdmiphy_core_ops,
+	.video = &hdmiphy_video_ops,
+};
+
+static int __devinit hdmiphy_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	static struct v4l2_subdev sd;
+
+	v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
+	dev_info(&client->dev, "probe successful\n");
+	return 0;
+}
+
+static int __devexit hdmiphy_remove(struct i2c_client *client)
+{
+	dev_info(&client->dev, "remove successful\n");
+	return 0;
+}
+
+static const struct i2c_device_id hdmiphy_id[] = {
+	{ "hdmiphy", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
+
+static struct i2c_driver hdmiphy_driver = {
+	.driver = {
+		.name	= "s5p-hdmiphy",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hdmiphy_probe,
+	.remove		= __devexit_p(hdmiphy_remove),
+	.id_table = hdmiphy_id,
+};
+
+static int __init hdmiphy_init(void)
+{
+	return i2c_add_driver(&hdmiphy_driver);
+}
+module_init(hdmiphy_init);
+
+static void __exit hdmiphy_exit(void)
+{
+	i2c_del_driver(&hdmiphy_driver);
+}
+module_exit(hdmiphy_exit);
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h
new file mode 100644
index 0000000..ac93ad6
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-hdmi.h
@@ -0,0 +1,141 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef SAMSUNG_REGS_HDMI_H
+#define SAMSUNG_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define HDMI_CTRL_BASE(x)		((x) + 0x00000000)
+#define HDMI_CORE_BASE(x)		((x) + 0x00010000)
+#define HDMI_TG_BASE(x)			((x) + 0x00050000)
+
+/* Control registers */
+#define HDMI_INTC_CON			HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG			HDMI_CTRL_BASE(0x0004)
+#define HDMI_HPD_STATUS			HDMI_CTRL_BASE(0x000C)
+#define HDMI_PHY_RSTOUT			HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_VPLL			HDMI_CTRL_BASE(0x0018)
+#define HDMI_PHY_CMU			HDMI_CTRL_BASE(0x001C)
+#define HDMI_CORE_RSTOUT		HDMI_CTRL_BASE(0x0020)
+
+/* Core registers */
+#define HDMI_CON_0			HDMI_CORE_BASE(0x0000)
+#define HDMI_CON_1			HDMI_CORE_BASE(0x0004)
+#define HDMI_CON_2			HDMI_CORE_BASE(0x0008)
+#define HDMI_SYS_STATUS			HDMI_CORE_BASE(0x0010)
+#define HDMI_PHY_STATUS			HDMI_CORE_BASE(0x0014)
+#define HDMI_STATUS_EN			HDMI_CORE_BASE(0x0020)
+#define HDMI_HPD			HDMI_CORE_BASE(0x0030)
+#define HDMI_MODE_SEL			HDMI_CORE_BASE(0x0040)
+#define HDMI_BLUE_SCREEN_0		HDMI_CORE_BASE(0x0050)
+#define HDMI_BLUE_SCREEN_1		HDMI_CORE_BASE(0x0054)
+#define HDMI_BLUE_SCREEN_2		HDMI_CORE_BASE(0x0058)
+#define HDMI_H_BLANK_0			HDMI_CORE_BASE(0x00A0)
+#define HDMI_H_BLANK_1			HDMI_CORE_BASE(0x00A4)
+#define HDMI_V_BLANK_0			HDMI_CORE_BASE(0x00B0)
+#define HDMI_V_BLANK_1			HDMI_CORE_BASE(0x00B4)
+#define HDMI_V_BLANK_2			HDMI_CORE_BASE(0x00B8)
+#define HDMI_H_V_LINE_0			HDMI_CORE_BASE(0x00C0)
+#define HDMI_H_V_LINE_1			HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_V_LINE_2			HDMI_CORE_BASE(0x00C8)
+#define HDMI_VSYNC_POL			HDMI_CORE_BASE(0x00E4)
+#define HDMI_INT_PRO_MODE		HDMI_CORE_BASE(0x00E8)
+#define HDMI_V_BLANK_F_0		HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F_1		HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F_2		HDMI_CORE_BASE(0x0118)
+#define HDMI_H_SYNC_GEN_0		HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_GEN_1		HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_GEN_2		HDMI_CORE_BASE(0x0128)
+#define HDMI_V_SYNC_GEN_1_0		HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_GEN_1_1		HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_GEN_1_2		HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_GEN_2_0		HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_GEN_2_1		HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_GEN_2_2		HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_GEN_3_0		HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_GEN_3_1		HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_GEN_3_2		HDMI_CORE_BASE(0x0158)
+#define HDMI_AVI_CON			HDMI_CORE_BASE(0x0300)
+#define HDMI_AVI_BYTE(n)		HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define	HDMI_DC_CONTROL			HDMI_CORE_BASE(0x05C0)
+#define HDMI_VIDEO_PATTERN_GEN		HDMI_CORE_BASE(0x05C4)
+#define HDMI_HPD_GEN			HDMI_CORE_BASE(0x05C8)
+
+/* Timing generator registers */
+#define HDMI_TG_CMD			HDMI_TG_BASE(0x0000)
+#define HDMI_TG_H_FSZ_L			HDMI_TG_BASE(0x0018)
+#define HDMI_TG_H_FSZ_H			HDMI_TG_BASE(0x001C)
+#define HDMI_TG_HACT_ST_L		HDMI_TG_BASE(0x0020)
+#define HDMI_TG_HACT_ST_H		HDMI_TG_BASE(0x0024)
+#define HDMI_TG_HACT_SZ_L		HDMI_TG_BASE(0x0028)
+#define HDMI_TG_HACT_SZ_H		HDMI_TG_BASE(0x002C)
+#define HDMI_TG_V_FSZ_L			HDMI_TG_BASE(0x0030)
+#define HDMI_TG_V_FSZ_H			HDMI_TG_BASE(0x0034)
+#define HDMI_TG_VSYNC_L			HDMI_TG_BASE(0x0038)
+#define HDMI_TG_VSYNC_H			HDMI_TG_BASE(0x003C)
+#define HDMI_TG_VSYNC2_L		HDMI_TG_BASE(0x0040)
+#define HDMI_TG_VSYNC2_H		HDMI_TG_BASE(0x0044)
+#define HDMI_TG_VACT_ST_L		HDMI_TG_BASE(0x0048)
+#define HDMI_TG_VACT_ST_H		HDMI_TG_BASE(0x004C)
+#define HDMI_TG_VACT_SZ_L		HDMI_TG_BASE(0x0050)
+#define HDMI_TG_VACT_SZ_H		HDMI_TG_BASE(0x0054)
+#define HDMI_TG_FIELD_CHG_L		HDMI_TG_BASE(0x0058)
+#define HDMI_TG_FIELD_CHG_H		HDMI_TG_BASE(0x005C)
+#define HDMI_TG_VACT_ST2_L		HDMI_TG_BASE(0x0060)
+#define HDMI_TG_VACT_ST2_H		HDMI_TG_BASE(0x0064)
+#define HDMI_TG_VSYNC_TOP_HDMI_L	HDMI_TG_BASE(0x0078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H	HDMI_TG_BASE(0x007C)
+#define HDMI_TG_VSYNC_BOT_HDMI_L	HDMI_TG_BASE(0x0080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H	HDMI_TG_BASE(0x0084)
+#define HDMI_TG_FIELD_TOP_HDMI_L	HDMI_TG_BASE(0x0088)
+#define HDMI_TG_FIELD_TOP_HDMI_H	HDMI_TG_BASE(0x008C)
+#define HDMI_TG_FIELD_BOT_HDMI_L	HDMI_TG_BASE(0x0090)
+#define HDMI_TG_FIELD_BOT_HDMI_H	HDMI_TG_BASE(0x0094)
+
+/*
+ * Bit definition part
+ */
+
+/* HDMI_INTC_CON */
+#define HDMI_INTC_EN_GLOBAL		(1 << 6)
+#define HDMI_INTC_EN_HPD_PLUG		(1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG		(1 << 2)
+
+/* HDMI_INTC_FLAG */
+#define HDMI_INTC_FLAG_HPD_PLUG		(1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG	(1 << 2)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT		(1 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT		(1 << 0)
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN		(1 << 5)
+#define HDMI_EN				(1 << 0)
+
+/* HDMI_PHY_STATUS */
+#define HDMI_PHY_STATUS_READY		(1 << 0)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN		(1 << 1)
+#define HDMI_MODE_DVI_EN		(1 << 0)
+#define HDMI_MODE_MASK			(3 << 0)
+
+/* HDMI_TG_CMD */
+#define HDMI_TG_EN			(1 << 0)
+
+#endif /* SAMSUNG_REGS_HDMI_H */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 7/8] v4l: s5p-tv: add SDO driver for Samsung S5P platform
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
                   ` (5 preceding siblings ...)
  2011-06-29 12:51 ` [PATCH 6/8] v4l: s5p-tv: add drivers for HDMI on Samsung S5P platform Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  2011-06-29 12:51 ` [PATCH 8/8] v4l: s5p-tv: add TV Mixer " Tomasz Stanislawski
  7 siblings, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Add drivers for Standard Definition output (SDO) on Samsung platforms
from S5P family. The driver provides control over streaming analog TV
via Composite connector.

Driver is using:
- v4l2 framework
- runtime PM

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/video/s5p-tv/Kconfig    |   11 +
 drivers/media/video/s5p-tv/Makefile   |    2 +
 drivers/media/video/s5p-tv/regs-sdo.h |   63 +++++
 drivers/media/video/s5p-tv/sdo_drv.c  |  479 +++++++++++++++++++++++++++++++++
 4 files changed, 555 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/s5p-tv/regs-sdo.h
 create mode 100644 drivers/media/video/s5p-tv/sdo_drv.c

diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index 893be5b..9c1f634 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -46,4 +46,15 @@ config VIDEO_SAMSUNG_S5P_HDMIPHY
 	  as module. It is an I2C driver, that exposes a V4L2
 	  subdev for use by other drivers.
 
+config VIDEO_SAMSUNG_S5P_SDO
+	tristate "Samsung Analog TV Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on VIDEO_SAMSUNG_S5P_TV
+	help
+	  Say Y here if you want support for the analog TV output
+	  interface in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an auxiliary driver, that exposes a V4L2
+	  subdev for use by other drivers. This driver requires
+	  hdmiphy driver to work correctly.
+
 endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
index 1b07132..c874d16 100644
--- a/drivers/media/video/s5p-tv/Makefile
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -10,4 +10,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
 s5p-hdmiphy-y += hdmiphy_drv.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
 s5p-hdmi-y += hdmi_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
+s5p-sdo-y += sdo_drv.o
 
diff --git a/drivers/media/video/s5p-tv/regs-sdo.h b/drivers/media/video/s5p-tv/regs-sdo.h
new file mode 100644
index 0000000..7f7c2b8
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-sdo.h
@@ -0,0 +1,63 @@
+/* drivers/media/video/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON			0x0000
+#define SDO_CONFIG			0x0008
+#define SDO_VBI				0x0014
+#define SDO_DAC				0x003C
+#define SDO_CCCON			0x0180
+#define SDO_IRQ				0x0280
+#define SDO_IRQMASK			0x0284
+#define SDO_VERSION			0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET		(1 << 4)
+#define SDO_TVOUT_CLOCK_READY		(1 << 1)
+#define SDO_TVOUT_CLOCK_ON		(1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE			(1 << 4)
+#define SDO_NTSC_M			0
+#define SDO_PAL_M			1
+#define SDO_PAL_BGHID			2
+#define SDO_PAL_N			3
+#define SDO_PAL_NC			4
+#define SDO_NTSC_443			8
+#define SDO_PAL_60			9
+#define SDO_STANDARD_MASK		0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS		(1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK	(3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC		(1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF	(1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF	(1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND		(1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
new file mode 100644
index 0000000..4dddd6b
--- /dev/null
+++ b/drivers/media/video/s5p-tv/sdo_drv.c
@@ -0,0 +1,479 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+#define SDO_DEFAULT_STD	V4L2_STD_PAL
+
+struct sdo_format {
+	v4l2_std_id id;
+	/* all modes are 720 pixels wide */
+	unsigned int height;
+	unsigned int cookie;
+};
+
+struct sdo_device {
+	/** pointer to device parent */
+	struct device *dev;
+	/** base address of SDO registers */
+	void __iomem *regs;
+	/** SDO interrupt */
+	unsigned int irq;
+	/** DAC source clock */
+	struct clk *sclk_dac;
+	/** DAC clock */
+	struct clk *dac;
+	/** DAC physical interface */
+	struct clk *dacphy;
+	/** clock for control of VPLL */
+	struct clk *fout_vpll;
+	/** regulator for SDO IP power */
+	struct regulator *vdac;
+	/** regulator for SDO plug detection */
+	struct regulator *vdet;
+	/** subdev used as device interface */
+	struct v4l2_subdev sd;
+	/** current format */
+	const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+	u32 old = readl(sdev->regs + reg_id);
+	value = (value & mask) | (old & ~mask);
+	writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+	writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+	return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+	struct sdo_device *sdev = dev_data;
+
+	/* clear interrupt */
+	sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+	return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+	dev_info(sdev->dev, #reg_id " = %08x\n", \
+		sdo_read(sdev, reg_id))
+
+	DBGREG(SDO_CLKCON);
+	DBGREG(SDO_CONFIG);
+	DBGREG(SDO_VBI);
+	DBGREG(SDO_DAC);
+	DBGREG(SDO_IRQ);
+	DBGREG(SDO_IRQMASK);
+	DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+	{ V4L2_STD_PAL_N,	.height = 576, .cookie = SDO_PAL_N },
+	{ V4L2_STD_PAL_Nc,	.height = 576, .cookie = SDO_PAL_NC },
+	{ V4L2_STD_PAL_M,	.height = 480, .cookie = SDO_PAL_M },
+	{ V4L2_STD_PAL_60,	.height = 480, .cookie = SDO_PAL_60 },
+	{ V4L2_STD_NTSC_443,	.height = 480, .cookie = SDO_NTSC_443 },
+	{ V4L2_STD_PAL,		.height = 576, .cookie = SDO_PAL_BGHID },
+	{ V4L2_STD_NTSC_M,	.height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+		if (sdo_format[i].id & id)
+			return &sdo_format[i];
+	return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+		V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+		V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+	return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+	const struct sdo_format *fmt;
+	fmt = sdo_find_format(std);
+	if (fmt == NULL)
+		return -EINVAL;
+	sdev->fmt = fmt;
+	return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*std = sd_to_sdev(sd)->fmt->id;
+	return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+	struct v4l2_mbus_framefmt *fmt)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	if (!sdev->fmt)
+		return -ENXIO;
+	/* all modes are 720 pixels wide */
+	fmt->width = 720;
+	fmt->height = sdev->fmt->height;
+	fmt->code = V4L2_MBUS_FMT_FIXED;
+	fmt->field = V4L2_FIELD_INTERLACED;
+	return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+	struct device *dev = sdev->dev;
+	int ret;
+
+	dev_info(dev, "sdo_s_power(%d)\n", on);
+
+	if (on)
+		ret = pm_runtime_get_sync(dev);
+	else
+		ret = pm_runtime_put_sync(dev);
+
+	/* only values < 0 indicate errors */
+	return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+	/* set proper clock for Timing Generator */
+	clk_set_rate(sdev->fout_vpll, 54000000);
+	dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+	clk_get_rate(sdev->fout_vpll));
+	/* enable clock in SDO */
+	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+	clk_enable(sdev->dacphy);
+	/* enable DAC */
+	sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+	sdo_reg_debug(sdev);
+	return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+	int tries;
+
+	sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+	clk_disable(sdev->dacphy);
+	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+	for (tries = 100; tries; --tries) {
+		if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+			break;
+		mdelay(1);
+	}
+	if (tries == 0)
+		dev_err(sdev->dev, "failed to stop streaming\n");
+	return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+	return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+	.s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+	.s_std_output = sdo_s_std_output,
+	.g_std_output = sdo_g_std_output,
+	.g_tvnorms_output = sdo_g_tvnorms_output,
+	.g_mbus_fmt = sdo_g_mbus_fmt,
+	.s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+	.core = &sdo_sd_core_ops,
+	.video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	dev_info(dev, "suspend\n");
+	regulator_disable(sdev->vdet);
+	regulator_disable(sdev->vdac);
+	clk_disable(sdev->sclk_dac);
+	return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	dev_info(dev, "resume\n");
+	clk_enable(sdev->sclk_dac);
+	regulator_enable(sdev->vdac);
+	regulator_enable(sdev->vdet);
+
+	/* software reset */
+	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+	mdelay(10);
+	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+	/* setting TV mode */
+	sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+	/* XXX: forcing interlaced mode using undocumented bit */
+	sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+	/* turn all VBI off */
+	sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+		SDO_CVBS_CLOSED_CAPTION_MASK);
+	/* turn all post processing off */
+	sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+		SDO_COMPENSATION_CVBS_COMP_OFF);
+	sdo_reg_debug(sdev);
+	return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+	.runtime_suspend = sdo_runtime_suspend,
+	.runtime_resume	 = sdo_runtime_resume,
+};
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sdo_device *sdev;
+	struct resource *res;
+	int ret = 0;
+	struct clk *sclk_vpll;
+
+	dev_info(dev, "probe start\n");
+	sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+	if (!sdev) {
+		dev_err(dev, "not enough memory.\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	sdev->dev = dev;
+
+	/* mapping registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(dev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail_sdev;
+	}
+
+	sdev->regs = ioremap(res->start, resource_size(res));
+	if (sdev->regs == NULL) {
+		dev_err(dev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail_sdev;
+	}
+
+	/* acquiring interrupt */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(dev, "get interrupt resource failed.\n");
+		ret = -ENXIO;
+		goto fail_regs;
+	}
+	ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+	if (ret) {
+		dev_err(dev, "request interrupt failed.\n");
+		goto fail_regs;
+	}
+	sdev->irq = res->start;
+
+	/* acquire clocks */
+	sdev->sclk_dac = clk_get(dev, "sclk_dac");
+	if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+		dev_err(dev, "failed to get clock 'sclk_dac'\n");
+		ret = -ENXIO;
+		goto fail_irq;
+	}
+	sdev->dac = clk_get(dev, "dac");
+	if (IS_ERR_OR_NULL(sdev->dac)) {
+		dev_err(dev, "failed to get clock 'dac'\n");
+		ret = -ENXIO;
+		goto fail_sclk_dac;
+	}
+	sdev->dacphy = clk_get(dev, "dacphy");
+	if (IS_ERR_OR_NULL(sdev->dacphy)) {
+		dev_err(dev, "failed to get clock 'dacphy'\n");
+		ret = -ENXIO;
+		goto fail_dac;
+	}
+	sclk_vpll = clk_get(dev, "sclk_vpll");
+	if (IS_ERR_OR_NULL(sclk_vpll)) {
+		dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+		ret = -ENXIO;
+		goto fail_dacphy;
+	}
+	clk_set_parent(sdev->sclk_dac, sclk_vpll);
+	clk_put(sclk_vpll);
+	sdev->fout_vpll = clk_get(dev, "fout_vpll");
+	if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+		dev_err(dev, "failed to get clock 'fout_vpll'\n");
+		goto fail_dacphy;
+	}
+	dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+	/* acquire regulator */
+	sdev->vdac = regulator_get(dev, "vdd33a_dac");
+	if (IS_ERR_OR_NULL(sdev->vdac)) {
+		dev_err(dev, "failed to get regulator 'vdac'\n");
+		goto fail_fout_vpll;
+	}
+	sdev->vdet = regulator_get(dev, "vdet");
+	if (IS_ERR_OR_NULL(sdev->vdet)) {
+		dev_err(dev, "failed to get regulator 'vdet'\n");
+		goto fail_vdac;
+	}
+
+	/* enable gate for dac clock, because mixer uses it */
+	clk_enable(sdev->dac);
+
+	/* configure power management */
+	pm_runtime_enable(dev);
+
+	/* configuration of interface subdevice */
+	v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
+	sdev->sd.owner = THIS_MODULE;
+	strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
+
+	/* set default format */
+	sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+	BUG_ON(sdev->fmt == NULL);
+
+	/* keeping subdev in device's private for use by other drivers */
+	dev_set_drvdata(dev, &sdev->sd);
+
+	dev_info(dev, "probe succeeded\n");
+	return 0;
+
+fail_vdac:
+	regulator_put(sdev->vdac);
+fail_fout_vpll:
+	clk_put(sdev->fout_vpll);
+fail_dacphy:
+	clk_put(sdev->dacphy);
+fail_dac:
+	clk_put(sdev->dac);
+fail_sclk_dac:
+	clk_put(sdev->sclk_dac);
+fail_irq:
+	free_irq(sdev->irq, sdev);
+fail_regs:
+	iounmap(sdev->regs);
+fail_sdev:
+	kfree(sdev);
+fail:
+	dev_info(dev, "probe failed\n");
+	return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	pm_runtime_disable(&pdev->dev);
+	clk_disable(sdev->dac);
+	regulator_put(sdev->vdet);
+	regulator_put(sdev->vdac);
+	clk_put(sdev->fout_vpll);
+	clk_put(sdev->dacphy);
+	clk_put(sdev->dac);
+	clk_put(sdev->sclk_dac);
+	free_irq(sdev->irq, sdev);
+	iounmap(sdev->regs);
+	kfree(sdev);
+
+	dev_info(&pdev->dev, "remove successful\n");
+	return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+	.probe = sdo_probe,
+	.remove = __devexit_p(sdo_remove),
+	.driver = {
+		.name = "s5p-sdo",
+		.owner = THIS_MODULE,
+		.pm = &sdo_pm_ops,
+	}
+};
+
+static int __init sdo_init(void)
+{
+	int ret;
+	static const char banner[] __initdata = KERN_INFO \
+		"Samsung Standard Definition Output (SDO) driver, "
+		"(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+	printk(banner);
+
+	ret = platform_driver_register(&sdo_driver);
+	if (ret)
+		printk(KERN_ERR "SDO platform driver register failed\n");
+
+	return ret;
+}
+module_init(sdo_init);
+
+static void __exit sdo_exit(void)
+{
+	platform_driver_unregister(&sdo_driver);
+}
+module_exit(sdo_exit);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 8/8] v4l: s5p-tv: add TV Mixer driver for Samsung S5P platform
  2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
                   ` (6 preceding siblings ...)
  2011-06-29 12:51 ` [PATCH 7/8] v4l: s5p-tv: add SDO driver for " Tomasz Stanislawski
@ 2011-06-29 12:51 ` Tomasz Stanislawski
  7 siblings, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-06-29 12:51 UTC (permalink / raw)
  To: linux-media
  Cc: m.szyprowski, t.stanislaws, kyungmin.park, hverkuil, laurent.pinchart

Add driver for TV Mixer on Samsung platforms from S5P family.
Mixer is responsible for merging images from three layers and
passing result to the output.

Interface:
- 3 video nodes with output queues
- support for multi plane API
- each nodes has up to 2 outputs (HDMI and SDO)
- outputs are controlled by S_STD and S_DV_PRESET ioctls

Drivers are using:
- v4l2 framework
- videobuf2
- videobuf2-dma-contig as memory allocator
- runtime PM

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/video/s5p-tv/Kconfig           |   16 +
 drivers/media/video/s5p-tv/Makefile          |    2 +
 drivers/media/video/s5p-tv/mixer.h           |  354 +++++++++
 drivers/media/video/s5p-tv/mixer_drv.c       |  487 +++++++++++++
 drivers/media/video/s5p-tv/mixer_grp_layer.c |  185 +++++
 drivers/media/video/s5p-tv/mixer_reg.c       |  541 ++++++++++++++
 drivers/media/video/s5p-tv/mixer_video.c     | 1006 ++++++++++++++++++++++++++
 drivers/media/video/s5p-tv/mixer_vp_layer.c  |  211 ++++++
 drivers/media/video/s5p-tv/regs-mixer.h      |  121 +++
 drivers/media/video/s5p-tv/regs-vp.h         |   88 +++
 10 files changed, 3011 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/s5p-tv/mixer.h
 create mode 100644 drivers/media/video/s5p-tv/mixer_drv.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_grp_layer.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_reg.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_video.c
 create mode 100644 drivers/media/video/s5p-tv/mixer_vp_layer.c
 create mode 100644 drivers/media/video/s5p-tv/regs-mixer.h
 create mode 100644 drivers/media/video/s5p-tv/regs-vp.h

diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index 9c1f634..9c37dee 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -57,4 +57,20 @@ config VIDEO_SAMSUNG_S5P_SDO
 	  subdev for use by other drivers. This driver requires
 	  hdmiphy driver to work correctly.
 
+config VIDEO_SAMSUNG_S5P_MIXER
+	tristate "Samsung Mixer and Video Processor Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on VIDEO_SAMSUNG_S5P_TV
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+	  This device produce image data to one of output interfaces.
+
+config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+	bool "Enable debug for Mixer Driver"
+	depends on VIDEO_SAMSUNG_S5P_MIXER
+	default n
+	help
+	  Enables debugging for Mixer driver.
+
 endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
index c874d16..37e4c17 100644
--- a/drivers/media/video/s5p-tv/Makefile
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -12,4 +12,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
 s5p-hdmi-y += hdmi_drv.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
 s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
 
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
new file mode 100644
index 0000000..e224224
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer.h
@@ -0,0 +1,354 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUNG_MIXER_H
+#define SAMSUNG_MIXER_H
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+	#define DEBUG
+#endif
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+
+#include "regs-mixer.h"
+
+/** maximum number of output interfaces */
+#define MXR_MAX_OUTPUTS 2
+/** maximum number of input interfaces (layers) */
+#define MXR_MAX_LAYERS 3
+#define MXR_DRIVER_NAME "s5p-mixer"
+/** maximal number of planes for every layer */
+#define MXR_MAX_PLANES	2
+
+#define MXR_ENABLE 1
+#define MXR_DISABLE 0
+
+/** description of a macroblock for packed formats */
+struct mxr_block {
+	/** vertical number of pixels in macroblock */
+	unsigned int width;
+	/** horizontal number of pixels in macroblock */
+	unsigned int height;
+	/** size of block in bytes */
+	unsigned int size;
+};
+
+/** description of supported format */
+struct mxr_format {
+	/** format name/mnemonic */
+	const char *name;
+	/** fourcc identifier */
+	u32 fourcc;
+	/** colorspace identifier */
+	enum v4l2_colorspace colorspace;
+	/** number of planes in image data */
+	int num_planes;
+	/** description of block for each plane */
+	struct mxr_block plane[MXR_MAX_PLANES];
+	/** number of subframes in image data */
+	int num_subframes;
+	/** specifies to which subframe belong given plane */
+	int plane2subframe[MXR_MAX_PLANES];
+	/** internal code, driver dependant */
+	unsigned long cookie;
+};
+
+/** description of crop configuration for image */
+struct mxr_crop {
+	/** width of layer in pixels */
+	unsigned int full_width;
+	/** height of layer in pixels */
+	unsigned int full_height;
+	/** horizontal offset of first pixel to be displayed */
+	unsigned int x_offset;
+	/** vertical offset of first pixel to be displayed */
+	unsigned int y_offset;
+	/** width of displayed data in pixels */
+	unsigned int width;
+	/** height of displayed data in pixels */
+	unsigned int height;
+	/** indicate which fields are present in buffer */
+	unsigned int field;
+};
+
+/** description of transformation from source to destination image */
+struct mxr_geometry {
+	/** cropping for source image */
+	struct mxr_crop src;
+	/** cropping for destination image */
+	struct mxr_crop dst;
+	/** layer-dependant description of horizontal scaling */
+	unsigned int x_ratio;
+	/** layer-dependant description of vertical scaling */
+	unsigned int y_ratio;
+};
+
+/** instance of a buffer */
+struct mxr_buffer {
+	/** common v4l buffer stuff -- must be first */
+	struct vb2_buffer	vb;
+	/** node for layer's lists */
+	struct list_head	list;
+};
+
+
+/** internal states of layer */
+enum mxr_layer_state {
+	/** layers is not shown */
+	MXR_LAYER_IDLE = 0,
+	/** state between STREAMON and hardware start */
+	MXR_LAYER_STREAMING_START,
+	/** layer is shown */
+	MXR_LAYER_STREAMING,
+	/** state before STREAMOFF is finished */
+	MXR_LAYER_STREAMING_FINISH,
+};
+
+/** forward declarations */
+struct mxr_device;
+struct mxr_layer;
+
+/** callback for layers operation */
+struct mxr_layer_ops {
+	/* TODO: try to port it to subdev API */
+	/** handler for resource release function */
+	void (*release)(struct mxr_layer *);
+	/** setting buffer to HW */
+	void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
+	/** setting format and geometry in HW */
+	void (*format_set)(struct mxr_layer *);
+	/** streaming stop/start */
+	void (*stream_set)(struct mxr_layer *, int);
+	/** adjusting geometry */
+	void (*fix_geometry)(struct mxr_layer *);
+};
+
+/** layer instance, a single window and content displayed on output */
+struct mxr_layer {
+	/** parent mixer device */
+	struct mxr_device *mdev;
+	/** layer index (unique identifier) */
+	int idx;
+	/** callbacks for layer methods */
+	struct mxr_layer_ops ops;
+	/** format array */
+	const struct mxr_format **fmt_array;
+	/** size of format array */
+	unsigned long fmt_array_size;
+
+	/** lock for protection of list and state fields */
+	spinlock_t enq_slock;
+	/** list for enqueued buffers */
+	struct list_head enq_list;
+	/** buffer currently owned by hardware in temporary registers */
+	struct mxr_buffer *update_buf;
+	/** buffer currently owned by hardware in shadow registers */
+	struct mxr_buffer *shadow_buf;
+	/** state of layer IDLE/STREAMING */
+	enum mxr_layer_state state;
+
+	/** mutex for protection of fields below */
+	struct mutex mutex;
+	/** handler for video node */
+	struct video_device vfd;
+	/** queue for output buffers */
+	struct vb2_queue vb_queue;
+	/** current image format */
+	const struct mxr_format *fmt;
+	/** current geometry of image */
+	struct mxr_geometry geo;
+};
+
+/** description of mixers output interface */
+struct mxr_output {
+	/** name of output */
+	char name[32];
+	/** output subdev */
+	struct v4l2_subdev *sd;
+	/** cookie used for configuration of registers */
+	int cookie;
+};
+
+/** specify source of output subdevs */
+struct mxr_output_conf {
+	/** name of output (connector) */
+	char *output_name;
+	/** name of module that generates output subdev */
+	char *module_name;
+	/** cookie need for mixer HW */
+	int cookie;
+};
+
+struct clk;
+struct regulator;
+
+/** auxiliary resources used my mixer */
+struct mxr_resources {
+	/** interrupt index */
+	int irq;
+	/** pointer to Mixer registers */
+	void __iomem *mxr_regs;
+	/** pointer to Video Processor registers */
+	void __iomem *vp_regs;
+	/** other resources, should used under mxr_device.mutex */
+	struct clk *mixer;
+	struct clk *vp;
+	struct clk *sclk_mixer;
+	struct clk *sclk_hdmi;
+	struct clk *sclk_dac;
+};
+
+/* event flags used  */
+enum mxr_devide_flags {
+	MXR_EVENT_VSYNC = 0,
+};
+
+/** drivers instance */
+struct mxr_device {
+	/** master device */
+	struct device *dev;
+	/** state of each layer */
+	struct mxr_layer *layer[MXR_MAX_LAYERS];
+	/** state of each output */
+	struct mxr_output *output[MXR_MAX_OUTPUTS];
+	/** number of registered outputs */
+	int output_cnt;
+
+	/* video resources */
+
+	/** V4L2 device */
+	struct v4l2_device v4l2_dev;
+	/** context of allocator */
+	void *alloc_ctx;
+	/** event wait queue */
+	wait_queue_head_t event_queue;
+	/** state flags */
+	unsigned long event_flags;
+
+	/** spinlock for protection of registers */
+	spinlock_t reg_slock;
+
+	/** mutex for protection of fields below */
+	struct mutex mutex;
+	/** number of entities depndant on output configuration */
+	int n_output;
+	/** number of users that do streaming */
+	int n_streamer;
+	/** index of current output */
+	int current_output;
+	/** auxiliary resources used my mixer */
+	struct mxr_resources res;
+};
+
+/** transform device structure into mixer device */
+static inline struct mxr_device *to_mdev(struct device *dev)
+{
+	struct v4l2_device *vdev = dev_get_drvdata(dev);
+	return container_of(vdev, struct mxr_device, v4l2_dev);
+}
+
+/** get current output data, should be called under mdev's mutex */
+static inline struct mxr_output *to_output(struct mxr_device *mdev)
+{
+	return mdev->output[mdev->current_output];
+}
+
+/** get current output subdev, should be called under mdev's mutex */
+static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
+{
+	struct mxr_output *out = to_output(mdev);
+	return out ? out->sd : NULL;
+}
+
+/** forward declaration for mixer platform data */
+struct mxr_platform_data;
+
+/** acquiring common video resources */
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+	struct mxr_output_conf *output_cont, int output_count);
+
+/** releasing common video resources */
+void __devexit mxr_release_video(struct mxr_device *mdev);
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+	int idx, char *name, struct mxr_layer_ops *ops);
+
+void mxr_base_layer_release(struct mxr_layer *layer);
+void mxr_layer_release(struct mxr_layer *layer);
+
+int mxr_base_layer_register(struct mxr_layer *layer);
+void mxr_base_layer_unregister(struct mxr_layer *layer);
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+	unsigned int width, unsigned int height);
+
+/** adds new consumer for mixer's power */
+int __must_check mxr_power_get(struct mxr_device *mdev);
+/** removes consumer for mixer's power */
+void mxr_power_put(struct mxr_device *mdev);
+/** add new client for output configuration */
+void mxr_output_get(struct mxr_device *mdev);
+/** removes new client for output configuration */
+void mxr_output_put(struct mxr_device *mdev);
+/** add new client for streaming */
+void mxr_streamer_get(struct mxr_device *mdev);
+/** removes new client for streaming */
+void mxr_streamer_put(struct mxr_device *mdev);
+/** returns format of data delivared to current output */
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *mbus_fmt);
+
+/* Debug */
+
+#define mxr_err(mdev, fmt, ...)  dev_err(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+	#define mxr_dbg(mdev, fmt, ...)  dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
+#else
+	#define mxr_dbg(mdev, fmt, ...)  do { (void) mdev; } while (0)
+#endif
+
+/* accessing Mixer's and Video Processor's registers */
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en);
+void mxr_reg_reset(struct mxr_device *mdev);
+irqreturn_t mxr_irq_handler(int irq, void *dev_data);
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
+void mxr_reg_streamon(struct mxr_device *mdev);
+void mxr_reg_streamoff(struct mxr_device *mdev);
+int mxr_reg_wait4vsync(struct mxr_device *mdev);
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *fmt);
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo);
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+	dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
+void mxr_reg_vp_format(struct mxr_device *mdev,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo);
+void mxr_reg_dump(struct mxr_device *mdev);
+
+#endif /* SAMSUNG_MIXER_H */
+
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
new file mode 100644
index 0000000..0064309
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -0,0 +1,487 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+	{
+		.output_name = "S5P HDMI connector",
+		.module_name = "s5p-hdmi",
+		.cookie = 1,
+	},
+	{
+		.output_name = "S5P SDO connector",
+		.module_name = "s5p-sdo",
+		.cookie = 0,
+	},
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *mbus_fmt)
+{
+	struct v4l2_subdev *sd;
+	int ret;
+
+	mutex_lock(&mdev->mutex);
+	sd = to_outsd(mdev);
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+	WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+	mutex_unlock(&mdev->mutex);
+}
+
+void mxr_streamer_get(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	++mdev->n_streamer;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+	if (mdev->n_streamer == 1) {
+		struct v4l2_subdev *sd = to_outsd(mdev);
+		struct v4l2_mbus_framefmt mbus_fmt;
+		struct mxr_resources *res = &mdev->res;
+		int ret;
+
+		if (to_output(mdev)->cookie == 0)
+			clk_set_parent(res->sclk_mixer, res->sclk_dac);
+		else
+			clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+		mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+		WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+		ret = v4l2_subdev_call(sd, video, s_stream, 1);
+		WARN(ret, "starting stream failed for output %s\n", sd->name);
+
+		mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
+		mxr_reg_streamon(mdev);
+		ret = mxr_reg_wait4vsync(mdev);
+		WARN(ret, "failed to get vsync (%d) from output\n", ret);
+	}
+	mutex_unlock(&mdev->mutex);
+	mxr_reg_dump(mdev);
+	/* FIXME: what to do when streaming fails? */
+}
+
+void mxr_streamer_put(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	--mdev->n_streamer;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+	if (mdev->n_streamer == 0) {
+		int ret;
+		struct v4l2_subdev *sd = to_outsd(mdev);
+
+		mxr_reg_streamoff(mdev);
+		/* vsync applies Mixer setup */
+		ret = mxr_reg_wait4vsync(mdev);
+		WARN(ret, "failed to get vsync (%d) from output\n", ret);
+		ret = v4l2_subdev_call(sd, video, s_stream, 0);
+		WARN(ret, "stopping stream failed for output %s\n", sd->name);
+	}
+	WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+		mdev->n_streamer);
+	mutex_unlock(&mdev->mutex);
+	mxr_reg_dump(mdev);
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	++mdev->n_output;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+	/* turn on auxiliary driver */
+	if (mdev->n_output == 1)
+		v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+	mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	--mdev->n_output;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+	/* turn on auxiliary driver */
+	if (mdev->n_output == 0)
+		v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+	WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+		mdev->n_output);
+	mutex_unlock(&mdev->mutex);
+}
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+	int ret = pm_runtime_get_sync(mdev->dev);
+
+	/* returning 1 means that power is already enabled,
+	 * so zero success be returned */
+	if (IS_ERR_VALUE(ret))
+		return ret;
+	return 0;
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+	pm_runtime_put_sync(mdev->dev);
+}
+
+/* --------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+	struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+	if (res == NULL) {
+		mxr_err(mdev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+	if (mdev->res.mxr_regs == NULL) {
+		mxr_err(mdev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+	if (res == NULL) {
+		mxr_err(mdev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail_mxr_regs;
+	}
+
+	mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+	if (mdev->res.vp_regs == NULL) {
+		mxr_err(mdev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail_mxr_regs;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+	if (res == NULL) {
+		mxr_err(mdev, "get interrupt resource failed.\n");
+		ret = -ENXIO;
+		goto fail_vp_regs;
+	}
+
+	ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+	if (ret) {
+		mxr_err(mdev, "request interrupt failed.\n");
+		goto fail_vp_regs;
+	}
+	mdev->res.irq = res->start;
+
+	return 0;
+
+fail_vp_regs:
+	iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+	iounmap(mdev->res.mxr_regs);
+
+fail:
+	return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+	free_irq(mdev->res.irq, mdev);
+	iounmap(mdev->res.vp_regs);
+	iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+	struct mxr_resources *res = &mdev->res;
+
+	if (!IS_ERR_OR_NULL(res->sclk_dac))
+		clk_put(res->sclk_dac);
+	if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+		clk_put(res->sclk_hdmi);
+	if (!IS_ERR_OR_NULL(res->sclk_mixer))
+		clk_put(res->sclk_mixer);
+	if (!IS_ERR_OR_NULL(res->vp))
+		clk_put(res->vp);
+	if (!IS_ERR_OR_NULL(res->mixer))
+		clk_put(res->mixer);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+	struct mxr_resources *res = &mdev->res;
+	struct device *dev = mdev->dev;
+
+	res->mixer = clk_get(dev, "mixer");
+	if (IS_ERR_OR_NULL(res->mixer)) {
+		mxr_err(mdev, "failed to get clock 'mixer'\n");
+		goto fail;
+	}
+	res->vp = clk_get(dev, "vp");
+	if (IS_ERR_OR_NULL(res->vp)) {
+		mxr_err(mdev, "failed to get clock 'vp'\n");
+		goto fail;
+	}
+	res->sclk_mixer = clk_get(dev, "sclk_mixer");
+	if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+		mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+		goto fail;
+	}
+	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+		mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+		goto fail;
+	}
+	res->sclk_dac = clk_get(dev, "sclk_dac");
+	if (IS_ERR_OR_NULL(res->sclk_dac)) {
+		mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+		goto fail;
+	}
+
+	return 0;
+fail:
+	mxr_release_clocks(mdev);
+	return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+	struct platform_device *pdev)
+{
+	int ret;
+	ret = mxr_acquire_plat_resources(mdev, pdev);
+
+	if (ret)
+		goto fail;
+
+	ret = mxr_acquire_clocks(mdev);
+	if (ret)
+		goto fail_plat;
+
+	mxr_info(mdev, "resources acquired\n");
+	return 0;
+
+fail_plat:
+	mxr_release_plat_resources(mdev);
+fail:
+	mxr_err(mdev, "resources acquire failed\n");
+	return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+	mxr_release_clocks(mdev);
+	mxr_release_plat_resources(mdev);
+	memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
+		if (mdev->layer[i])
+			mxr_layer_release(mdev->layer[i]);
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+	struct mxr_platform_data *pdata)
+{
+	mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
+	mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
+	mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
+
+	if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
+		mxr_err(mdev, "failed to acquire layers\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	mxr_release_layers(mdev);
+	return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+	struct mxr_device *mdev = to_mdev(dev);
+	struct mxr_resources *res = &mdev->res;
+
+	mxr_dbg(mdev, "resume - start\n");
+	mutex_lock(&mdev->mutex);
+	/* turn clocks on */
+	clk_enable(res->mixer);
+	clk_enable(res->vp);
+	clk_enable(res->sclk_mixer);
+	/* apply default configuration */
+	mxr_reg_reset(mdev);
+	mxr_dbg(mdev, "resume - finished\n");
+
+	mutex_unlock(&mdev->mutex);
+	return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+	struct mxr_device *mdev = to_mdev(dev);
+	struct mxr_resources *res = &mdev->res;
+	mxr_dbg(mdev, "suspend - start\n");
+	mutex_lock(&mdev->mutex);
+	/* turn clocks off */
+	clk_disable(res->sclk_mixer);
+	clk_disable(res->vp);
+	clk_disable(res->mixer);
+	mutex_unlock(&mdev->mutex);
+	mxr_dbg(mdev, "suspend - finished\n");
+	return 0;
+}
+
+static const struct dev_pm_ops mxr_pm_ops = {
+	.runtime_suspend = mxr_runtime_suspend,
+	.runtime_resume	 = mxr_runtime_resume,
+};
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxr_platform_data *pdata = dev->platform_data;
+	struct mxr_device *mdev;
+	int ret;
+
+	/* mdev does not exist yet so no mxr_dbg is used */
+	dev_info(dev, "probe start\n");
+
+	mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+	if (!mdev) {
+		mxr_err(mdev, "not enough memory.\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* setup pointer to master device */
+	mdev->dev = dev;
+
+	mutex_init(&mdev->mutex);
+	spin_lock_init(&mdev->reg_slock);
+	init_waitqueue_head(&mdev->event_queue);
+
+	/* acquire resources: regs, irqs, clocks, regulators */
+	ret = mxr_acquire_resources(mdev, pdev);
+	if (ret)
+		goto fail_mem;
+
+	/* configure resources for video output */
+	ret = mxr_acquire_video(mdev, mxr_output_conf,
+		ARRAY_SIZE(mxr_output_conf));
+	if (ret)
+		goto fail_resources;
+
+	/* configure layers */
+	ret = mxr_acquire_layers(mdev, pdata);
+	if (ret)
+		goto fail_video;
+
+	pm_runtime_enable(dev);
+
+	mxr_info(mdev, "probe successful\n");
+	return 0;
+
+fail_video:
+	mxr_release_video(mdev);
+
+fail_resources:
+	mxr_release_resources(mdev);
+
+fail_mem:
+	kfree(mdev);
+
+fail:
+	dev_info(dev, "probe failed\n");
+	return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxr_device *mdev = to_mdev(dev);
+
+	pm_runtime_disable(dev);
+
+	mxr_release_layers(mdev);
+	mxr_release_video(mdev);
+	mxr_release_resources(mdev);
+
+	kfree(mdev);
+
+	dev_info(dev, "remove sucessful\n");
+	return 0;
+}
+
+static struct platform_driver mxr_driver __refdata = {
+	.probe = mxr_probe,
+	.remove = __devexit_p(mxr_remove),
+	.driver = {
+		.name = MXR_DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.pm = &mxr_pm_ops,
+	}
+};
+
+static int __init mxr_init(void)
+{
+	int i, ret;
+	static const char banner[] __initdata = KERN_INFO
+		"Samsung TV Mixer driver, "
+		"(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+	printk(banner);
+
+	/* Loading auxiliary modules */
+	for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+		request_module(mxr_output_conf[i].module_name);
+
+	ret = platform_driver_register(&mxr_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "registration of MIXER driver failed\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+module_init(mxr_init);
+
+static void __exit mxr_exit(void)
+{
+	platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
new file mode 100644
index 0000000..58f0ba4
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c
@@ -0,0 +1,185 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+
+static const struct mxr_format mxr_fb_fmt_rgb565 = {
+	.name = "RGB565",
+	.fourcc = V4L2_PIX_FMT_RGB565,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.num_planes = 1,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = 4,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb1555 = {
+	.name = "ARGB1555",
+	.num_planes = 1,
+	.fourcc = V4L2_PIX_FMT_RGB555,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = 5,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb4444 = {
+	.name = "ARGB4444",
+	.num_planes = 1,
+	.fourcc = V4L2_PIX_FMT_RGB444,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = 6,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb8888 = {
+	.name = "ARGB8888",
+	.fourcc = V4L2_PIX_FMT_BGR32,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.num_planes = 1,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 4 },
+	},
+	.num_subframes = 1,
+	.cookie = 7,
+};
+
+static const struct mxr_format *mxr_graph_format[] = {
+	&mxr_fb_fmt_rgb565,
+	&mxr_fb_fmt_argb1555,
+	&mxr_fb_fmt_argb4444,
+	&mxr_fb_fmt_argb8888,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_graph_layer_release(struct mxr_layer *layer)
+{
+	mxr_base_layer_unregister(layer);
+	mxr_base_layer_release(layer);
+}
+
+static void mxr_graph_buffer_set(struct mxr_layer *layer,
+	struct mxr_buffer *buf)
+{
+	dma_addr_t addr = 0;
+
+	if (buf)
+		addr = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+	mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
+}
+
+static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
+{
+	mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_graph_format_set(struct mxr_layer *layer)
+{
+	mxr_reg_graph_format(layer->mdev, layer->idx,
+		layer->fmt, &layer->geo);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+{
+	struct mxr_geometry *geo = &layer->geo;
+
+	/* limit to boundary size */
+	geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
+	geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
+	geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
+	geo->src.width = min(geo->src.width, 2047U);
+	/* not possible to crop of Y axis */
+	geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
+	geo->src.height = geo->src.full_height - geo->src.y_offset;
+	/* limitting offset */
+	geo->src.x_offset = min(geo->src.x_offset,
+		geo->src.full_width - geo->src.width);
+
+	/* setting position in output */
+	geo->dst.width = min(geo->dst.width, geo->dst.full_width);
+	geo->dst.height = min(geo->dst.height, geo->dst.full_height);
+
+	/* Mixer supports only 1x and 2x scaling */
+	if (geo->dst.width >= 2 * geo->src.width) {
+		geo->x_ratio = 1;
+		geo->dst.width = 2 * geo->src.width;
+	} else {
+		geo->x_ratio = 0;
+		geo->dst.width = geo->src.width;
+	}
+
+	if (geo->dst.height >= 2 * geo->src.height) {
+		geo->y_ratio = 1;
+		geo->dst.height = 2 * geo->src.height;
+	} else {
+		geo->y_ratio = 0;
+		geo->dst.height = geo->src.height;
+	}
+
+	geo->dst.x_offset = min(geo->dst.x_offset,
+		geo->dst.full_width - geo->dst.width);
+	geo->dst.y_offset = min(geo->dst.y_offset,
+		geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
+{
+	struct mxr_layer *layer;
+	int ret;
+	struct mxr_layer_ops ops = {
+		.release = mxr_graph_layer_release,
+		.buffer_set = mxr_graph_buffer_set,
+		.stream_set = mxr_graph_stream_set,
+		.format_set = mxr_graph_format_set,
+		.fix_geometry = mxr_graph_fix_geometry,
+	};
+	char name[32];
+
+	sprintf(name, "graph%d", idx);
+
+	layer = mxr_base_layer_create(mdev, idx, name, &ops);
+	if (layer == NULL) {
+		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+		goto fail;
+	}
+
+	layer->fmt_array = mxr_graph_format;
+	layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
+
+	ret = mxr_base_layer_register(layer);
+	if (ret)
+		goto fail_layer;
+
+	return layer;
+
+fail_layer:
+	mxr_base_layer_release(layer);
+
+fail:
+	return NULL;
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
new file mode 100644
index 0000000..38dac67
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_reg.c
@@ -0,0 +1,541 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
+
+#include <linux/delay.h>
+
+/* Register access subroutines */
+
+static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
+{
+	return readl(mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+	writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
+	u32 val, u32 mask)
+{
+	u32 old = vp_read(mdev, reg_id);
+
+	val = (val & mask) | (old & ~mask);
+	writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
+{
+	return readl(mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+	writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
+	u32 val, u32 mask)
+{
+	u32 old = mxr_read(mdev, reg_id);
+
+	val = (val & mask) | (old & ~mask);
+	writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en)
+{
+	/* block update on vsync */
+	mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
+		MXR_STATUS_SYNC_ENABLE);
+	vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
+}
+
+static void __mxr_reg_vp_reset(struct mxr_device *mdev)
+{
+	int tries = 100;
+
+	vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
+	for (tries = 100; tries; --tries) {
+		/* waiting until VP_SRESET_PROCESSING is 0 */
+		if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
+			break;
+		mdelay(10);
+	}
+	WARN(tries == 0, "failed to reset Video Processor\n");
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
+
+void mxr_reg_reset(struct mxr_device *mdev)
+{
+	unsigned long flags;
+	u32 val; /* value stored to register */
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	/* set output in RGB888 mode */
+	mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444);
+
+	/* 16 beat burst in DMA */
+	mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
+		MXR_STATUS_BURST_MASK);
+
+	/* setting default layer priority: layer1 > video > layer0
+	 * because typical usage scenario would be
+	 * layer0 - framebuffer
+	 * video - video overlay
+	 * layer1 - OSD
+	 */
+	val  = MXR_LAYER_CFG_GRP0_VAL(1);
+	val |= MXR_LAYER_CFG_VP_VAL(2);
+	val |= MXR_LAYER_CFG_GRP1_VAL(3);
+	mxr_write(mdev, MXR_LAYER_CFG, val);
+
+	/* use dark gray background color */
+	mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
+	mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
+	mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
+
+	/* setting graphical layers */
+
+	val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+	val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
+	val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+	/* the same configuration for both layers */
+	mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
+	mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
+
+	/* configuration of Video Processor Registers */
+	__mxr_reg_vp_reset(mdev);
+	mxr_reg_vp_default_filter(mdev);
+
+	/* enable all interrupts */
+	mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	/* setup format */
+	mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
+		MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK);
+
+	/* setup geometry */
+	mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
+	val  = MXR_GRP_WH_WIDTH(geo->src.width);
+	val |= MXR_GRP_WH_HEIGHT(geo->src.height);
+	val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
+	val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
+	mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
+
+	/* setup offsets in source image */
+	val  = MXR_GRP_SXY_SX(geo->src.x_offset);
+	val |= MXR_GRP_SXY_SY(geo->src.y_offset);
+	mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
+
+	/* setup offsets in display image */
+	val  = MXR_GRP_DXY_DX(geo->dst.x_offset);
+	val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
+	mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_format(struct mxr_device *mdev,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
+
+	/* setting size of input image */
+	vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
+		VP_IMG_VSIZE(geo->src.full_height));
+	/* chroma height has to reduced by 2 to avoid chroma distorions */
+	vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
+		VP_IMG_VSIZE(geo->src.full_height / 2));
+
+	vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
+	vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
+	vp_write(mdev, VP_SRC_H_POSITION,
+		VP_SRC_H_POSITION_VAL(geo->src.x_offset));
+	vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
+
+	vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
+	vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
+	if (geo->dst.field == V4L2_FIELD_INTERLACED) {
+		vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
+		vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
+	} else {
+		vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
+		vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
+	}
+
+	vp_write(mdev, VP_H_RATIO, geo->x_ratio);
+	vp_write(mdev, VP_V_RATIO, geo->y_ratio);
+
+	vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+
+}
+
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
+{
+	u32 val = addr ? ~0 : 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	if (idx == 0)
+		mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+	else
+		mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+	mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+	dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
+{
+	u32 val = luma_addr[0] ? ~0 : 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
+	vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
+	/* TODO: fix tiled mode */
+	vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
+	vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
+	vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
+	vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+static void mxr_irq_layer_handle(struct mxr_layer *layer)
+{
+	struct list_head *head = &layer->enq_list;
+	struct mxr_buffer *done;
+
+	/* skip non-existing layer */
+	if (layer == NULL)
+		return;
+
+	spin_lock(&layer->enq_slock);
+	if (layer->state == MXR_LAYER_IDLE)
+		goto done;
+
+	done = layer->shadow_buf;
+	layer->shadow_buf = layer->update_buf;
+
+	if (list_empty(head)) {
+		if (layer->state != MXR_LAYER_STREAMING)
+			layer->update_buf = NULL;
+	} else {
+		struct mxr_buffer *next;
+		next = list_first_entry(head, struct mxr_buffer, list);
+		list_del(&next->list);
+		layer->update_buf = next;
+	}
+
+	layer->ops.buffer_set(layer, layer->update_buf);
+
+	if (done && done != layer->shadow_buf)
+		vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
+
+done:
+	spin_unlock(&layer->enq_slock);
+}
+
+irqreturn_t mxr_irq_handler(int irq, void *dev_data)
+{
+	struct mxr_device *mdev = dev_data;
+	u32 i, val;
+
+	spin_lock(&mdev->reg_slock);
+	val = mxr_read(mdev, MXR_INT_STATUS);
+
+	/* wake up process waiting for VSYNC */
+	if (val & MXR_INT_STATUS_VSYNC) {
+		set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+		wake_up(&mdev->event_queue);
+	}
+
+	/* clear interrupts */
+	if (~val & MXR_INT_EN_VSYNC) {
+		/* vsync interrupt use different bit for read and clear */
+		val &= ~MXR_INT_EN_VSYNC;
+		val |= MXR_INT_CLEAR_VSYNC;
+	}
+	mxr_write(mdev, MXR_INT_STATUS, val);
+
+	spin_unlock(&mdev->reg_slock);
+	/* leave on non-vsync event */
+	if (~val & MXR_INT_CLEAR_VSYNC)
+		return IRQ_HANDLED;
+	for (i = 0; i < MXR_MAX_LAYERS; ++i)
+		mxr_irq_layer_handle(mdev->layer[i]);
+	return IRQ_HANDLED;
+}
+
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
+{
+	u32 val;
+
+	val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
+	mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
+}
+
+void mxr_reg_streamon(struct mxr_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	/* single write -> no need to block vsync update */
+
+	/* start MIXER */
+	mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_streamoff(struct mxr_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	/* single write -> no need to block vsync update */
+
+	/* stop MIXER */
+	mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+int mxr_reg_wait4vsync(struct mxr_device *mdev)
+{
+	int ret;
+
+	clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+	/* TODO: consider adding interruptible */
+	ret = wait_event_timeout(mdev->event_queue,
+		test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
+		msecs_to_jiffies(1000));
+	if (ret > 0)
+		return 0;
+	if (ret < 0)
+		return ret;
+	mxr_warn(mdev, "no vsync detected - timeout\n");
+	return -ETIME;
+}
+
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *fmt)
+{
+	u32 val = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	/* choosing between interlace and progressive mode */
+	if (fmt->field == V4L2_FIELD_INTERLACED)
+		val |= MXR_CFG_SCAN_INTERLACE;
+	else
+		val |= MXR_CFG_SCAN_PROGRASSIVE;
+
+	/* choosing between porper HD and SD mode */
+	if (fmt->height == 480)
+		val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+	else if (fmt->height == 576)
+		val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+	else if (fmt->height == 720)
+		val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+	else if (fmt->height == 1080)
+		val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+	else
+		WARN(1, "unrecognized mbus height %u!\n", fmt->height);
+
+	mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK);
+
+	val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
+	vp_write_mask(mdev, VP_MODE, val,
+		VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+	/* no extra actions need to be done */
+}
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
+{
+	/* no extra actions need to be done */
+}
+
+static const u8 filter_y_horiz_tap8[] = {
+	0,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	0,	0,	0,
+	0,	2,	4,	5,	6,	6,	6,	6,
+	6,	5,	5,	4,	3,	2,	1,	1,
+	0,	-6,	-12,	-16,	-18,	-20,	-21,	-20,
+	-20,	-18,	-16,	-13,	-10,	-8,	-5,	-2,
+	127,	126,	125,	121,	114,	107,	99,	89,
+	79,	68,	57,	46,	35,	25,	16,	8,
+};
+
+static const u8 filter_y_vert_tap4[] = {
+	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
+	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
+	127,	126,	124,	118,	111,	102,	92,	81,
+	70,	59,	48,	37,	27,	19,	11,	5,
+	0,	5,	11,	19,	27,	37,	48,	59,
+	70,	81,	92,	102,	111,	118,	124,	126,
+	0,	0,	-1,	-1,	-2,	-3,	-4,	-5,
+	-6,	-7,	-8,	-8,	-8,	-8,	-6,	-3,
+};
+
+static const u8 filter_cr_horiz_tap4[] = {
+	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
+	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
+	127,	126,	124,	118,	111,	102,	92,	81,
+	70,	59,	48,	37,	27,	19,	11,	5,
+};
+
+static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
+	int reg_id, const u8 *data, unsigned int size)
+{
+	/* assure 4-byte align */
+	BUG_ON(size & 3);
+	for (; size; size -= 4, reg_id += 4, data += 4) {
+		u32 val = (data[0] << 24) |  (data[1] << 16) |
+			(data[2] << 8) | data[3];
+		vp_write(mdev, reg_id, val);
+	}
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
+{
+	mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
+		filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+	mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
+		filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+	mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
+		filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+}
+
+static void mxr_reg_mxr_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+	mxr_dbg(mdev, #reg_id " = %08x\n", \
+		(u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+	DUMPREG(MXR_STATUS);
+	DUMPREG(MXR_CFG);
+	DUMPREG(MXR_INT_EN);
+	DUMPREG(MXR_INT_STATUS);
+
+	DUMPREG(MXR_LAYER_CFG);
+	DUMPREG(MXR_VIDEO_CFG);
+
+	DUMPREG(MXR_GRAPHIC0_CFG);
+	DUMPREG(MXR_GRAPHIC0_BASE);
+	DUMPREG(MXR_GRAPHIC0_SPAN);
+	DUMPREG(MXR_GRAPHIC0_WH);
+	DUMPREG(MXR_GRAPHIC0_SXY);
+	DUMPREG(MXR_GRAPHIC0_DXY);
+
+	DUMPREG(MXR_GRAPHIC1_CFG);
+	DUMPREG(MXR_GRAPHIC1_BASE);
+	DUMPREG(MXR_GRAPHIC1_SPAN);
+	DUMPREG(MXR_GRAPHIC1_WH);
+	DUMPREG(MXR_GRAPHIC1_SXY);
+	DUMPREG(MXR_GRAPHIC1_DXY);
+#undef DUMPREG
+}
+
+static void mxr_reg_vp_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+	mxr_dbg(mdev, #reg_id " = %08x\n", \
+		(u32) readl(mdev->res.vp_regs + reg_id)); \
+} while (0)
+
+
+	DUMPREG(VP_ENABLE);
+	DUMPREG(VP_SRESET);
+	DUMPREG(VP_SHADOW_UPDATE);
+	DUMPREG(VP_FIELD_ID);
+	DUMPREG(VP_MODE);
+	DUMPREG(VP_IMG_SIZE_Y);
+	DUMPREG(VP_IMG_SIZE_C);
+	DUMPREG(VP_PER_RATE_CTRL);
+	DUMPREG(VP_TOP_Y_PTR);
+	DUMPREG(VP_BOT_Y_PTR);
+	DUMPREG(VP_TOP_C_PTR);
+	DUMPREG(VP_BOT_C_PTR);
+	DUMPREG(VP_ENDIAN_MODE);
+	DUMPREG(VP_SRC_H_POSITION);
+	DUMPREG(VP_SRC_V_POSITION);
+	DUMPREG(VP_SRC_WIDTH);
+	DUMPREG(VP_SRC_HEIGHT);
+	DUMPREG(VP_DST_H_POSITION);
+	DUMPREG(VP_DST_V_POSITION);
+	DUMPREG(VP_DST_WIDTH);
+	DUMPREG(VP_DST_HEIGHT);
+	DUMPREG(VP_H_RATIO);
+	DUMPREG(VP_V_RATIO);
+
+#undef DUMPREG
+}
+
+void mxr_reg_dump(struct mxr_device *mdev)
+{
+	mxr_reg_mxr_dump(mdev);
+	mxr_reg_vp_dump(mdev);
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
new file mode 100644
index 0000000..43ac22f
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -0,0 +1,1006 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <media/videobuf2-dma-contig.h>
+
+static int find_reg_callback(struct device *dev, void *p)
+{
+	struct v4l2_subdev **sd = p;
+
+	*sd = dev_get_drvdata(dev);
+	/* non-zero value stops iteration */
+	return 1;
+}
+
+static struct v4l2_subdev *find_and_register_subdev(
+	struct mxr_device *mdev, char *module_name)
+{
+	struct device_driver *drv;
+	struct v4l2_subdev *sd = NULL;
+	int ret;
+
+	/* TODO: add waiting until probe is finished */
+	drv = driver_find(module_name, &platform_bus_type);
+	if (!drv) {
+		mxr_warn(mdev, "module %s is missing\n", module_name);
+		return NULL;
+	}
+	/* driver refcnt is increased, it is safe to iterate over devices */
+	ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
+	/* ret == 0 means that find_reg_callback was never executed */
+	if (sd == NULL) {
+		mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
+		goto done;
+	}
+	/* v4l2_device_register_subdev detects if sd is NULL */
+	ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
+	if (ret) {
+		mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
+		sd = NULL;
+	}
+
+done:
+	put_driver(drv);
+	return sd;
+}
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+	struct mxr_output_conf *output_conf, int output_count)
+{
+	struct device *dev = mdev->dev;
+	struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
+	int i;
+	int ret = 0;
+	struct v4l2_subdev *sd;
+
+	strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
+	/* prepare context for V4L2 device */
+	ret = v4l2_device_register(dev, v4l2_dev);
+	if (ret) {
+		mxr_err(mdev, "could not register v4l2 device.\n");
+		goto fail;
+	}
+
+	mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
+	if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+		mxr_err(mdev, "could not acquire vb2 allocator\n");
+		goto fail_v4l2_dev;
+	}
+
+	/* registering outputs */
+	mdev->output_cnt = 0;
+	for (i = 0; i < output_count; ++i) {
+		struct mxr_output_conf *conf = &output_conf[i];
+		struct mxr_output *out;
+
+		sd = find_and_register_subdev(mdev, conf->module_name);
+		/* trying to register next output */
+		if (sd == NULL)
+			continue;
+		out = kzalloc(sizeof *out, GFP_KERNEL);
+		if (out == NULL) {
+			mxr_err(mdev, "no memory for '%s'\n",
+				conf->output_name);
+			ret = -ENOMEM;
+			/* registered subdevs are removed in fail_v4l2_dev */
+			goto fail_output;
+		}
+		strlcpy(out->name, conf->output_name, sizeof(out->name));
+		out->sd = sd;
+		out->cookie = conf->cookie;
+		mdev->output[mdev->output_cnt++] = out;
+		mxr_info(mdev, "added output '%s' from module '%s'\n",
+			conf->output_name, conf->module_name);
+		/* checking if maximal number of outputs is reached */
+		if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+			break;
+	}
+
+	if (mdev->output_cnt == 0) {
+		mxr_err(mdev, "failed to register any output\n");
+		ret = -ENODEV;
+		/* skipping fail_output because there is nothing to free */
+		goto fail_vb2_allocator;
+	}
+
+	return 0;
+
+fail_output:
+	/* kfree is NULL-safe */
+	for (i = 0; i < mdev->output_cnt; ++i)
+		kfree(mdev->output[i]);
+	memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+	/* freeing allocator context */
+	vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+
+fail_v4l2_dev:
+	/* NOTE: automatically unregister all subdevs */
+	v4l2_device_unregister(v4l2_dev);
+
+fail:
+	return ret;
+}
+
+void __devexit mxr_release_video(struct mxr_device *mdev)
+{
+	int i;
+
+	/* kfree is NULL-safe */
+	for (i = 0; i < mdev->output_cnt; ++i)
+		kfree(mdev->output[i]);
+
+	vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+	v4l2_device_unregister(&mdev->v4l2_dev);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+	struct v4l2_capability *cap)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+	strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+	sprintf(cap->bus_info, "%d", layer->idx);
+	cap->version = KERNEL_VERSION(0, 1, 0);
+	cap->capabilities = V4L2_CAP_STREAMING |
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+	return 0;
+}
+
+/* Geometry handling */
+static void mxr_layer_geo_fix(struct mxr_layer *layer)
+{
+	struct mxr_device *mdev = layer->mdev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	/* TODO: add some dirty flag to avoid unnecessary adjustments */
+	mxr_get_mbus_fmt(mdev, &mbus_fmt);
+	layer->geo.dst.full_width = mbus_fmt.width;
+	layer->geo.dst.full_height = mbus_fmt.height;
+	layer->geo.dst.field = mbus_fmt.field;
+	layer->ops.fix_geometry(layer);
+}
+
+static void mxr_layer_default_geo(struct mxr_layer *layer)
+{
+	struct mxr_device *mdev = layer->mdev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	memset(&layer->geo, 0, sizeof layer->geo);
+
+	mxr_get_mbus_fmt(mdev, &mbus_fmt);
+
+	layer->geo.dst.full_width = mbus_fmt.width;
+	layer->geo.dst.full_height = mbus_fmt.height;
+	layer->geo.dst.width = layer->geo.dst.full_width;
+	layer->geo.dst.height = layer->geo.dst.full_height;
+	layer->geo.dst.field = mbus_fmt.field;
+
+	layer->geo.src.full_width = mbus_fmt.width;
+	layer->geo.src.full_height = mbus_fmt.height;
+	layer->geo.src.width = layer->geo.src.full_width;
+	layer->geo.src.height = layer->geo.src.full_height;
+
+	layer->ops.fix_geometry(layer);
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+	mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+		geo->src.full_width, geo->src.full_height);
+	mxr_dbg(mdev, "src.size = (%u, %u)\n",
+		geo->src.width, geo->src.height);
+	mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+		geo->src.x_offset, geo->src.y_offset);
+	mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+		geo->dst.full_width, geo->dst.full_height);
+	mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+		geo->dst.width, geo->dst.height);
+	mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+		geo->dst.x_offset, geo->dst.y_offset);
+	mxr_dbg(mdev, "ratio = (%u, %u)\n",
+		geo->x_ratio, geo->y_ratio);
+}
+
+
+static const struct mxr_format *find_format_by_fourcc(
+	struct mxr_layer *layer, unsigned long fourcc);
+static const struct mxr_format *find_format_by_index(
+	struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *f)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	const struct mxr_format *fmt;
+
+	mxr_dbg(mdev, "%s\n", __func__);
+	fmt = find_format_by_index(layer, f->index);
+	if (fmt == NULL)
+		return -EINVAL;
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int mxr_s_fmt(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	const struct mxr_format *fmt;
+	struct v4l2_pix_format_mplane *pix;
+	struct mxr_device *mdev = layer->mdev;
+	struct mxr_geometry *geo = &layer->geo;
+
+	mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+	pix = &f->fmt.pix_mp;
+	fmt = find_format_by_fourcc(layer, pix->pixelformat);
+	if (fmt == NULL) {
+		mxr_warn(mdev, "not recognized fourcc: %08x\n",
+			pix->pixelformat);
+		return -EINVAL;
+	}
+	layer->fmt = fmt;
+	geo->src.full_width = pix->width;
+	geo->src.width = pix->width;
+	geo->src.full_height = pix->height;
+	geo->src.height = pix->height;
+	/* assure consistency of geometry */
+	mxr_layer_geo_fix(layer);
+	mxr_dbg(mdev, "width=%u height=%u span=%u\n",
+		geo->src.width, geo->src.height, geo->src.full_width);
+
+	return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+	return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+	unsigned int width, unsigned int height)
+{
+	unsigned int bl_width = divup(width, blk->width);
+	unsigned int bl_height = divup(height, blk->height);
+
+	return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+	const struct mxr_format *fmt, u32 width, u32 height)
+{
+	int i;
+
+	memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
+	for (i = 0; i < fmt->num_planes; ++i) {
+		struct v4l2_plane_pix_format *plane = planes
+			+ fmt->plane2subframe[i];
+		const struct mxr_block *blk = &fmt->plane[i];
+		u32 bl_width = divup(width, blk->width);
+		u32 bl_height = divup(height, blk->height);
+		u32 sizeimage = bl_width * bl_height * blk->size;
+		u16 bytesperline = bl_width * blk->size / blk->height;
+
+		plane->sizeimage += sizeimage;
+		plane->bytesperline = max(plane->bytesperline, bytesperline);
+	}
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+			     struct v4l2_format *f)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	pix->width = layer->geo.src.full_width;
+	pix->height = layer->geo.src.full_height;
+	pix->field = V4L2_FIELD_NONE;
+	pix->pixelformat = layer->fmt->fourcc;
+	pix->colorspace = layer->fmt->colorspace;
+	mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+	return 0;
+}
+
+static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
+	enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		return &geo->dst;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		return &geo->src;
+	default:
+		return NULL;
+	}
+}
+
+static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_crop *crop;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	crop = choose_crop_by_type(&layer->geo, a->type);
+	if (crop == NULL)
+		return -EINVAL;
+	mxr_layer_geo_fix(layer);
+	a->c.left = crop->x_offset;
+	a->c.top = crop->y_offset;
+	a->c.width = crop->width;
+	a->c.height = crop->height;
+	return 0;
+}
+
+static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_crop *crop;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	crop = choose_crop_by_type(&layer->geo, a->type);
+	if (crop == NULL)
+		return -EINVAL;
+	crop->x_offset = a->c.left;
+	crop->y_offset = a->c.top;
+	crop->width = a->c.width;
+	crop->height = a->c.height;
+	mxr_layer_geo_fix(layer);
+	return 0;
+}
+
+static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_crop *crop;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	crop = choose_crop_by_type(&layer->geo, a->type);
+	if (crop == NULL)
+		return -EINVAL;
+	mxr_layer_geo_fix(layer);
+	a->bounds.left = 0;
+	a->bounds.top = 0;
+	a->bounds.width = crop->full_width;
+	a->bounds.top = crop->full_height;
+	a->defrect = a->bounds;
+	/* setting pixel aspect to 1/1 */
+	a->pixelaspect.numerator = 1;
+	a->pixelaspect.denominator = 1;
+	return 0;
+}
+
+static int mxr_enum_dv_presets(struct file *file, void *fh,
+	struct v4l2_dv_enum_preset *preset)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+	ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+	struct v4l2_dv_preset *preset)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+
+	/* preset change cannot be done while there is an entity
+	 * dependant on output configuration
+	 */
+	if (mdev->n_output > 0) {
+		mutex_unlock(&mdev->mutex);
+		return -EBUSY;
+	}
+
+	ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+	mutex_unlock(&mdev->mutex);
+
+	/* any failure should return EINVAL according to V4L2 doc */
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+	struct v4l2_dv_preset *preset)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+	ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+
+	/* standard change cannot be done while there is an entity
+	 * dependant on output configuration
+	 */
+	if (mdev->n_output > 0) {
+		mutex_unlock(&mdev->mutex);
+		return -EBUSY;
+	}
+
+	ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+	ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	struct mxr_output *out;
+	struct v4l2_subdev *sd;
+
+	if (a->index >= mdev->output_cnt)
+		return -EINVAL;
+	out = mdev->output[a->index];
+	BUG_ON(out == NULL);
+	sd = out->sd;
+	strlcpy(a->name, out->name, sizeof(a->name));
+
+	/* try to obtain supported tv norms */
+	v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+	a->capabilities = 0;
+	if (sd->ops->video && sd->ops->video->s_dv_preset)
+		a->capabilities |= V4L2_OUT_CAP_PRESETS;
+	if (sd->ops->video && sd->ops->video->s_std_output)
+		a->capabilities |= V4L2_OUT_CAP_STD;
+	a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+	return 0;
+}
+
+static int mxr_s_output(struct file *file, void *fh, unsigned int i)
+{
+	struct video_device *vfd = video_devdata(file);
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret = 0;
+
+	if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+		return -EINVAL;
+
+	mutex_lock(&mdev->mutex);
+	if (mdev->n_output > 0) {
+		ret = -EBUSY;
+		goto done;
+	}
+	mdev->current_output = i;
+	vfd->tvnorms = 0;
+	v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
+		&vfd->tvnorms);
+	mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
+
+done:
+	mutex_unlock(&mdev->mutex);
+	return ret;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+
+	mutex_lock(&mdev->mutex);
+	*p = mdev->current_output;
+	mutex_unlock(&mdev->mutex);
+
+	return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
+	return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+	.vidioc_querycap = mxr_querycap,
+	/* format handling */
+	.vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+	.vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+	.vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+	/* buffer control */
+	.vidioc_reqbufs = mxr_reqbufs,
+	.vidioc_querybuf = mxr_querybuf,
+	.vidioc_qbuf = mxr_qbuf,
+	.vidioc_dqbuf = mxr_dqbuf,
+	/* Streaming control */
+	.vidioc_streamon = mxr_streamon,
+	.vidioc_streamoff = mxr_streamoff,
+	/* Preset functions */
+	.vidioc_enum_dv_presets = mxr_enum_dv_presets,
+	.vidioc_s_dv_preset = mxr_s_dv_preset,
+	.vidioc_g_dv_preset = mxr_g_dv_preset,
+	/* analog TV standard functions */
+	.vidioc_s_std = mxr_s_std,
+	.vidioc_g_std = mxr_g_std,
+	/* Output handling */
+	.vidioc_enum_output = mxr_enum_output,
+	.vidioc_s_output = mxr_s_output,
+	.vidioc_g_output = mxr_g_output,
+	/* Crop ioctls */
+	.vidioc_g_crop = mxr_g_crop,
+	.vidioc_s_crop = mxr_s_crop,
+	.vidioc_cropcap = mxr_cropcap,
+};
+
+static int mxr_video_open(struct file *file)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret = 0;
+
+	mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+	/* assure device probe is finished */
+	wait_for_device_probe();
+	/* creating context for file descriptor */
+	ret = v4l2_fh_open(file);
+	if (ret) {
+		mxr_err(mdev, "v4l2_fh_open failed\n");
+		return ret;
+	}
+
+	/* leaving if layer is already initialized */
+	if (!v4l2_fh_is_singular_file(file))
+		return 0;
+
+	/* FIXME: should power be enabled on open? */
+	ret = mxr_power_get(mdev);
+	if (ret) {
+		mxr_err(mdev, "power on failed\n");
+		goto fail_fh_open;
+	}
+
+	ret = vb2_queue_init(&layer->vb_queue);
+	if (ret != 0) {
+		mxr_err(mdev, "failed to initialize vb2 queue\n");
+		goto fail_power;
+	}
+	/* set default format, first on the list */
+	layer->fmt = layer->fmt_array[0];
+	/* setup default geometry */
+	mxr_layer_default_geo(layer);
+
+	return 0;
+
+fail_power:
+	mxr_power_put(mdev);
+
+fail_fh_open:
+	v4l2_fh_release(file);
+
+	return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	return vb2_poll(&layer->vb_queue, file, wait);
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	return vb2_mmap(&layer->vb_queue, vma);
+}
+
+static int mxr_video_release(struct file *file)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	if (v4l2_fh_is_singular_file(file)) {
+		vb2_queue_release(&layer->vb_queue);
+		mxr_power_put(layer->mdev);
+	}
+	v4l2_fh_release(file);
+	return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+	.owner = THIS_MODULE,
+	.open = mxr_video_open,
+	.poll = mxr_video_poll,
+	.mmap = mxr_video_mmap,
+	.release = mxr_video_release,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+	unsigned int *nplanes, unsigned long sizes[],
+	void *alloc_ctxs[])
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+	const struct mxr_format *fmt = layer->fmt;
+	int i;
+	struct mxr_device *mdev = layer->mdev;
+	struct v4l2_plane_pix_format planes[3];
+
+	mxr_dbg(mdev, "%s\n", __func__);
+	/* checking if format was configured */
+	if (fmt == NULL)
+		return -EINVAL;
+	mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+	mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+		layer->geo.src.full_height);
+
+	*nplanes = fmt->num_subframes;
+	for (i = 0; i < fmt->num_subframes; ++i) {
+		alloc_ctxs[i] = layer->mdev->alloc_ctx;
+		sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
+		mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
+	}
+
+	if (*nbuffers == 0)
+		*nbuffers = 1;
+
+	return 0;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+	struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+	struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+	int must_start = 0;
+
+	spin_lock_irqsave(&layer->enq_slock, flags);
+	if (layer->state == MXR_LAYER_STREAMING_START) {
+		layer->state = MXR_LAYER_STREAMING;
+		must_start = 1;
+	}
+	list_add_tail(&buffer->list, &layer->enq_list);
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+	if (must_start) {
+		layer->ops.stream_set(layer, MXR_ENABLE);
+		mxr_streamer_get(mdev);
+	}
+
+	mxr_dbg(mdev, "queuing buffer\n");
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+	mxr_dbg(layer->mdev, "%s\n", __func__);
+	mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+	mxr_dbg(layer->mdev, "%s\n", __func__);
+	mutex_unlock(&layer->mutex);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+
+	mxr_dbg(mdev, "%s\n", __func__);
+	/* block any changes in output configuration */
+	mxr_output_get(mdev);
+
+	/* update layers geometry */
+	mxr_layer_geo_fix(layer);
+	mxr_geometry_dump(mdev, &layer->geo);
+
+	layer->ops.format_set(layer);
+	/* enabling layer in hardware */
+	spin_lock_irqsave(&layer->enq_slock, flags);
+	layer->state = MXR_LAYER_STREAMING_START;
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+	struct mxr_layer *layer = (struct mxr_layer *) arg;
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+
+	mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+	spin_lock_irqsave(&layer->enq_slock, flags);
+
+	if (layer->update_buf == layer->shadow_buf)
+		layer->update_buf = NULL;
+	if (layer->update_buf) {
+		vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+		layer->update_buf = NULL;
+	}
+	if (layer->shadow_buf) {
+		vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+		layer->shadow_buf = NULL;
+	}
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+	struct timer_list watchdog;
+	struct mxr_buffer *buf, *buf_tmp;
+
+	mxr_dbg(mdev, "%s\n", __func__);
+
+	spin_lock_irqsave(&layer->enq_slock, flags);
+
+	/* reset list */
+	layer->state = MXR_LAYER_STREAMING_FINISH;
+
+	/* set all buffer to be done */
+	list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	/* give 1 seconds to complete to complete last buffers */
+	setup_timer_on_stack(&watchdog, mxr_watchdog,
+		(unsigned long)layer);
+	mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+	/* wait until all buffers are goes to done state */
+	vb2_wait_for_all_buffers(vq);
+
+	/* stop timer if all synchronization is done */
+	del_timer_sync(&watchdog);
+	destroy_timer_on_stack(&watchdog);
+
+	/* stopping hardware */
+	spin_lock_irqsave(&layer->enq_slock, flags);
+	layer->state = MXR_LAYER_IDLE;
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	/* disabling layer in hardware */
+	layer->ops.stream_set(layer, MXR_DISABLE);
+	/* remove one streamer */
+	mxr_streamer_put(mdev);
+	/* allow changes in output configuration */
+	mxr_output_put(mdev);
+	return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+	.queue_setup = queue_setup,
+	.buf_queue = buf_queue,
+	.wait_prepare = wait_unlock,
+	.wait_finish = wait_lock,
+	.start_streaming = start_streaming,
+	.stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		mxr_err(mdev, "failed to register video device\n");
+	else
+		mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+			layer->vfd.name, layer->vfd.num);
+	return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+	video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+	if (layer->ops.release)
+		layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+	kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+	printk(KERN_INFO "video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+	int idx, char *name, struct mxr_layer_ops *ops)
+{
+	struct mxr_layer *layer;
+
+	layer = kzalloc(sizeof *layer, GFP_KERNEL);
+	if (layer == NULL) {
+		mxr_err(mdev, "not enough memory for layer.\n");
+		goto fail;
+	}
+
+	layer->mdev = mdev;
+	layer->idx = idx;
+	layer->ops = *ops;
+
+	spin_lock_init(&layer->enq_slock);
+	INIT_LIST_HEAD(&layer->enq_list);
+	mutex_init(&layer->mutex);
+
+	layer->vfd = (struct video_device) {
+		.minor = -1,
+		.release = mxr_vfd_release,
+		.fops = &mxr_fops,
+		.ioctl_ops = &mxr_ioctl_ops,
+	};
+	strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+	/* let framework control PRIORITY */
+	set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+	video_set_drvdata(&layer->vfd, layer);
+	layer->vfd.lock = &layer->mutex;
+	layer->vfd.v4l2_dev = &mdev->v4l2_dev;
+
+	layer->vb_queue = (struct vb2_queue) {
+		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+		.io_modes = VB2_MMAP | VB2_USERPTR,
+		.drv_priv = layer,
+		.buf_struct_size = sizeof(struct mxr_buffer),
+		.ops = &mxr_video_qops,
+		.mem_ops = &vb2_dma_contig_memops,
+	};
+
+	return layer;
+
+fail:
+	return NULL;
+}
+
+static const struct mxr_format *find_format_by_fourcc(
+	struct mxr_layer *layer, unsigned long fourcc)
+{
+	int i;
+
+	for (i = 0; i < layer->fmt_array_size; ++i)
+		if (layer->fmt_array[i]->fourcc == fourcc)
+			return layer->fmt_array[i];
+	return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+	struct mxr_layer *layer, unsigned long index)
+{
+	if (index >= layer->fmt_array_size)
+		return NULL;
+	return layer->fmt_array[index];
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c
new file mode 100644
index 0000000..6950ed8
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c
@@ -0,0 +1,211 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include "regs-vp.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+static const struct mxr_format mxr_fmt_nv12 = {
+	.name = "NV12",
+	.fourcc = V4L2_PIX_FMT_NV12,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 1 },
+		{ .width = 2, .height = 2, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv21 = {
+	.name = "NV21",
+	.fourcc = V4L2_PIX_FMT_NV21,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 1 },
+		{ .width = 2, .height = 2, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12m = {
+	.name = "NV12 (mplane)",
+	.fourcc = V4L2_PIX_FMT_NV12M,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 1 },
+		{ .width = 2, .height = 2, .size = 2 },
+	},
+	.num_subframes = 2,
+	.plane2subframe = {0, 1},
+	.cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12mt = {
+	.name = "NV12 tiled (mplane)",
+	.fourcc = V4L2_PIX_FMT_NV12MT,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 128, .height = 32, .size = 4096 },
+		{ .width = 128, .height = 32, .size = 2048 },
+	},
+	.num_subframes = 2,
+	.plane2subframe = {0, 1},
+	.cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
+};
+
+static const struct mxr_format *mxr_video_format[] = {
+	&mxr_fmt_nv12,
+	&mxr_fmt_nv21,
+	&mxr_fmt_nv12m,
+	&mxr_fmt_nv12mt,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_vp_layer_release(struct mxr_layer *layer)
+{
+	mxr_base_layer_unregister(layer);
+	mxr_base_layer_release(layer);
+}
+
+static void mxr_vp_buffer_set(struct mxr_layer *layer,
+	struct mxr_buffer *buf)
+{
+	dma_addr_t luma_addr[2] = {0, 0};
+	dma_addr_t chroma_addr[2] = {0, 0};
+
+	if (buf == NULL) {
+		mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+		return;
+	}
+	luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+	if (layer->fmt->num_subframes == 2) {
+		chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1);
+	} else {
+		/* FIXME: mxr_get_plane_size compute integer division,
+		 * which is slow and should not be performed in interrupt */
+		chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
+			&layer->fmt->plane[0], layer->geo.src.full_width,
+			layer->geo.src.full_height);
+	}
+	if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
+		luma_addr[1] = luma_addr[0] + 0x40;
+		chroma_addr[1] = chroma_addr[0] + 0x40;
+	} else {
+		luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
+		chroma_addr[1] = chroma_addr[0];
+	}
+	mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+}
+
+static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
+{
+	mxr_reg_vp_layer_stream(layer->mdev, en);
+}
+
+static void mxr_vp_format_set(struct mxr_layer *layer)
+{
+	mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
+}
+
+static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+{
+	struct mxr_geometry *geo = &layer->geo;
+
+	/* align horizontal size to 8 pixels */
+	geo->src.full_width = ALIGN(geo->src.full_width, 8);
+	/* limit to boundary size */
+	geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
+	geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
+	geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
+	geo->src.width = min(geo->src.width, 2047U);
+	geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
+	geo->src.height = min(geo->src.height, 2047U);
+
+	/* setting size of output window */
+	geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
+	geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
+
+	/* ensure that scaling is in range 1/4x to 16x */
+	if (geo->src.width >= 4 * geo->dst.width)
+		geo->src.width = 4 * geo->dst.width;
+	if (geo->dst.width >= 16 * geo->src.width)
+		geo->dst.width = 16 * geo->src.width;
+	if (geo->src.height >= 4 * geo->dst.height)
+		geo->src.height = 4 * geo->dst.height;
+	if (geo->dst.height >= 16 * geo->src.height)
+		geo->dst.height = 16 * geo->src.height;
+
+	/* setting scaling ratio */
+	geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
+	geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
+
+	/* adjust offsets */
+	geo->src.x_offset = min(geo->src.x_offset,
+		geo->src.full_width - geo->src.width);
+	geo->src.y_offset = min(geo->src.y_offset,
+		geo->src.full_height - geo->src.height);
+	geo->dst.x_offset = min(geo->dst.x_offset,
+		geo->dst.full_width - geo->dst.width);
+	geo->dst.y_offset = min(geo->dst.y_offset,
+		geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
+{
+	struct mxr_layer *layer;
+	int ret;
+	struct mxr_layer_ops ops = {
+		.release = mxr_vp_layer_release,
+		.buffer_set = mxr_vp_buffer_set,
+		.stream_set = mxr_vp_stream_set,
+		.format_set = mxr_vp_format_set,
+		.fix_geometry = mxr_vp_fix_geometry,
+	};
+	char name[32];
+
+	sprintf(name, "video%d", idx);
+
+	layer = mxr_base_layer_create(mdev, idx, name, &ops);
+	if (layer == NULL) {
+		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+		goto fail;
+	}
+
+	layer->fmt_array = mxr_video_format;
+	layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
+
+	ret = mxr_base_layer_register(layer);
+	if (ret)
+		goto fail_layer;
+
+	return layer;
+
+fail_layer:
+	mxr_base_layer_release(layer);
+
+fail:
+	return NULL;
+}
+
diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/video/s5p-tv/regs-mixer.h
new file mode 100644
index 0000000..3c84426
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-mixer.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Mixer register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#ifndef SAMSUNG_REGS_MIXER_H
+#define SAMSUNG_REGS_MIXER_H
+
+/*
+ * Register part
+ */
+#define MXR_STATUS			0x0000
+#define MXR_CFG				0x0004
+#define MXR_INT_EN			0x0008
+#define MXR_INT_STATUS			0x000C
+#define MXR_LAYER_CFG			0x0010
+#define MXR_VIDEO_CFG			0x0014
+#define MXR_GRAPHIC0_CFG		0x0020
+#define MXR_GRAPHIC0_BASE		0x0024
+#define MXR_GRAPHIC0_SPAN		0x0028
+#define MXR_GRAPHIC0_SXY		0x002C
+#define MXR_GRAPHIC0_WH			0x0030
+#define MXR_GRAPHIC0_DXY		0x0034
+#define MXR_GRAPHIC0_BLANK		0x0038
+#define MXR_GRAPHIC1_CFG		0x0040
+#define MXR_GRAPHIC1_BASE		0x0044
+#define MXR_GRAPHIC1_SPAN		0x0048
+#define MXR_GRAPHIC1_SXY		0x004C
+#define MXR_GRAPHIC1_WH			0x0050
+#define MXR_GRAPHIC1_DXY		0x0054
+#define MXR_GRAPHIC1_BLANK		0x0058
+#define MXR_BG_CFG			0x0060
+#define MXR_BG_COLOR0			0x0064
+#define MXR_BG_COLOR1			0x0068
+#define MXR_BG_COLOR2			0x006C
+
+/* for parametrized access to layer registers */
+#define MXR_GRAPHIC_CFG(i)		(0x0020 + (i) * 0x20)
+#define MXR_GRAPHIC_BASE(i)		(0x0024 + (i) * 0x20)
+#define MXR_GRAPHIC_SPAN(i)		(0x0028 + (i) * 0x20)
+#define MXR_GRAPHIC_SXY(i)		(0x002C + (i) * 0x20)
+#define MXR_GRAPHIC_WH(i)		(0x0030 + (i) * 0x20)
+#define MXR_GRAPHIC_DXY(i)		(0x0034 + (i) * 0x20)
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+#define MXR_MASK(high_bit, low_bit) \
+	(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define MXR_MASK_VAL(val, high_bit, low_bit) \
+	(((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
+
+/* bits for MXR_STATUS */
+#define MXR_STATUS_16_BURST		(1 << 7)
+#define MXR_STATUS_BURST_MASK		(1 << 7)
+#define MXR_STATUS_SYNC_ENABLE		(1 << 2)
+#define MXR_STATUS_REG_RUN		(1 << 0)
+
+/* bits for MXR_CFG */
+#define MXR_CFG_OUT_YUV444		(0 << 8)
+#define MXR_CFG_OUT_RGB888		(1 << 8)
+#define MXR_CFG_DST_SDO			(0 << 7)
+#define MXR_CFG_DST_HDMI		(1 << 7)
+#define MXR_CFG_DST_MASK		(1 << 7)
+#define MXR_CFG_SCAN_HD_720		(0 << 6)
+#define MXR_CFG_SCAN_HD_1080		(1 << 6)
+#define MXR_CFG_GRP1_ENABLE		(1 << 5)
+#define MXR_CFG_GRP0_ENABLE		(1 << 4)
+#define MXR_CFG_VP_ENABLE		(1 << 3)
+#define MXR_CFG_SCAN_INTERLACE		(0 << 2)
+#define MXR_CFG_SCAN_PROGRASSIVE	(1 << 2)
+#define MXR_CFG_SCAN_NTSC		(0 << 1)
+#define MXR_CFG_SCAN_PAL		(1 << 1)
+#define MXR_CFG_SCAN_SD			(0 << 0)
+#define MXR_CFG_SCAN_HD			(1 << 0)
+#define MXR_CFG_SCAN_MASK		0x47
+
+/* bits for MXR_GRAPHICn_CFG */
+#define MXR_GRP_CFG_COLOR_KEY_DISABLE	(1 << 21)
+#define MXR_GRP_CFG_BLEND_PRE_MUL	(1 << 20)
+#define MXR_GRP_CFG_FORMAT_VAL(x)	MXR_MASK_VAL(x, 11, 8)
+#define MXR_GRP_CFG_FORMAT_MASK		MXR_GRP_CFG_FORMAT_VAL(~0)
+#define MXR_GRP_CFG_ALPHA_VAL(x)	MXR_MASK_VAL(x, 7, 0)
+
+/* bits for MXR_GRAPHICn_WH */
+#define MXR_GRP_WH_H_SCALE(x)		MXR_MASK_VAL(x, 28, 28)
+#define MXR_GRP_WH_V_SCALE(x)		MXR_MASK_VAL(x, 12, 12)
+#define MXR_GRP_WH_WIDTH(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_WH_HEIGHT(x)		MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_SXY */
+#define MXR_GRP_SXY_SX(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_SXY_SY(x)		MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_DXY */
+#define MXR_GRP_DXY_DX(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_DXY_DY(x)		MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_INT_EN */
+#define MXR_INT_EN_VSYNC		(1 << 11)
+#define MXR_INT_EN_ALL			(0x0f << 8)
+
+/* bit for MXR_INT_STATUS */
+#define MXR_INT_CLEAR_VSYNC		(1 << 11)
+#define MXR_INT_STATUS_VSYNC		(1 << 0)
+
+/* bit for MXR_LAYER_CFG */
+#define MXR_LAYER_CFG_GRP1_VAL(x)	MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP0_VAL(x)	MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_VP_VAL(x)		MXR_MASK_VAL(x, 3, 0)
+
+#endif /* SAMSUNG_REGS_MIXER_H */
+
diff --git a/drivers/media/video/s5p-tv/regs-vp.h b/drivers/media/video/s5p-tv/regs-vp.h
new file mode 100644
index 0000000..6c63984
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-vp.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * Video processor register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_VP_H
+#define SAMSUNG_REGS_VP_H
+
+/*
+ * Register part
+ */
+
+#define VP_ENABLE			0x0000
+#define VP_SRESET			0x0004
+#define VP_SHADOW_UPDATE		0x0008
+#define VP_FIELD_ID			0x000C
+#define VP_MODE				0x0010
+#define VP_IMG_SIZE_Y			0x0014
+#define VP_IMG_SIZE_C			0x0018
+#define VP_PER_RATE_CTRL		0x001C
+#define VP_TOP_Y_PTR			0x0028
+#define VP_BOT_Y_PTR			0x002C
+#define VP_TOP_C_PTR			0x0030
+#define VP_BOT_C_PTR			0x0034
+#define VP_ENDIAN_MODE			0x03CC
+#define VP_SRC_H_POSITION		0x0044
+#define VP_SRC_V_POSITION		0x0048
+#define VP_SRC_WIDTH			0x004C
+#define VP_SRC_HEIGHT			0x0050
+#define VP_DST_H_POSITION		0x0054
+#define VP_DST_V_POSITION		0x0058
+#define VP_DST_WIDTH			0x005C
+#define VP_DST_HEIGHT			0x0060
+#define VP_H_RATIO			0x0064
+#define VP_V_RATIO			0x0068
+#define VP_POLY8_Y0_LL			0x006C
+#define VP_POLY4_Y0_LL			0x00EC
+#define VP_POLY4_C0_LL			0x012C
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+
+#define VP_MASK(high_bit, low_bit) \
+	(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define VP_MASK_VAL(val, high_bit, low_bit) \
+	(((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
+
+ /* VP_ENABLE */
+#define VP_ENABLE_ON			(1 << 0)
+
+/* VP_SRESET */
+#define VP_SRESET_PROCESSING		(1 << 0)
+
+/* VP_SHADOW_UPDATE */
+#define VP_SHADOW_UPDATE_ENABLE		(1 << 0)
+
+/* VP_MODE */
+#define VP_MODE_NV12			(0 << 6)
+#define VP_MODE_NV21			(1 << 6)
+#define VP_MODE_LINE_SKIP		(1 << 5)
+#define VP_MODE_MEM_LINEAR		(0 << 4)
+#define VP_MODE_MEM_TILED		(1 << 4)
+#define VP_MODE_FMT_MASK		(5 << 4)
+#define VP_MODE_FIELD_ID_AUTO_TOGGLING	(1 << 2)
+#define VP_MODE_2D_IPC			(1 << 1)
+
+/* VP_IMG_SIZE_Y */
+/* VP_IMG_SIZE_C */
+#define VP_IMG_HSIZE(x)			VP_MASK_VAL(x, 29, 16)
+#define VP_IMG_VSIZE(x)			VP_MASK_VAL(x, 13, 0)
+
+/* VP_SRC_H_POSITION */
+#define VP_SRC_H_POSITION_VAL(x)	VP_MASK_VAL(x, 14, 4)
+
+/* VP_ENDIAN_MODE */
+#define VP_ENDIAN_MODE_LITTLE		(1 << 0)
+
+#endif /* SAMSUNG_REGS_VP_H */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-06-29 12:51 ` [PATCH 1/8] v4l: add macro for 1080p59_54 preset Tomasz Stanislawski
@ 2011-07-04 16:09   ` Mauro Carvalho Chehab
  2011-07-04 22:47     ` Laurent Pinchart
  2011-07-05  7:26     ` Hans Verkuil
  0 siblings, 2 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-04 16:09 UTC (permalink / raw)
  To: Tomasz Stanislawski
  Cc: linux-media, m.szyprowski, kyungmin.park, hverkuil, laurent.pinchart

Em 29-06-2011 09:51, Tomasz Stanislawski escreveu:
> The 1080p59_94 is supported by latest Samsung SoC.
> 
> Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
> ---
>  drivers/media/video/v4l2-common.c |    1 +
>  include/linux/videodev2.h         |    1 +
>  2 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
> index 06b9f9f..003e648 100644
> --- a/drivers/media/video/v4l2-common.c
> +++ b/drivers/media/video/v4l2-common.c
> @@ -582,6 +582,7 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
>  		{ 1920, 1080, "1080p@30" },	/* V4L2_DV_1080P30 */
>  		{ 1920, 1080, "1080p@50" },	/* V4L2_DV_1080P50 */
>  		{ 1920, 1080, "1080p@60" },	/* V4L2_DV_1080P60 */
> +		{ 1920, 1080, "1080p@59.94" },	/* V4L2_DV_1080P59_94 */
>  	};
>  
>  	if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index 8a4c309..7c77c4e 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -872,6 +872,7 @@ struct v4l2_dv_enum_preset {
>  #define		V4L2_DV_1080P30		16 /* SMPTE 296M */
>  #define		V4L2_DV_1080P50		17 /* BT.1120 */
>  #define		V4L2_DV_1080P60		18 /* BT.1120 */
> +#define		V4L2_DV_1080P59_94	19
>  
>  /*
>   *	D V 	B T	T I M I N G S

This patch deserves further discussions, as the specs that define the presets
are not so clear with respect to 60Hz and 60/1.001 Hz.

Let me summarize the issue.



1) PRESET STANDARDS
   ====== =========

There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and CEA 861.

At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz". BT.1120
follows the same logic, as it uses BT.709 as a reference for video timings.

The CEA-861-E spec says at item 4, that:

	A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00,
	120.00 or 240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing
	information but where the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001,
	60/1.001, 120/1.001 or 240/1.001). That is, they are considered two versions of the same video timing but
	with slightly different pixel clock frequencies. Therefore, a DTV that declares it is capable of displaying a
	video timing with a vertical frequency that is either an integer multiple of 6 Hz or an integer multiple of 6
	Hz adjusted by a factor of 1000/1001 shall be capable of displaying both versions of the video timing.

At the same item, the table 2 describes several video parameters for each preset, associating the
Video Identification Codes (VIC) for each preset.

Table 4 associates each VIC with the supported formats. For example, VIC 16 means a resolution of
1920x1080 at 59.94Hz/60Hz. The spec does explicitly allow that all vertical frequencies that are
multiple of 6 Hz to accept both 59.94 Hz and 60 Hz, as said at note 3 of table 2:

	3. A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00, 120.00 or
	240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing information but where
	the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001, 60/1.001, 120/1.001 or
	240/1.001). That is, they are considered two versions of the same video timing but with slightly different pixel clock
	frequencies. The vertical frequencies of the 240p, 480p, and 480i video formats are typically adjusted by a factor of
	exactly 1000/1001 for NTSC video compatibility, while the 576p, 576i, and the HDTV video formats are not. The
	VESA DMT standard [65] specifies a ± 0.5% pixel clock frequency tolerance. Therefore, the nominally 25.175 MHz
	pixel clock frequency value given for video identification code 1 may be adjusted to 25.2 MHz to obtain an exact 60
	Hz vertical frequency.

In other words, the preset for 1920x1080p@60Hz can be used for both 60Hz and 59.94 Hz,
according with the above note, being 59.94 Hz the typical value (e. g. the value that
should be used on most places).

However, there are some "60 Hz" vertical resolutions that have VIC's with 
different framerates (like 59.94Hz, 60.054Hz, etc). Those seem to not be
covered by the "multiple of 6.00 Hz" rule.

2. V4L2 API
   ==== ===

The V4L2 specs define a DV timing as having those fields:

__u32	width	Width of the active video in pixels
__u32	height	Height of the active video in lines
__u32	interlaced	Progressive (0) or interlaced (1)
__u32	polarities	This is a bit mask that defines polarities of sync signals. 
__u64	pixelclock	Pixel clock in Hz. Ex. 74.25MHz->74250000
__u32	hfrontporch	Horizontal front porch in pixels
__u32	hsync	Horizontal sync length in pixels
__u32	hbackporch	Horizontal back porch in pixels
__u32	vfrontporch	Vertical front porch in lines
__u32	vsync	Vertical sync length in lines
__u32	vbackporch	Vertical back porch in lines
__u32	il_vfrontporch	Vertical front porch in lines for bottom field of interlaced field formats
__u32	il_vsync	Vertical sync length in lines for bottom field of interlaced field formats
__u32	il_vbackporch	Vertical back porch in lines for bottom field of interlaced field formats

[1] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-dv-timings.html

So, it basically allows adjusting the timings for each of the VIC's, but it seems that there
is one limitation at the current API:

vblank is an integer value, for both frames 0 and 1. So, it doesn't allow to adjust vblanks
like 22.5. This prevents specifying presets like VICs 10/11.

The presets ioctl's [2] provide the following fields:

__u32	index	Number of the DV preset, set by the application.
__u32	preset	This field identifies one of the DV preset values listed in Table A.15, “struct DV Presets”.
__u8	name[24]	Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is intended for the user.
__u32	width	Width of the active video in pixels for the DV preset.
__u32	height	Height of the active video in lines for the DV preset.

[2] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-enum-dv-presets.html#v4l2-dv-presets-vals

Where "preset" can mean:

V4L2_DV_INVALID		0	Invalid preset value.
V4L2_DV_480P59_94	1	720x480 progressive video at 59.94 fps as per BT.1362.
V4L2_DV_576P50		2	720x576 progressive video at 50 fps as per BT.1362.
V4L2_DV_720P24		3	1280x720 progressive video at 24 fps as per SMPTE 296M.
V4L2_DV_720P25		4	1280x720 progressive video at 25 fps as per SMPTE 296M.
V4L2_DV_720P30		5	1280x720 progressive video at 30 fps as per SMPTE 296M.
V4L2_DV_720P50		6	1280x720 progressive video at 50 fps as per SMPTE 296M.
V4L2_DV_720P59_94	7	1280x720 progressive video at 59.94 fps as per SMPTE 274M.
V4L2_DV_720P60		8	1280x720 progressive video at 60 fps as per SMPTE 274M/296M.
V4L2_DV_1080I29_97	9	1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.
V4L2_DV_1080I30		10	1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.
V4L2_DV_1080I25		11	1920x1080 interlaced video at 25 fps as per BT.1120.
V4L2_DV_1080I50		12	1920x1080 interlaced video at 50 fps as per SMPTE 296M.
V4L2_DV_1080I60		13	1920x1080 interlaced video at 60 fps as per SMPTE 296M.
V4L2_DV_1080P24		14	1920x1080 progressive video at 24 fps as per SMPTE 296M.
V4L2_DV_1080P25		15	1920x1080 progressive video at 25 fps as per SMPTE 296M.
V4L2_DV_1080P30		16	1920x1080 progressive video at 30 fps as per SMPTE 296M.
V4L2_DV_1080P50		17	1920x1080 progressive video at 50 fps as per BT.1120.
V4L2_DV_1080P60		18	1920x1080 progressive video at 60 fps as per BT.1120.


3. ISSUES AT V4L2 API
   ====== == ==== ===

There are some troubles at the way we currently define the presets:

3.1) The preset macros have the name of the active video lines, but this is also present at
     the height field;

3.2) The preset macros don't have the name of the active video columns;

3.3) If someone would want to add a preset for some CEA-861-E VICs, namespace conflicts will
     happen. For example, a preset for 1440x576@50Hz would have the same name as a preset
     for 2880x576p at 50 Hz. Both would be called as V4L2_DV_576P50.

3.4) It doesn't mind what DV timing is used, CEA-861-E and BT.709 allows to use the 60Hz
     timings as either 60Hz or 59.94 Hz. That applies to all VIC format timings at table 2
     for 60 Hz, 120 Hz and 240 Hz.

3.5) There are lots of format at CEA-861-E without a V4L2 preset.

4. PROPOSED SOLUTION
   ======== ========

In order to fix the issue, we need change the API without breaking the current apps that
use the timings ioctls. Also, the vertical rate clock for 60Hz formats needs to allow
a fractional adjustment of either 1 or 1000/1001, in order to support the specs.

4.1) Preset renaming
     ---------------

To avoid having duplicated namespace conflicts, the better seems to rename the existing
presets to contain both width and height at their macro definitions, like:

#define V4L2_DV_1920_1080P60	18	1920x1080 progressive video at 60 fps as per BT.1120

(for the sake of simplicity, I just took one value from the table. The same fix is needed
 to be applied for the other macro definitions)

To avoid breaking userspace, the old names need to be associated with the new ones, with:

#define V4L2_DV_1080P60		V4L2_DV_1920_1080P60

This fixes issue 3.2 and 3.3. Unfortunately, fixing 3.1 is not possible anymore, so,
we have to keep the same information duplicated on two places (at the macro name and
at the width/height).

The question that remains unsolved is what an userspace application would handle a driver
that might eventually provide inconsistent data at width/height and at the macro names?

4.2) Framerate selection for 60Hz preset
     -----------------------------------

As the spec allows using any format that it is multiple of 6.00 Hz multiplied by either
1 or 1000/1001, the selection betweem them should be done via VIDIOC_G_PARM/VIDIOC_S_PARM.
So, V4L2 spec should say, at the "Digital Video (DV) Timings" section:

	Devices that implement DV timings shall implement VIDIOC_G_PARM/VIDIOC_S_PARM,
	in order to allow controlling the vertical frame rate for the presets whose
	vertical rate is multiple of 6.00 Hz, in order to allow setting the timing
	between 60 Hz and 59.94 Hz. The default value, at device init, shall be 59.94 Hz.

4.3) Add the missing CEA-861-E presets
     ---------------------------------

As those formats are part of the spec that is implemented by this V4L2 API, the better
would be to implement all the missing formats at the V4L2 spec. As a generic rule, we
don't add support at the Kernel without having a driver using it, but, in this specific
case, we want to be able to be compatible with the specs, so, it seems a good idea to
implement the remaining ones, or, at least reserve its namespace at the DocBook. This
solves issue 3.5.

5) S5P-TV SUPPORT FOR 59.94 HZ
   ===========================

It is not clear, from this patch, if you're really wanting to implement support for VIC
16 format @59.94 Hz, or something else. From CEA-861-E, it seems to be the case, as
this is the only 1920x1080p format for 60 Hz. If this is the case, according with my
proposal, the driver should be using the 60Hz format, instead, and implement S_PARM 
to allow selecting between 60Hz and 59.94Hz.


Comments?

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-04 16:09   ` [RFC] DV timings spec fixes at V4L2 API - was: " Mauro Carvalho Chehab
@ 2011-07-04 22:47     ` Laurent Pinchart
  2011-07-04 23:28       ` Mauro Carvalho Chehab
  2011-07-05  6:46       ` Hans Verkuil
  2011-07-05  7:26     ` Hans Verkuil
  1 sibling, 2 replies; 37+ messages in thread
From: Laurent Pinchart @ 2011-07-04 22:47 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park, hverkuil

Hi Mauro,

On Monday 04 July 2011 18:09:18 Mauro Carvalho Chehab wrote:

[snip]

> 1) PRESET STANDARDS
>    ====== =========
> 
> There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and
> CEA 861.
> 
> At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz".
> BT.1120 follows the same logic, as it uses BT.709 as a reference for video
> timings.
> 
> The CEA-861-E spec says at item 4, that:

[snip]

> At the same item, the table 2 describes several video parameters for each
> preset, associating the Video Identification Codes (VIC) for each preset.

This might be a bit out of scope, but why aren't we using the VICs as DV 
presets ?

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-04 22:47     ` Laurent Pinchart
@ 2011-07-04 23:28       ` Mauro Carvalho Chehab
  2011-07-05  6:46       ` Hans Verkuil
  1 sibling, 0 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-04 23:28 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park, hverkuil

Em 04-07-2011 19:47, Laurent Pinchart escreveu:
> Hi Mauro,
> 
> On Monday 04 July 2011 18:09:18 Mauro Carvalho Chehab wrote:
> 
> [snip]
> 
>> 1) PRESET STANDARDS
>>    ====== =========
>>
>> There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and
>> CEA 861.
>>
>> At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz".
>> BT.1120 follows the same logic, as it uses BT.709 as a reference for video
>> timings.
>>
>> The CEA-861-E spec says at item 4, that:
> 
> [snip]
> 
>> At the same item, the table 2 describes several video parameters for each
>> preset, associating the Video Identification Codes (VIC) for each preset.
> 
> This might be a bit out of scope, but why aren't we using the VICs as DV 
> presets ?

I had the same question after analyzing the specs ;)

That's said, abstracting from the spec could be a good idea if we have newer
versions of the spec re-defining the VICs.

Maybe the right thing to do would be to rename the presets as:

V4L2_DV_CEA861_VIC_16
V4L2_DV_CEA861_VIC_35_36
...

(or course, preserving the old names with compatibility macros)

Cheers,
Mauro


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-04 22:47     ` Laurent Pinchart
  2011-07-04 23:28       ` Mauro Carvalho Chehab
@ 2011-07-05  6:46       ` Hans Verkuil
  1 sibling, 0 replies; 37+ messages in thread
From: Hans Verkuil @ 2011-07-05  6:46 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mauro Carvalho Chehab, Tomasz Stanislawski, linux-media,
	m.szyprowski, kyungmin.park

On Tuesday, July 05, 2011 00:47:43 Laurent Pinchart wrote:
> Hi Mauro,
> 
> On Monday 04 July 2011 18:09:18 Mauro Carvalho Chehab wrote:
> 
> [snip]
> 
> > 1) PRESET STANDARDS
> >    ====== =========
> > 
> > There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and
> > CEA 861.
> > 
> > At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz".
> > BT.1120 follows the same logic, as it uses BT.709 as a reference for video
> > timings.
> > 
> > The CEA-861-E spec says at item 4, that:
> 
> [snip]
> 
> > At the same item, the table 2 describes several video parameters for each
> > preset, associating the Video Identification Codes (VIC) for each preset.
> 
> This might be a bit out of scope, but why aren't we using the VICs as DV 
> presets ?

The VIC does more than just set the timings. It also determines the pixel
aspect ratio. So exactly the same video timings may have two VICs, the only
difference being the pixel aspect which is *not* part of the timings. The VIC
is part of the AVI InfoFrame, however.

So VIC != timings.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-04 16:09   ` [RFC] DV timings spec fixes at V4L2 API - was: " Mauro Carvalho Chehab
  2011-07-04 22:47     ` Laurent Pinchart
@ 2011-07-05  7:26     ` Hans Verkuil
  2011-07-05 12:08       ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 37+ messages in thread
From: Hans Verkuil @ 2011-07-05  7:26 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

On Monday, July 04, 2011 18:09:18 Mauro Carvalho Chehab wrote:
> Em 29-06-2011 09:51, Tomasz Stanislawski escreveu:
> > The 1080p59_94 is supported by latest Samsung SoC.
> > 
> > Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
> > ---
> >  drivers/media/video/v4l2-common.c |    1 +
> >  include/linux/videodev2.h         |    1 +
> >  2 files changed, 2 insertions(+), 0 deletions(-)
> > 
> > diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
> > index 06b9f9f..003e648 100644
> > --- a/drivers/media/video/v4l2-common.c
> > +++ b/drivers/media/video/v4l2-common.c
> > @@ -582,6 +582,7 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
> >  		{ 1920, 1080, "1080p@30" },	/* V4L2_DV_1080P30 */
> >  		{ 1920, 1080, "1080p@50" },	/* V4L2_DV_1080P50 */
> >  		{ 1920, 1080, "1080p@60" },	/* V4L2_DV_1080P60 */
> > +		{ 1920, 1080, "1080p@59.94" },	/* V4L2_DV_1080P59_94 */
> >  	};
> >  
> >  	if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
> > diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> > index 8a4c309..7c77c4e 100644
> > --- a/include/linux/videodev2.h
> > +++ b/include/linux/videodev2.h
> > @@ -872,6 +872,7 @@ struct v4l2_dv_enum_preset {
> >  #define		V4L2_DV_1080P30		16 /* SMPTE 296M */
> >  #define		V4L2_DV_1080P50		17 /* BT.1120 */
> >  #define		V4L2_DV_1080P60		18 /* BT.1120 */
> > +#define		V4L2_DV_1080P59_94	19
> >  
> >  /*
> >   *	D V 	B T	T I M I N G S
> 
> This patch deserves further discussions, as the specs that define the presets
> are not so clear with respect to 60Hz and 60/1.001 Hz.
> 
> Let me summarize the issue.
> 
> 
> 
> 1) PRESET STANDARDS
>    ====== =========
> 
> There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and CEA 861.
> 
> At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz". BT.1120
> follows the same logic, as it uses BT.709 as a reference for video timings.
> 
> The CEA-861-E spec says at item 4, that:
> 
> 	A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00,
> 	120.00 or 240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing
> 	information but where the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001,
> 	60/1.001, 120/1.001 or 240/1.001). That is, they are considered two versions of the same video timing but
> 	with slightly different pixel clock frequencies. Therefore, a DTV that declares it is capable of displaying a
> 	video timing with a vertical frequency that is either an integer multiple of 6 Hz or an integer multiple of 6
> 	Hz adjusted by a factor of 1000/1001 shall be capable of displaying both versions of the video timing.
> 
> At the same item, the table 2 describes several video parameters for each preset, associating the
> Video Identification Codes (VIC) for each preset.

No, *multiple VICs* are associated with each preset. VIC != preset.

Also, the VICs do not differentiate between 60 and 59.94 Hz.

> Table 4 associates each VIC with the supported formats. For example, VIC 16 means a resolution of
> 1920x1080 at 59.94Hz/60Hz. The spec does explicitly allow that all vertical frequencies that are
> multiple of 6 Hz to accept both 59.94 Hz and 60 Hz, as said at note 3 of table 2:
> 
> 	3. A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00, 120.00 or
> 	240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing information but where
> 	the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001, 60/1.001, 120/1.001 or
> 	240/1.001). That is, they are considered two versions of the same video timing but with slightly different pixel clock
> 	frequencies. The vertical frequencies of the 240p, 480p, and 480i video formats are typically adjusted by a factor of
> 	exactly 1000/1001 for NTSC video compatibility, while the 576p, 576i, and the HDTV video formats are not. The
> 	VESA DMT standard [65] specifies a ± 0.5% pixel clock frequency tolerance. Therefore, the nominally 25.175 MHz
> 	pixel clock frequency value given for video identification code 1 may be adjusted to 25.2 MHz to obtain an exact 60
> 	Hz vertical frequency.
> 
> In other words, the preset for 1920x1080p@60Hz can be used for both 60Hz and 59.94 Hz,
> according with the above note, being 59.94 Hz the typical value (e. g. the value that
> should be used on most places).
> 
> However, there are some "60 Hz" vertical resolutions that have VIC's with 
> different framerates (like 59.94Hz, 60.054Hz, etc). Those seem to not be
> covered by the "multiple of 6.00 Hz" rule.

No. A preset identifies one specific modeline (to use the terminology from the
GPU world). It defines the front/back porches, sync lengths, active area and
pixelclock frequency. Any ambiguities as to the timings of a preset should be
resolved by the documentation (which clearly needs a bit more work). In general,
though, all the currently defined presets refer to CEA-861. The standards
mentioned in videodev2.h all refer to the same things, but CEA-861 is the standard
where it all comes together.

In practice there are four different standards that the preset API can use:

CEA-861 for all things HDTV (HDMI)
VESA DMT timings for DVI-D (PC) type timings (VGA, XVGA, etc.)
VESA GTF timings (officially deprecated, but still quite common algorithm to
	calculate timings)
VESA CVT timings (the newer algorithm to calculate timings)

GTF and CVT pose there own problems and Cisco will be making a proposal for
how to handle this some time this year.

VESA DMT timings as easy to add since they are well-defined. We plan on doing
that.

> 
> 2. V4L2 API
>    ==== ===
> 
> The V4L2 specs define a DV timing as having those fields:
> 
> __u32	width	Width of the active video in pixels
> __u32	height	Height of the active video in lines
> __u32	interlaced	Progressive (0) or interlaced (1)
> __u32	polarities	This is a bit mask that defines polarities of sync signals. 
> __u64	pixelclock	Pixel clock in Hz. Ex. 74.25MHz->74250000
> __u32	hfrontporch	Horizontal front porch in pixels
> __u32	hsync	Horizontal sync length in pixels
> __u32	hbackporch	Horizontal back porch in pixels
> __u32	vfrontporch	Vertical front porch in lines
> __u32	vsync	Vertical sync length in lines
> __u32	vbackporch	Vertical back porch in lines
> __u32	il_vfrontporch	Vertical front porch in lines for bottom field of interlaced field formats
> __u32	il_vsync	Vertical sync length in lines for bottom field of interlaced field formats
> __u32	il_vbackporch	Vertical back porch in lines for bottom field of interlaced field formats
> 
> [1] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-dv-timings.html
> 
> So, it basically allows adjusting the timings for each of the VIC's, but it seems that there
> is one limitation at the current API:
> 
> vblank is an integer value, for both frames 0 and 1. So, it doesn't allow to adjust vblanks
> like 22.5. This prevents specifying presets like VICs 10/11.

vblanks are never halflines. One field is one line longer than the other. As note 1 in table 2
says: "fractional values indicate that the number of blanking lines varies". It's why we have
those il_ fields.

> 
> The presets ioctl's [2] provide the following fields:
> 
> __u32	index	Number of the DV preset, set by the application.
> __u32	preset	This field identifies one of the DV preset values listed in Table A.15, “struct DV Presets”.
> __u8	name[24]	Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is intended for the user.
> __u32	width	Width of the active video in pixels for the DV preset.
> __u32	height	Height of the active video in lines for the DV preset.
> 
> [2] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-enum-dv-presets.html#v4l2-dv-presets-vals
> 
> Where "preset" can mean:
> 
> V4L2_DV_INVALID		0	Invalid preset value.
> V4L2_DV_480P59_94	1	720x480 progressive video at 59.94 fps as per BT.1362.
> V4L2_DV_576P50		2	720x576 progressive video at 50 fps as per BT.1362.
> V4L2_DV_720P24		3	1280x720 progressive video at 24 fps as per SMPTE 296M.
> V4L2_DV_720P25		4	1280x720 progressive video at 25 fps as per SMPTE 296M.
> V4L2_DV_720P30		5	1280x720 progressive video at 30 fps as per SMPTE 296M.
> V4L2_DV_720P50		6	1280x720 progressive video at 50 fps as per SMPTE 296M.
> V4L2_DV_720P59_94	7	1280x720 progressive video at 59.94 fps as per SMPTE 274M.
> V4L2_DV_720P60		8	1280x720 progressive video at 60 fps as per SMPTE 274M/296M.
> V4L2_DV_1080I29_97	9	1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.
> V4L2_DV_1080I30		10	1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.
> V4L2_DV_1080I25		11	1920x1080 interlaced video at 25 fps as per BT.1120.
> V4L2_DV_1080I50		12	1920x1080 interlaced video at 50 fps as per SMPTE 296M.
> V4L2_DV_1080I60		13	1920x1080 interlaced video at 60 fps as per SMPTE 296M.
> V4L2_DV_1080P24		14	1920x1080 progressive video at 24 fps as per SMPTE 296M.
> V4L2_DV_1080P25		15	1920x1080 progressive video at 25 fps as per SMPTE 296M.
> V4L2_DV_1080P30		16	1920x1080 progressive video at 30 fps as per SMPTE 296M.
> V4L2_DV_1080P50		17	1920x1080 progressive video at 50 fps as per BT.1120.
> V4L2_DV_1080P60		18	1920x1080 progressive video at 60 fps as per BT.1120.

All these standards need to be replaced with CEA-861.

> 
> 
> 3. ISSUES AT V4L2 API
>    ====== == ==== ===
> 
> There are some troubles at the way we currently define the presets:
> 
> 3.1) The preset macros have the name of the active video lines, but this is also present at
>      the height field;

??? While a human can see that V4L2_DV_1080P60 refers to 1080 lines, a computer
can't. The macro is a just a number, so you need to communicate the width and
height explicitly.

> 3.2) The preset macros don't have the name of the active video columns;

For the current set of macros the industry convention is used. 1080P50 always
refers to 1920x1080. Anything else should be made explicit.
 
> 3.3) If someone would want to add a preset for some CEA-861-E VICs, namespace conflicts will
>      happen. For example, a preset for 1440x576@50Hz would have the same name as a preset
>      for 2880x576p at 50 Hz. Both would be called as V4L2_DV_576P50.

Obviously that would have to be called V4L2_DV_2880X576P50 (or something similar).

> 3.4) It doesn't mind what DV timing is used, CEA-861-E and BT.709 allows to use the 60Hz
>      timings as either 60Hz or 59.94 Hz. That applies to all VIC format timings at table 2
>      for 60 Hz, 120 Hz and 240 Hz.

No, the pixelclock is part of the preset timings. So V4L2_DV_1080P60 and V4L2_DV_1080P59_94
are different presets with different timings. Just as they would be different modelines
for your graphics card. I really don't see the problem here.

> 3.5) There are lots of format at CEA-861-E without a V4L2 preset.

True. Frankly I have yet to encounter any of the weird ones (i.e. other than
640x480, 480p/i, 576p/i, 720p/i and 1080p/i with their various framerates).

> 
> 4. PROPOSED SOLUTION
>    ======== ========
> 
> In order to fix the issue, we need change the API without breaking the current apps that
> use the timings ioctls. Also, the vertical rate clock for 60Hz formats needs to allow
> a fractional adjustment of either 1 or 1000/1001, in order to support the specs.
> 
> 4.1) Preset renaming
>      ---------------
> 
> To avoid having duplicated namespace conflicts, the better seems to rename the existing
> presets to contain both width and height at their macro definitions, like:
> 
> #define V4L2_DV_1920_1080P60	18	1920x1080 progressive video at 60 fps as per BT.1120
> 
> (for the sake of simplicity, I just took one value from the table. The same fix is needed
>  to be applied for the other macro definitions)
> 
> To avoid breaking userspace, the old names need to be associated with the new ones, with:
> 
> #define V4L2_DV_1080P60		V4L2_DV_1920_1080P60

I've no problem with that. 1080P60 is still a useful shorthand.

> 
> This fixes issue 3.2 and 3.3. Unfortunately, fixing 3.1 is not possible anymore, so,
> we have to keep the same information duplicated on two places (at the macro name and
> at the width/height).

As I mentioned above, for a program the macro name is useless.

> The question that remains unsolved is what an userspace application would handle a driver
> that might eventually provide inconsistent data at width/height and at the macro names?

That's a driver bug.

> 4.2) Framerate selection for 60Hz preset
>      -----------------------------------
> 
> As the spec allows using any format that it is multiple of 6.00 Hz multiplied by either
> 1 or 1000/1001, the selection betweem them should be done via VIDIOC_G_PARM/VIDIOC_S_PARM.
> So, V4L2 spec should say, at the "Digital Video (DV) Timings" section:
> 
> 	Devices that implement DV timings shall implement VIDIOC_G_PARM/VIDIOC_S_PARM,
> 	in order to allow controlling the vertical frame rate for the presets whose
> 	vertical rate is multiple of 6.00 Hz, in order to allow setting the timing
> 	between 60 Hz and 59.94 Hz. The default value, at device init, shall be 59.94 Hz.

NACK.

The pixel clock is part of the video timings and hence defined by the preset.

VIDIOC_S_PARM is used when the desired framerate differs from the actual framerate
and the driver can do frame repeating or frameskipping. At least that's what the
V4L2 spec says. In practice it is used to set the framerate for sensors. I'm not sure
if there is any driver that actually uses it for frameskipping. To my knowledge it is
not used at all for video output.

> 4.3) Add the missing CEA-861-E presets
>      ---------------------------------
> 
> As those formats are part of the spec that is implemented by this V4L2 API, the better
> would be to implement all the missing formats at the V4L2 spec. As a generic rule, we
> don't add support at the Kernel without having a driver using it, but, in this specific
> case, we want to be able to be compatible with the specs, so, it seems a good idea to
> implement the remaining ones, or, at least reserve its namespace at the DocBook. This
> solves issue 3.5.

I'm not so sure. There are lots of weird resolutions in CEA-861 that I have never
seen in use. A better approach IMHO is that whenever we add a resolution to the
preset table, then we do that for all variants of that resolution.

> 5) S5P-TV SUPPORT FOR 59.94 HZ
>    ===========================
> 
> It is not clear, from this patch, if you're really wanting to implement support for VIC
> 16 format @59.94 Hz, or something else. From CEA-861-E, it seems to be the case, as
> this is the only 1920x1080p format for 60 Hz. If this is the case, according with my
> proposal, the driver should be using the 60Hz format, instead, and implement S_PARM 
> to allow selecting between 60Hz and 59.94Hz.

NACK. You need two presets: V4L2_DV_1080P60 and 1080P59_94. Just as is already there
for 720P60 and 720P59_94. I really don't see the problem.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-05  7:26     ` Hans Verkuil
@ 2011-07-05 12:08       ` Mauro Carvalho Chehab
  2011-07-05 13:20         ` Hans Verkuil
  0 siblings, 1 reply; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-05 12:08 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 05-07-2011 04:26, Hans Verkuil escreveu:
> On Monday, July 04, 2011 18:09:18 Mauro Carvalho Chehab wrote:
>> Em 29-06-2011 09:51, Tomasz Stanislawski escreveu:
>>> The 1080p59_94 is supported by latest Samsung SoC.
>>>
>>> Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
>>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>>> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
>>> ---
>>>  drivers/media/video/v4l2-common.c |    1 +
>>>  include/linux/videodev2.h         |    1 +
>>>  2 files changed, 2 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
>>> index 06b9f9f..003e648 100644
>>> --- a/drivers/media/video/v4l2-common.c
>>> +++ b/drivers/media/video/v4l2-common.c
>>> @@ -582,6 +582,7 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
>>>  		{ 1920, 1080, "1080p@30" },	/* V4L2_DV_1080P30 */
>>>  		{ 1920, 1080, "1080p@50" },	/* V4L2_DV_1080P50 */
>>>  		{ 1920, 1080, "1080p@60" },	/* V4L2_DV_1080P60 */
>>> +		{ 1920, 1080, "1080p@59.94" },	/* V4L2_DV_1080P59_94 */
>>>  	};
>>>  
>>>  	if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
>>> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
>>> index 8a4c309..7c77c4e 100644
>>> --- a/include/linux/videodev2.h
>>> +++ b/include/linux/videodev2.h
>>> @@ -872,6 +872,7 @@ struct v4l2_dv_enum_preset {
>>>  #define		V4L2_DV_1080P30		16 /* SMPTE 296M */
>>>  #define		V4L2_DV_1080P50		17 /* BT.1120 */
>>>  #define		V4L2_DV_1080P60		18 /* BT.1120 */
>>> +#define		V4L2_DV_1080P59_94	19
>>>  
>>>  /*
>>>   *	D V 	B T	T I M I N G S
>>
>> This patch deserves further discussions, as the specs that define the presets
>> are not so clear with respect to 60Hz and 60/1.001 Hz.
>>
>> Let me summarize the issue.
>>
>>
>>
>> 1) PRESET STANDARDS
>>    ====== =========
>>
>> There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and CEA 861.
>>
>> At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz". BT.1120
>> follows the same logic, as it uses BT.709 as a reference for video timings.
>>
>> The CEA-861-E spec says at item 4, that:
>>
>> 	A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00,
>> 	120.00 or 240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing
>> 	information but where the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001,
>> 	60/1.001, 120/1.001 or 240/1.001). That is, they are considered two versions of the same video timing but
>> 	with slightly different pixel clock frequencies. Therefore, a DTV that declares it is capable of displaying a
>> 	video timing with a vertical frequency that is either an integer multiple of 6 Hz or an integer multiple of 6
>> 	Hz adjusted by a factor of 1000/1001 shall be capable of displaying both versions of the video timing.
>>
>> At the same item, the table 2 describes several video parameters for each preset, associating the
>> Video Identification Codes (VIC) for each preset.
> 
> No, *multiple VICs* are associated with each preset. VIC != preset.

There are two VIC's for several presets, as it is also used at the spec to determine the aspect ratio, but, basically,
for one given VIC, there's just one timings preset at the table 2.

> Also, the VICs do not differentiate between 60 and 59.94 Hz.

Yes, but V4L2 DV timings also don't differentiate.

>> Table 4 associates each VIC with the supported formats. For example, VIC 16 means a resolution of
>> 1920x1080 at 59.94Hz/60Hz. The spec does explicitly allow that all vertical frequencies that are
>> multiple of 6 Hz to accept both 59.94 Hz and 60 Hz, as said at note 3 of table 2:
>>
>> 	3. A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00, 120.00 or
>> 	240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing information but where
>> 	the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001, 60/1.001, 120/1.001 or
>> 	240/1.001). That is, they are considered two versions of the same video timing but with slightly different pixel clock
>> 	frequencies. The vertical frequencies of the 240p, 480p, and 480i video formats are typically adjusted by a factor of
>> 	exactly 1000/1001 for NTSC video compatibility, while the 576p, 576i, and the HDTV video formats are not. The
>> 	VESA DMT standard [65] specifies a ± 0.5% pixel clock frequency tolerance. Therefore, the nominally 25.175 MHz
>> 	pixel clock frequency value given for video identification code 1 may be adjusted to 25.2 MHz to obtain an exact 60
>> 	Hz vertical frequency.
>>
>> In other words, the preset for 1920x1080p@60Hz can be used for both 60Hz and 59.94 Hz,
>> according with the above note, being 59.94 Hz the typical value (e. g. the value that
>> should be used on most places).
>>
>> However, there are some "60 Hz" vertical resolutions that have VIC's with 
>> different framerates (like 59.94Hz, 60.054Hz, etc). Those seem to not be
>> covered by the "multiple of 6.00 Hz" rule.
> 
> No. A preset identifies one specific modeline (to use the terminology from the
> GPU world). It defines the front/back porches, sync lengths, active area and
> pixelclock frequency. Any ambiguities as to the timings of a preset should be
> resolved by the documentation (which clearly needs a bit more work).

As I pointed before, it is not just documentation. For all the 6.00 Hz multiple standard,
CEA defines that, using the same DV timings, it is possible to choose to shift the clock
by 1000/1001 to support the "59.94Hz". So, this applies to several VIC's for 60Hz,
120 Hz and 240Hz.

While it is possible to duplicate the DV timing line for all affected VICs,
We'll end by having a very messy API, as there will be two 60 Hz standards, one
with the shift and the other without, for the same CEA VIC, plus the CEA
standards that are defined for other vertical resolutions like 60.054 Hz, 
59.826 Hz, 119.88 Hz, 239.76 Hz and even 59.940 Hz.

Part of the problem is the u32 "preset" var, at v4l2_dv_enum_preset. It
requires a namespace to identify the presets, but this can become very
confusing with time. How would you distinguish from a CEA-861 60.00 Hz standard
with a Vertical frequency shift of 1000/1001 and a CEA-861 59.94 Hz? The current
namespace doesn't allow that, and creating a namespace to accommodate would be
weird and would easily be very confusing.

> In general,
> though, all the currently defined presets refer to CEA-861. The standards
> mentioned in videodev2.h all refer to the same things, but CEA-861 is the standard
> where it all comes together.
> 
> In practice there are four different standards that the preset API can use:
> 
> CEA-861 for all things HDTV (HDMI)
> VESA DMT timings for DVI-D (PC) type timings (VGA, XVGA, etc.)
> VESA GTF timings (officially deprecated, but still quite common algorithm to
> 	calculate timings)
> VESA CVT timings (the newer algorithm to calculate timings)
> 
> GTF and CVT pose there own problems and Cisco will be making a proposal for
> how to handle this some time this year.
> 
> VESA DMT timings as easy to add since they are well-defined. We plan on doing
> that.

Well, try to accomodate all those timings using the current namespace for
preset. I bet you'll end by having lots of duplicated names for distinct
timings.

The API needs to be fixed, and it is better sooner than later.

>> 2. V4L2 API
>>    ==== ===
>>
>> The V4L2 specs define a DV timing as having those fields:
>>
>> __u32	width	Width of the active video in pixels
>> __u32	height	Height of the active video in lines
>> __u32	interlaced	Progressive (0) or interlaced (1)
>> __u32	polarities	This is a bit mask that defines polarities of sync signals. 
>> __u64	pixelclock	Pixel clock in Hz. Ex. 74.25MHz->74250000
>> __u32	hfrontporch	Horizontal front porch in pixels
>> __u32	hsync	Horizontal sync length in pixels
>> __u32	hbackporch	Horizontal back porch in pixels
>> __u32	vfrontporch	Vertical front porch in lines
>> __u32	vsync	Vertical sync length in lines
>> __u32	vbackporch	Vertical back porch in lines
>> __u32	il_vfrontporch	Vertical front porch in lines for bottom field of interlaced field formats
>> __u32	il_vsync	Vertical sync length in lines for bottom field of interlaced field formats
>> __u32	il_vbackporch	Vertical back porch in lines for bottom field of interlaced field formats
>>
>> [1] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-dv-timings.html
>>
>> So, it basically allows adjusting the timings for each of the VIC's, but it seems that there
>> is one limitation at the current API:
>>
>> vblank is an integer value, for both frames 0 and 1. So, it doesn't allow to adjust vblanks
>> like 22.5. This prevents specifying presets like VICs 10/11.
> 
> vblanks are never halflines. One field is one line longer than the other. As note 1 in table 2
> says: "fractional values indicate that the number of blanking lines varies". It's why we have
> those il_ fields.

OK.

>>
>> The presets ioctl's [2] provide the following fields:
>>
>> __u32	index	Number of the DV preset, set by the application.
>> __u32	preset	This field identifies one of the DV preset values listed in Table A.15, “struct DV Presets”.
>> __u8	name[24]	Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is intended for the user.
>> __u32	width	Width of the active video in pixels for the DV preset.
>> __u32	height	Height of the active video in lines for the DV preset.
>>
>> [2] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-enum-dv-presets.html#v4l2-dv-presets-vals
>>
>> Where "preset" can mean:
>>
>> V4L2_DV_INVALID		0	Invalid preset value.
>> V4L2_DV_480P59_94	1	720x480 progressive video at 59.94 fps as per BT.1362.
>> V4L2_DV_576P50		2	720x576 progressive video at 50 fps as per BT.1362.
>> V4L2_DV_720P24		3	1280x720 progressive video at 24 fps as per SMPTE 296M.
>> V4L2_DV_720P25		4	1280x720 progressive video at 25 fps as per SMPTE 296M.
>> V4L2_DV_720P30		5	1280x720 progressive video at 30 fps as per SMPTE 296M.
>> V4L2_DV_720P50		6	1280x720 progressive video at 50 fps as per SMPTE 296M.
>> V4L2_DV_720P59_94	7	1280x720 progressive video at 59.94 fps as per SMPTE 274M.
>> V4L2_DV_720P60		8	1280x720 progressive video at 60 fps as per SMPTE 274M/296M.
>> V4L2_DV_1080I29_97	9	1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.
>> V4L2_DV_1080I30		10	1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.
>> V4L2_DV_1080I25		11	1920x1080 interlaced video at 25 fps as per BT.1120.
>> V4L2_DV_1080I50		12	1920x1080 interlaced video at 50 fps as per SMPTE 296M.
>> V4L2_DV_1080I60		13	1920x1080 interlaced video at 60 fps as per SMPTE 296M.
>> V4L2_DV_1080P24		14	1920x1080 progressive video at 24 fps as per SMPTE 296M.
>> V4L2_DV_1080P25		15	1920x1080 progressive video at 25 fps as per SMPTE 296M.
>> V4L2_DV_1080P30		16	1920x1080 progressive video at 30 fps as per SMPTE 296M.
>> V4L2_DV_1080P50		17	1920x1080 progressive video at 50 fps as per BT.1120.
>> V4L2_DV_1080P60		18	1920x1080 progressive video at 60 fps as per BT.1120.
> 
> All these standards need to be replaced with CEA-861.

Sorry, but I couldn't understand your proposal here.

>>
>>
>> 3. ISSUES AT V4L2 API
>>    ====== == ==== ===
>>
>> There are some troubles at the way we currently define the presets:
>>
>> 3.1) The preset macros have the name of the active video lines, but this is also present at
>>      the height field;
> 
> ??? While a human can see that V4L2_DV_1080P60 refers to 1080 lines, a computer
> can't. The macro is a just a number, so you need to communicate the width and
> height explicitly.

Yes, but the namespace is confusing, and developers might code it as:

if (preset >= V4L2_DV_1080I29_97  || preset <= V4L2_DV_1080P60)
	width = 1080;

(or doing the same inside a switch, although I've seen several userspace applications
 implementing things like above).

The above would be valid, and the end result is that a duplicated information is provided.

I failed to see what information is provided by the "presets" name. If this were removed
from the ioctl, and fps would be added instead, the API would be clearer. The only
adjustment would be to use "index" as the preset selection key. Anyway, it is too late
for such change. We need to live with that.

> 
>> 3.2) The preset macros don't have the name of the active video columns;
> 
> For the current set of macros the industry convention is used. 1080P50 always
> refers to 1920x1080. Anything else should be made explicit.
>  
>> 3.3) If someone would want to add a preset for some CEA-861-E VICs, namespace conflicts will
>>      happen. For example, a preset for 1440x576@50Hz would have the same name as a preset
>>      for 2880x576p at 50 Hz. Both would be called as V4L2_DV_576P50.
> 
> Obviously that would have to be called V4L2_DV_2880X576P50 (or something similar).

So, the namespace will become messy, with will make developers very confused about what they
should use.  As you've mentioned, there are currently 4 standards with timings that will
needed to be supported. So, at the end of the day, we'll have:

V4L2_DV_576P50
V4L2_DV_576P50_foo
V4L2_DV_576P50_bar
V4L2_DV_576P50_delta
V4L2_DV_2880X576P50
V4L2_DV_2880X576P50_foo
V4L2_DV_2880X576P50_bar
V4L2_DV_2880X576P50_delta
...

where foo, bar, and delta would be some othe DV-timings based naming. It will become a nightmare
for developers to discover, from the above list, what are the timings from VESA DMT and what
are from CEA-861.

The solution is to associate its name to the standards naming, like:

	V4L2_DV_CEA_861_VIC_35_36

For the timings associated with VICs 35 and 36.

> 
>> 3.4) It doesn't mind what DV timing is used, CEA-861-E and BT.709 allows to use the 60Hz
>>      timings as either 60Hz or 59.94 Hz. That applies to all VIC format timings at table 2
>>      for 60 Hz, 120 Hz and 240 Hz.
> 
> No, the pixelclock is part of the preset timings. So V4L2_DV_1080P60 and V4L2_DV_1080P59_94
> are different presets with different timings. Just as they would be different modelines
> for your graphics card. I really don't see the problem here.

Sorry, but the current way that this documented is not clear enough. Also, there's nothing
at VIDIOC_ENUM_DV_PRESETS that allows checking the fps, except for the preset name, which
is confusing enough.

>> 3.5) There are lots of format at CEA-861-E without a V4L2 preset.
> 
> True. Frankly I have yet to encounter any of the weird ones (i.e. other than
> 640x480, 480p/i, 576p/i, 720p/i and 1080p/i with their various framerates).
> 
>>
>> 4. PROPOSED SOLUTION
>>    ======== ========
>>
>> In order to fix the issue, we need change the API without breaking the current apps that
>> use the timings ioctls. Also, the vertical rate clock for 60Hz formats needs to allow
>> a fractional adjustment of either 1 or 1000/1001, in order to support the specs.
>>
>> 4.1) Preset renaming
>>      ---------------
>>
>> To avoid having duplicated namespace conflicts, the better seems to rename the existing
>> presets to contain both width and height at their macro definitions, like:
>>
>> #define V4L2_DV_1920_1080P60	18	1920x1080 progressive video at 60 fps as per BT.1120
>>
>> (for the sake of simplicity, I just took one value from the table. The same fix is needed
>>  to be applied for the other macro definitions)
>>
>> To avoid breaking userspace, the old names need to be associated with the new ones, with:
>>
>> #define V4L2_DV_1080P60		V4L2_DV_1920_1080P60
> 
> I've no problem with that. 1080P60 is still a useful shorthand.

As I said before, it will be better to change it to explicitly associate with the specs
that defined that video timing, with whatever ID code there. So, for CEA-861, it would
be, in this case:

#define V4L2_DV_CEA_861_VIC_16	18

and the legacy compat macro:
	#define V4L2_DV_1080P60		V4L2_DV_CEA_861_VIC_16

>>
>> This fixes issue 3.2 and 3.3. Unfortunately, fixing 3.1 is not possible anymore, so,
>> we have to keep the same information duplicated on two places (at the macro name and
>> at the width/height).
> 
> As I mentioned above, for a program the macro name is useless.
> 
>> The question that remains unsolved is what an userspace application would handle a driver
>> that might eventually provide inconsistent data at width/height and at the macro names?
> 
> That's a driver bug.
> 
>> 4.2) Framerate selection for 60Hz preset
>>      -----------------------------------
>>
>> As the spec allows using any format that it is multiple of 6.00 Hz multiplied by either
>> 1 or 1000/1001, the selection betweem them should be done via VIDIOC_G_PARM/VIDIOC_S_PARM.
>> So, V4L2 spec should say, at the "Digital Video (DV) Timings" section:
>>
>> 	Devices that implement DV timings shall implement VIDIOC_G_PARM/VIDIOC_S_PARM,
>> 	in order to allow controlling the vertical frame rate for the presets whose
>> 	vertical rate is multiple of 6.00 Hz, in order to allow setting the timing
>> 	between 60 Hz and 59.94 Hz. The default value, at device init, shall be 59.94 Hz.
> 
> NACK.
> 
> The pixel clock is part of the video timings and hence defined by the preset.
> 
> VIDIOC_S_PARM is used when the desired framerate differs from the actual framerate
> and the driver can do frame repeating or frameskipping.

NO. VIDIOC_S_PARM is used on all places where the user desires to specify a framerate. All
webcams use it to select the desired framerate.

> At least that's what the V4L2 spec says. 

I'll prepare a patch fixing it. This is one of the parts of the API that got outdated with
time.

> In practice it is used to set the framerate for sensors. I'm not sure
> if there is any driver that actually uses it for frameskipping. 

There are some video capture drivers that implement it, so I think that some use it for
frameskipping.

> To my knowledge it is not used at all for video output.

In any case, selecting a DV timing preset with an specific fps is currently confusing, and
requires that the userspace application to have a switch(v4l2_dv_enum_preset.preset) in order
to associate a preset macro name with a fps. This is a very bad idea.

I see only two practical solutions for that. The first one is to use S_PARAM. The other one 
is to stop providing the frequency inside the macro name, and add a field for that at the 
v4l2_dv_enum_preset struct:

struct v4l2_dv_enum_preset {
	__u32		index;
	__u32		preset;
	__u8		name[32]; /* Name of the preset timing */
	__u32		width;
	__u32		height;
	v4l2_fract	fps;
	__u32		reserved[2];
};

So, for example, a driver that supports only CEA-861 VIC 16 will report 2 presets:

struct v4l2_dv_enum_preset dv[] = {
	{ 0, V4L2_DV_CEA_861_VIC_16__60HZ,    "CEA-861 1920x1080p 60Hz", 1920, 1080, {60, 1} },
	{ 1, V4L2_DV_CEA_861_VIC_16__59_94HZ, "CEA-861 1920x1080p 59.94Hz", 1920, 1080, {60000, 1001} },
};

Yet, we should be sure that this will also cover all current VESA standards.

>> 4.3) Add the missing CEA-861-E presets
>>      ---------------------------------
>>
>> As those formats are part of the spec that is implemented by this V4L2 API, the better
>> would be to implement all the missing formats at the V4L2 spec. As a generic rule, we
>> don't add support at the Kernel without having a driver using it, but, in this specific
>> case, we want to be able to be compatible with the specs, so, it seems a good idea to
>> implement the remaining ones, or, at least reserve its namespace at the DocBook. This
>> solves issue 3.5.
> 
> I'm not so sure. There are lots of weird resolutions in CEA-861 that I have never
> seen in use. A better approach IMHO is that whenever we add a resolution to the
> preset table, then we do that for all variants of that resolution.

This works for me.

>> 5) S5P-TV SUPPORT FOR 59.94 HZ
>>    ===========================
>>
>> It is not clear, from this patch, if you're really wanting to implement support for VIC
>> 16 format @59.94 Hz, or something else. From CEA-861-E, it seems to be the case, as
>> this is the only 1920x1080p format for 60 Hz. If this is the case, according with my
>> proposal, the driver should be using the 60Hz format, instead, and implement S_PARM 
>> to allow selecting between 60Hz and 59.94Hz.
> 
> NACK. You need two presets: V4L2_DV_1080P60 and 1080P59_94. Just as is already there
> for 720P60 and 720P59_94. I really don't see the problem.

NACK adding it as "V4L2_DV_1080P59_94". 

Let's fix the namespace and provide a way to specify/enumberate the fps first, and then
change the patch to follow whatever decided.

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-05 12:08       ` Mauro Carvalho Chehab
@ 2011-07-05 13:20         ` Hans Verkuil
  2011-07-05 19:02           ` Andy Walls
  2011-07-06 11:04           ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 37+ messages in thread
From: Hans Verkuil @ 2011-07-05 13:20 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

On Tuesday, July 05, 2011 14:08:03 Mauro Carvalho Chehab wrote:
> Em 05-07-2011 04:26, Hans Verkuil escreveu:
> > On Monday, July 04, 2011 18:09:18 Mauro Carvalho Chehab wrote:
> >> Em 29-06-2011 09:51, Tomasz Stanislawski escreveu:
> >>> The 1080p59_94 is supported by latest Samsung SoC.
> >>>
> >>> Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
> >>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
> >>> ---
> >>>  drivers/media/video/v4l2-common.c |    1 +
> >>>  include/linux/videodev2.h         |    1 +
> >>>  2 files changed, 2 insertions(+), 0 deletions(-)
> >>>
> >>> diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
> >>> index 06b9f9f..003e648 100644
> >>> --- a/drivers/media/video/v4l2-common.c
> >>> +++ b/drivers/media/video/v4l2-common.c
> >>> @@ -582,6 +582,7 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
> >>>  		{ 1920, 1080, "1080p@30" },	/* V4L2_DV_1080P30 */
> >>>  		{ 1920, 1080, "1080p@50" },	/* V4L2_DV_1080P50 */
> >>>  		{ 1920, 1080, "1080p@60" },	/* V4L2_DV_1080P60 */
> >>> +		{ 1920, 1080, "1080p@59.94" },	/* V4L2_DV_1080P59_94 */
> >>>  	};
> >>>  
> >>>  	if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
> >>> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> >>> index 8a4c309..7c77c4e 100644
> >>> --- a/include/linux/videodev2.h
> >>> +++ b/include/linux/videodev2.h
> >>> @@ -872,6 +872,7 @@ struct v4l2_dv_enum_preset {
> >>>  #define		V4L2_DV_1080P30		16 /* SMPTE 296M */
> >>>  #define		V4L2_DV_1080P50		17 /* BT.1120 */
> >>>  #define		V4L2_DV_1080P60		18 /* BT.1120 */
> >>> +#define		V4L2_DV_1080P59_94	19
> >>>  
> >>>  /*
> >>>   *	D V 	B T	T I M I N G S
> >>
> >> This patch deserves further discussions, as the specs that define the presets
> >> are not so clear with respect to 60Hz and 60/1.001 Hz.
> >>
> >> Let me summarize the issue.
> >>
> >>
> >>
> >> 1) PRESET STANDARDS
> >>    ====== =========
> >>
> >> There are 3 specs involved with DV presets: ITU-R BT 709 and BT 1120 and CEA 861.
> >>
> >> At ITU-R BT.709, both 60Hz and 60/1.001 Hz are equally called as "60 Hz". BT.1120
> >> follows the same logic, as it uses BT.709 as a reference for video timings.
> >>
> >> The CEA-861-E spec says at item 4, that:
> >>
> >> 	A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00,
> >> 	120.00 or 240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing
> >> 	information but where the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001,
> >> 	60/1.001, 120/1.001 or 240/1.001). That is, they are considered two versions of the same video timing but
> >> 	with slightly different pixel clock frequencies. Therefore, a DTV that declares it is capable of displaying a
> >> 	video timing with a vertical frequency that is either an integer multiple of 6 Hz or an integer multiple of 6
> >> 	Hz adjusted by a factor of 1000/1001 shall be capable of displaying both versions of the video timing.
> >>
> >> At the same item, the table 2 describes several video parameters for each preset, associating the
> >> Video Identification Codes (VIC) for each preset.
> > 
> > No, *multiple VICs* are associated with each preset. VIC != preset.
> 
> There are two VIC's for several presets, as it is also used at the spec to determine the aspect ratio, but, basically,
> for one given VIC, there's just one timings preset at the table 2.

Sigh. VIC != video timings. It just gives some additional information regarding aspect ration
(duplicated information actually).

The simple fact that you can't use it to determine the pixelclock and thus the vertical
frequency means that it is *not* suitable as a way to determine the video timings.

I've been working with HDMI receivers and transmitters for several years now, and
it simply is not suitable.

> > Also, the VICs do not differentiate between 60 and 59.94 Hz.
> 
> Yes, but V4L2 DV timings also don't differentiate.

??? Yes, they do. There is a 720P60 and a 720P59_94. Also 1080I29_97 and 1080I30.
The 1080P59_94 is simply missing because nobody needed it yet.
 
> >> Table 4 associates each VIC with the supported formats. For example, VIC 16 means a resolution of
> >> 1920x1080 at 59.94Hz/60Hz. The spec does explicitly allow that all vertical frequencies that are
> >> multiple of 6 Hz to accept both 59.94 Hz and 60 Hz, as said at note 3 of table 2:
> >>
> >> 	3. A video timing with a vertical frequency that is an integer multiple of 6.00 Hz (i.e. 24.00, 30.00, 60.00, 120.00 or
> >> 	240.00 Hz) is considered to be the same as a video timing with the equivalent detailed timing information but where
> >> 	the vertical frequency is adjusted by a factor of 1000/1001 (i.e., 24/1.001, 30/1.001, 60/1.001, 120/1.001 or
> >> 	240/1.001). That is, they are considered two versions of the same video timing but with slightly different pixel clock
> >> 	frequencies. The vertical frequencies of the 240p, 480p, and 480i video formats are typically adjusted by a factor of
> >> 	exactly 1000/1001 for NTSC video compatibility, while the 576p, 576i, and the HDTV video formats are not. The
> >> 	VESA DMT standard [65] specifies a ± 0.5% pixel clock frequency tolerance. Therefore, the nominally 25.175 MHz
> >> 	pixel clock frequency value given for video identification code 1 may be adjusted to 25.2 MHz to obtain an exact 60
> >> 	Hz vertical frequency.
> >>
> >> In other words, the preset for 1920x1080p@60Hz can be used for both 60Hz and 59.94 Hz,
> >> according with the above note, being 59.94 Hz the typical value (e. g. the value that
> >> should be used on most places).
> >>
> >> However, there are some "60 Hz" vertical resolutions that have VIC's with 
> >> different framerates (like 59.94Hz, 60.054Hz, etc). Those seem to not be
> >> covered by the "multiple of 6.00 Hz" rule.
> > 
> > No. A preset identifies one specific modeline (to use the terminology from the
> > GPU world). It defines the front/back porches, sync lengths, active area and
> > pixelclock frequency. Any ambiguities as to the timings of a preset should be
> > resolved by the documentation (which clearly needs a bit more work).
> 
> As I pointed before, it is not just documentation. For all the 6.00 Hz multiple standard,
> CEA defines that, using the same DV timings, it is possible to choose to shift the clock
> by 1000/1001 to support the "59.94Hz". So, this applies to several VIC's for 60Hz,
> 120 Hz and 240Hz.
> 
> While it is possible to duplicate the DV timing line for all affected VICs,
> We'll end by having a very messy API, as there will be two 60 Hz standards, one
> with the shift and the other without, for the same CEA VIC, plus the CEA
> standards that are defined for other vertical resolutions like 60.054 Hz, 
> 59.826 Hz, 119.88 Hz, 239.76 Hz and even 59.940 Hz.

So? Different timings, different preset. BTW, as I mentioned earlier, most of the
weirder resolution I never see in practice. Just 480, 576, 720 and 1080. Which is
why I don't think it is useful to add them unless someone really needs them.

> Part of the problem is the u32 "preset" var, at v4l2_dv_enum_preset. It
> requires a namespace to identify the presets, but this can become very
> confusing with time. How would you distinguish from a CEA-861 60.00 Hz standard
> with a Vertical frequency shift of 1000/1001 and a CEA-861 59.94 Hz? The current

All CEA-861 59.94 standards have identical timings as the 60 Hz standards, except
for the different pixelclock (which is responsible for the frequency shift).
So it's unambiguous.

> namespace doesn't allow that, and creating a namespace to accommodate would be
> weird and would easily be very confusing.
> 
> > In general,
> > though, all the currently defined presets refer to CEA-861. The standards
> > mentioned in videodev2.h all refer to the same things, but CEA-861 is the standard
> > where it all comes together.
> > 
> > In practice there are four different standards that the preset API can use:
> > 
> > CEA-861 for all things HDTV (HDMI)
> > VESA DMT timings for DVI-D (PC) type timings (VGA, XVGA, etc.)
> > VESA GTF timings (officially deprecated, but still quite common algorithm to
> > 	calculate timings)
> > VESA CVT timings (the newer algorithm to calculate timings)
> > 
> > GTF and CVT pose there own problems and Cisco will be making a proposal for
> > how to handle this some time this year.
> > 
> > VESA DMT timings as easy to add since they are well-defined. We plan on doing
> > that.
> 
> Well, try to accomodate all those timings using the current namespace for
> preset. I bet you'll end by having lots of duplicated names for distinct
> timings.

We have done that for DMT already. CVT and GTF are a separate issue since
presets do not work there. Most likely the VIDIOC_G/S_DV_TIMINGS ioctls
will need to be used there.
 
> The API needs to be fixed, and it is better sooner than later.

The API works perfectly well. CEA-861, VESA DMT, no problem at all. There
are a few things that need to be added to v4l2_dv_enum_dv_presets such as
framerate and interlaced vs progressive. Although I don't want to make changes
there until I know how GTF/CVT are going to be handled.

The whole preset API was made to 1) provide a simple way to use the common
video formats and 2) handle receivers/transmitters that only provided a limited
set of formats. There are quite a few of those that only support the 480/576/720/1080
lines formats.

For more complex timings use VIDIOC_G/S_DV_TIMINGS.

> 
> >> 2. V4L2 API
> >>    ==== ===
> >>
> >> The V4L2 specs define a DV timing as having those fields:
> >>
> >> __u32	width	Width of the active video in pixels
> >> __u32	height	Height of the active video in lines
> >> __u32	interlaced	Progressive (0) or interlaced (1)
> >> __u32	polarities	This is a bit mask that defines polarities of sync signals. 
> >> __u64	pixelclock	Pixel clock in Hz. Ex. 74.25MHz->74250000
> >> __u32	hfrontporch	Horizontal front porch in pixels
> >> __u32	hsync	Horizontal sync length in pixels
> >> __u32	hbackporch	Horizontal back porch in pixels
> >> __u32	vfrontporch	Vertical front porch in lines
> >> __u32	vsync	Vertical sync length in lines
> >> __u32	vbackporch	Vertical back porch in lines
> >> __u32	il_vfrontporch	Vertical front porch in lines for bottom field of interlaced field formats
> >> __u32	il_vsync	Vertical sync length in lines for bottom field of interlaced field formats
> >> __u32	il_vbackporch	Vertical back porch in lines for bottom field of interlaced field formats
> >>
> >> [1] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-dv-timings.html
> >>
> >> So, it basically allows adjusting the timings for each of the VIC's, but it seems that there
> >> is one limitation at the current API:
> >>
> >> vblank is an integer value, for both frames 0 and 1. So, it doesn't allow to adjust vblanks
> >> like 22.5. This prevents specifying presets like VICs 10/11.
> > 
> > vblanks are never halflines. One field is one line longer than the other. As note 1 in table 2
> > says: "fractional values indicate that the number of blanking lines varies". It's why we have
> > those il_ fields.
> 
> OK.
> 
> >>
> >> The presets ioctl's [2] provide the following fields:
> >>
> >> __u32	index	Number of the DV preset, set by the application.
> >> __u32	preset	This field identifies one of the DV preset values listed in Table A.15, “struct DV Presets”.
> >> __u8	name[24]	Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is intended for the user.
> >> __u32	width	Width of the active video in pixels for the DV preset.
> >> __u32	height	Height of the active video in lines for the DV preset.
> >>
> >> [2] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-enum-dv-presets.html#v4l2-dv-presets-vals
> >>
> >> Where "preset" can mean:
> >>
> >> V4L2_DV_INVALID		0	Invalid preset value.
> >> V4L2_DV_480P59_94	1	720x480 progressive video at 59.94 fps as per BT.1362.
> >> V4L2_DV_576P50		2	720x576 progressive video at 50 fps as per BT.1362.
> >> V4L2_DV_720P24		3	1280x720 progressive video at 24 fps as per SMPTE 296M.
> >> V4L2_DV_720P25		4	1280x720 progressive video at 25 fps as per SMPTE 296M.
> >> V4L2_DV_720P30		5	1280x720 progressive video at 30 fps as per SMPTE 296M.
> >> V4L2_DV_720P50		6	1280x720 progressive video at 50 fps as per SMPTE 296M.
> >> V4L2_DV_720P59_94	7	1280x720 progressive video at 59.94 fps as per SMPTE 274M.
> >> V4L2_DV_720P60		8	1280x720 progressive video at 60 fps as per SMPTE 274M/296M.
> >> V4L2_DV_1080I29_97	9	1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.
> >> V4L2_DV_1080I30		10	1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.
> >> V4L2_DV_1080I25		11	1920x1080 interlaced video at 25 fps as per BT.1120.
> >> V4L2_DV_1080I50		12	1920x1080 interlaced video at 50 fps as per SMPTE 296M.
> >> V4L2_DV_1080I60		13	1920x1080 interlaced video at 60 fps as per SMPTE 296M.
> >> V4L2_DV_1080P24		14	1920x1080 progressive video at 24 fps as per SMPTE 296M.
> >> V4L2_DV_1080P25		15	1920x1080 progressive video at 25 fps as per SMPTE 296M.
> >> V4L2_DV_1080P30		16	1920x1080 progressive video at 30 fps as per SMPTE 296M.
> >> V4L2_DV_1080P50		17	1920x1080 progressive video at 50 fps as per BT.1120.
> >> V4L2_DV_1080P60		18	1920x1080 progressive video at 60 fps as per BT.1120.
> > 
> > All these standards need to be replaced with CEA-861.
> 
> Sorry, but I couldn't understand your proposal here.
> 
> >>
> >>
> >> 3. ISSUES AT V4L2 API
> >>    ====== == ==== ===
> >>
> >> There are some troubles at the way we currently define the presets:
> >>
> >> 3.1) The preset macros have the name of the active video lines, but this is also present at
> >>      the height field;
> > 
> > ??? While a human can see that V4L2_DV_1080P60 refers to 1080 lines, a computer
> > can't. The macro is a just a number, so you need to communicate the width and
> > height explicitly.
> 
> Yes, but the namespace is confusing, and developers might code it as:
> 
> if (preset >= V4L2_DV_1080I29_97  || preset <= V4L2_DV_1080P60)
> 	width = 1080;
> 
> (or doing the same inside a switch, although I've seen several userspace applications
>  implementing things like above).
> 
> The above would be valid, and the end result is that a duplicated information is provided.

That's why we have the VIDIOC_DV_ENUM_PRESETS that you can give the preset and get
back WxH. How does this differ between v4l2_std_id and ENUMSTD?

> I failed to see what information is provided by the "presets" name. If this were removed
> from the ioctl, and fps would be added instead, the API would be clearer. The only
> adjustment would be to use "index" as the preset selection key. Anyway, it is too late
> for such change. We need to live with that.

Adding the fps solves nothing. Because that still does not give you specific timings.
You can have 1920x1080P60 that has quite different timings from the CEA-861 standard
and that may not be supported by a TV.

If you are working with HDMI, then you may want to filter all supported presets to
those of the CEA standard.

That's one thing that is missing at the moment: that presets belonging to a certain
standard get their own range. Since we only do CEA861 right now it hasn't been an
issue, but it will.

> > 
> >> 3.2) The preset macros don't have the name of the active video columns;
> > 
> > For the current set of macros the industry convention is used. 1080P50 always
> > refers to 1920x1080. Anything else should be made explicit.
> >  
> >> 3.3) If someone would want to add a preset for some CEA-861-E VICs, namespace conflicts will
> >>      happen. For example, a preset for 1440x576@50Hz would have the same name as a preset
> >>      for 2880x576p at 50 Hz. Both would be called as V4L2_DV_576P50.
> > 
> > Obviously that would have to be called V4L2_DV_2880X576P50 (or something similar).
> 
> So, the namespace will become messy, with will make developers very confused about what they
> should use.  As you've mentioned, there are currently 4 standards with timings that will
> needed to be supported. So, at the end of the day, we'll have:
> 
> V4L2_DV_576P50
> V4L2_DV_576P50_foo
> V4L2_DV_576P50_bar
> V4L2_DV_576P50_delta
> V4L2_DV_2880X576P50
> V4L2_DV_2880X576P50_foo
> V4L2_DV_2880X576P50_bar
> V4L2_DV_2880X576P50_delta
> ...
> 
> where foo, bar, and delta would be some othe DV-timings based naming. It will become a nightmare
> for developers to discover, from the above list, what are the timings from VESA DMT and what
> are from CEA-861.
> 
> The solution is to associate its name to the standards naming, like:
> 
> 	V4L2_DV_CEA_861_VIC_35_36
> 
> For the timings associated with VICs 35 and 36.

I've no problem with the CEA_861 prefix. Using VIC is not a good idea for the reasons outlined
above.

V4L2_DV_CEA_861_1920X1080P60
V4L2_DV_CEA_861_1920X1080P59_94

etc. is fine as far as I am concerned. It's a needed improvement, and the current names
are perfectly acceptable as aliases.

> 
> > 
> >> 3.4) It doesn't mind what DV timing is used, CEA-861-E and BT.709 allows to use the 60Hz
> >>      timings as either 60Hz or 59.94 Hz. That applies to all VIC format timings at table 2
> >>      for 60 Hz, 120 Hz and 240 Hz.
> > 
> > No, the pixelclock is part of the preset timings. So V4L2_DV_1080P60 and V4L2_DV_1080P59_94
> > are different presets with different timings. Just as they would be different modelines
> > for your graphics card. I really don't see the problem here.
> 
> Sorry, but the current way that this documented is not clear enough. Also, there's nothing
> at VIDIOC_ENUM_DV_PRESETS that allows checking the fps, except for the preset name, which
> is confusing enough.

Improving the documentation is always useful. If it wasn't clear enough to you, then other
will most likely have the same problem.

Adding some way to determine the fps with ENUM_DV_PRESETS is needed as well. It just needs
some careful thinking how this should be done. I don't know whether a v4l2_fract can
represent all frequencies. I would need to experiment a bit.

> >> 3.5) There are lots of format at CEA-861-E without a V4L2 preset.
> > 
> > True. Frankly I have yet to encounter any of the weird ones (i.e. other than
> > 640x480, 480p/i, 576p/i, 720p/i and 1080p/i with their various framerates).
> > 
> >>
> >> 4. PROPOSED SOLUTION
> >>    ======== ========
> >>
> >> In order to fix the issue, we need change the API without breaking the current apps that
> >> use the timings ioctls. Also, the vertical rate clock for 60Hz formats needs to allow
> >> a fractional adjustment of either 1 or 1000/1001, in order to support the specs.
> >>
> >> 4.1) Preset renaming
> >>      ---------------
> >>
> >> To avoid having duplicated namespace conflicts, the better seems to rename the existing
> >> presets to contain both width and height at their macro definitions, like:
> >>
> >> #define V4L2_DV_1920_1080P60	18	1920x1080 progressive video at 60 fps as per BT.1120
> >>
> >> (for the sake of simplicity, I just took one value from the table. The same fix is needed
> >>  to be applied for the other macro definitions)
> >>
> >> To avoid breaking userspace, the old names need to be associated with the new ones, with:
> >>
> >> #define V4L2_DV_1080P60		V4L2_DV_1920_1080P60
> > 
> > I've no problem with that. 1080P60 is still a useful shorthand.
> 
> As I said before, it will be better to change it to explicitly associate with the specs
> that defined that video timing, with whatever ID code there. So, for CEA-861, it would
> be, in this case:
> 
> #define V4L2_DV_CEA_861_VIC_16	18
> 
> and the legacy compat macro:
> 	#define V4L2_DV_1080P60		V4L2_DV_CEA_861_VIC_16

I agree with the standard, but not with the VIC part.
 
> >>
> >> This fixes issue 3.2 and 3.3. Unfortunately, fixing 3.1 is not possible anymore, so,
> >> we have to keep the same information duplicated on two places (at the macro name and
> >> at the width/height).
> > 
> > As I mentioned above, for a program the macro name is useless.
> > 
> >> The question that remains unsolved is what an userspace application would handle a driver
> >> that might eventually provide inconsistent data at width/height and at the macro names?
> > 
> > That's a driver bug.
> > 
> >> 4.2) Framerate selection for 60Hz preset
> >>      -----------------------------------
> >>
> >> As the spec allows using any format that it is multiple of 6.00 Hz multiplied by either
> >> 1 or 1000/1001, the selection betweem them should be done via VIDIOC_G_PARM/VIDIOC_S_PARM.
> >> So, V4L2 spec should say, at the "Digital Video (DV) Timings" section:
> >>
> >> 	Devices that implement DV timings shall implement VIDIOC_G_PARM/VIDIOC_S_PARM,
> >> 	in order to allow controlling the vertical frame rate for the presets whose
> >> 	vertical rate is multiple of 6.00 Hz, in order to allow setting the timing
> >> 	between 60 Hz and 59.94 Hz. The default value, at device init, shall be 59.94 Hz.
> > 
> > NACK.
> > 
> > The pixel clock is part of the video timings and hence defined by the preset.
> > 
> > VIDIOC_S_PARM is used when the desired framerate differs from the actual framerate
> > and the driver can do frame repeating or frameskipping.
> 
> NO. VIDIOC_S_PARM is used on all places where the user desires to specify a framerate. All
> webcams use it to select the desired framerate.
> 
> > At least that's what the V4L2 spec says. 
> 
> I'll prepare a patch fixing it. This is one of the parts of the API that got outdated with
> time.
> 
> > In practice it is used to set the framerate for sensors. I'm not sure
> > if there is any driver that actually uses it for frameskipping. 
> 
> There are some video capture drivers that implement it, so I think that some use it for
> frameskipping.

G/S_PARM makes sense for sensors, but not for video receivers/transmitters. It
simply makes no sense and makes it harder on drivers and applications alike.

> 
> > To my knowledge it is not used at all for video output.
> 
> In any case, selecting a DV timing preset with an specific fps is currently confusing, and
> requires that the userspace application to have a switch(v4l2_dv_enum_preset.preset) in order
> to associate a preset macro name with a fps. This is a very bad idea.

Again, that's not how it works. For transmitting the application will enumerate the supported
presets and show it to the user who can select from it. For embedded apps it is more likely
that the application will hardcode the presets.

For receiving you call QUERY_DV_PRESET and then use it with S_DV_PRESET.

You should never have to do a switch.

And yes, I know that ENUM_DV_PRESETS needs to return the fps. It's on the TODO list.
 
> I see only two practical solutions for that. The first one is to use S_PARAM. The other one 
> is to stop providing the frequency inside the macro name, and add a field for that at the 
> v4l2_dv_enum_preset struct:
> 
> struct v4l2_dv_enum_preset {
> 	__u32		index;
> 	__u32		preset;
> 	__u8		name[32]; /* Name of the preset timing */
> 	__u32		width;
> 	__u32		height;
> 	v4l2_fract	fps;
> 	__u32		reserved[2];
> };
> 
> So, for example, a driver that supports only CEA-861 VIC 16 will report 2 presets:
> 
> struct v4l2_dv_enum_preset dv[] = {
> 	{ 0, V4L2_DV_CEA_861_VIC_16__60HZ,    "CEA-861 1920x1080p 60Hz", 1920, 1080, {60, 1} },
> 	{ 1, V4L2_DV_CEA_861_VIC_16__59_94HZ, "CEA-861 1920x1080p 59.94Hz", 1920, 1080, {60000, 1001} },
> };
> 
> Yet, we should be sure that this will also cover all current VESA standards.

Well, yes, that's the plan. It just needs more research to determine whether v4l2_fract
is the best way to specify the fps and how to handle CVT/GTF.

> 
> >> 4.3) Add the missing CEA-861-E presets
> >>      ---------------------------------
> >>
> >> As those formats are part of the spec that is implemented by this V4L2 API, the better
> >> would be to implement all the missing formats at the V4L2 spec. As a generic rule, we
> >> don't add support at the Kernel without having a driver using it, but, in this specific
> >> case, we want to be able to be compatible with the specs, so, it seems a good idea to
> >> implement the remaining ones, or, at least reserve its namespace at the DocBook. This
> >> solves issue 3.5.
> > 
> > I'm not so sure. There are lots of weird resolutions in CEA-861 that I have never
> > seen in use. A better approach IMHO is that whenever we add a resolution to the
> > preset table, then we do that for all variants of that resolution.
> 
> This works for me.
> 
> >> 5) S5P-TV SUPPORT FOR 59.94 HZ
> >>    ===========================
> >>
> >> It is not clear, from this patch, if you're really wanting to implement support for VIC
> >> 16 format @59.94 Hz, or something else. From CEA-861-E, it seems to be the case, as
> >> this is the only 1920x1080p format for 60 Hz. If this is the case, according with my
> >> proposal, the driver should be using the 60Hz format, instead, and implement S_PARM 
> >> to allow selecting between 60Hz and 59.94Hz.
> > 
> > NACK. You need two presets: V4L2_DV_1080P60 and 1080P59_94. Just as is already there
> > for 720P60 and 720P59_94. I really don't see the problem.
> 
> NACK adding it as "V4L2_DV_1080P59_94". 
> 
> Let's fix the namespace and provide a way to specify/enumberate the fps first, and then
> change the patch to follow whatever decided.

So, after all this talk it boils down to:

- Add a CEA_861 namespace
- Add a way to specify the fps in VIDIOC_DV_ENUM_PRESETS

I can work on the proposal this week for that. The only reason the fps hasn't been added
yet is that I never had the time to do the research on how to represent the fps reliably
for all CEA/VESA formats. Hmm, pixelclock / total_framesize should always work, of course.

We can add a flags field as well (for interlaced vs progressive and perhaps others such as
normal vs reduced blanking).

That leaves the problem with GTF/CVT. I'll get back to that tomorrow. I have ideas, but
I need to discuss it first.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-05 13:20         ` Hans Verkuil
@ 2011-07-05 19:02           ` Andy Walls
  2011-07-05 23:25             ` Mauro Carvalho Chehab
  2011-07-06 11:04           ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 37+ messages in thread
From: Andy Walls @ 2011-07-05 19:02 UTC (permalink / raw)
  To: Hans Verkuil, Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Hans Verkuil <hverkuil@xs4all.nl> wrote:
>I can work on the proposal this week for that. The only reason the fps
>hasn't been added
>yet is that I never had the time to do the research on how to represent
>the fps reliably
>for all CEA/VESA formats. Hmm, pixelclock / total_framesize should
>always work, of course.
>
>We can add a flags field as well (for interlaced vs progressive and
>perhaps others such as
>normal vs reduced blanking).
>
>That leaves the problem with GTF/CVT. I'll get back to that tomorrow. I
>have ideas, but
>I need to discuss it first.
>
>Regards,
>
>	Hans
>--
>To unsubscribe from this list: send the line "unsubscribe linux-media"
>in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

For fps you could use horizontal_line_freq/lines_per_frame.

However, all of the non-integer fps numbers I have seen in this email chain all seem to be multiples of 29.97002997 Hz. So maybe you could just use the closest integer rate with a flag labeled "ntsc_bw_timing_hack" to indicate the fractional rates. :) 

That 29.97 Hz number comes from the NTSC decision in 1953(!) to change the horizontal line freq to 4.5 MHz/286.  Note that

(4.5 MHz/286)/525 = 30 * (1000/1001) = 29.97002997 Hz

It is interesting to see one of the most ingenious analog hacks in TV history (to achieve color and B&W backward compatabilty while staying in the 10% tolerance of the old B&W receivers) being codified in digital standards over 50 years later. It boggles the mind...

Regards,
Andy

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-05 19:02           ` Andy Walls
@ 2011-07-05 23:25             ` Mauro Carvalho Chehab
  2011-07-06  1:05               ` Andy Walls
  0 siblings, 1 reply; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-05 23:25 UTC (permalink / raw)
  To: Andy Walls
  Cc: Hans Verkuil, Tomasz Stanislawski, linux-media, m.szyprowski,
	kyungmin.park, laurent.pinchart

Em 05-07-2011 16:02, Andy Walls escreveu:
> Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> I can work on the proposal this week for that. The only reason the fps
>> hasn't been added
>> yet is that I never had the time to do the research on how to represent
>> the fps reliably
>> for all CEA/VESA formats. Hmm, pixelclock / total_framesize should
>> always work, of course.
>>
>> We can add a flags field as well (for interlaced vs progressive and
>> perhaps others such as
>> normal vs reduced blanking).
>>
>> That leaves the problem with GTF/CVT. I'll get back to that tomorrow. I
>> have ideas, but
>> I need to discuss it first.
>>
>> Regards,
>>
>> 	Hans
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media"
>> in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> For fps you could use horizontal_line_freq/lines_per_frame.
> 
> However, all of the non-integer fps numbers I have seen in this email chain all seem to be multiples of 29.97002997 Hz. So maybe you could just use the closest integer rate with a flag labeled "ntsc_bw_timing_hack" to indicate the fractional rates. :) 

CEA-861 has some other timings that are not 60 Hz * 1000/1001. Yet, v4l2_fract
is capable of handling any of such timings, as, whatever frequency taken, it
needs to be a fractional number. Btw, even some userspace libraries prefer to
represent fps using a fraction, instead of a float, to avoid rounding issues.

> 
> That 29.97 Hz number comes from the NTSC decision in 1953(!) to change the horizontal line freq to 4.5 MHz/286.  Note that
> 
> (4.5 MHz/286)/525 = 30 * (1000/1001) = 29.97002997 Hz

One of the rationale for that decision was to avoid flicking issues with cathodic 
ray monitors and fluorescent lamps.
 
> It is interesting to see one of the most ingenious analog hacks in TV history (to achieve color and B&W backward compatabilty while staying in the 10% tolerance of the old B&W receivers) being codified in digital standards over 50 years later. It boggles the mind...

Yes. Bad (and good) API decisions will stay forever.

Cheers,
Mauro.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-05 23:25             ` Mauro Carvalho Chehab
@ 2011-07-06  1:05               ` Andy Walls
  0 siblings, 0 replies; 37+ messages in thread
From: Andy Walls @ 2011-07-06  1:05 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Hans Verkuil, Tomasz Stanislawski, linux-media, m.szyprowski,
	kyungmin.park, laurent.pinchart

Mauro Carvalho Chehab <mchehab@redhat.com> wrote:

>Em 05-07-2011 16:02, Andy Walls escreveu:
>> Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> I can work on the proposal this week for that. The only reason the
>fps
>>> hasn't been added
>>> yet is that I never had the time to do the research on how to
>represent
>>> the fps reliably
>>> for all CEA/VESA formats. Hmm, pixelclock / total_framesize should
>>> always work, of course.
>>>
>>> We can add a flags field as well (for interlaced vs progressive and
>>> perhaps others such as
>>> normal vs reduced blanking).
>>>
>>> That leaves the problem with GTF/CVT. I'll get back to that
>tomorrow. I
>>> have ideas, but
>>> I need to discuss it first.
>>>
>>> Regards,
>>>
>>> 	Hans
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe
>linux-media"
>>> in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> 
>> For fps you could use horizontal_line_freq/lines_per_frame.
>> 
>> However, all of the non-integer fps numbers I have seen in this email
>chain all seem to be multiples of 29.97002997 Hz. So maybe you could
>just use the closest integer rate with a flag labeled
>"ntsc_bw_timing_hack" to indicate the fractional rates. :) 
>
>CEA-861 has some other timings that are not 60 Hz * 1000/1001. Yet,
>v4l2_fract
>is capable of handling any of such timings, as, whatever frequency
>taken, it
>needs to be a fractional number. Btw, even some userspace libraries
>prefer to
>represent fps using a fraction, instead of a float, to avoid rounding
>issues.
>
>> 
>> That 29.97 Hz number comes from the NTSC decision in 1953(!) to
>change the horizontal line freq to 4.5 MHz/286.  Note that
>> 
>> (4.5 MHz/286)/525 = 30 * (1000/1001) = 29.97002997 Hz
>
>One of the rationale for that decision was to avoid flicking issues
>with cathodic 
>ray monitors and fluorescent lamps.
> 
>> It is interesting to see one of the most ingenious analog hacks in TV
>history (to achieve color and B&W backward compatabilty while staying
>in the 10% tolerance of the old B&W receivers) being codified in
>digital standards over 50 years later. It boggles the mind...
>
>Yes. Bad (and good) API decisions will stay forever.
>
>Cheers,
>Mauro.

Oops, yes I see the 60.054 Hz rate corresponds to a 262 line field (524 line frame) at the standard NTSC line rate.

Weird stuff.

Regards,
Andy

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-05 13:20         ` Hans Verkuil
  2011-07-05 19:02           ` Andy Walls
@ 2011-07-06 11:04           ` Mauro Carvalho Chehab
  2011-07-06 11:31             ` Hans Verkuil
  1 sibling, 1 reply; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 11:04 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 05-07-2011 10:20, Hans Verkuil escreveu:
 
>> I failed to see what information is provided by the "presets" name. If this were removed
>> from the ioctl, and fps would be added instead, the API would be clearer. The only
>> adjustment would be to use "index" as the preset selection key. Anyway, it is too late
>> for such change. We need to live with that.
> 
> Adding the fps solves nothing. Because that still does not give you specific timings.
> You can have 1920x1080P60 that has quite different timings from the CEA-861 standard
> and that may not be supported by a TV.
> 
> If you are working with HDMI, then you may want to filter all supported presets to
> those of the CEA standard.
> 
> That's one thing that is missing at the moment: that presets belonging to a certain
> standard get their own range. Since we only do CEA861 right now it hasn't been an
> issue, but it will.

I prepared a long email about that, but then I realized that we're investing our time into
something broken, at the light of all DV timing standards. So, I've dropped it and
started from scratch.

>From what I've got, there are some hardware that can only do a limited set of DV timings.
If this were not the case, we could simply just use the VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
and put the CEA 861 and VESA timings into some userspace library.

In other words, the PRESET API is meant to solve the case where hardware only support
a limited set of frequencies, that may or may not be inside the CEA standard.

Let's assume we never added the current API, and discuss how it would properly fulfill
the user needs. An API that would likely work is:

struct v4l2_dv_enum_preset2 {
	__u32	  index;
	__u8	  name[32]; /* Name of the preset timing */

	struct v4l2_fract fps;

#define DV_PRESET_IS_PROGRESSIVE	1<<31
#define DV_PRESET_SPEC(flag)		(flag && 0xff)
#define DV_PRESET_IS_CEA861		1
#define DV_PRESET_IS_DMT		2
#define DV_PRESET_IS_CVF		3
#define DV_PRESET_IS_GTF		4
#define DV_PRESET_IS_VENDOR_SPECIFIC	5

	__u32	flags;		/* Interlaced/progressive, DV specs, etc */

	__u32	width;		/* width in pixels */
	__u32	height;		/* height in lines */
	__u32	polarities;	/* Positive or negative polarity */
	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
	__u32	hsync;		/* Horizontal Sync length in pixels */
	__u32	hbackporch;	/* Horizontal back porch in pixels */
	__u32	vfrontporch;	/* Vertical front porch in pixels */
	__u32	vsync;		/* Vertical Sync length in lines */
	__u32	vbackporch;	/* Vertical back porch in lines */
	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
				 * interlaced field formats
				 */
	__u32	il_vsync;	/* Vertical sync length for bottom field of
				 * interlaced field formats
				 */
	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
				 * interlaced field formats
				 */
	__u32	  reserved[4];
};

#define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct v4l2_dv_enum_preset2)
#define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
#define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)

Such preset API seems to work for all cases. Userspace can use any DV timing
information to select the desired format, and don't need to have a switch for
a preset macro to try to guess what the format actually means. Also, there's no
need to touch at the API spec every time a new DV timeline is needed.

Also, it should be noticed that, since the size of the data on the above definitions
are different than the old ones, _IO macros will provide a different magic number,
so, adding these won't break the existing API.

So, I think we should work on this proposal, and mark the existing one as deprecated.

Thanks,
Mauro



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 11:04           ` Mauro Carvalho Chehab
@ 2011-07-06 11:31             ` Hans Verkuil
  2011-07-06 11:48               ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 37+ messages in thread
From: Hans Verkuil @ 2011-07-06 11:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>
>>> I failed to see what information is provided by the "presets" name. If
>>> this were removed
>>> from the ioctl, and fps would be added instead, the API would be
>>> clearer. The only
>>> adjustment would be to use "index" as the preset selection key. Anyway,
>>> it is too late
>>> for such change. We need to live with that.
>>
>> Adding the fps solves nothing. Because that still does not give you
>> specific timings.
>> You can have 1920x1080P60 that has quite different timings from the
>> CEA-861 standard
>> and that may not be supported by a TV.
>>
>> If you are working with HDMI, then you may want to filter all supported
>> presets to
>> those of the CEA standard.
>>
>> That's one thing that is missing at the moment: that presets belonging
>> to a certain
>> standard get their own range. Since we only do CEA861 right now it
>> hasn't been an
>> issue, but it will.
>
> I prepared a long email about that, but then I realized that we're
> investing our time into
> something broken, at the light of all DV timing standards. So, I've
> dropped it and
> started from scratch.
>
> From what I've got, there are some hardware that can only do a limited set
> of DV timings.
> If this were not the case, we could simply just use the
> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
> and put the CEA 861 and VESA timings into some userspace library.
>
> In other words, the PRESET API is meant to solve the case where hardware
> only support
> a limited set of frequencies, that may or may not be inside the CEA
> standard.
>
> Let's assume we never added the current API, and discuss how it would
> properly fulfill
> the user needs. An API that would likely work is:
>
> struct v4l2_dv_enum_preset2 {
> 	__u32	  index;
> 	__u8	  name[32]; /* Name of the preset timing */
>
> 	struct v4l2_fract fps;
>
> #define DV_PRESET_IS_PROGRESSIVE	1<<31
> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
> #define DV_PRESET_IS_CEA861		1
> #define DV_PRESET_IS_DMT		2
> #define DV_PRESET_IS_CVF		3
> #define DV_PRESET_IS_GTF		4
> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>
> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>
> 	__u32	width;		/* width in pixels */
> 	__u32	height;		/* height in lines */
> 	__u32	polarities;	/* Positive or negative polarity */
> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
> 	__u32	hsync;		/* Horizontal Sync length in pixels */
> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
> 	__u32	vsync;		/* Vertical Sync length in lines */
> 	__u32	vbackporch;	/* Vertical back porch in lines */
> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
> 				 * interlaced field formats
> 				 */
> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
> 				 * interlaced field formats
> 				 */
> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
> 				 * interlaced field formats
> 				 */
> 	__u32	  reserved[4];
> };
>
> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
> v4l2_dv_enum_preset2)
> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>
> Such preset API seems to work for all cases. Userspace can use any DV
> timing
> information to select the desired format, and don't need to have a switch
> for
> a preset macro to try to guess what the format actually means. Also,
> there's no
> need to touch at the API spec every time a new DV timeline is needed.
>
> Also, it should be noticed that, since the size of the data on the above
> definitions
> are different than the old ones, _IO macros will provide a different magic
> number,
> so, adding these won't break the existing API.
>
> So, I think we should work on this proposal, and mark the existing one as
> deprecated.

This proposal makes it very hard for applications to directly select a
format like 720p50 because the indices can change at any time. I think
this is a very desirable feature, particularly for apps running on
embedded systems where the hardware is known. This was one of the design
considerations at the time this API was made.

But looking at this I wonder if we shouldn't just make a
VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you get
all the timing information back. No need to deprecate anything. I'm not
even sure if with this change we need to modify struct v4l2_dv_enum_preset
as I proposed in my RFC, although I think we should.

Regards,

     Hans


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 11:31             ` Hans Verkuil
@ 2011-07-06 11:48               ` Mauro Carvalho Chehab
  2011-07-06 12:03                 ` Laurent Pinchart
  2011-07-06 12:14                 ` Hans Verkuil
  0 siblings, 2 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 11:48 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 06-07-2011 08:31, Hans Verkuil escreveu:
>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>
>>>> I failed to see what information is provided by the "presets" name. If
>>>> this were removed
>>>> from the ioctl, and fps would be added instead, the API would be
>>>> clearer. The only
>>>> adjustment would be to use "index" as the preset selection key. Anyway,
>>>> it is too late
>>>> for such change. We need to live with that.
>>>
>>> Adding the fps solves nothing. Because that still does not give you
>>> specific timings.
>>> You can have 1920x1080P60 that has quite different timings from the
>>> CEA-861 standard
>>> and that may not be supported by a TV.
>>>
>>> If you are working with HDMI, then you may want to filter all supported
>>> presets to
>>> those of the CEA standard.
>>>
>>> That's one thing that is missing at the moment: that presets belonging
>>> to a certain
>>> standard get their own range. Since we only do CEA861 right now it
>>> hasn't been an
>>> issue, but it will.
>>
>> I prepared a long email about that, but then I realized that we're
>> investing our time into
>> something broken, at the light of all DV timing standards. So, I've
>> dropped it and
>> started from scratch.
>>
>> From what I've got, there are some hardware that can only do a limited set
>> of DV timings.
>> If this were not the case, we could simply just use the
>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>> and put the CEA 861 and VESA timings into some userspace library.
>>
>> In other words, the PRESET API is meant to solve the case where hardware
>> only support
>> a limited set of frequencies, that may or may not be inside the CEA
>> standard.
>>
>> Let's assume we never added the current API, and discuss how it would
>> properly fulfill
>> the user needs. An API that would likely work is:
>>
>> struct v4l2_dv_enum_preset2 {
>> 	__u32	  index;
>> 	__u8	  name[32]; /* Name of the preset timing */
>>
>> 	struct v4l2_fract fps;
>>
>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>> #define DV_PRESET_IS_CEA861		1
>> #define DV_PRESET_IS_DMT		2
>> #define DV_PRESET_IS_CVF		3
>> #define DV_PRESET_IS_GTF		4
>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>
>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>
>> 	__u32	width;		/* width in pixels */
>> 	__u32	height;		/* height in lines */
>> 	__u32	polarities;	/* Positive or negative polarity */
>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>> 	__u32	vsync;		/* Vertical Sync length in lines */
>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>> 				 * interlaced field formats
>> 				 */
>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>> 				 * interlaced field formats
>> 				 */
>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>> 				 * interlaced field formats
>> 				 */
>> 	__u32	  reserved[4];
>> };
>>
>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>> v4l2_dv_enum_preset2)
>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>
>> Such preset API seems to work for all cases. Userspace can use any DV
>> timing
>> information to select the desired format, and don't need to have a switch
>> for
>> a preset macro to try to guess what the format actually means. Also,
>> there's no
>> need to touch at the API spec every time a new DV timeline is needed.
>>
>> Also, it should be noticed that, since the size of the data on the above
>> definitions
>> are different than the old ones, _IO macros will provide a different magic
>> number,
>> so, adding these won't break the existing API.
>>
>> So, I think we should work on this proposal, and mark the existing one as
>> deprecated.
> 
> This proposal makes it very hard for applications to directly select a
> format like 720p50 because the indices can change at any time.

Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
check what line it wants, and do a S_DV_PRESET2, just like any other place
where V4L2 defines an ENUM function.

The enum won't change during application runtime, so, they can be stored
if the application would need to switch to other formats latter.

> I think
> this is a very desirable feature, particularly for apps running on
> embedded systems where the hardware is known. This was one of the design
> considerations at the time this API was made.

This is a very weak argument. With just one ENUM loop, the application can
quickly get the right format(s), and associate them with any internal 
namespace.

> But looking at this I wonder if we shouldn't just make a
> VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you get
> all the timing information back. No need to deprecate anything. I'm not
> even sure if with this change we need to modify struct v4l2_dv_enum_preset
> as I proposed in my RFC, although I think we should.

Won't solve the issue: one new #define is needed for each video timing,
namespaces will be confusing, no support for VESA GVF/ VESA CVT timings
(or worse: we'll end by having thousands of formats at the end of the day),
instead of just one ENUM ioctl, an extra ioctl will be required for each
returned value, etc.

Cheers,
Mauro.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 11:48               ` Mauro Carvalho Chehab
@ 2011-07-06 12:03                 ` Laurent Pinchart
  2011-07-06 12:09                   ` Mauro Carvalho Chehab
  2011-07-06 12:14                 ` Hans Verkuil
  1 sibling, 1 reply; 37+ messages in thread
From: Laurent Pinchart @ 2011-07-06 12:03 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Hans Verkuil, Tomasz Stanislawski, linux-media, m.szyprowski,
	kyungmin.park

On Wednesday 06 July 2011 13:48:35 Mauro Carvalho Chehab wrote:
> Em 06-07-2011 08:31, Hans Verkuil escreveu:
> >> Em 05-07-2011 10:20, Hans Verkuil escreveu:
> >>>> I failed to see what information is provided by the "presets" name. If
> >>>> this were removed from the ioctl, and fps would be added instead, the
> >>>> API would be clearer. The only adjustment would be to use "index" as
> >>>> the preset selection key. Anyway, it is too late for such change. We
> >>>> need to live with that.
> >>> 
> >>> Adding the fps solves nothing. Because that still does not give you
> >>> specific timings. You can have 1920x1080P60 that has quite different
> >>> timings from the CEA-861 standard and that may not be supported by a TV.
> >>> 
> >>> If you are working with HDMI, then you may want to filter all supported
> >>> presets to those of the CEA standard.
> >>> 
> >>> That's one thing that is missing at the moment: that presets belonging
> >>> to a certain standard get their own range. Since we only do CEA861 right
> >>> now it hasn't been an issue, but it will.
> >> 
> >> I prepared a long email about that, but then I realized that we're
> >> investing our time intosomething broken, at the light of all DV timing
> >> standards. So, I've dropped it and started from scratch.
> >> 
> >> From what I've got, there are some hardware that can only do a limited
> >> set of DV timings. If this were not the case, we could simply just use
> >> the VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS, and put the CEA 861 and VESA
> >> timings into some userspace library.
> >> 
> >> In other words, the PRESET API is meant to solve the case where hardware
> >> only support a limited set of frequencies, that may or may not be inside
> >> the CEA standard.
> >> 
> >> Let's assume we never added the current API, and discuss how it would
> >> properly fulfill the user needs. An API that would likely work is:
> >> 
> >> struct v4l2_dv_enum_preset2 {
> >> 
> >> 	__u32	  index;
> >> 	__u8	  name[32]; /* Name of the preset timing */
> >> 	
> >> 	struct v4l2_fract fps;
> >> 
> >> #define DV_PRESET_IS_PROGRESSIVE	1<<31
> >> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
> >> #define DV_PRESET_IS_CEA861		1
> >> #define DV_PRESET_IS_DMT		2
> >> #define DV_PRESET_IS_CVF		3
> >> #define DV_PRESET_IS_GTF		4
> >> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
> >> 
> >> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
> >> 	
> >> 	__u32	width;		/* width in pixels */
> >> 	__u32	height;		/* height in lines */
> >> 	__u32	polarities;	/* Positive or negative polarity */
> >> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
> >> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
> >> 	__u32	hsync;		/* Horizontal Sync length in pixels */
> >> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
> >> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
> >> 	__u32	vsync;		/* Vertical Sync length in lines */
> >> 	__u32	vbackporch;	/* Vertical back porch in lines */
> >> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
> >> 	
> >> 				 * interlaced field formats
> >> 				 */
> >> 	
> >> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
> >> 	
> >> 				 * interlaced field formats
> >> 				 */
> >> 	
> >> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
> >> 	
> >> 				 * interlaced field formats
> >> 				 */
> >> 	
> >> 	__u32	  reserved[4];
> >> 
> >> };
> >> 
> >> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
> >> v4l2_dv_enum_preset2)
> >> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
> >> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
> >> 
> >> Such preset API seems to work for all cases. Userspace can use any DV
> >> timing information to select the desired format, and don't need to have a
> >> switch for a preset macro to try to guess what the format actually means.
> >> Also, there's no need to touch at the API spec every time a new DV
> >> timeline is needed.
> >> 
> >> Also, it should be noticed that, since the size of the data on the above
> >> definitions are different than the old ones, _IO macros will provide a
> >> different magic number, so, adding these won't break the existing API.
> >> 
> >> So, I think we should work on this proposal, and mark the existing one
> >> as deprecated.
> > 
> > This proposal makes it very hard for applications to directly select a
> > format like 720p50 because the indices can change at any time.
> 
> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
> check what line it wants, and do a S_DV_PRESET2, just like any other place
> where V4L2 defines an ENUM function.

Forcing applications to enumerate all presets when they already know what 
preset they want doesn't seem like a very good solution to me.

> 
> The enum won't change during application runtime, so, they can be stored
> if the application would need to switch to other formats latter.
> 
> > I think this is a very desirable feature, particularly for apps running on
> > embedded systems where the hardware is known. This was one of the design
> > considerations at the time this API was made.
> 
> This is a very weak argument. With just one ENUM loop, the application can
> quickly get the right format(s), and associate them with any internal
> namespace.
> 
> > But looking at this I wonder if we shouldn't just make a
> > VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you get
> > all the timing information back. No need to deprecate anything. I'm not
> > even sure if with this change we need to modify struct
> > v4l2_dv_enum_preset as I proposed in my RFC, although I think we should.
> 
> Won't solve the issue: one new #define is needed for each video timing,
> namespaces will be confusing, no support for VESA GVF/ VESA CVT timings
> (or worse: we'll end by having thousands of formats at the end of the day),
> instead of just one ENUM ioctl, an extra ioctl will be required for each
> returned value, etc.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:03                 ` Laurent Pinchart
@ 2011-07-06 12:09                   ` Mauro Carvalho Chehab
  2011-07-06 12:13                     ` Laurent Pinchart
  0 siblings, 1 reply; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 12:09 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Tomasz Stanislawski, linux-media, m.szyprowski,
	kyungmin.park

Em 06-07-2011 09:03, Laurent Pinchart escreveu:
> On Wednesday 06 July 2011 13:48:35 Mauro Carvalho Chehab wrote:
>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>>> I failed to see what information is provided by the "presets" name. If
>>>>>> this were removed from the ioctl, and fps would be added instead, the
>>>>>> API would be clearer. The only adjustment would be to use "index" as
>>>>>> the preset selection key. Anyway, it is too late for such change. We
>>>>>> need to live with that.
>>>>>
>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>> specific timings. You can have 1920x1080P60 that has quite different
>>>>> timings from the CEA-861 standard and that may not be supported by a TV.
>>>>>
>>>>> If you are working with HDMI, then you may want to filter all supported
>>>>> presets to those of the CEA standard.
>>>>>
>>>>> That's one thing that is missing at the moment: that presets belonging
>>>>> to a certain standard get their own range. Since we only do CEA861 right
>>>>> now it hasn't been an issue, but it will.
>>>>
>>>> I prepared a long email about that, but then I realized that we're
>>>> investing our time intosomething broken, at the light of all DV timing
>>>> standards. So, I've dropped it and started from scratch.
>>>>
>>>> From what I've got, there are some hardware that can only do a limited
>>>> set of DV timings. If this were not the case, we could simply just use
>>>> the VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS, and put the CEA 861 and VESA
>>>> timings into some userspace library.
>>>>
>>>> In other words, the PRESET API is meant to solve the case where hardware
>>>> only support a limited set of frequencies, that may or may not be inside
>>>> the CEA standard.
>>>>
>>>> Let's assume we never added the current API, and discuss how it would
>>>> properly fulfill the user needs. An API that would likely work is:
>>>>
>>>> struct v4l2_dv_enum_preset2 {
>>>>
>>>> 	__u32	  index;
>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>> 	
>>>> 	struct v4l2_fract fps;
>>>>
>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>> #define DV_PRESET_IS_CEA861		1
>>>> #define DV_PRESET_IS_DMT		2
>>>> #define DV_PRESET_IS_CVF		3
>>>> #define DV_PRESET_IS_GTF		4
>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>
>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>> 	
>>>> 	__u32	width;		/* width in pixels */
>>>> 	__u32	height;		/* height in lines */
>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>> 	
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	
>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>> 	
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	
>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>> 	
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	
>>>> 	__u32	  reserved[4];
>>>>
>>>> };
>>>>
>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>> v4l2_dv_enum_preset2)
>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>
>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>> timing information to select the desired format, and don't need to have a
>>>> switch for a preset macro to try to guess what the format actually means.
>>>> Also, there's no need to touch at the API spec every time a new DV
>>>> timeline is needed.
>>>>
>>>> Also, it should be noticed that, since the size of the data on the above
>>>> definitions are different than the old ones, _IO macros will provide a
>>>> different magic number, so, adding these won't break the existing API.
>>>>
>>>> So, I think we should work on this proposal, and mark the existing one
>>>> as deprecated.
>>>
>>> This proposal makes it very hard for applications to directly select a
>>> format like 720p50 because the indices can change at any time.
>>
>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
>> check what line it wants, and do a S_DV_PRESET2, just like any other place
>> where V4L2 defines an ENUM function.
> 
> Forcing applications to enumerate all presets when they already know what 
> preset they want doesn't seem like a very good solution to me.

If the app already know, it might simply do VIDIOC_S_DV_PRESET2(index). This would
work for an embedded hardware. The only care to be taken is to change the index
number if the Kernel changes, or to be sure that, on the embedded tree, that newer
DV lines will be added only after the previous one.

Anyway, a broken API cannot be justified by a weak argument that not needing to do
an ENUM will save a few nanosseconds for some embedded hardware during application
initialization time.

Mauro.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:09                   ` Mauro Carvalho Chehab
@ 2011-07-06 12:13                     ` Laurent Pinchart
  2011-07-06 12:20                       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 37+ messages in thread
From: Laurent Pinchart @ 2011-07-06 12:13 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Hans Verkuil, Tomasz Stanislawski, linux-media, m.szyprowski,
	kyungmin.park

On Wednesday 06 July 2011 14:09:38 Mauro Carvalho Chehab wrote:
> Em 06-07-2011 09:03, Laurent Pinchart escreveu:
> > On Wednesday 06 July 2011 13:48:35 Mauro Carvalho Chehab wrote:
> >> Em 06-07-2011 08:31, Hans Verkuil escreveu:
> >>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
> >>>>>> I failed to see what information is provided by the "presets" name.
> >>>>>> If this were removed from the ioctl, and fps would be added
> >>>>>> instead, the API would be clearer. The only adjustment would be to
> >>>>>> use "index" as the preset selection key. Anyway, it is too late for
> >>>>>> such change. We need to live with that.
> >>>>> 
> >>>>> Adding the fps solves nothing. Because that still does not give you
> >>>>> specific timings. You can have 1920x1080P60 that has quite different
> >>>>> timings from the CEA-861 standard and that may not be supported by a
> >>>>> TV.
> >>>>> 
> >>>>> If you are working with HDMI, then you may want to filter all
> >>>>> supported presets to those of the CEA standard.
> >>>>> 
> >>>>> That's one thing that is missing at the moment: that presets
> >>>>> belonging to a certain standard get their own range. Since we only
> >>>>> do CEA861 right now it hasn't been an issue, but it will.
> >>>> 
> >>>> I prepared a long email about that, but then I realized that we're
> >>>> investing our time intosomething broken, at the light of all DV timing
> >>>> standards. So, I've dropped it and started from scratch.
> >>>> 
> >>>> From what I've got, there are some hardware that can only do a limited
> >>>> set of DV timings. If this were not the case, we could simply just use
> >>>> the VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS, and put the CEA 861 and
> >>>> VESA timings into some userspace library.
> >>>> 
> >>>> In other words, the PRESET API is meant to solve the case where
> >>>> hardware only support a limited set of frequencies, that may or may
> >>>> not be inside the CEA standard.
> >>>> 
> >>>> Let's assume we never added the current API, and discuss how it would
> >>>> properly fulfill the user needs. An API that would likely work is:
> >>>> 
> >>>> struct v4l2_dv_enum_preset2 {
> >>>> 
> >>>> 	__u32	  index;
> >>>> 	__u8	  name[32]; /* Name of the preset timing */
> >>>> 	
> >>>> 	struct v4l2_fract fps;
> >>>> 
> >>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
> >>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
> >>>> #define DV_PRESET_IS_CEA861		1
> >>>> #define DV_PRESET_IS_DMT		2
> >>>> #define DV_PRESET_IS_CVF		3
> >>>> #define DV_PRESET_IS_GTF		4
> >>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
> >>>> 
> >>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
> >>>> 	
> >>>> 	__u32	width;		/* width in pixels */
> >>>> 	__u32	height;		/* height in lines */
> >>>> 	__u32	polarities;	/* Positive or negative polarity */
> >>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
> >>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
> >>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
> >>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
> >>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
> >>>> 	__u32	vsync;		/* Vertical Sync length in lines */
> >>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
> >>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
> >>>> 	
> >>>> 				 * interlaced field formats
> >>>> 				 */
> >>>> 	
> >>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
> >>>> 	
> >>>> 				 * interlaced field formats
> >>>> 				 */
> >>>> 	
> >>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
> >>>> 	
> >>>> 				 * interlaced field formats
> >>>> 				 */
> >>>> 	
> >>>> 	__u32	  reserved[4];
> >>>> 
> >>>> };
> >>>> 
> >>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
> >>>> v4l2_dv_enum_preset2)
> >>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
> >>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
> >>>> 
> >>>> Such preset API seems to work for all cases. Userspace can use any DV
> >>>> timing information to select the desired format, and don't need to
> >>>> have a switch for a preset macro to try to guess what the format
> >>>> actually means. Also, there's no need to touch at the API spec every
> >>>> time a new DV timeline is needed.
> >>>> 
> >>>> Also, it should be noticed that, since the size of the data on the
> >>>> above definitions are different than the old ones, _IO macros will
> >>>> provide a different magic number, so, adding these won't break the
> >>>> existing API.
> >>>> 
> >>>> So, I think we should work on this proposal, and mark the existing one
> >>>> as deprecated.
> >>> 
> >>> This proposal makes it very hard for applications to directly select a
> >>> format like 720p50 because the indices can change at any time.
> >> 
> >> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
> >> check what line it wants, and do a S_DV_PRESET2, just like any other
> >> place where V4L2 defines an ENUM function.
> > 
> > Forcing applications to enumerate all presets when they already know what
> > preset they want doesn't seem like a very good solution to me.
> 
> If the app already know, it might simply do VIDIOC_S_DV_PRESET2(index).
> This would work for an embedded hardware. The only care to be taken is to
> change the index number if the Kernel changes, or to be sure that, on the
> embedded tree, that newer DV lines will be added only after the previous
> one.
> 
> Anyway, a broken API cannot be justified by a weak argument that not
> needing to do an ENUM will save a few nanosseconds for some embedded
> hardware during application initialization time.

We're talking about dozens of syscalls, not a couple of nanoseconds.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 11:48               ` Mauro Carvalho Chehab
  2011-07-06 12:03                 ` Laurent Pinchart
@ 2011-07-06 12:14                 ` Hans Verkuil
  2011-07-06 12:31                   ` Mauro Carvalho Chehab
  2011-07-06 19:39                   ` Mauro Carvalho Chehab
  1 sibling, 2 replies; 37+ messages in thread
From: Hans Verkuil @ 2011-07-06 12:14 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>
>>>>> I failed to see what information is provided by the "presets" name.
>>>>> If
>>>>> this were removed
>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>> clearer. The only
>>>>> adjustment would be to use "index" as the preset selection key.
>>>>> Anyway,
>>>>> it is too late
>>>>> for such change. We need to live with that.
>>>>
>>>> Adding the fps solves nothing. Because that still does not give you
>>>> specific timings.
>>>> You can have 1920x1080P60 that has quite different timings from the
>>>> CEA-861 standard
>>>> and that may not be supported by a TV.
>>>>
>>>> If you are working with HDMI, then you may want to filter all
>>>> supported
>>>> presets to
>>>> those of the CEA standard.
>>>>
>>>> That's one thing that is missing at the moment: that presets belonging
>>>> to a certain
>>>> standard get their own range. Since we only do CEA861 right now it
>>>> hasn't been an
>>>> issue, but it will.
>>>
>>> I prepared a long email about that, but then I realized that we're
>>> investing our time into
>>> something broken, at the light of all DV timing standards. So, I've
>>> dropped it and
>>> started from scratch.
>>>
>>> From what I've got, there are some hardware that can only do a limited
>>> set
>>> of DV timings.
>>> If this were not the case, we could simply just use the
>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>> and put the CEA 861 and VESA timings into some userspace library.
>>>
>>> In other words, the PRESET API is meant to solve the case where
>>> hardware
>>> only support
>>> a limited set of frequencies, that may or may not be inside the CEA
>>> standard.
>>>
>>> Let's assume we never added the current API, and discuss how it would
>>> properly fulfill
>>> the user needs. An API that would likely work is:
>>>
>>> struct v4l2_dv_enum_preset2 {
>>> 	__u32	  index;
>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>
>>> 	struct v4l2_fract fps;
>>>
>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>> #define DV_PRESET_IS_CEA861		1
>>> #define DV_PRESET_IS_DMT		2
>>> #define DV_PRESET_IS_CVF		3
>>> #define DV_PRESET_IS_GTF		4
>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>
>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>
>>> 	__u32	width;		/* width in pixels */
>>> 	__u32	height;		/* height in lines */
>>> 	__u32	polarities;	/* Positive or negative polarity */
>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>> 				 * interlaced field formats
>>> 				 */
>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>> 				 * interlaced field formats
>>> 				 */
>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>> 				 * interlaced field formats
>>> 				 */
>>> 	__u32	  reserved[4];
>>> };
>>>
>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>> v4l2_dv_enum_preset2)
>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>
>>> Such preset API seems to work for all cases. Userspace can use any DV
>>> timing
>>> information to select the desired format, and don't need to have a
>>> switch
>>> for
>>> a preset macro to try to guess what the format actually means. Also,
>>> there's no
>>> need to touch at the API spec every time a new DV timeline is needed.
>>>
>>> Also, it should be noticed that, since the size of the data on the
>>> above
>>> definitions
>>> are different than the old ones, _IO macros will provide a different
>>> magic
>>> number,
>>> so, adding these won't break the existing API.
>>>
>>> So, I think we should work on this proposal, and mark the existing one
>>> as
>>> deprecated.
>>
>> This proposal makes it very hard for applications to directly select a
>> format like 720p50 because the indices can change at any time.
>
> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
> check what line it wants,

It's not so easy as you think to find the right timings: you have to check
many parameters to be certain you have the right one and not some subtle
variation.

> and do a S_DV_PRESET2, just like any other place
> where V4L2 defines an ENUM function.
>
> The enum won't change during application runtime, so, they can be stored
> if the application would need to switch to other formats latter.
>
>> I think
>> this is a very desirable feature, particularly for apps running on
>> embedded systems where the hardware is known. This was one of the design
>> considerations at the time this API was made.
>
> This is a very weak argument. With just one ENUM loop, the application can
> quickly get the right format(s), and associate them with any internal
> namespace.

That actually isn't easy at all.

>> But looking at this I wonder if we shouldn't just make a
>> VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you get
>> all the timing information back. No need to deprecate anything. I'm not
>> even sure if with this change we need to modify struct
>> v4l2_dv_enum_preset
>> as I proposed in my RFC, although I think we should.
>
> Won't solve the issue: one new #define is needed for each video timing,
> namespaces will be confusing, no support for VESA GVF/ VESA CVT timings
> (or worse: we'll end by having thousands of formats at the end of the
> day),
> instead of just one ENUM ioctl, an extra ioctl will be required for each
> returned value, etc.

Presets for GTF/CVT are useless (and I have never seen hardware that has
such presets). In practice you have CEA and DMT presets and nothing else.

We may need to add PRESET_PRIVATE (just like we do for controls) should we
get non-CEA/DMT formats as well. There is no point in having specific
preset defines for those IMHO.

I see very little advantage in throwing away an API that works quite well
in practice only to add a new one that isn't much better IMO. Instead we
can easily improve the existing API.

I *want* to be able to specify the most common CEA/DMT standards directly
and unambiguously through presets. It is very easy and nice to use in
practice. Once you go into the realm of GTF/CVT, then the preset API is
too limited and G/S_DV_TIMINGS need to be used, but that requires much
more effort on the part of the application.

I hope others will pitch in as well with their opinions.

Regards,

     Hans


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:13                     ` Laurent Pinchart
@ 2011-07-06 12:20                       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 12:20 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Tomasz Stanislawski, linux-media, m.szyprowski,
	kyungmin.park

Em 06-07-2011 09:13, Laurent Pinchart escreveu:
> On Wednesday 06 July 2011 14:09:38 Mauro Carvalho Chehab wrote:
>> Em 06-07-2011 09:03, Laurent Pinchart escreveu:
>>> On Wednesday 06 July 2011 13:48:35 Mauro Carvalho Chehab wrote:
>>>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>>>> If this were removed from the ioctl, and fps would be added
>>>>>>>> instead, the API would be clearer. The only adjustment would be to
>>>>>>>> use "index" as the preset selection key. Anyway, it is too late for
>>>>>>>> such change. We need to live with that.
>>>>>>>
>>>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>>>> specific timings. You can have 1920x1080P60 that has quite different
>>>>>>> timings from the CEA-861 standard and that may not be supported by a
>>>>>>> TV.
>>>>>>>
>>>>>>> If you are working with HDMI, then you may want to filter all
>>>>>>> supported presets to those of the CEA standard.
>>>>>>>
>>>>>>> That's one thing that is missing at the moment: that presets
>>>>>>> belonging to a certain standard get their own range. Since we only
>>>>>>> do CEA861 right now it hasn't been an issue, but it will.
>>>>>>
>>>>>> I prepared a long email about that, but then I realized that we're
>>>>>> investing our time intosomething broken, at the light of all DV timing
>>>>>> standards. So, I've dropped it and started from scratch.
>>>>>>
>>>>>> From what I've got, there are some hardware that can only do a limited
>>>>>> set of DV timings. If this were not the case, we could simply just use
>>>>>> the VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS, and put the CEA 861 and
>>>>>> VESA timings into some userspace library.
>>>>>>
>>>>>> In other words, the PRESET API is meant to solve the case where
>>>>>> hardware only support a limited set of frequencies, that may or may
>>>>>> not be inside the CEA standard.
>>>>>>
>>>>>> Let's assume we never added the current API, and discuss how it would
>>>>>> properly fulfill the user needs. An API that would likely work is:
>>>>>>
>>>>>> struct v4l2_dv_enum_preset2 {
>>>>>>
>>>>>> 	__u32	  index;
>>>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>>> 	
>>>>>> 	struct v4l2_fract fps;
>>>>>>
>>>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>>>> #define DV_PRESET_IS_CEA861		1
>>>>>> #define DV_PRESET_IS_DMT		2
>>>>>> #define DV_PRESET_IS_CVF		3
>>>>>> #define DV_PRESET_IS_GTF		4
>>>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>>>
>>>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>>> 	
>>>>>> 	__u32	width;		/* width in pixels */
>>>>>> 	__u32	height;		/* height in lines */
>>>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>>>> 	
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	
>>>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>>>> 	
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	
>>>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>>>> 	
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	
>>>>>> 	__u32	  reserved[4];
>>>>>>
>>>>>> };
>>>>>>
>>>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>>>> v4l2_dv_enum_preset2)
>>>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>>>
>>>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>>>> timing information to select the desired format, and don't need to
>>>>>> have a switch for a preset macro to try to guess what the format
>>>>>> actually means. Also, there's no need to touch at the API spec every
>>>>>> time a new DV timeline is needed.
>>>>>>
>>>>>> Also, it should be noticed that, since the size of the data on the
>>>>>> above definitions are different than the old ones, _IO macros will
>>>>>> provide a different magic number, so, adding these won't break the
>>>>>> existing API.
>>>>>>
>>>>>> So, I think we should work on this proposal, and mark the existing one
>>>>>> as deprecated.
>>>>>
>>>>> This proposal makes it very hard for applications to directly select a
>>>>> format like 720p50 because the indices can change at any time.
>>>>
>>>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
>>>> check what line it wants, and do a S_DV_PRESET2, just like any other
>>>> place where V4L2 defines an ENUM function.
>>>
>>> Forcing applications to enumerate all presets when they already know what
>>> preset they want doesn't seem like a very good solution to me.
>>
>> If the app already know, it might simply do VIDIOC_S_DV_PRESET2(index).
>> This would work for an embedded hardware. The only care to be taken is to
>> change the index number if the Kernel changes, or to be sure that, on the
>> embedded tree, that newer DV lines will be added only after the previous
>> one.
>>
>> Anyway, a broken API cannot be justified by a weak argument that not
>> needing to do an ENUM will save a few nanosseconds for some embedded
>> hardware during application initialization time.
> 
> We're talking about dozens of syscalls, not a couple of nanoseconds.

hundreds of nanoseconds? Those systemcalls are just reading a table, and,
once the right standard is selected, application can stop the loop. The
current tables have up to 18 DV formats. I doubt that it would affect 
application performance on any way. 

The old ir-keytable used to do 128.000 system calls to cleanup the IR table
and add a new one, due to an API limitation. It were capable of doing that
on fractions of a second.

Mauro.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:14                 ` Hans Verkuil
@ 2011-07-06 12:31                   ` Mauro Carvalho Chehab
  2011-07-06 12:56                     ` Hans Verkuil
  2011-07-06 19:39                   ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 12:31 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 06-07-2011 09:14, Hans Verkuil escreveu:
>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>
>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>> If
>>>>>> this were removed
>>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>>> clearer. The only
>>>>>> adjustment would be to use "index" as the preset selection key.
>>>>>> Anyway,
>>>>>> it is too late
>>>>>> for such change. We need to live with that.
>>>>>
>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>> specific timings.
>>>>> You can have 1920x1080P60 that has quite different timings from the
>>>>> CEA-861 standard
>>>>> and that may not be supported by a TV.
>>>>>
>>>>> If you are working with HDMI, then you may want to filter all
>>>>> supported
>>>>> presets to
>>>>> those of the CEA standard.
>>>>>
>>>>> That's one thing that is missing at the moment: that presets belonging
>>>>> to a certain
>>>>> standard get their own range. Since we only do CEA861 right now it
>>>>> hasn't been an
>>>>> issue, but it will.
>>>>
>>>> I prepared a long email about that, but then I realized that we're
>>>> investing our time into
>>>> something broken, at the light of all DV timing standards. So, I've
>>>> dropped it and
>>>> started from scratch.
>>>>
>>>> From what I've got, there are some hardware that can only do a limited
>>>> set
>>>> of DV timings.
>>>> If this were not the case, we could simply just use the
>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>>> and put the CEA 861 and VESA timings into some userspace library.
>>>>
>>>> In other words, the PRESET API is meant to solve the case where
>>>> hardware
>>>> only support
>>>> a limited set of frequencies, that may or may not be inside the CEA
>>>> standard.
>>>>
>>>> Let's assume we never added the current API, and discuss how it would
>>>> properly fulfill
>>>> the user needs. An API that would likely work is:
>>>>
>>>> struct v4l2_dv_enum_preset2 {
>>>> 	__u32	  index;
>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>
>>>> 	struct v4l2_fract fps;
>>>>
>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>> #define DV_PRESET_IS_CEA861		1
>>>> #define DV_PRESET_IS_DMT		2
>>>> #define DV_PRESET_IS_CVF		3
>>>> #define DV_PRESET_IS_GTF		4
>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>
>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>
>>>> 	__u32	width;		/* width in pixels */
>>>> 	__u32	height;		/* height in lines */
>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	__u32	  reserved[4];
>>>> };
>>>>
>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>> v4l2_dv_enum_preset2)
>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>
>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>> timing
>>>> information to select the desired format, and don't need to have a
>>>> switch
>>>> for
>>>> a preset macro to try to guess what the format actually means. Also,
>>>> there's no
>>>> need to touch at the API spec every time a new DV timeline is needed.
>>>>
>>>> Also, it should be noticed that, since the size of the data on the
>>>> above
>>>> definitions
>>>> are different than the old ones, _IO macros will provide a different
>>>> magic
>>>> number,
>>>> so, adding these won't break the existing API.
>>>>
>>>> So, I think we should work on this proposal, and mark the existing one
>>>> as
>>>> deprecated.
>>>
>>> This proposal makes it very hard for applications to directly select a
>>> format like 720p50 because the indices can change at any time.
>>
>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
>> check what line it wants,
> 
> It's not so easy as you think to find the right timings: you have to check
> many parameters to be certain you have the right one and not some subtle
> variation.

Or you can do a strcmp(v4l2_dv_enum_preset2.name,"my preset").

>> and do a S_DV_PRESET2, just like any other place
>> where V4L2 defines an ENUM function.
>>
>> The enum won't change during application runtime, so, they can be stored
>> if the application would need to switch to other formats latter.
>>
>>> I think
>>> this is a very desirable feature, particularly for apps running on
>>> embedded systems where the hardware is known. This was one of the design
>>> considerations at the time this API was made.
>>
>> This is a very weak argument. With just one ENUM loop, the application can
>> quickly get the right format(s), and associate them with any internal
>> namespace.
> 
> That actually isn't easy at all.

???

>>> But looking at this I wonder if we shouldn't just make a
>>> VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you get
>>> all the timing information back. No need to deprecate anything. I'm not
>>> even sure if with this change we need to modify struct
>>> v4l2_dv_enum_preset
>>> as I proposed in my RFC, although I think we should.
>>
>> Won't solve the issue: one new #define is needed for each video timing,
>> namespaces will be confusing, no support for VESA GVF/ VESA CVT timings
>> (or worse: we'll end by having thousands of formats at the end of the
>> day),
>> instead of just one ENUM ioctl, an extra ioctl will be required for each
>> returned value, etc.
> 
> Presets for GTF/CVT are useless (and I have never seen hardware that has
> such presets). In practice you have CEA and DMT presets and nothing else.
> 
> We may need to add PRESET_PRIVATE (just like we do for controls) should we
> get non-CEA/DMT formats as well. There is no point in having specific
> preset defines for those IMHO.

A PRESET_PRIVATE would mean just one DV timing, as the "preset" is the index
to get data. So, this won't fix the API.

> 
> I see very little advantage in throwing away an API that works quite well
> in practice only to add a new one that isn't much better IMO. Instead we
> can easily improve the existing API.
> 
> I *want* to be able to specify the most common CEA/DMT standards directly
> and unambiguously through presets. 

With my proposal, you can do it.

> It is very easy and nice to use in
> practice. Once you go into the realm of GTF/CVT, then the preset API is
> too limited and G/S_DV_TIMINGS need to be used, but that requires much
> more effort on the part of the application.

The usage of G/S_DV_TIMINGS require an extra care: in the past, old VGA hardware
(and/or monitors) could be damaged if it is programed with some parameters.
It used to have some viruses that damaged hardware using it. So, any driver
implementing it will need to validate the timings, to be sure that they are
on an acceptable range and won't damage the hardware in any way, or it will 
need to require some special capability (root access) to avoid that an userspace
program to damage the hardware.

The timings on a preset table should be ok, so it is safer to implement the *PRESET
ioctls than the *TIMINGS one.

> I hope others will pitch in as well with their opinions.

Agreed.

Thanks,
Mauro.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:31                   ` Mauro Carvalho Chehab
@ 2011-07-06 12:56                     ` Hans Verkuil
  2011-07-06 14:10                       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 37+ messages in thread
From: Hans Verkuil @ 2011-07-06 12:56 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

> Em 06-07-2011 09:14, Hans Verkuil escreveu:
>>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>>
>>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>>> If
>>>>>>> this were removed
>>>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>>>> clearer. The only
>>>>>>> adjustment would be to use "index" as the preset selection key.
>>>>>>> Anyway,
>>>>>>> it is too late
>>>>>>> for such change. We need to live with that.
>>>>>>
>>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>>> specific timings.
>>>>>> You can have 1920x1080P60 that has quite different timings from the
>>>>>> CEA-861 standard
>>>>>> and that may not be supported by a TV.
>>>>>>
>>>>>> If you are working with HDMI, then you may want to filter all
>>>>>> supported
>>>>>> presets to
>>>>>> those of the CEA standard.
>>>>>>
>>>>>> That's one thing that is missing at the moment: that presets
>>>>>> belonging
>>>>>> to a certain
>>>>>> standard get their own range. Since we only do CEA861 right now it
>>>>>> hasn't been an
>>>>>> issue, but it will.
>>>>>
>>>>> I prepared a long email about that, but then I realized that we're
>>>>> investing our time into
>>>>> something broken, at the light of all DV timing standards. So, I've
>>>>> dropped it and
>>>>> started from scratch.
>>>>>
>>>>> From what I've got, there are some hardware that can only do a
>>>>> limited
>>>>> set
>>>>> of DV timings.
>>>>> If this were not the case, we could simply just use the
>>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>>>> and put the CEA 861 and VESA timings into some userspace library.
>>>>>
>>>>> In other words, the PRESET API is meant to solve the case where
>>>>> hardware
>>>>> only support
>>>>> a limited set of frequencies, that may or may not be inside the CEA
>>>>> standard.
>>>>>
>>>>> Let's assume we never added the current API, and discuss how it would
>>>>> properly fulfill
>>>>> the user needs. An API that would likely work is:
>>>>>
>>>>> struct v4l2_dv_enum_preset2 {
>>>>> 	__u32	  index;
>>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>>
>>>>> 	struct v4l2_fract fps;
>>>>>
>>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>>> #define DV_PRESET_IS_CEA861		1
>>>>> #define DV_PRESET_IS_DMT		2
>>>>> #define DV_PRESET_IS_CVF		3
>>>>> #define DV_PRESET_IS_GTF		4
>>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>>
>>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>>
>>>>> 	__u32	width;		/* width in pixels */
>>>>> 	__u32	height;		/* height in lines */
>>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>>> 				 * interlaced field formats
>>>>> 				 */
>>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>>> 				 * interlaced field formats
>>>>> 				 */
>>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>>> 				 * interlaced field formats
>>>>> 				 */
>>>>> 	__u32	  reserved[4];
>>>>> };
>>>>>
>>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>>> v4l2_dv_enum_preset2)
>>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>>
>>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>>> timing
>>>>> information to select the desired format, and don't need to have a
>>>>> switch
>>>>> for
>>>>> a preset macro to try to guess what the format actually means. Also,
>>>>> there's no
>>>>> need to touch at the API spec every time a new DV timeline is needed.
>>>>>
>>>>> Also, it should be noticed that, since the size of the data on the
>>>>> above
>>>>> definitions
>>>>> are different than the old ones, _IO macros will provide a different
>>>>> magic
>>>>> number,
>>>>> so, adding these won't break the existing API.
>>>>>
>>>>> So, I think we should work on this proposal, and mark the existing
>>>>> one
>>>>> as
>>>>> deprecated.
>>>>
>>>> This proposal makes it very hard for applications to directly select a
>>>> format like 720p50 because the indices can change at any time.
>>>
>>> Why? All the application needs to do is to call
>>> VIDIOC_ENUM_DV_PRESETS2,
>>> check what line it wants,
>>
>> It's not so easy as you think to find the right timings: you have to
>> check
>> many parameters to be certain you have the right one and not some subtle
>> variation.
>
> Or you can do a strcmp(v4l2_dv_enum_preset2.name,"my preset").

Yuck. Then you also need to define the names so you know what name to
match on. Since once you allow this you can never modify the names again.

>
>>> and do a S_DV_PRESET2, just like any other place
>>> where V4L2 defines an ENUM function.
>>>
>>> The enum won't change during application runtime, so, they can be
>>> stored
>>> if the application would need to switch to other formats latter.
>>>
>>>> I think
>>>> this is a very desirable feature, particularly for apps running on
>>>> embedded systems where the hardware is known. This was one of the
>>>> design
>>>> considerations at the time this API was made.
>>>
>>> This is a very weak argument. With just one ENUM loop, the application
>>> can
>>> quickly get the right format(s), and associate them with any internal
>>> namespace.
>>
>> That actually isn't easy at all.
>
> ???
>
>>>> But looking at this I wonder if we shouldn't just make a
>>>> VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you
>>>> get
>>>> all the timing information back. No need to deprecate anything. I'm
>>>> not
>>>> even sure if with this change we need to modify struct
>>>> v4l2_dv_enum_preset
>>>> as I proposed in my RFC, although I think we should.
>>>
>>> Won't solve the issue: one new #define is needed for each video timing,
>>> namespaces will be confusing, no support for VESA GVF/ VESA CVT timings
>>> (or worse: we'll end by having thousands of formats at the end of the
>>> day),
>>> instead of just one ENUM ioctl, an extra ioctl will be required for
>>> each
>>> returned value, etc.
>>
>> Presets for GTF/CVT are useless (and I have never seen hardware that has
>> such presets). In practice you have CEA and DMT presets and nothing
>> else.
>>
>> We may need to add PRESET_PRIVATE (just like we do for controls) should
>> we
>> get non-CEA/DMT formats as well. There is no point in having specific
>> preset defines for those IMHO.
>
> A PRESET_PRIVATE would mean just one DV timing, as the "preset" is the
> index
> to get data. So, this won't fix the API.

PRESET_PRIVATE, PRESET_PRIVATE+1, +2, etc. Just as is done in other places.

>
>>
>> I see very little advantage in throwing away an API that works quite
>> well
>> in practice only to add a new one that isn't much better IMO. Instead we
>> can easily improve the existing API.
>>
>> I *want* to be able to specify the most common CEA/DMT standards
>> directly
>> and unambiguously through presets.
>
> With my proposal, you can do it.
>
>> It is very easy and nice to use in
>> practice. Once you go into the realm of GTF/CVT, then the preset API is
>> too limited and G/S_DV_TIMINGS need to be used, but that requires much
>> more effort on the part of the application.
>
> The usage of G/S_DV_TIMINGS require an extra care: in the past, old VGA
> hardware
> (and/or monitors) could be damaged if it is programed with some
> parameters.
> It used to have some viruses that damaged hardware using it. So, any
> driver
> implementing it will need to validate the timings, to be sure that they
> are
> on an acceptable range and won't damage the hardware in any way, or it
> will
> need to require some special capability (root access) to avoid that an
> userspace
> program to damage the hardware.

Drivers need to validate if necessary, of course.

> The timings on a preset table should be ok, so it is safer to implement
> the *PRESET
> ioctls than the *TIMINGS one.

You will need the TIMINGS ioctls if you want to handle GTF/CVT formats.
Those are calculated so the preset API is a poor fit.

Regards,

       Hans

>> I hope others will pitch in as well with their opinions.
>
> Agreed.
>
> Thanks,
> Mauro.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:56                     ` Hans Verkuil
@ 2011-07-06 14:10                       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 14:10 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 06-07-2011 09:56, Hans Verkuil escreveu:
>> Em 06-07-2011 09:14, Hans Verkuil escreveu:
>>>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>>>
>>>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>>>> If
>>>>>>>> this were removed
>>>>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>>>>> clearer. The only
>>>>>>>> adjustment would be to use "index" as the preset selection key.
>>>>>>>> Anyway,
>>>>>>>> it is too late
>>>>>>>> for such change. We need to live with that.
>>>>>>>
>>>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>>>> specific timings.
>>>>>>> You can have 1920x1080P60 that has quite different timings from the
>>>>>>> CEA-861 standard
>>>>>>> and that may not be supported by a TV.
>>>>>>>
>>>>>>> If you are working with HDMI, then you may want to filter all
>>>>>>> supported
>>>>>>> presets to
>>>>>>> those of the CEA standard.
>>>>>>>
>>>>>>> That's one thing that is missing at the moment: that presets
>>>>>>> belonging
>>>>>>> to a certain
>>>>>>> standard get their own range. Since we only do CEA861 right now it
>>>>>>> hasn't been an
>>>>>>> issue, but it will.
>>>>>>
>>>>>> I prepared a long email about that, but then I realized that we're
>>>>>> investing our time into
>>>>>> something broken, at the light of all DV timing standards. So, I've
>>>>>> dropped it and
>>>>>> started from scratch.
>>>>>>
>>>>>> From what I've got, there are some hardware that can only do a
>>>>>> limited
>>>>>> set
>>>>>> of DV timings.
>>>>>> If this were not the case, we could simply just use the
>>>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>>>>> and put the CEA 861 and VESA timings into some userspace library.
>>>>>>
>>>>>> In other words, the PRESET API is meant to solve the case where
>>>>>> hardware
>>>>>> only support
>>>>>> a limited set of frequencies, that may or may not be inside the CEA
>>>>>> standard.
>>>>>>
>>>>>> Let's assume we never added the current API, and discuss how it would
>>>>>> properly fulfill
>>>>>> the user needs. An API that would likely work is:
>>>>>>
>>>>>> struct v4l2_dv_enum_preset2 {
>>>>>> 	__u32	  index;
>>>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>>>
>>>>>> 	struct v4l2_fract fps;
>>>>>>
>>>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>>>> #define DV_PRESET_IS_CEA861		1
>>>>>> #define DV_PRESET_IS_DMT		2
>>>>>> #define DV_PRESET_IS_CVF		3
>>>>>> #define DV_PRESET_IS_GTF		4
>>>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>>>
>>>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>>>
>>>>>> 	__u32	width;		/* width in pixels */
>>>>>> 	__u32	height;		/* height in lines */
>>>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	__u32	  reserved[4];
>>>>>> };
>>>>>>
>>>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>>>> v4l2_dv_enum_preset2)
>>>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>>>
>>>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>>>> timing
>>>>>> information to select the desired format, and don't need to have a
>>>>>> switch
>>>>>> for
>>>>>> a preset macro to try to guess what the format actually means. Also,
>>>>>> there's no
>>>>>> need to touch at the API spec every time a new DV timeline is needed.
>>>>>>
>>>>>> Also, it should be noticed that, since the size of the data on the
>>>>>> above
>>>>>> definitions
>>>>>> are different than the old ones, _IO macros will provide a different
>>>>>> magic
>>>>>> number,
>>>>>> so, adding these won't break the existing API.
>>>>>>
>>>>>> So, I think we should work on this proposal, and mark the existing
>>>>>> one
>>>>>> as
>>>>>> deprecated.
>>>>>
>>>>> This proposal makes it very hard for applications to directly select a
>>>>> format like 720p50 because the indices can change at any time.
>>>>
>>>> Why? All the application needs to do is to call
>>>> VIDIOC_ENUM_DV_PRESETS2,
>>>> check what line it wants,
>>>
>>> It's not so easy as you think to find the right timings: you have to
>>> check
>>> many parameters to be certain you have the right one and not some subtle
>>> variation.
>>
>> Or you can do a strcmp(v4l2_dv_enum_preset2.name,"my preset").
> 
> Yuck. Then you also need to define the names so you know what name to
> match on. Since once you allow this you can never modify the names again.

Once you add names to the API, the above is allowed, as the name is part of
the API. So, names can't be changed, as changing them can break things.

The alternative is to remove the names from the new API.

>>>> and do a S_DV_PRESET2, just like any other place
>>>> where V4L2 defines an ENUM function.
>>>>
>>>> The enum won't change during application runtime, so, they can be
>>>> stored
>>>> if the application would need to switch to other formats latter.
>>>>
>>>>> I think
>>>>> this is a very desirable feature, particularly for apps running on
>>>>> embedded systems where the hardware is known. This was one of the
>>>>> design
>>>>> considerations at the time this API was made.
>>>>
>>>> This is a very weak argument. With just one ENUM loop, the application
>>>> can
>>>> quickly get the right format(s), and associate them with any internal
>>>> namespace.
>>>
>>> That actually isn't easy at all.
>>
>> ???
>>
>>>>> But looking at this I wonder if we shouldn't just make a
>>>>> VIDIOC_G_PRESET_TIMINGS function? You give it the preset ID and you
>>>>> get
>>>>> all the timing information back. No need to deprecate anything. I'm
>>>>> not
>>>>> even sure if with this change we need to modify struct
>>>>> v4l2_dv_enum_preset
>>>>> as I proposed in my RFC, although I think we should.
>>>>
>>>> Won't solve the issue: one new #define is needed for each video timing,
>>>> namespaces will be confusing, no support for VESA GVF/ VESA CVT timings
>>>> (or worse: we'll end by having thousands of formats at the end of the
>>>> day),
>>>> instead of just one ENUM ioctl, an extra ioctl will be required for
>>>> each
>>>> returned value, etc.
>>>
>>> Presets for GTF/CVT are useless (and I have never seen hardware that has
>>> such presets). In practice you have CEA and DMT presets and nothing
>>> else.
>>>
>>> We may need to add PRESET_PRIVATE (just like we do for controls) should
>>> we
>>> get non-CEA/DMT formats as well. There is no point in having specific
>>> preset defines for those IMHO.
>>
>> A PRESET_PRIVATE would mean just one DV timing, as the "preset" is the
>> index
>> to get data. So, this won't fix the API.
> 
> PRESET_PRIVATE, PRESET_PRIVATE+1, +2, etc. Just as is done in other places.

Yuck. This is very ugly. NACK.

>>> I see very little advantage in throwing away an API that works quite
>>> well
>>> in practice only to add a new one that isn't much better IMO. Instead we
>>> can easily improve the existing API.
>>>
>>> I *want* to be able to specify the most common CEA/DMT standards
>>> directly
>>> and unambiguously through presets.
>>
>> With my proposal, you can do it.
>>
>>> It is very easy and nice to use in
>>> practice. Once you go into the realm of GTF/CVT, then the preset API is
>>> too limited and G/S_DV_TIMINGS need to be used, but that requires much
>>> more effort on the part of the application.
>>
>> The usage of G/S_DV_TIMINGS require an extra care: in the past, old VGA
>> hardware
>> (and/or monitors) could be damaged if it is programed with some
>> parameters.
>> It used to have some viruses that damaged hardware using it. So, any
>> driver
>> implementing it will need to validate the timings, to be sure that they
>> are
>> on an acceptable range and won't damage the hardware in any way, or it
>> will
>> need to require some special capability (root access) to avoid that an
>> userspace
>> program to damage the hardware.
> 
> Drivers need to validate if necessary, of course.
> 
>> The timings on a preset table should be ok, so it is safer to implement
>> the *PRESET
>> ioctls than the *TIMINGS one.
> 
> You will need the TIMINGS ioctls if you want to handle GTF/CVT formats.
> Those are calculated so the preset API is a poor fit.

If you want full support for it, yes. But, if all it is needed are the
common resolutions/fps (1024x768p60, 1920x1080p50, ...), GTF/CVT format
presets may fit well.

Regards,
Mauro.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 12:14                 ` Hans Verkuil
  2011-07-06 12:31                   ` Mauro Carvalho Chehab
@ 2011-07-06 19:39                   ` Mauro Carvalho Chehab
  2011-07-07 11:33                     ` Hans Verkuil
  1 sibling, 1 reply; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-06 19:39 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 06-07-2011 09:14, Hans Verkuil escreveu:
>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>
>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>> If
>>>>>> this were removed
>>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>>> clearer. The only
>>>>>> adjustment would be to use "index" as the preset selection key.
>>>>>> Anyway,
>>>>>> it is too late
>>>>>> for such change. We need to live with that.
>>>>>
>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>> specific timings.
>>>>> You can have 1920x1080P60 that has quite different timings from the
>>>>> CEA-861 standard
>>>>> and that may not be supported by a TV.
>>>>>
>>>>> If you are working with HDMI, then you may want to filter all
>>>>> supported
>>>>> presets to
>>>>> those of the CEA standard.
>>>>>
>>>>> That's one thing that is missing at the moment: that presets belonging
>>>>> to a certain
>>>>> standard get their own range. Since we only do CEA861 right now it
>>>>> hasn't been an
>>>>> issue, but it will.
>>>>
>>>> I prepared a long email about that, but then I realized that we're
>>>> investing our time into
>>>> something broken, at the light of all DV timing standards. So, I've
>>>> dropped it and
>>>> started from scratch.
>>>>
>>>> From what I've got, there are some hardware that can only do a limited
>>>> set
>>>> of DV timings.
>>>> If this were not the case, we could simply just use the
>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>>> and put the CEA 861 and VESA timings into some userspace library.
>>>>
>>>> In other words, the PRESET API is meant to solve the case where
>>>> hardware
>>>> only support
>>>> a limited set of frequencies, that may or may not be inside the CEA
>>>> standard.
>>>>
>>>> Let's assume we never added the current API, and discuss how it would
>>>> properly fulfill
>>>> the user needs. An API that would likely work is:
>>>>
>>>> struct v4l2_dv_enum_preset2 {
>>>> 	__u32	  index;
>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>
>>>> 	struct v4l2_fract fps;
>>>>
>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>> #define DV_PRESET_IS_CEA861		1
>>>> #define DV_PRESET_IS_DMT		2
>>>> #define DV_PRESET_IS_CVF		3
>>>> #define DV_PRESET_IS_GTF		4
>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>
>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>
>>>> 	__u32	width;		/* width in pixels */
>>>> 	__u32	height;		/* height in lines */
>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>> 				 * interlaced field formats
>>>> 				 */
>>>> 	__u32	  reserved[4];
>>>> };
>>>>
>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>> v4l2_dv_enum_preset2)
>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>
>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>> timing
>>>> information to select the desired format, and don't need to have a
>>>> switch
>>>> for
>>>> a preset macro to try to guess what the format actually means. Also,
>>>> there's no
>>>> need to touch at the API spec every time a new DV timeline is needed.
>>>>
>>>> Also, it should be noticed that, since the size of the data on the
>>>> above
>>>> definitions
>>>> are different than the old ones, _IO macros will provide a different
>>>> magic
>>>> number,
>>>> so, adding these won't break the existing API.
>>>>
>>>> So, I think we should work on this proposal, and mark the existing one
>>>> as
>>>> deprecated.
>>>
>>> This proposal makes it very hard for applications to directly select a
>>> format like 720p50 because the indices can change at any time.
>>
>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
>> check what line it wants,
> 
> It's not so easy as you think to find the right timings: you have to check
> many parameters to be certain you have the right one and not some subtle
> variation.
> 
>> and do a S_DV_PRESET2, just like any other place
>> where V4L2 defines an ENUM function.
>>
>> The enum won't change during application runtime, so, they can be stored
>> if the application would need to switch to other formats latter.
>>
>>> I think
>>> this is a very desirable feature, particularly for apps running on
>>> embedded systems where the hardware is known. This was one of the design
>>> considerations at the time this API was made.
>>
>> This is a very weak argument. With just one ENUM loop, the application can
>> quickly get the right format(s), and associate them with any internal
>> namespace.
> 
> That actually isn't easy at all.

For the trivial case where the application just wants one of the CEA861 standard
(or VESA DMT), the check is trivial.


The speed of the test can even be improved if the order at the struct would
be changed to be:

struct v4l2_dv_enum_preset2 {
	__u32	index;
	__u32	flags;

	struct v4l2_fract fps;
 	__u32	width;		/* width in pixels */
 	__u32	height;		/* height in lines */

	...
}

The dv preset seek routine at the application can then be coded as:

struct seek_preset {		/* Need to follow the same order/arguments as v4l2_dv_enum_preset2 */
	struct v4l2_fract fps;
 	__u32	width;
 	__u32	height;
};

struct myapp_preset {
	__u32 flags;

	struct seek_preset preset;
};

struct  myapp_preset cea861_vic16  = {
	.flags = DV_PRESET_IS_PROGRESSIVE | DV_PRESET_IS_CEA861,
	.width = 1920,
	.height = 1080,
};

int return_dv_preset_index(fp, struct  myapp_preset *needed)
{
	int found = -1;
	struct v4l2_dv_enum_preset2 preset;
	do {
		rc = ioctl(fp, VIDIOC_ENUM_DV_PRESETS, &preset);
		if (rc == -1)
			break;
		if ((preset.flags & needed->flags) != needed->flags)
			continue;
		if (!memcmp(&preset.fps, &needed->preset)) {
			found = preset->index;
			break;
		}	
	} while (!rc && found < 0);
}

void main(void) {
...
	index = return_dv_preset_index(fp, cea861_vic16);
...
}


Cheers,
Mauro

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-06 19:39                   ` Mauro Carvalho Chehab
@ 2011-07-07 11:33                     ` Hans Verkuil
  2011-07-07 13:52                       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 37+ messages in thread
From: Hans Verkuil @ 2011-07-07 11:33 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

On Wednesday, July 06, 2011 21:39:46 Mauro Carvalho Chehab wrote:
> Em 06-07-2011 09:14, Hans Verkuil escreveu:
> >> Em 06-07-2011 08:31, Hans Verkuil escreveu:
> >>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
> >>>>
> >>>>>> I failed to see what information is provided by the "presets" name.
> >>>>>> If
> >>>>>> this were removed
> >>>>>> from the ioctl, and fps would be added instead, the API would be
> >>>>>> clearer. The only
> >>>>>> adjustment would be to use "index" as the preset selection key.
> >>>>>> Anyway,
> >>>>>> it is too late
> >>>>>> for such change. We need to live with that.
> >>>>>
> >>>>> Adding the fps solves nothing. Because that still does not give you
> >>>>> specific timings.
> >>>>> You can have 1920x1080P60 that has quite different timings from the
> >>>>> CEA-861 standard
> >>>>> and that may not be supported by a TV.
> >>>>>
> >>>>> If you are working with HDMI, then you may want to filter all
> >>>>> supported
> >>>>> presets to
> >>>>> those of the CEA standard.
> >>>>>
> >>>>> That's one thing that is missing at the moment: that presets belonging
> >>>>> to a certain
> >>>>> standard get their own range. Since we only do CEA861 right now it
> >>>>> hasn't been an
> >>>>> issue, but it will.
> >>>>
> >>>> I prepared a long email about that, but then I realized that we're
> >>>> investing our time into
> >>>> something broken, at the light of all DV timing standards. So, I've
> >>>> dropped it and
> >>>> started from scratch.
> >>>>
> >>>> From what I've got, there are some hardware that can only do a limited
> >>>> set
> >>>> of DV timings.
> >>>> If this were not the case, we could simply just use the
> >>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
> >>>> and put the CEA 861 and VESA timings into some userspace library.
> >>>>
> >>>> In other words, the PRESET API is meant to solve the case where
> >>>> hardware
> >>>> only support
> >>>> a limited set of frequencies, that may or may not be inside the CEA
> >>>> standard.
> >>>>
> >>>> Let's assume we never added the current API, and discuss how it would
> >>>> properly fulfill
> >>>> the user needs. An API that would likely work is:
> >>>>
> >>>> struct v4l2_dv_enum_preset2 {
> >>>> 	__u32	  index;
> >>>> 	__u8	  name[32]; /* Name of the preset timing */
> >>>>
> >>>> 	struct v4l2_fract fps;
> >>>>
> >>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
> >>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
> >>>> #define DV_PRESET_IS_CEA861		1
> >>>> #define DV_PRESET_IS_DMT		2
> >>>> #define DV_PRESET_IS_CVF		3
> >>>> #define DV_PRESET_IS_GTF		4
> >>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
> >>>>
> >>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
> >>>>
> >>>> 	__u32	width;		/* width in pixels */
> >>>> 	__u32	height;		/* height in lines */
> >>>> 	__u32	polarities;	/* Positive or negative polarity */
> >>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
> >>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
> >>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
> >>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
> >>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
> >>>> 	__u32	vsync;		/* Vertical Sync length in lines */
> >>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
> >>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
> >>>> 				 * interlaced field formats
> >>>> 				 */
> >>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
> >>>> 				 * interlaced field formats
> >>>> 				 */
> >>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
> >>>> 				 * interlaced field formats
> >>>> 				 */
> >>>> 	__u32	  reserved[4];
> >>>> };
> >>>>
> >>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
> >>>> v4l2_dv_enum_preset2)
> >>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
> >>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
> >>>>
> >>>> Such preset API seems to work for all cases. Userspace can use any DV
> >>>> timing
> >>>> information to select the desired format, and don't need to have a
> >>>> switch
> >>>> for
> >>>> a preset macro to try to guess what the format actually means. Also,
> >>>> there's no
> >>>> need to touch at the API spec every time a new DV timeline is needed.
> >>>>
> >>>> Also, it should be noticed that, since the size of the data on the
> >>>> above
> >>>> definitions
> >>>> are different than the old ones, _IO macros will provide a different
> >>>> magic
> >>>> number,
> >>>> so, adding these won't break the existing API.
> >>>>
> >>>> So, I think we should work on this proposal, and mark the existing one
> >>>> as
> >>>> deprecated.
> >>>
> >>> This proposal makes it very hard for applications to directly select a
> >>> format like 720p50 because the indices can change at any time.
> >>
> >> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
> >> check what line it wants,
> > 
> > It's not so easy as you think to find the right timings: you have to check
> > many parameters to be certain you have the right one and not some subtle
> > variation.
> > 
> >> and do a S_DV_PRESET2, just like any other place
> >> where V4L2 defines an ENUM function.
> >>
> >> The enum won't change during application runtime, so, they can be stored
> >> if the application would need to switch to other formats latter.
> >>
> >>> I think
> >>> this is a very desirable feature, particularly for apps running on
> >>> embedded systems where the hardware is known. This was one of the design
> >>> considerations at the time this API was made.
> >>
> >> This is a very weak argument. With just one ENUM loop, the application can
> >> quickly get the right format(s), and associate them with any internal
> >> namespace.
> > 
> > That actually isn't easy at all.
> 
> For the trivial case where the application just wants one of the CEA861 standard
> (or VESA DMT), the check is trivial.
> 
> 
> The speed of the test can even be improved if the order at the struct would
> be changed to be:
> 
> struct v4l2_dv_enum_preset2 {
> 	__u32	index;
> 	__u32	flags;
> 
> 	struct v4l2_fract fps;
>  	__u32	width;		/* width in pixels */
>  	__u32	height;		/* height in lines */
> 
> 	...
> }
> 
> The dv preset seek routine at the application can then be coded as:
> 
> struct seek_preset {		/* Need to follow the same order/arguments as v4l2_dv_enum_preset2 */
> 	struct v4l2_fract fps;
>  	__u32	width;
>  	__u32	height;
> };
> 
> struct myapp_preset {
> 	__u32 flags;
> 
> 	struct seek_preset preset;
> };
> 
> struct  myapp_preset cea861_vic16  = {
> 	.flags = DV_PRESET_IS_PROGRESSIVE | DV_PRESET_IS_CEA861,
> 	.width = 1920,
> 	.height = 1080,
> };
> 
> int return_dv_preset_index(fp, struct  myapp_preset *needed)
> {
> 	int found = -1;
> 	struct v4l2_dv_enum_preset2 preset;
> 	do {
> 		rc = ioctl(fp, VIDIOC_ENUM_DV_PRESETS, &preset);
> 		if (rc == -1)
> 			break;
> 		if ((preset.flags & needed->flags) != needed->flags)
> 			continue;
> 		if (!memcmp(&preset.fps, &needed->preset)) {
> 			found = preset->index;
> 			break;
> 		}	
> 	} while (!rc && found < 0);
> }
> 
> void main(void) {
> ...
> 	index = return_dv_preset_index(fp, cea861_vic16);
> ...
> }

And the current equivalent is:

	struct v4l_dv_preset preset = { V4L2_DV_1080P60 };
	ioctl(f, VIDIOC_S_DV_PRESET, &preset);

You want a whole new API that in my view makes things only more complicated and
misses existing functionality (such as the one above).

Whereas with a few tweaks and possibly a new VIDIOC_G_PRESET_TIMINGS ioctl you
can offer the same functionality with the existing API.

So, once again my proposal:

ENUM_DV_PRESETS is extended with a flags field and a fps v4l2_fract (or frame_period,
whatever works best). Flags give you progressive vs interlaced, and I've no problem
adding things like IS_CEA861 or similar flags to that.

The current set of presets remain in use (but get renamed with the old ones as aliases)
for CEA861 and (in the near future) VESA DMT timings. Note that all the hardware I
know that has predefined timings does so only for those two standards. Makes sense
too: only the consumer electronic standards for SDTV/HDTV and the VGA-like PC monitor
standards are typical standards.

For presets not related to those standards the easiest method I see is just to assign
a preset like (0x80000000 | index).

We may need to add a VIDIOC_G_PRESET_TIMINGS, but I am not certain we really need
that. ENUM_DV_PRESETS may give sufficient information already.

Based on my experience with GTF/CVT formats I strongly suspect that drivers will
need to implement a VIDIOC_QUERY_DV_TIMINGS ioctl and let a userspace library detect
the GTF/CVT standard. This is surprisingly complex (mostly due to extremely shoddy
standards). For GTF/CVT output you want to use VIDIOC_S_DV_TIMINGS anyway. The reason
there is no GTF/CVT support yet is simply because I don't want to make proposals
unless I actually implemented it and worked with it for some time to see what works
best.

Everything you can do with your proposal you can do with mine, and mine doesn't
deprecate anything.

BTW, in the case of HD-SDI transmitters/receivers the CEA-861 standard does not
apply, strictly speaking. That standard is covered by SMPTE 292M. It does support
most of the usual SDTV/HDTV formats as are defined in CEA-861, except that things
like front/back porch etc. do not apply to this serial interface. The idea behind
the presets is that it defines industry standard resolution/framerate combinations,
but the standards behind those differ per interface type. You don't really care
about those in an application. The user (or developer) just wants to select 1080P60 or
WUXGA. I am frankly not certain anymore if we want to have the standard as part of
the macro name. Something like V4L2_DV_HDTV_1920X1080P60 might be more appropriate,
with comments next to it referring to the relevant standards depending on the
physical interface type.

And instead of using flags to denote the used standard, it might be better to
reserve a u16 for the standard.

History has shown that video formats stay around for a looong time, but the standards
describing them evolve continuously.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-07 11:33                     ` Hans Verkuil
@ 2011-07-07 13:52                       ` Mauro Carvalho Chehab
  2011-07-07 14:58                         ` Hans Verkuil
  2011-07-07 17:52                         ` Tomasz Stanislawski
  0 siblings, 2 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-07 13:52 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 07-07-2011 08:33, Hans Verkuil escreveu:
> On Wednesday, July 06, 2011 21:39:46 Mauro Carvalho Chehab wrote:
>> Em 06-07-2011 09:14, Hans Verkuil escreveu:
>>>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>>>
>>>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>>>> If
>>>>>>>> this were removed
>>>>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>>>>> clearer. The only
>>>>>>>> adjustment would be to use "index" as the preset selection key.
>>>>>>>> Anyway,
>>>>>>>> it is too late
>>>>>>>> for such change. We need to live with that.
>>>>>>>
>>>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>>>> specific timings.
>>>>>>> You can have 1920x1080P60 that has quite different timings from the
>>>>>>> CEA-861 standard
>>>>>>> and that may not be supported by a TV.
>>>>>>>
>>>>>>> If you are working with HDMI, then you may want to filter all
>>>>>>> supported
>>>>>>> presets to
>>>>>>> those of the CEA standard.
>>>>>>>
>>>>>>> That's one thing that is missing at the moment: that presets belonging
>>>>>>> to a certain
>>>>>>> standard get their own range. Since we only do CEA861 right now it
>>>>>>> hasn't been an
>>>>>>> issue, but it will.
>>>>>>
>>>>>> I prepared a long email about that, but then I realized that we're
>>>>>> investing our time into
>>>>>> something broken, at the light of all DV timing standards. So, I've
>>>>>> dropped it and
>>>>>> started from scratch.
>>>>>>
>>>>>> From what I've got, there are some hardware that can only do a limited
>>>>>> set
>>>>>> of DV timings.
>>>>>> If this were not the case, we could simply just use the
>>>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>>>>> and put the CEA 861 and VESA timings into some userspace library.
>>>>>>
>>>>>> In other words, the PRESET API is meant to solve the case where
>>>>>> hardware
>>>>>> only support
>>>>>> a limited set of frequencies, that may or may not be inside the CEA
>>>>>> standard.
>>>>>>
>>>>>> Let's assume we never added the current API, and discuss how it would
>>>>>> properly fulfill
>>>>>> the user needs. An API that would likely work is:
>>>>>>
>>>>>> struct v4l2_dv_enum_preset2 {
>>>>>> 	__u32	  index;
>>>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>>>
>>>>>> 	struct v4l2_fract fps;
>>>>>>
>>>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>>>> #define DV_PRESET_IS_CEA861		1
>>>>>> #define DV_PRESET_IS_DMT		2
>>>>>> #define DV_PRESET_IS_CVF		3
>>>>>> #define DV_PRESET_IS_GTF		4
>>>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>>>
>>>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>>>
>>>>>> 	__u32	width;		/* width in pixels */
>>>>>> 	__u32	height;		/* height in lines */
>>>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>>>> 				 * interlaced field formats
>>>>>> 				 */
>>>>>> 	__u32	  reserved[4];
>>>>>> };
>>>>>>
>>>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>>>> v4l2_dv_enum_preset2)
>>>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>>>
>>>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>>>> timing
>>>>>> information to select the desired format, and don't need to have a
>>>>>> switch
>>>>>> for
>>>>>> a preset macro to try to guess what the format actually means. Also,
>>>>>> there's no
>>>>>> need to touch at the API spec every time a new DV timeline is needed.
>>>>>>
>>>>>> Also, it should be noticed that, since the size of the data on the
>>>>>> above
>>>>>> definitions
>>>>>> are different than the old ones, _IO macros will provide a different
>>>>>> magic
>>>>>> number,
>>>>>> so, adding these won't break the existing API.
>>>>>>
>>>>>> So, I think we should work on this proposal, and mark the existing one
>>>>>> as
>>>>>> deprecated.
>>>>>
>>>>> This proposal makes it very hard for applications to directly select a
>>>>> format like 720p50 because the indices can change at any time.
>>>>
>>>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
>>>> check what line it wants,
>>>
>>> It's not so easy as you think to find the right timings: you have to check
>>> many parameters to be certain you have the right one and not some subtle
>>> variation.
>>>
>>>> and do a S_DV_PRESET2, just like any other place
>>>> where V4L2 defines an ENUM function.
>>>>
>>>> The enum won't change during application runtime, so, they can be stored
>>>> if the application would need to switch to other formats latter.
>>>>
>>>>> I think
>>>>> this is a very desirable feature, particularly for apps running on
>>>>> embedded systems where the hardware is known. This was one of the design
>>>>> considerations at the time this API was made.
>>>>
>>>> This is a very weak argument. With just one ENUM loop, the application can
>>>> quickly get the right format(s), and associate them with any internal
>>>> namespace.
>>>
>>> That actually isn't easy at all.
>>
>> For the trivial case where the application just wants one of the CEA861 standard
>> (or VESA DMT), the check is trivial.
>>
>>
>> The speed of the test can even be improved if the order at the struct would
>> be changed to be:
>>
>> struct v4l2_dv_enum_preset2 {
>> 	__u32	index;
>> 	__u32	flags;
>>
>> 	struct v4l2_fract fps;
>>  	__u32	width;		/* width in pixels */
>>  	__u32	height;		/* height in lines */
>>
>> 	...
>> }
>>
>> The dv preset seek routine at the application can then be coded as:
>>
>> struct seek_preset {		/* Need to follow the same order/arguments as v4l2_dv_enum_preset2 */
>> 	struct v4l2_fract fps;
>>  	__u32	width;
>>  	__u32	height;
>> };
>>
>> struct myapp_preset {
>> 	__u32 flags;
>>
>> 	struct seek_preset preset;
>> };
>>
>> struct  myapp_preset cea861_vic16  = {
>> 	.flags = DV_PRESET_IS_PROGRESSIVE | DV_PRESET_IS_CEA861,
>> 	.width = 1920,
>> 	.height = 1080,
>> };
>>
>> int return_dv_preset_index(fp, struct  myapp_preset *needed)
>> {
>> 	int found = -1;
>> 	struct v4l2_dv_enum_preset2 preset;
>> 	do {
>> 		rc = ioctl(fp, VIDIOC_ENUM_DV_PRESETS, &preset);
>> 		if (rc == -1)
>> 			break;
>> 		if ((preset.flags & needed->flags) != needed->flags)
>> 			continue;
>> 		if (!memcmp(&preset.fps, &needed->preset)) {
>> 			found = preset->index;
>> 			break;
>> 		}	
>> 	} while (!rc && found < 0);
>> }
>>
>> void main(void) {
>> ...
>> 	index = return_dv_preset_index(fp, cea861_vic16);
>> ...
>> }
> 
> And the current equivalent is:
> 
> 	struct v4l_dv_preset preset = { V4L2_DV_1080P60 };
> 	ioctl(f, VIDIOC_S_DV_PRESET, &preset);

Yes, except for the fact that:
	- API spec needs addition for every new preset that we standardize;
	- It doesn't support a vendor-specific preset, as there's no way to
	  discover what are the timing constants for the preset;
	- Namespacing is broken.

> You want a whole new API that in my view makes things only more complicated and
> misses existing functionality (such as the one above).

I prefer to fix the API, if it is possible/doable on a non-messy way. Yet, as this
API is currently used only by two drivers (DaVinci and tvp7002), it is better to fix
it sooner than later, to avoid more efforts on fixing it.
 
> Whereas with a few tweaks and possibly a new VIDIOC_G_PRESET_TIMINGS ioctl you
> can offer the same functionality with the existing API.

You're proposing a new "enum" preset timings that would present the missing info
that VIDIOC_S_DV_PRESET doesn't present, except that an application will need to call
2 ioctl's in order to enumerate the presets, instead of one.

> So, once again my proposal:
> 
> ENUM_DV_PRESETS is extended with a flags field and a fps v4l2_fract (or frame_period,
> whatever works best). Flags give you progressive vs interlaced, and I've no problem
> adding things like IS_CEA861 or similar flags to that.
> 
> The current set of presets remain in use (but get renamed with the old ones as aliases)
> for CEA861 and (in the near future) VESA DMT timings. 


> Note that all the hardware I
> know that has predefined timings does so only for those two standards. Makes sense
> too: only the consumer electronic standards for SDTV/HDTV and the VGA-like PC monitor
> standards are typical standards.

We need a further investigation about that. What are the predefined timings defined for Samgung
hardware?

Also, one possible implementation for output devices would be to use EDID to retrieve the
timings acceptable by the monitor/TV and compare to its internal capabilities. This is
probably the only way to avoid requiring CAP_SYS_ADMIN for the DV calls, as a bad timing
may damage the monitor and/or the V4L device.

If a vendor decides to implement something like that (either in firmware or on Kernel), then 
the list of presets will likely have a mix with all standards.

> For presets not related to those standards the easiest method I see is just to assign
> a preset like (0x80000000 | index).

I've thinked about that already. Yeah, this would fix part of the problem, allowing
the implementation of vendor-specific timings and the support for other standards not
covered yet. There are, however, some issues:
	1) the API will be messier;
	2) Imagine that a new timing were added as a vendor-specific timing. Later,
that standard got recognized by some forum and were added at some standard. In that
case, the vendor cannot simply change the preset index, as it will break the API.
Also, duplicating the information is not a good idea. With the preset standards as
flags, when this happens, all the driver needs is to add a new flag, without breaking
the API.

> We may need to add a VIDIOC_G_PRESET_TIMINGS, but I am not certain we really need
> that. ENUM_DV_PRESETS may give sufficient information already.

This will only work if there aren't two timings with the same fps/resolution, including
on the vendor-specific timings. Let's suppose that there are two non-DMT, non-CEA
standars, from two different vendors, that have different timings. With the current
API, there's no way to differentiate them.

> Based on my experience with GTF/CVT formats I strongly suspect that drivers will
> need to implement a VIDIOC_QUERY_DV_TIMINGS ioctl and let a userspace library detect
> the GTF/CVT standard. This is surprisingly complex (mostly due to extremely shoddy
> standards). 

Maybe, but I bet that there are a few GTF/CVT standards that are implemented on
a large amount of TV/monitors. It may make sense to have those added as presets.
I'd love to get some feedback from other developers about that. Samsung?

The issue with S_DV_TIMINGS is that we likely need to request for CAP_SYS_ADMIN,
as a bad timing may damage the hardware.

Currently, there's not such requirement for DaVinci/tvp7002, nor v4l2-ioctl enforces
that, but this needs a fix.

> For GTF/CVT output you want to use VIDIOC_S_DV_TIMINGS anyway.

True.

> The reason
> there is no GTF/CVT support yet is simply because I don't want to make proposals
> unless I actually implemented it and worked with it for some time to see what works
> best.
> 
> Everything you can do with your proposal you can do with mine, and mine doesn't
> deprecate anything.

See above.

> BTW, in the case of HD-SDI transmitters/receivers the CEA-861 standard does not
> apply, strictly speaking. That standard is covered by SMPTE 292M. It does support
> most of the usual SDTV/HDTV formats as are defined in CEA-861, except that things
> like front/back porch etc. do not apply to this serial interface. The idea behind
> the presets is that it defines industry standard resolution/framerate combinations,
> but the standards behind those differ per interface type. You don't really care
> about those in an application. The user (or developer) just wants to select 1080P60 or
> WUXGA. 

Ok.

> I am frankly not certain anymore if we want to have the standard as part of
> the macro name. Something like V4L2_DV_HDTV_1920X1080P60 might be more appropriate,
> with comments next to it referring to the relevant standards depending on the
> physical interface type.

That's the problem with the namespace. I think that that's basically the reason why
Xorg never created a macro naming for the resolutions. Whatever namespace we choose,
we'll have troubles. I bet that, with your proposal, we'll end by having conflicts
between two different standards that implement the same resolution/fps/"progressiveness".

> And instead of using flags to denote the used standard, it might be better to
> reserve a u16 for the standard.

It seems that a standards bitmask may work better, as, eventually, the same timing may
be defined by more than one standard.

> History has shown that video formats stay around for a looong time, but the standards
> describing them evolve continuously.

True. We might end to have some timings that are different on a new standard revision,
in order to fix some issue. That's why I think we need to expose all the timings at
the DV enum ioctl. This gives more flexibility to the application to reject an specific
standard if needed for whatever reason.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-07 13:52                       ` Mauro Carvalho Chehab
@ 2011-07-07 14:58                         ` Hans Verkuil
  2011-07-07 16:18                           ` Mauro Carvalho Chehab
  2011-07-07 17:52                         ` Tomasz Stanislawski
  1 sibling, 1 reply; 37+ messages in thread
From: Hans Verkuil @ 2011-07-07 14:58 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

On Thursday, July 07, 2011 15:52:53 Mauro Carvalho Chehab wrote:
> Em 07-07-2011 08:33, Hans Verkuil escreveu:
> > On Wednesday, July 06, 2011 21:39:46 Mauro Carvalho Chehab wrote:
> >> Em 06-07-2011 09:14, Hans Verkuil escreveu:
> >>>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
> >>>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
> >>>>>>
> >>>>>>>> I failed to see what information is provided by the "presets" name.
> >>>>>>>> If
> >>>>>>>> this were removed
> >>>>>>>> from the ioctl, and fps would be added instead, the API would be
> >>>>>>>> clearer. The only
> >>>>>>>> adjustment would be to use "index" as the preset selection key.
> >>>>>>>> Anyway,
> >>>>>>>> it is too late
> >>>>>>>> for such change. We need to live with that.
> >>>>>>>
> >>>>>>> Adding the fps solves nothing. Because that still does not give you
> >>>>>>> specific timings.
> >>>>>>> You can have 1920x1080P60 that has quite different timings from the
> >>>>>>> CEA-861 standard
> >>>>>>> and that may not be supported by a TV.
> >>>>>>>
> >>>>>>> If you are working with HDMI, then you may want to filter all
> >>>>>>> supported
> >>>>>>> presets to
> >>>>>>> those of the CEA standard.
> >>>>>>>
> >>>>>>> That's one thing that is missing at the moment: that presets belonging
> >>>>>>> to a certain
> >>>>>>> standard get their own range. Since we only do CEA861 right now it
> >>>>>>> hasn't been an
> >>>>>>> issue, but it will.
> >>>>>>
> >>>>>> I prepared a long email about that, but then I realized that we're
> >>>>>> investing our time into
> >>>>>> something broken, at the light of all DV timing standards. So, I've
> >>>>>> dropped it and
> >>>>>> started from scratch.
> >>>>>>
> >>>>>> From what I've got, there are some hardware that can only do a limited
> >>>>>> set
> >>>>>> of DV timings.
> >>>>>> If this were not the case, we could simply just use the
> >>>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
> >>>>>> and put the CEA 861 and VESA timings into some userspace library.
> >>>>>>
> >>>>>> In other words, the PRESET API is meant to solve the case where
> >>>>>> hardware
> >>>>>> only support
> >>>>>> a limited set of frequencies, that may or may not be inside the CEA
> >>>>>> standard.
> >>>>>>
> >>>>>> Let's assume we never added the current API, and discuss how it would
> >>>>>> properly fulfill
> >>>>>> the user needs. An API that would likely work is:
> >>>>>>
> >>>>>> struct v4l2_dv_enum_preset2 {
> >>>>>> 	__u32	  index;
> >>>>>> 	__u8	  name[32]; /* Name of the preset timing */
> >>>>>>
> >>>>>> 	struct v4l2_fract fps;
> >>>>>>
> >>>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
> >>>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
> >>>>>> #define DV_PRESET_IS_CEA861		1
> >>>>>> #define DV_PRESET_IS_DMT		2
> >>>>>> #define DV_PRESET_IS_CVF		3
> >>>>>> #define DV_PRESET_IS_GTF		4
> >>>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
> >>>>>>
> >>>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
> >>>>>>
> >>>>>> 	__u32	width;		/* width in pixels */
> >>>>>> 	__u32	height;		/* height in lines */
> >>>>>> 	__u32	polarities;	/* Positive or negative polarity */
> >>>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
> >>>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
> >>>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
> >>>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
> >>>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
> >>>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
> >>>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
> >>>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
> >>>>>> 				 * interlaced field formats
> >>>>>> 				 */
> >>>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
> >>>>>> 				 * interlaced field formats
> >>>>>> 				 */
> >>>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
> >>>>>> 				 * interlaced field formats
> >>>>>> 				 */
> >>>>>> 	__u32	  reserved[4];
> >>>>>> };
> >>>>>>
> >>>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
> >>>>>> v4l2_dv_enum_preset2)
> >>>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
> >>>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
> >>>>>>
> >>>>>> Such preset API seems to work for all cases. Userspace can use any DV
> >>>>>> timing
> >>>>>> information to select the desired format, and don't need to have a
> >>>>>> switch
> >>>>>> for
> >>>>>> a preset macro to try to guess what the format actually means. Also,
> >>>>>> there's no
> >>>>>> need to touch at the API spec every time a new DV timeline is needed.
> >>>>>>
> >>>>>> Also, it should be noticed that, since the size of the data on the
> >>>>>> above
> >>>>>> definitions
> >>>>>> are different than the old ones, _IO macros will provide a different
> >>>>>> magic
> >>>>>> number,
> >>>>>> so, adding these won't break the existing API.
> >>>>>>
> >>>>>> So, I think we should work on this proposal, and mark the existing one
> >>>>>> as
> >>>>>> deprecated.
> >>>>>
> >>>>> This proposal makes it very hard for applications to directly select a
> >>>>> format like 720p50 because the indices can change at any time.
> >>>>
> >>>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
> >>>> check what line it wants,
> >>>
> >>> It's not so easy as you think to find the right timings: you have to check
> >>> many parameters to be certain you have the right one and not some subtle
> >>> variation.
> >>>
> >>>> and do a S_DV_PRESET2, just like any other place
> >>>> where V4L2 defines an ENUM function.
> >>>>
> >>>> The enum won't change during application runtime, so, they can be stored
> >>>> if the application would need to switch to other formats latter.
> >>>>
> >>>>> I think
> >>>>> this is a very desirable feature, particularly for apps running on
> >>>>> embedded systems where the hardware is known. This was one of the design
> >>>>> considerations at the time this API was made.
> >>>>
> >>>> This is a very weak argument. With just one ENUM loop, the application can
> >>>> quickly get the right format(s), and associate them with any internal
> >>>> namespace.
> >>>
> >>> That actually isn't easy at all.
> >>
> >> For the trivial case where the application just wants one of the CEA861 standard
> >> (or VESA DMT), the check is trivial.
> >>
> >>
> >> The speed of the test can even be improved if the order at the struct would
> >> be changed to be:
> >>
> >> struct v4l2_dv_enum_preset2 {
> >> 	__u32	index;
> >> 	__u32	flags;
> >>
> >> 	struct v4l2_fract fps;
> >>  	__u32	width;		/* width in pixels */
> >>  	__u32	height;		/* height in lines */
> >>
> >> 	...
> >> }
> >>
> >> The dv preset seek routine at the application can then be coded as:
> >>
> >> struct seek_preset {		/* Need to follow the same order/arguments as v4l2_dv_enum_preset2 */
> >> 	struct v4l2_fract fps;
> >>  	__u32	width;
> >>  	__u32	height;
> >> };
> >>
> >> struct myapp_preset {
> >> 	__u32 flags;
> >>
> >> 	struct seek_preset preset;
> >> };
> >>
> >> struct  myapp_preset cea861_vic16  = {
> >> 	.flags = DV_PRESET_IS_PROGRESSIVE | DV_PRESET_IS_CEA861,
> >> 	.width = 1920,
> >> 	.height = 1080,
> >> };
> >>
> >> int return_dv_preset_index(fp, struct  myapp_preset *needed)
> >> {
> >> 	int found = -1;
> >> 	struct v4l2_dv_enum_preset2 preset;
> >> 	do {
> >> 		rc = ioctl(fp, VIDIOC_ENUM_DV_PRESETS, &preset);
> >> 		if (rc == -1)
> >> 			break;
> >> 		if ((preset.flags & needed->flags) != needed->flags)
> >> 			continue;
> >> 		if (!memcmp(&preset.fps, &needed->preset)) {
> >> 			found = preset->index;
> >> 			break;
> >> 		}	
> >> 	} while (!rc && found < 0);
> >> }
> >>
> >> void main(void) {
> >> ...
> >> 	index = return_dv_preset_index(fp, cea861_vic16);
> >> ...
> >> }
> > 
> > And the current equivalent is:
> > 
> > 	struct v4l_dv_preset preset = { V4L2_DV_1080P60 };
> > 	ioctl(f, VIDIOC_S_DV_PRESET, &preset);
> 
> Yes, except for the fact that:
> 	- API spec needs addition for every new preset that we standardize;

True. But I believe that it is very useful to have such standardized presets.

> 	- It doesn't support a vendor-specific preset, as there's no way to
> 	  discover what are the timing constants for the preset;

That's why I propose a G_PRESET_TIMINGS.

In my experience most applications do not care about such timings unless you want to
support a wide range of formats, in which case you are more likely to use the DV_TIMINGS
API (if supported by the hardware). Note that the fps+flags fields should certainly
be added to v4l2_enum_dv_preset. No doubt about that.

> 	- Namespacing is broken.

That could be improved, indeed. Deciding on a right namespace isn't that easy, though.

> 
> > You want a whole new API that in my view makes things only more complicated and
> > misses existing functionality (such as the one above).
> 
> I prefer to fix the API, if it is possible/doable on a non-messy way. Yet, as this
> API is currently used only by two drivers (DaVinci and tvp7002), it is better to fix
> it sooner than later, to avoid more efforts on fixing it.
>  
> > Whereas with a few tweaks and possibly a new VIDIOC_G_PRESET_TIMINGS ioctl you
> > can offer the same functionality with the existing API.
> 
> You're proposing a new "enum" preset timings that would present the missing info
> that VIDIOC_S_DV_PRESET doesn't present, except that an application will need to call
> 2 ioctl's in order to enumerate the presets, instead of one.

Very few applications actually need such precise information. Resolution, fps and
interlaced/progressive is enough for most.

> > So, once again my proposal:
> > 
> > ENUM_DV_PRESETS is extended with a flags field and a fps v4l2_fract (or frame_period,
> > whatever works best). Flags give you progressive vs interlaced, and I've no problem
> > adding things like IS_CEA861 or similar flags to that.
> > 
> > The current set of presets remain in use (but get renamed with the old ones as aliases)
> > for CEA861 and (in the near future) VESA DMT timings. 
> 
> 
> > Note that all the hardware I
> > know that has predefined timings does so only for those two standards. Makes sense
> > too: only the consumer electronic standards for SDTV/HDTV and the VGA-like PC monitor
> > standards are typical standards.
> 
> We need a further investigation about that. What are the predefined timings defined for Samgung
> hardware?
> 
> Also, one possible implementation for output devices would be to use EDID to retrieve the
> timings acceptable by the monitor/TV and compare to its internal capabilities. This is
> probably the only way to avoid requiring CAP_SYS_ADMIN for the DV calls, as a bad timing
> may damage the monitor and/or the V4L device.

Is CAP_SYS_ADMIN needed today to set graphics modelines? I am not aware of any checks being
done (other than probably against EDID information, if present).

To my (limited) knowledge hardware that can be broken that way is very, very old and
very unlikely to have EDID capabilities.

> If a vendor decides to implement something like that (either in firmware or on Kernel), then 
> the list of presets will likely have a mix with all standards.

The EDID does not make the list of presets, that is based on the capabilities of the
transmitter (or receiver, for that matter). The EDID may be used to filter the list of
presets, though.
 
> > For presets not related to those standards the easiest method I see is just to assign
> > a preset like (0x80000000 | index).
> 
> I've thinked about that already. Yeah, this would fix part of the problem, allowing
> the implementation of vendor-specific timings and the support for other standards not
> covered yet. There are, however, some issues:
> 	1) the API will be messier;
> 	2) Imagine that a new timing were added as a vendor-specific timing. Later,
> that standard got recognized by some forum and were added at some standard. In that
> case, the vendor cannot simply change the preset index, as it will break the API.

Why would that break the API? The preset was 0x80000000 | 42 (or whatever), now it
becomes V4L2_DV_FOO_WXHP50. You couldn't rely on the first preset to stay the same
anyway.

> Also, duplicating the information is not a good idea. With the preset standards as
> flags, when this happens, all the driver needs is to add a new flag, without breaking
> the API.
> 
> > We may need to add a VIDIOC_G_PRESET_TIMINGS, but I am not certain we really need
> > that. ENUM_DV_PRESETS may give sufficient information already.
> 
> This will only work if there aren't two timings with the same fps/resolution, including
> on the vendor-specific timings. Let's suppose that there are two non-DMT, non-CEA
> standars, from two different vendors, that have different timings. With the current
> API, there's no way to differentiate them.

That's why G_PRESET_TIMINGS may be necessary. I'm just doubtful that applications will
know what to do with that information.
 
> > Based on my experience with GTF/CVT formats I strongly suspect that drivers will
> > need to implement a VIDIOC_QUERY_DV_TIMINGS ioctl and let a userspace library detect
> > the GTF/CVT standard. This is surprisingly complex (mostly due to extremely shoddy
> > standards). 
> 
> Maybe, but I bet that there are a few GTF/CVT standards that are implemented on
> a large amount of TV/monitors. It may make sense to have those added as presets.

Sure, many TVs and monitors support GTF and CVT, but they are not presets as such
but algorithms to allow almost all possible combinations of resolution and fps.

CVT formats can be detected based on hsync and vsync polarities and the vertical
sync width. GTF is much harder to detect, unfortunately.

The CEA standard has only positive hsync+vsync or negative hsync+vsync polarities.
Except for one single timing (VIC 39). Which @#$^%@@ imbecile came up with that
bright idea?!

> I'd love to get some feedback from other developers about that. Samsung?
> 
> The issue with S_DV_TIMINGS is that we likely need to request for CAP_SYS_ADMIN,
> as a bad timing may damage the hardware.

How would this help? Changing my graphics card resolution today doesn't require me to
be root either. The only time this might conceivably be an issue is for analog
video transmitters. I would need to do more research on this. Does anyone else know
much about what constitutes a bad timing and how it might damage hardware?

> Currently, there's not such requirement for DaVinci/tvp7002, nor v4l2-ioctl enforces
> that, but this needs a fix.
> 
> > For GTF/CVT output you want to use VIDIOC_S_DV_TIMINGS anyway.
> 
> True.
> 
> > The reason
> > there is no GTF/CVT support yet is simply because I don't want to make proposals
> > unless I actually implemented it and worked with it for some time to see what works
> > best.
> > 
> > Everything you can do with your proposal you can do with mine, and mine doesn't
> > deprecate anything.
> 
> See above.
> 
> > BTW, in the case of HD-SDI transmitters/receivers the CEA-861 standard does not
> > apply, strictly speaking. That standard is covered by SMPTE 292M. It does support
> > most of the usual SDTV/HDTV formats as are defined in CEA-861, except that things
> > like front/back porch etc. do not apply to this serial interface. The idea behind
> > the presets is that it defines industry standard resolution/framerate combinations,
> > but the standards behind those differ per interface type. You don't really care
> > about those in an application. The user (or developer) just wants to select 1080P60 or
> > WUXGA. 
> 
> Ok.
> 
> > I am frankly not certain anymore if we want to have the standard as part of
> > the macro name. Something like V4L2_DV_HDTV_1920X1080P60 might be more appropriate,
> > with comments next to it referring to the relevant standards depending on the
> > physical interface type.
> 
> That's the problem with the namespace. I think that that's basically the reason why
> Xorg never created a macro naming for the resolutions. Whatever namespace we choose,
> we'll have troubles. I bet that, with your proposal, we'll end by having conflicts
> between two different standards that implement the same resolution/fps/"progressiveness".
> 
> > And instead of using flags to denote the used standard, it might be better to
> > reserve a u16 for the standard.
> 
> It seems that a standards bitmask may work better, as, eventually, the same timing may
> be defined by more than one standard.

That's makes the interesting assumption that there will be no more than 32 standards :-)

> > History has shown that video formats stay around for a looong time, but the standards
> > describing them evolve continuously.
> 
> True. We might end to have some timings that are different on a new standard revision,
> in order to fix some issue. That's why I think we need to expose all the timings at
> the DV enum ioctl. This gives more flexibility to the application to reject an specific
> standard if needed for whatever reason.

Let's stop discussing this for a bit until we get some feedback from others. It's more
a ping-pong match between us right now and I would really like to hear the opinions of
others (Samsung in particular).

Regards,

	Hans

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-07 14:58                         ` Hans Verkuil
@ 2011-07-07 16:18                           ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-07 16:18 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Tomasz Stanislawski, linux-media, m.szyprowski, kyungmin.park,
	laurent.pinchart

Em 07-07-2011 11:58, Hans Verkuil escreveu:
> On Thursday, July 07, 2011 15:52:53 Mauro Carvalho Chehab wrote:
>> Em 07-07-2011 08:33, Hans Verkuil escreveu:
>>> On Wednesday, July 06, 2011 21:39:46 Mauro Carvalho Chehab wrote:
>>>> Em 06-07-2011 09:14, Hans Verkuil escreveu:
>>>>>> Em 06-07-2011 08:31, Hans Verkuil escreveu:
>>>>>>>> Em 05-07-2011 10:20, Hans Verkuil escreveu:
>>>>>>>>
>>>>>>>>>> I failed to see what information is provided by the "presets" name.
>>>>>>>>>> If
>>>>>>>>>> this were removed
>>>>>>>>>> from the ioctl, and fps would be added instead, the API would be
>>>>>>>>>> clearer. The only
>>>>>>>>>> adjustment would be to use "index" as the preset selection key.
>>>>>>>>>> Anyway,
>>>>>>>>>> it is too late
>>>>>>>>>> for such change. We need to live with that.
>>>>>>>>>
>>>>>>>>> Adding the fps solves nothing. Because that still does not give you
>>>>>>>>> specific timings.
>>>>>>>>> You can have 1920x1080P60 that has quite different timings from the
>>>>>>>>> CEA-861 standard
>>>>>>>>> and that may not be supported by a TV.
>>>>>>>>>
>>>>>>>>> If you are working with HDMI, then you may want to filter all
>>>>>>>>> supported
>>>>>>>>> presets to
>>>>>>>>> those of the CEA standard.
>>>>>>>>>
>>>>>>>>> That's one thing that is missing at the moment: that presets belonging
>>>>>>>>> to a certain
>>>>>>>>> standard get their own range. Since we only do CEA861 right now it
>>>>>>>>> hasn't been an
>>>>>>>>> issue, but it will.
>>>>>>>>
>>>>>>>> I prepared a long email about that, but then I realized that we're
>>>>>>>> investing our time into
>>>>>>>> something broken, at the light of all DV timing standards. So, I've
>>>>>>>> dropped it and
>>>>>>>> started from scratch.
>>>>>>>>
>>>>>>>> From what I've got, there are some hardware that can only do a limited
>>>>>>>> set
>>>>>>>> of DV timings.
>>>>>>>> If this were not the case, we could simply just use the
>>>>>>>> VIDIOC_S_DV_TIMINGS/VIDIOC_G_DV_TIMINGS,
>>>>>>>> and put the CEA 861 and VESA timings into some userspace library.
>>>>>>>>
>>>>>>>> In other words, the PRESET API is meant to solve the case where
>>>>>>>> hardware
>>>>>>>> only support
>>>>>>>> a limited set of frequencies, that may or may not be inside the CEA
>>>>>>>> standard.
>>>>>>>>
>>>>>>>> Let's assume we never added the current API, and discuss how it would
>>>>>>>> properly fulfill
>>>>>>>> the user needs. An API that would likely work is:
>>>>>>>>
>>>>>>>> struct v4l2_dv_enum_preset2 {
>>>>>>>> 	__u32	  index;
>>>>>>>> 	__u8	  name[32]; /* Name of the preset timing */
>>>>>>>>
>>>>>>>> 	struct v4l2_fract fps;
>>>>>>>>
>>>>>>>> #define DV_PRESET_IS_PROGRESSIVE	1<<31
>>>>>>>> #define DV_PRESET_SPEC(flag)		(flag && 0xff)
>>>>>>>> #define DV_PRESET_IS_CEA861		1
>>>>>>>> #define DV_PRESET_IS_DMT		2
>>>>>>>> #define DV_PRESET_IS_CVF		3
>>>>>>>> #define DV_PRESET_IS_GTF		4
>>>>>>>> #define DV_PRESET_IS_VENDOR_SPECIFIC	5
>>>>>>>>
>>>>>>>> 	__u32	flags;		/* Interlaced/progressive, DV specs, etc */
>>>>>>>>
>>>>>>>> 	__u32	width;		/* width in pixels */
>>>>>>>> 	__u32	height;		/* height in lines */
>>>>>>>> 	__u32	polarities;	/* Positive or negative polarity */
>>>>>>>> 	__u64	pixelclock;	/* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
>>>>>>>> 	__u32	hfrontporch;	/* Horizpontal front porch in pixels */
>>>>>>>> 	__u32	hsync;		/* Horizontal Sync length in pixels */
>>>>>>>> 	__u32	hbackporch;	/* Horizontal back porch in pixels */
>>>>>>>> 	__u32	vfrontporch;	/* Vertical front porch in pixels */
>>>>>>>> 	__u32	vsync;		/* Vertical Sync length in lines */
>>>>>>>> 	__u32	vbackporch;	/* Vertical back porch in lines */
>>>>>>>> 	__u32	il_vfrontporch;	/* Vertical front porch for bottom field of
>>>>>>>> 				 * interlaced field formats
>>>>>>>> 				 */
>>>>>>>> 	__u32	il_vsync;	/* Vertical sync length for bottom field of
>>>>>>>> 				 * interlaced field formats
>>>>>>>> 				 */
>>>>>>>> 	__u32	il_vbackporch;	/* Vertical back porch for bottom field of
>>>>>>>> 				 * interlaced field formats
>>>>>>>> 				 */
>>>>>>>> 	__u32	  reserved[4];
>>>>>>>> };
>>>>>>>>
>>>>>>>> #define	VIDIOC_ENUM_DV_PRESETS2	_IOWR('V', 83, struct
>>>>>>>> v4l2_dv_enum_preset2)
>>>>>>>> #define	VIDIOC_S_DV_PRESET2	_IOWR('V', 84, u32 index)
>>>>>>>> #define	VIDIOC_G_DV_PRESET2	_IOWR('V', 85, u32 index)
>>>>>>>>
>>>>>>>> Such preset API seems to work for all cases. Userspace can use any DV
>>>>>>>> timing
>>>>>>>> information to select the desired format, and don't need to have a
>>>>>>>> switch
>>>>>>>> for
>>>>>>>> a preset macro to try to guess what the format actually means. Also,
>>>>>>>> there's no
>>>>>>>> need to touch at the API spec every time a new DV timeline is needed.
>>>>>>>>
>>>>>>>> Also, it should be noticed that, since the size of the data on the
>>>>>>>> above
>>>>>>>> definitions
>>>>>>>> are different than the old ones, _IO macros will provide a different
>>>>>>>> magic
>>>>>>>> number,
>>>>>>>> so, adding these won't break the existing API.
>>>>>>>>
>>>>>>>> So, I think we should work on this proposal, and mark the existing one
>>>>>>>> as
>>>>>>>> deprecated.
>>>>>>>
>>>>>>> This proposal makes it very hard for applications to directly select a
>>>>>>> format like 720p50 because the indices can change at any time.
>>>>>>
>>>>>> Why? All the application needs to do is to call VIDIOC_ENUM_DV_PRESETS2,
>>>>>> check what line it wants,
>>>>>
>>>>> It's not so easy as you think to find the right timings: you have to check
>>>>> many parameters to be certain you have the right one and not some subtle
>>>>> variation.
>>>>>
>>>>>> and do a S_DV_PRESET2, just like any other place
>>>>>> where V4L2 defines an ENUM function.
>>>>>>
>>>>>> The enum won't change during application runtime, so, they can be stored
>>>>>> if the application would need to switch to other formats latter.
>>>>>>
>>>>>>> I think
>>>>>>> this is a very desirable feature, particularly for apps running on
>>>>>>> embedded systems where the hardware is known. This was one of the design
>>>>>>> considerations at the time this API was made.
>>>>>>
>>>>>> This is a very weak argument. With just one ENUM loop, the application can
>>>>>> quickly get the right format(s), and associate them with any internal
>>>>>> namespace.
>>>>>
>>>>> That actually isn't easy at all.
>>>>
>>>> For the trivial case where the application just wants one of the CEA861 standard
>>>> (or VESA DMT), the check is trivial.
>>>>
>>>>
>>>> The speed of the test can even be improved if the order at the struct would
>>>> be changed to be:
>>>>
>>>> struct v4l2_dv_enum_preset2 {
>>>> 	__u32	index;
>>>> 	__u32	flags;
>>>>
>>>> 	struct v4l2_fract fps;
>>>>  	__u32	width;		/* width in pixels */
>>>>  	__u32	height;		/* height in lines */
>>>>
>>>> 	...
>>>> }
>>>>
>>>> The dv preset seek routine at the application can then be coded as:
>>>>
>>>> struct seek_preset {		/* Need to follow the same order/arguments as v4l2_dv_enum_preset2 */
>>>> 	struct v4l2_fract fps;
>>>>  	__u32	width;
>>>>  	__u32	height;
>>>> };
>>>>
>>>> struct myapp_preset {
>>>> 	__u32 flags;
>>>>
>>>> 	struct seek_preset preset;
>>>> };
>>>>
>>>> struct  myapp_preset cea861_vic16  = {
>>>> 	.flags = DV_PRESET_IS_PROGRESSIVE | DV_PRESET_IS_CEA861,
>>>> 	.width = 1920,
>>>> 	.height = 1080,
>>>> };
>>>>
>>>> int return_dv_preset_index(fp, struct  myapp_preset *needed)
>>>> {
>>>> 	int found = -1;
>>>> 	struct v4l2_dv_enum_preset2 preset;
>>>> 	do {
>>>> 		rc = ioctl(fp, VIDIOC_ENUM_DV_PRESETS, &preset);
>>>> 		if (rc == -1)
>>>> 			break;
>>>> 		if ((preset.flags & needed->flags) != needed->flags)
>>>> 			continue;
>>>> 		if (!memcmp(&preset.fps, &needed->preset)) {
>>>> 			found = preset->index;
>>>> 			break;
>>>> 		}	
>>>> 	} while (!rc && found < 0);
>>>> }
>>>>
>>>> void main(void) {
>>>> ...
>>>> 	index = return_dv_preset_index(fp, cea861_vic16);
>>>> ...
>>>> }
>>>
>>> And the current equivalent is:
>>>
>>> 	struct v4l_dv_preset preset = { V4L2_DV_1080P60 };
>>> 	ioctl(f, VIDIOC_S_DV_PRESET, &preset);
>>
>> Yes, except for the fact that:
>> 	- API spec needs addition for every new preset that we standardize;
> 
> True. But I believe that it is very useful to have such standardized presets.

Here is one of the points that we disagree. I think that a proper seek mechanism
is preferred, providing more information for the userspace to do the right choice.

> 
>> 	- It doesn't support a vendor-specific preset, as there's no way to
>> 	  discover what are the timing constants for the preset;
> 
> That's why I propose a G_PRESET_TIMINGS.
> 
> In my experience most applications do not care about such timings unless you want to
> support a wide range of formats, in which case you are more likely to use the DV_TIMINGS
> API (if supported by the hardware). Note that the fps+flags fields should certainly
> be added to v4l2_enum_dv_preset. No doubt about that.

If hardware or driver doesn't support, apps need to use the preset API.

>> 	- Namespacing is broken.
> 
> That could be improved, indeed. Deciding on a right namespace isn't that easy, though.

I seriously doubt that we could find a proper future-proof namespacing. Standards will
add more things, and might eventually review a few badly-specified timings.

>>> You want a whole new API that in my view makes things only more complicated and
>>> misses existing functionality (such as the one above).
>>
>> I prefer to fix the API, if it is possible/doable on a non-messy way. Yet, as this
>> API is currently used only by two drivers (DaVinci and tvp7002), it is better to fix
>> it sooner than later, to avoid more efforts on fixing it.
>>  
>>> Whereas with a few tweaks and possibly a new VIDIOC_G_PRESET_TIMINGS ioctl you
>>> can offer the same functionality with the existing API.
>>
>> You're proposing a new "enum" preset timings that would present the missing info
>> that VIDIOC_S_DV_PRESET doesn't present, except that an application will need to call
>> 2 ioctl's in order to enumerate the presets, instead of one.
> 
> Very few applications actually need such precise information. Resolution, fps and
> interlaced/progressive is enough for most.

most =! all. Removing the amount of provided information due to the assumption that applications
may not want is a wrong decision for such API. There's no big deal on providing all preset
parameters to userspace. This is not a time-critical API, and will be called once at the
application runtime. 

If, on some particular application, a developer found that this might actually represent
a significant amount of time for whatever reason (with I seriously doubt), it could just code a 
"cache" file that will be filled the first time the application boots with a new kernel, 
replicating exactly the same mechanism as you've conceived before: once the association is 
found, it will just use the index discovered at the first run.

>>> So, once again my proposal:
>>>
>>> ENUM_DV_PRESETS is extended with a flags field and a fps v4l2_fract (or frame_period,
>>> whatever works best). Flags give you progressive vs interlaced, and I've no problem
>>> adding things like IS_CEA861 or similar flags to that.
>>>
>>> The current set of presets remain in use (but get renamed with the old ones as aliases)
>>> for CEA861 and (in the near future) VESA DMT timings. 
>>
>>
>>> Note that all the hardware I
>>> know that has predefined timings does so only for those two standards. Makes sense
>>> too: only the consumer electronic standards for SDTV/HDTV and the VGA-like PC monitor
>>> standards are typical standards.
>>
>> We need a further investigation about that. What are the predefined timings defined for Samgung
>> hardware?
>>
>> Also, one possible implementation for output devices would be to use EDID to retrieve the
>> timings acceptable by the monitor/TV and compare to its internal capabilities. This is
>> probably the only way to avoid requiring CAP_SYS_ADMIN for the DV calls, as a bad timing
>> may damage the monitor and/or the V4L device.
> 
> Is CAP_SYS_ADMIN needed today to set graphics modelines? I am not aware of any checks being
> done (other than probably against EDID information, if present).

With great power comes great responsibility. The VESA FB driver explicitly checks for CAP_SYS_ADMIN.
Xorg process runs as root, as almost all resources required for controlling the video display
requires root, and a non-root access may damage the hardware and/or BIOS. The security solution
used there is to lock things like /dev/mem to be accessible only by root (e. g. the entire char 
device is protected).

In the case of V4L, we need to provide an ioctl-based security mechanism, as only a very few
set of ioctl's can be dangerous.

> To my (limited) knowledge hardware that can be broken that way is very, very old and
> very unlikely to have EDID capabilities.

A quick Google search for "permanent damage lcd due to wrong video settings" hits 5.380.000 pages.
A look at those two specs:

	http://www.viewsonic.com.au/support/manuals/files/LCD/Series%20X/VX510-1%20User%20Guide%20English.pdf
	http://pt.scribd.com/doc/20791522/VA2226w-LCD-Display

Both have the same kind of warning:

WARNING: Do not set the graphics card in your computer to exceed the
	maximum refresh rate of 85Hz/ 1024 x 768@75Hz;
	doing so may result in permanent damage to your LCD display.
(VX510 manual, page 7. A similar text is at page 8 of VA2226w manual)

The VA2226w manual was written in 2008, so it is very likely that it supports EDID.

So, AFAIK, your assumption is wrong. Monitors can be damaged if a wrong DV timing is selected.

We need to restrict the DV S_ preset/timings calls for output devices with CAP_SYS_ADMIN, except
if the driver or firmware provides some other explicit mechanism to protect such damages.

>> If a vendor decides to implement something like that (either in firmware or on Kernel), then 
>> the list of presets will likely have a mix with all standards.
> 
> The EDID does not make the list of presets, that is based on the capabilities of the
> transmitter (or receiver, for that matter). The EDID may be used to filter the list of
> presets, though.

Yes, that's what I meant to say. Setting to a timing that is compatible with EDID information
doesn't need to require root access, but it there's no such check in kernel/hardware/firmware,
then userspace calls need protection mechanisms.

>>> For presets not related to those standards the easiest method I see is just to assign
>>> a preset like (0x80000000 | index).
>>
>> I've thinked about that already. Yeah, this would fix part of the problem, allowing
>> the implementation of vendor-specific timings and the support for other standards not
>> covered yet. There are, however, some issues:
>> 	1) the API will be messier;
>> 	2) Imagine that a new timing were added as a vendor-specific timing. Later,
>> that standard got recognized by some forum and were added at some standard. In that
>> case, the vendor cannot simply change the preset index, as it will break the API.
> 
> Why would that break the API? The preset was 0x80000000 | 42 (or whatever), now it
> becomes V4L2_DV_FOO_WXHP50. You couldn't rely on the first preset to stay the same
> anyway.

Because the preset index is a sequential number. V4L2_DV_FOO_WXHP50 is index #42 on driver 
foo, but it may have index #10 on other drivers.

See the issue? Using a preset macro for seek is not flexible.

An implementation like G_PRESET_FOR_STD that will return the index for a macro name
and a full-featured preset ENUM would be better than the current mechanism.

Yet, I fail to see that seeking for a preset internally at the driver (either with 
the current G/S PRESET ioctl's or with a newly G_PRESET_FOR_STD) would really bring
and significant performance improvement to justify not implementing an ENUM loop
in userspace.

>> Also, duplicating the information is not a good idea. With the preset standards as
>> flags, when this happens, all the driver needs is to add a new flag, without breaking
>> the API.
>>
>>> We may need to add a VIDIOC_G_PRESET_TIMINGS, but I am not certain we really need
>>> that. ENUM_DV_PRESETS may give sufficient information already.
>>
>> This will only work if there aren't two timings with the same fps/resolution, including
>> on the vendor-specific timings. Let's suppose that there are two non-DMT, non-CEA
>> standars, from two different vendors, that have different timings. With the current
>> API, there's no way to differentiate them.
> 
> That's why G_PRESET_TIMINGS may be necessary. I'm just doubtful that applications will
> know what to do with that information.
>  
>>> Based on my experience with GTF/CVT formats I strongly suspect that drivers will
>>> need to implement a VIDIOC_QUERY_DV_TIMINGS ioctl and let a userspace library detect
>>> the GTF/CVT standard. This is surprisingly complex (mostly due to extremely shoddy
>>> standards). 
>>
>> Maybe, but I bet that there are a few GTF/CVT standards that are implemented on
>> a large amount of TV/monitors. It may make sense to have those added as presets.
> 
> Sure, many TVs and monitors support GTF and CVT, but they are not presets as such
> but algorithms to allow almost all possible combinations of resolution and fps.
> 
> CVT formats can be detected based on hsync and vsync polarities and the vertical
> sync width. GTF is much harder to detect, unfortunately.
> 
> The CEA standard has only positive hsync+vsync or negative hsync+vsync polarities.
> Except for one single timing (VIC 39). Which @#$^%@@ imbecile came up with that
> bright idea?!
> 
>> I'd love to get some feedback from other developers about that. Samsung?
>>
>> The issue with S_DV_TIMINGS is that we likely need to request for CAP_SYS_ADMIN,
>> as a bad timing may damage the hardware.
> 
> How would this help? Changing my graphics card resolution today doesn't require me to
> be root either. 

It does requre. Xorg runs as root:

$ ls -la /usr/bin/Xorg
-rws--x--x 1 root root 1932152 Abr  7 18:46 /usr/bin/Xorg

This type of permission was ever required since XFree86 old days.

> The only time this might conceivably be an issue is for analog
> video transmitters. I would need to do more research on this. Does anyone else know
> much about what constitutes a bad timing and how it might damage hardware?
> 
>> Currently, there's not such requirement for DaVinci/tvp7002, nor v4l2-ioctl enforces
>> that, but this needs a fix.
>>
>>> For GTF/CVT output you want to use VIDIOC_S_DV_TIMINGS anyway.
>>
>> True.
>>
>>> The reason
>>> there is no GTF/CVT support yet is simply because I don't want to make proposals
>>> unless I actually implemented it and worked with it for some time to see what works
>>> best.
>>>
>>> Everything you can do with your proposal you can do with mine, and mine doesn't
>>> deprecate anything.
>>
>> See above.
>>
>>> BTW, in the case of HD-SDI transmitters/receivers the CEA-861 standard does not
>>> apply, strictly speaking. That standard is covered by SMPTE 292M. It does support
>>> most of the usual SDTV/HDTV formats as are defined in CEA-861, except that things
>>> like front/back porch etc. do not apply to this serial interface. The idea behind
>>> the presets is that it defines industry standard resolution/framerate combinations,
>>> but the standards behind those differ per interface type. You don't really care
>>> about those in an application. The user (or developer) just wants to select 1080P60 or
>>> WUXGA. 
>>
>> Ok.
>>
>>> I am frankly not certain anymore if we want to have the standard as part of
>>> the macro name. Something like V4L2_DV_HDTV_1920X1080P60 might be more appropriate,
>>> with comments next to it referring to the relevant standards depending on the
>>> physical interface type.
>>
>> That's the problem with the namespace. I think that that's basically the reason why
>> Xorg never created a macro naming for the resolutions. Whatever namespace we choose,
>> we'll have troubles. I bet that, with your proposal, we'll end by having conflicts
>> between two different standards that implement the same resolution/fps/"progressiveness".
>>
>>> And instead of using flags to denote the used standard, it might be better to
>>> reserve a u16 for the standard.
>>
>> It seems that a standards bitmask may work better, as, eventually, the same timing may
>> be defined by more than one standard.
> 
> That's makes the interesting assumption that there will be no more than 32 standards :-)

:) Well, we may use u64 ;)

I'm in doubt between using u16 or a bitmask, as we may have the same timings defined
on two or more standards.

>>> History has shown that video formats stay around for a looong time, but the standards
>>> describing them evolve continuously.
>>
>> True. We might end to have some timings that are different on a new standard revision,
>> in order to fix some issue. That's why I think we need to expose all the timings at
>> the DV enum ioctl. This gives more flexibility to the application to reject an specific
>> standard if needed for whatever reason.
> 
> Let's stop discussing this for a bit until we get some feedback from others. It's more
> a ping-pong match between us right now and I would really like to hear the opinions of
> others (Samsung in particular).

Agreed.

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC] DV timings spec fixes at V4L2 API - was: [PATCH 1/8] v4l: add macro for 1080p59_54 preset
  2011-07-07 13:52                       ` Mauro Carvalho Chehab
  2011-07-07 14:58                         ` Hans Verkuil
@ 2011-07-07 17:52                         ` Tomasz Stanislawski
  1 sibling, 0 replies; 37+ messages in thread
From: Tomasz Stanislawski @ 2011-07-07 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil
  Cc: linux-media, m.szyprowski, kyungmin.park, laurent.pinchart

Hi Mauro, Hans,

I am really surprised by the havoc caused by the little 2-line patch.

Let me sum up what I (don't) like in Hans' and Mauro's approaches:

Hans approach:
- extend v4l2_enum_dv_preset with fps and flags fields,
- allow enumerating presets by both index and preset code
- add standard to macro names for presets

Pros:
- backward compatible with existing api
- very simple and effective. Setting desired preset using only 2 lines 
of code
- easy to add unfortunate 1080p59_94
- easy to differentiate 1080p59_94 from 1080p60 using VIDIOC_ENUM_DV_PRESET

Cons:
- number of existing macros must increase extensionally with number of 
features. Height, progressiveness, frequency are already present. 
Standard family is added in Hans' RFC. Some presets involve width. 
Therefore multiple holes are expected making usage of macros very 
unreliable.
- it is not possible to use VIDIOC_S_DV_PRESET to handle case when 
application just wants a preset that has 720 height. The application has 
to enumerate all existing/possible presets  (number of possible 
combinations may be large) to find a preset that suits to the 
application's needs.
- unnecessary redundancy, preset is nothing more than a standardized index

Mauro's approach:
- enumerate all possible presets using VIDIOC_ENUM_DV_PRESETS2
- choose suitable preset using index field from

Pros:
- consistency: preset can only be addressed by index field,
- no preset macros

Cons:
- structure v4l2_dv_enum_preset2 contains BT.656/BT.1120 timing related 
data, the structure should be more general. Most application would not 
use timing fields, so maybe there is no need of adding them to the 
structure.
- applications still has to enumerate through all possible combinations 
to find a suitable preset
- not compatible with existing API, two way to configure DV hardware

I propose following requirements for DV preset api basing on pros and 
cons from overmentioned approaches.
- an application should be able to choose a preset with desired 
parameters using single ioctl call
- preset should be accessed using single key. I prefer to use index as a 
key because it gives more flexibility to a driver.
- compatible with existing api as much as possible

What do you think about approach similar to S_FMT?
Please look at the code below.

struct v4l2_dv_preset2 {
    u16 width;
    u16 height;
    v4l2_fract fps;
    u32 flags; /* progressiveness, standard hints, rounding constraints */
    u32 reserved[];
};

/* Values for the standard field */
#define V4L2_DV_BT_656_1120     0       /* BT.656/1120 timing type */

struct v4l2_enum_dv_preset2 {
    u32 index;
    char name[32];
    struct v4l2_dv_preset2 preset;
    struct v4l2_dv_timings timings; /* to be removed ? */
    u32 reserved[];
};

#define    VIDIOC_ENUM_DV_PRESETS2    _IOWR('V', 83, struct 
v4l2_dv_enum_preset2)
#define    VIDIOC_S_DV_PRESET2    _IOWR('V', 84, struct v4l2_dv_preset2)
#define    VIDIOC_G_DV_PRESET2    _IOWR('V', 85, struct v4l2_dv_preset2)
#define    VIDIOC_TRY_DV_PRESET2    _IOWR('V', 86, struct v4l2_dv_preset2)

To set a mode with height 720 lines the applications would execute code 
below:

struct v4l2_dv_preset2 preset = {    .height = 720 };
ioctl(fd, VIDIOC_S_DV_PRESET2, &preset);

The preset is selected using the most interesting features like 
width/height/frequency and progressiveness.
The driver would find the preset with vertical resolution as close as 
possible to 720.
The width and fps is zero so driver is free to choose suitable/default ones.
The field flags may contain hind about choosing preset that belong to 
specific DV standard family.

I do not feel competent in the field of DV standard. Could give me more 
ideas about flags?
The flags could contain  constraint  bits similar to ones presented in 
SELECTION api.
Maybe structures v4l2_dv_preset and v4l2_enum_dv_presets could be 
utilized for purpose of presented api.
Maybe using some union/structure align magic it would be possible to 
keep binary compatibility with existing programs.

For now, I have removed unfortunate 1080P59_94 format from S5P-TV driver.
I would be very happy if the driver was merged into 3.1.
I think that it would be not possible due to 1080p59_94 issue.
The driver did not lose much of its functionality because it still 
supports 1080p60.
Moreover, adding 1080p59_94 is relatively trivial.

I hope you find this information useful.

Regards,
Tomasz Stanislawski

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/8] v4l: fix v4l_fill_dv_preset_info function
  2011-06-29 12:51 ` [PATCH 5/8] v4l: fix v4l_fill_dv_preset_info function Tomasz Stanislawski
@ 2011-07-14 16:02   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 37+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-14 16:02 UTC (permalink / raw)
  To: Tomasz Stanislawski
  Cc: linux-media, m.szyprowski, kyungmin.park, hverkuil, laurent.pinchart

Em 29-06-2011 09:51, Tomasz Stanislawski escreveu:
> The function fills struct v4l2_dv_enum_preset with appropriate
> preset parameters but it forgets to zero field named reserved.
> This patch fixes this bug.
> 
> Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
> ---
>  drivers/media/video/v4l2-common.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
> index 003e648..e7c02e9 100644
> --- a/drivers/media/video/v4l2-common.c
> +++ b/drivers/media/video/v4l2-common.c
> @@ -592,6 +592,8 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
>  	info->width = dv_presets[preset].width;
>  	info->height = dv_presets[preset].height;
>  	strlcpy(info->name, dv_presets[preset].name, sizeof(info->name));
> +	/* assure that reserved fields are zeroed */
> +	memset(info->reserved, 0, sizeof(info->reserved));
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);

This patch is not needed, except if you're doing a different logic.
v4l2-ioctl makes sure of cleaning the reserved and write fields from
the structs before passing the syscall to the drivers.

So, if you're filling data from an userspace call, you don't need to
use. If you're instead allocating data, use *zalloc calls.

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2011-07-14 16:02 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-29 12:51 [PATCH v6 0/8] TV drivers for Samsung S5P platform (media part) Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 1/8] v4l: add macro for 1080p59_54 preset Tomasz Stanislawski
2011-07-04 16:09   ` [RFC] DV timings spec fixes at V4L2 API - was: " Mauro Carvalho Chehab
2011-07-04 22:47     ` Laurent Pinchart
2011-07-04 23:28       ` Mauro Carvalho Chehab
2011-07-05  6:46       ` Hans Verkuil
2011-07-05  7:26     ` Hans Verkuil
2011-07-05 12:08       ` Mauro Carvalho Chehab
2011-07-05 13:20         ` Hans Verkuil
2011-07-05 19:02           ` Andy Walls
2011-07-05 23:25             ` Mauro Carvalho Chehab
2011-07-06  1:05               ` Andy Walls
2011-07-06 11:04           ` Mauro Carvalho Chehab
2011-07-06 11:31             ` Hans Verkuil
2011-07-06 11:48               ` Mauro Carvalho Chehab
2011-07-06 12:03                 ` Laurent Pinchart
2011-07-06 12:09                   ` Mauro Carvalho Chehab
2011-07-06 12:13                     ` Laurent Pinchart
2011-07-06 12:20                       ` Mauro Carvalho Chehab
2011-07-06 12:14                 ` Hans Verkuil
2011-07-06 12:31                   ` Mauro Carvalho Chehab
2011-07-06 12:56                     ` Hans Verkuil
2011-07-06 14:10                       ` Mauro Carvalho Chehab
2011-07-06 19:39                   ` Mauro Carvalho Chehab
2011-07-07 11:33                     ` Hans Verkuil
2011-07-07 13:52                       ` Mauro Carvalho Chehab
2011-07-07 14:58                         ` Hans Verkuil
2011-07-07 16:18                           ` Mauro Carvalho Chehab
2011-07-07 17:52                         ` Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 2/8] v4l: add g_tvnorms_output callback to V4L2 subdev Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 3/8] v4l: add g_dv_preset " Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 4/8] v4l: add g_std_output " Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 5/8] v4l: fix v4l_fill_dv_preset_info function Tomasz Stanislawski
2011-07-14 16:02   ` Mauro Carvalho Chehab
2011-06-29 12:51 ` [PATCH 6/8] v4l: s5p-tv: add drivers for HDMI on Samsung S5P platform Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 7/8] v4l: s5p-tv: add SDO driver for " Tomasz Stanislawski
2011-06-29 12:51 ` [PATCH 8/8] v4l: s5p-tv: add TV Mixer " Tomasz Stanislawski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).