diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 20:03:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 20:03:51 -0400 |
commit | 19c5abcb74b712a7824ae7c55862932534e7dfec (patch) | |
tree | 006822aa663cb9ee886773e819d4793fe3947626 | |
parent | 675e0655c12209ba1f40af0dff7cd76b17a1315c (diff) | |
parent | aff093d4bbca91f543e24cde2135f393b8130f4b (diff) |
Merge tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- added support for Intersil/Techwell TW686x-based video capture cards
- v4l PCI skeleton driver moved to samples directory
- Documentation cleanups and improvements
- RC: reduced the memory footprint for IR raw events
- tpg: Export the tpg code from vivid as a module
- adv7180: Add device tree binding documentation
- lots of driver improvements and fixes
* tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (173 commits)
[media] exynos-gsc: avoid build warning without CONFIG_OF
[media] samples: v4l: from Documentation to samples directory
[media] dib0700: add USB ID for another STK8096-PVR ref design based card
[media] tvp5150: propagate I2C write error in .s_register callback
[media] tvp5150: return I2C write operation failure to callers
[media] em28xx: add support for Hauppauge WinTV-dualHD DVB tuner
[media] em28xx: add missing USB IDs
[media] update cx23885 and em28xx cardlists
[media] media: au0828 fix au0828_v4l2_device_register() to not unlock and free
[media] c8sectpfe: Rework firmware loading mechanism
[media] c8sectpfe: Demote print to dev_dbg
[media] c8sectpfe: Fix broken circular buffer wp management
[media] media-device: Simplify compat32 logic
[media] media: i2c: ths7303: remove redundant assignment on bt
[media] dvb-usb: hide unused functions
[media] xilinx-vipp: remove unnecessary of_node_put
[media] drivers/media/media-devnode: clear private_data before put_device()
[media] drivers/media/media-device: move debug log before _devnode_unregister()
[media] drivers/media/rc: postpone kfree(rc_dev)
[media] media/dvb-core: forward media_create_pad_links() return value
...
192 files changed, 6757 insertions, 3001 deletions
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 184f3c7b5145..893b2cabf7e4 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl | |||
@@ -233,6 +233,7 @@ X!Isound/sound_firmware.c | |||
233 | !Iinclude/media/v4l2-mediabus.h | 233 | !Iinclude/media/v4l2-mediabus.h |
234 | !Iinclude/media/v4l2-mem2mem.h | 234 | !Iinclude/media/v4l2-mem2mem.h |
235 | !Iinclude/media/v4l2-of.h | 235 | !Iinclude/media/v4l2-of.h |
236 | !Iinclude/media/v4l2-rect.h | ||
236 | !Iinclude/media/v4l2-subdev.h | 237 | !Iinclude/media/v4l2-subdev.h |
237 | !Iinclude/media/videobuf2-core.h | 238 | !Iinclude/media/videobuf2-core.h |
238 | !Iinclude/media/videobuf2-v4l2.h | 239 | !Iinclude/media/videobuf2-v4l2.h |
diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml index d2e44b7e07df..da095ed0b75c 100644 --- a/Documentation/DocBook/media/dvb/net.xml +++ b/Documentation/DocBook/media/dvb/net.xml | |||
@@ -15,7 +15,7 @@ | |||
15 | that are present on the transport stream. This is done through | 15 | that are present on the transport stream. This is done through |
16 | <constant>/dev/dvb/adapter?/net?</constant> device node. | 16 | <constant>/dev/dvb/adapter?/net?</constant> device node. |
17 | The data will be available via virtual <constant>dvb?_?</constant> | 17 | The data will be available via virtual <constant>dvb?_?</constant> |
18 | network interfaces, and will be controled/routed via the standard | 18 | network interfaces, and will be controlled/routed via the standard |
19 | ip tools (like ip, route, netstat, ifconfig, etc).</para> | 19 | ip tools (like ip, route, netstat, ifconfig, etc).</para> |
20 | <para> Data types and and ioctl definitions are defined via | 20 | <para> Data types and and ioctl definitions are defined via |
21 | <constant>linux/dvb/net.h</constant> header.</para> | 21 | <constant>linux/dvb/net.h</constant> header.</para> |
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 5399e8904715..82fa328abd58 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml | |||
@@ -2686,50 +2686,12 @@ and may change in the future.</para> | |||
2686 | 2686 | ||
2687 | <itemizedlist> | 2687 | <itemizedlist> |
2688 | <listitem> | 2688 | <listitem> |
2689 | <para>Video Output Overlay (OSD) Interface, <xref | ||
2690 | linkend="osd" />.</para> | ||
2691 | </listitem> | ||
2692 | <listitem> | ||
2693 | <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER; | 2689 | <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER; |
2694 | ioctls.</para> | 2690 | ioctls.</para> |
2695 | </listitem> | 2691 | </listitem> |
2696 | <listitem> | 2692 | <listitem> |
2697 | <para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para> | 2693 | <para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para> |
2698 | </listitem> | 2694 | </listitem> |
2699 | <listitem> | ||
2700 | <para>&VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and | ||
2701 | &VIDIOC-DV-TIMINGS-CAP; ioctls.</para> | ||
2702 | </listitem> | ||
2703 | <listitem> | ||
2704 | <para>Flash API. <xref linkend="flash-controls" /></para> | ||
2705 | </listitem> | ||
2706 | <listitem> | ||
2707 | <para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para> | ||
2708 | </listitem> | ||
2709 | <listitem> | ||
2710 | <para>Selection API. <xref linkend="selection-api" /></para> | ||
2711 | </listitem> | ||
2712 | <listitem> | ||
2713 | <para>Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION; | ||
2714 | and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para> | ||
2715 | </listitem> | ||
2716 | <listitem> | ||
2717 | <para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para> | ||
2718 | </listitem> | ||
2719 | <listitem> | ||
2720 | <para>Vendor and device specific media bus pixel formats. | ||
2721 | <xref linkend="v4l2-mbus-vendor-spec-fmts" />.</para> | ||
2722 | </listitem> | ||
2723 | <listitem> | ||
2724 | <para>Importing DMABUF file descriptors as a new IO method described | ||
2725 | in <xref linkend="dmabuf" />.</para> | ||
2726 | </listitem> | ||
2727 | <listitem> | ||
2728 | <para>Exporting DMABUF files using &VIDIOC-EXPBUF; ioctl.</para> | ||
2729 | </listitem> | ||
2730 | <listitem> | ||
2731 | <para>Software Defined Radio (SDR) Interface, <xref linkend="sdr" />.</para> | ||
2732 | </listitem> | ||
2733 | </itemizedlist> | 2695 | </itemizedlist> |
2734 | </section> | 2696 | </section> |
2735 | 2697 | ||
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 361040e6b0f4..81efa883f67d 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml | |||
@@ -4272,13 +4272,6 @@ manually or automatically if set to zero. Unit, range and step are driver-specif | |||
4272 | <section id="flash-controls"> | 4272 | <section id="flash-controls"> |
4273 | <title>Flash Control Reference</title> | 4273 | <title>Flash Control Reference</title> |
4274 | 4274 | ||
4275 | <note> | ||
4276 | <title>Experimental</title> | ||
4277 | |||
4278 | <para>This is an <link linkend="experimental">experimental</link> | ||
4279 | interface and may change in the future.</para> | ||
4280 | </note> | ||
4281 | |||
4282 | <para> | 4275 | <para> |
4283 | The V4L2 flash controls are intended to provide generic access | 4276 | The V4L2 flash controls are intended to provide generic access |
4284 | to flash controller devices. Flash controller devices are | 4277 | to flash controller devices. Flash controller devices are |
@@ -4743,14 +4736,6 @@ interface and may change in the future.</para> | |||
4743 | <section id="image-source-controls"> | 4736 | <section id="image-source-controls"> |
4744 | <title>Image Source Control Reference</title> | 4737 | <title>Image Source Control Reference</title> |
4745 | 4738 | ||
4746 | <note> | ||
4747 | <title>Experimental</title> | ||
4748 | |||
4749 | <para>This is an <link | ||
4750 | linkend="experimental">experimental</link> interface and may | ||
4751 | change in the future.</para> | ||
4752 | </note> | ||
4753 | |||
4754 | <para> | 4739 | <para> |
4755 | The Image Source control class is intended for low-level | 4740 | The Image Source control class is intended for low-level |
4756 | control of image source devices such as image sensors. The | 4741 | control of image source devices such as image sensors. The |
@@ -4862,14 +4847,6 @@ interface and may change in the future.</para> | |||
4862 | <section id="image-process-controls"> | 4847 | <section id="image-process-controls"> |
4863 | <title>Image Process Control Reference</title> | 4848 | <title>Image Process Control Reference</title> |
4864 | 4849 | ||
4865 | <note> | ||
4866 | <title>Experimental</title> | ||
4867 | |||
4868 | <para>This is an <link | ||
4869 | linkend="experimental">experimental</link> interface and may | ||
4870 | change in the future.</para> | ||
4871 | </note> | ||
4872 | |||
4873 | <para> | 4850 | <para> |
4874 | The Image Process control class is intended for low-level control of | 4851 | The Image Process control class is intended for low-level control of |
4875 | image processing functions. Unlike | 4852 | image processing functions. Unlike |
@@ -4955,14 +4932,6 @@ interface and may change in the future.</para> | |||
4955 | <section id="dv-controls"> | 4932 | <section id="dv-controls"> |
4956 | <title>Digital Video Control Reference</title> | 4933 | <title>Digital Video Control Reference</title> |
4957 | 4934 | ||
4958 | <note> | ||
4959 | <title>Experimental</title> | ||
4960 | |||
4961 | <para>This is an <link | ||
4962 | linkend="experimental">experimental</link> interface and may | ||
4963 | change in the future.</para> | ||
4964 | </note> | ||
4965 | |||
4966 | <para> | 4935 | <para> |
4967 | The Digital Video control class is intended to control receivers | 4936 | The Digital Video control class is intended to control receivers |
4968 | and transmitters for <ulink url="http://en.wikipedia.org/wiki/Vga">VGA</ulink>, | 4937 | and transmitters for <ulink url="http://en.wikipedia.org/wiki/Vga">VGA</ulink>, |
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml index a659771f7b7c..6da1157fb5bd 100644 --- a/Documentation/DocBook/media/v4l/dev-sdr.xml +++ b/Documentation/DocBook/media/v4l/dev-sdr.xml | |||
@@ -1,11 +1,5 @@ | |||
1 | <title>Software Defined Radio Interface (SDR)</title> | 1 | <title>Software Defined Radio Interface (SDR)</title> |
2 | 2 | ||
3 | <note> | ||
4 | <title>Experimental</title> | ||
5 | <para>This is an <link linkend="experimental"> experimental </link> | ||
6 | interface and may change in the future.</para> | ||
7 | </note> | ||
8 | |||
9 | <para> | 3 | <para> |
10 | SDR is an abbreviation of Software Defined Radio, the radio device | 4 | SDR is an abbreviation of Software Defined Radio, the radio device |
11 | which uses application software for modulation or demodulation. This interface | 5 | which uses application software for modulation or demodulation. This interface |
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml index 4f0ba58c9bd9..f4bc27af83eb 100644 --- a/Documentation/DocBook/media/v4l/dev-subdev.xml +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml | |||
@@ -1,11 +1,5 @@ | |||
1 | <title>Sub-device Interface</title> | 1 | <title>Sub-device Interface</title> |
2 | 2 | ||
3 | <note> | ||
4 | <title>Experimental</title> | ||
5 | <para>This is an <link linkend="experimental">experimental</link> | ||
6 | interface and may change in the future.</para> | ||
7 | </note> | ||
8 | |||
9 | <para>The complex nature of V4L2 devices, where hardware is often made of | 3 | <para>The complex nature of V4L2 devices, where hardware is often made of |
10 | several integrated circuits that need to interact with each other in a | 4 | several integrated circuits that need to interact with each other in a |
11 | controlled way, leads to complex V4L2 drivers. The drivers usually reflect | 5 | controlled way, leads to complex V4L2 drivers. The drivers usually reflect |
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 144158b3a5ac..e09025db92bd 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml | |||
@@ -475,12 +475,6 @@ rest should be evident.</para> | |||
475 | <section id="dmabuf"> | 475 | <section id="dmabuf"> |
476 | <title>Streaming I/O (DMA buffer importing)</title> | 476 | <title>Streaming I/O (DMA buffer importing)</title> |
477 | 477 | ||
478 | <note> | ||
479 | <title>Experimental</title> | ||
480 | <para>This is an <link linkend="experimental">experimental</link> | ||
481 | interface and may change in the future.</para> | ||
482 | </note> | ||
483 | |||
484 | <para>The DMABUF framework provides a generic method for sharing buffers | 478 | <para>The DMABUF framework provides a generic method for sharing buffers |
485 | between multiple devices. Device drivers that support DMABUF can export a DMA | 479 | between multiple devices. Device drivers that support DMABUF can export a DMA |
486 | buffer to userspace as a file descriptor (known as the exporter role), import a | 480 | buffer to userspace as a file descriptor (known as the exporter role), import a |
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml index 28cbded766c9..b764cba150d1 100644 --- a/Documentation/DocBook/media/v4l/selection-api.xml +++ b/Documentation/DocBook/media/v4l/selection-api.xml | |||
@@ -1,13 +1,6 @@ | |||
1 | <section id="selection-api"> | 1 | <section id="selection-api"> |
2 | 2 | ||
3 | <title>Experimental API for cropping, composing and scaling</title> | 3 | <title>API for cropping, composing and scaling</title> |
4 | |||
5 | <note> | ||
6 | <title>Experimental</title> | ||
7 | |||
8 | <para>This is an <link linkend="experimental">experimental</link> | ||
9 | interface and may change in the future.</para> | ||
10 | </note> | ||
11 | 4 | ||
12 | <section> | 5 | <section> |
13 | <title>Introduction</title> | 6 | <title>Introduction</title> |
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 4e73345e3eab..199c84e3aede 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml | |||
@@ -4002,12 +4002,6 @@ see <xref linkend="colorspaces" />.</entry> | |||
4002 | <section id="v4l2-mbus-vendor-spec-fmts"> | 4002 | <section id="v4l2-mbus-vendor-spec-fmts"> |
4003 | <title>Vendor and Device Specific Formats</title> | 4003 | <title>Vendor and Device Specific Formats</title> |
4004 | 4004 | ||
4005 | <note> | ||
4006 | <title>Experimental</title> | ||
4007 | <para>This is an <link linkend="experimental">experimental</link> | ||
4008 | interface and may change in the future.</para> | ||
4009 | </note> | ||
4010 | |||
4011 | <para>This section lists complex data formats that are either vendor or | 4005 | <para>This section lists complex data formats that are either vendor or |
4012 | device specific. | 4006 | device specific. |
4013 | </para> | 4007 | </para> |
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml index d81fa0d4016b..6528e97b8990 100644 --- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental"> experimental </link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>This ioctl is used to create buffers for <link linkend="mmap">memory | 52 | <para>This ioctl is used to create buffers for <link linkend="mmap">memory |
59 | mapped</link> or <link linkend="userp">user pointer</link> or <link | 53 | mapped</link> or <link linkend="userp">user pointer</link> or <link |
60 | linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in | 54 | linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in |
diff --git a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml index a2017bfcaed2..ca9ffce9b4c1 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml | |||
@@ -49,14 +49,9 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | 52 | <para>To query the capabilities of the DV receiver/transmitter applications initialize the |
53 | <title>Experimental</title> | 53 | <structfield>pad</structfield> field to 0, zero the reserved array of &v4l2-dv-timings-cap; |
54 | <para>This is an <link linkend="experimental"> experimental </link> | 54 | and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node |
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>To query the capabilities of the DV receiver/transmitter applications | ||
59 | can call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node | ||
60 | and the driver will fill in the structure. Note that drivers may return | 55 | and the driver will fill in the structure. Note that drivers may return |
61 | different values after switching the video input or output.</para> | 56 | different values after switching the video input or output.</para> |
62 | 57 | ||
@@ -65,8 +60,8 @@ queried by calling the <constant>VIDIOC_SUBDEV_DV_TIMINGS_CAP</constant> ioctl | |||
65 | directly on a subdevice node. The capabilities are specific to inputs (for DV | 60 | directly on a subdevice node. The capabilities are specific to inputs (for DV |
66 | receivers) or outputs (for DV transmitters), applications must specify the | 61 | receivers) or outputs (for DV transmitters), applications must specify the |
67 | desired pad number in the &v4l2-dv-timings-cap; <structfield>pad</structfield> | 62 | desired pad number in the &v4l2-dv-timings-cap; <structfield>pad</structfield> |
68 | field. Attempts to query capabilities on a pad that doesn't support them will | 63 | field and zero the <structfield>reserved</structfield> array. Attempts to query |
69 | return an &EINVAL;.</para> | 64 | capabilities on a pad that doesn't support them will return an &EINVAL;.</para> |
70 | 65 | ||
71 | <table pgwide="1" frame="none" id="v4l2-bt-timings-cap"> | 66 | <table pgwide="1" frame="none" id="v4l2-bt-timings-cap"> |
72 | <title>struct <structname>v4l2_bt_timings_cap</structname></title> | 67 | <title>struct <structname>v4l2_bt_timings_cap</structname></title> |
@@ -145,7 +140,8 @@ return an &EINVAL;.</para> | |||
145 | <row> | 140 | <row> |
146 | <entry>__u32</entry> | 141 | <entry>__u32</entry> |
147 | <entry><structfield>reserved</structfield>[2]</entry> | 142 | <entry><structfield>reserved</structfield>[2]</entry> |
148 | <entry>Reserved for future extensions. Drivers must set the array to zero.</entry> | 143 | <entry>Reserved for future extensions. Drivers and applications must |
144 | set the array to zero.</entry> | ||
149 | </row> | 145 | </row> |
150 | <row> | 146 | <row> |
151 | <entry>union</entry> | 147 | <entry>union</entry> |
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml index 6e3cadd4e1f9..9b3d42018b69 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml | |||
@@ -49,20 +49,15 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental"> experimental </link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>While some DV receivers or transmitters support a wide range of timings, others | 52 | <para>While some DV receivers or transmitters support a wide range of timings, others |
59 | support only a limited number of timings. With this ioctl applications can enumerate a list | 53 | support only a limited number of timings. With this ioctl applications can enumerate a list |
60 | of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other | 54 | of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other |
61 | standards or even custom timings that are not in this list.</para> | 55 | standards or even custom timings that are not in this list.</para> |
62 | 56 | ||
63 | <para>To query the available timings, applications initialize the | 57 | <para>To query the available timings, applications initialize the |
64 | <structfield>index</structfield> field and zero the reserved array of &v4l2-enum-dv-timings; | 58 | <structfield>index</structfield> field, set the <structfield>pad</structfield> field to 0, |
65 | and call the <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a | 59 | zero the reserved array of &v4l2-enum-dv-timings; and call the |
60 | <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a | ||
66 | pointer to this structure. Drivers fill the rest of the structure or return an | 61 | pointer to this structure. Drivers fill the rest of the structure or return an |
67 | &EINVAL; when the index is out of bounds. To enumerate all supported DV timings, | 62 | &EINVAL; when the index is out of bounds. To enumerate all supported DV timings, |
68 | applications shall begin at index zero, incrementing by one until the | 63 | applications shall begin at index zero, incrementing by one until the |
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml b/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml index 4e8ea65f7282..a0608abc1ab8 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental"> experimental </link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>Enumerates the frequency bands that a tuner or modulator supports. | 52 | <para>Enumerates the frequency bands that a tuner or modulator supports. |
59 | To do this applications initialize the <structfield>tuner</structfield>, | 53 | To do this applications initialize the <structfield>tuner</structfield>, |
60 | <structfield>type</structfield> and <structfield>index</structfield> fields, | 54 | <structfield>type</structfield> and <structfield>index</structfield> fields, |
diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml index 0ae0b6a915d0..a6558a676ef3 100644 --- a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental"> experimental </link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>This ioctl is an extension to the <link linkend="mmap">memory | 52 | <para>This ioctl is an extension to the <link linkend="mmap">memory |
59 | mapping</link> I/O method, therefore it is available only for | 53 | mapping</link> I/O method, therefore it is available only for |
60 | <constant>V4L2_MEMORY_MMAP</constant> buffers. It can be used to export a | 54 | <constant>V4L2_MEMORY_MMAP</constant> buffers. It can be used to export a |
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml index 2702536bbc7c..b7602d30f596 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml | |||
@@ -1,6 +1,6 @@ | |||
1 | <refentry id="vidioc-g-edid"> | 1 | <refentry id="vidioc-g-edid"> |
2 | <refmeta> | 2 | <refmeta> |
3 | <refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID</refentrytitle> | 3 | <refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID, VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</refentrytitle> |
4 | &manvol; | 4 | &manvol; |
5 | </refmeta> | 5 | </refmeta> |
6 | 6 | ||
@@ -71,7 +71,8 @@ | |||
71 | 71 | ||
72 | <para>To get the EDID data the application has to fill in the <structfield>pad</structfield>, | 72 | <para>To get the EDID data the application has to fill in the <structfield>pad</structfield>, |
73 | <structfield>start_block</structfield>, <structfield>blocks</structfield> and <structfield>edid</structfield> | 73 | <structfield>start_block</structfield>, <structfield>blocks</structfield> and <structfield>edid</structfield> |
74 | fields and call <constant>VIDIOC_G_EDID</constant>. The current EDID from block | 74 | fields, zero the <structfield>reserved</structfield> array and call |
75 | <constant>VIDIOC_G_EDID</constant>. The current EDID from block | ||
75 | <structfield>start_block</structfield> and of size <structfield>blocks</structfield> | 76 | <structfield>start_block</structfield> and of size <structfield>blocks</structfield> |
76 | will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield> | 77 | will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield> |
77 | pointer must point to memory at least <structfield>blocks</structfield> * 128 bytes | 78 | pointer must point to memory at least <structfield>blocks</structfield> * 128 bytes |
@@ -92,8 +93,9 @@ | |||
92 | the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para> | 93 | the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para> |
93 | 94 | ||
94 | <para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>, | 95 | <para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>, |
95 | <structfield>blocks</structfield> and <structfield>edid</structfield> fields and set | 96 | <structfield>blocks</structfield> and <structfield>edid</structfield> fields, set |
96 | <structfield>start_block</structfield> to 0. It is not possible to set part of an EDID, | 97 | <structfield>start_block</structfield> to 0 and zero the <structfield>reserved</structfield> array. |
98 | It is not possible to set part of an EDID, | ||
97 | it is always all or nothing. Setting the EDID data is only valid for receivers as it makes | 99 | it is always all or nothing. Setting the EDID data is only valid for receivers as it makes |
98 | no sense for a transmitter.</para> | 100 | no sense for a transmitter.</para> |
99 | 101 | ||
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml index 7865351688da..9523bc5650f9 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml | |||
@@ -50,12 +50,6 @@ | |||
50 | <refsect1> | 50 | <refsect1> |
51 | <title>Description</title> | 51 | <title>Description</title> |
52 | 52 | ||
53 | <note> | ||
54 | <title>Experimental</title> | ||
55 | <para>This is an <link linkend="experimental"> experimental </link> | ||
56 | interface and may change in the future.</para> | ||
57 | </note> | ||
58 | |||
59 | <para>The ioctls are used to query and configure selection rectangles.</para> | 53 | <para>The ioctls are used to query and configure selection rectangles.</para> |
60 | 54 | ||
61 | <para>To query the cropping (composing) rectangle set &v4l2-selection; | 55 | <para>To query the cropping (composing) rectangle set &v4l2-selection; |
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml index fa7ad7e33228..7bde698760e4 100644 --- a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml | |||
@@ -48,12 +48,6 @@ | |||
48 | <refsect1> | 48 | <refsect1> |
49 | <title>Description</title> | 49 | <title>Description</title> |
50 | 50 | ||
51 | <note> | ||
52 | <title>Experimental</title> | ||
53 | <para>This is an <link linkend="experimental"> experimental </link> | ||
54 | interface and may change in the future.</para> | ||
55 | </note> | ||
56 | |||
57 | <para>Applications can optionally call the | 51 | <para>Applications can optionally call the |
58 | <constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer | 52 | <constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer |
59 | to the driver before actually enqueuing it, using the | 53 | to the driver before actually enqueuing it, using the |
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml index 0c93677d16b4..d41bf47ee5a2 100644 --- a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml +++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml | |||
@@ -50,12 +50,6 @@ input</refpurpose> | |||
50 | <refsect1> | 50 | <refsect1> |
51 | <title>Description</title> | 51 | <title>Description</title> |
52 | 52 | ||
53 | <note> | ||
54 | <title>Experimental</title> | ||
55 | <para>This is an <link linkend="experimental"> experimental </link> | ||
56 | interface and may change in the future.</para> | ||
57 | </note> | ||
58 | |||
59 | <para>The hardware may be able to detect the current DV timings | 53 | <para>The hardware may be able to detect the current DV timings |
60 | automatically, similar to sensing the video standard. To do so, applications | 54 | automatically, similar to sensing the video standard. To do so, applications |
61 | call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a | 55 | call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a |
diff --git a/Documentation/DocBook/media/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml index df2c63d07bac..89fd7ce964f9 100644 --- a/Documentation/DocBook/media/v4l/vidioc-streamon.xml +++ b/Documentation/DocBook/media/v4l/vidioc-streamon.xml | |||
@@ -123,6 +123,14 @@ synchronize with other events.</para> | |||
123 | </para> | 123 | </para> |
124 | </listitem> | 124 | </listitem> |
125 | </varlistentry> | 125 | </varlistentry> |
126 | <varlistentry> | ||
127 | <term><errorcode>ENOLINK</errorcode></term> | ||
128 | <listitem> | ||
129 | <para>The driver implements Media Controller interface and | ||
130 | the pipeline link configuration is invalid. | ||
131 | </para> | ||
132 | </listitem> | ||
133 | </varlistentry> | ||
126 | </variablelist> | 134 | </variablelist> |
127 | </refsect1> | 135 | </refsect1> |
128 | </refentry> | 136 | </refentry> |
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml index cff59f5cbf04..9d0251a27e5f 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental">experimental</link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>This ioctl lets applications enumerate available frame intervals on a | 52 | <para>This ioctl lets applications enumerate available frame intervals on a |
59 | given sub-device pad. Frame intervals only makes sense for sub-devices that | 53 | given sub-device pad. Frame intervals only makes sense for sub-devices that |
60 | can control the frame period on their own. This includes, for instance, | 54 | can control the frame period on their own. This includes, for instance, |
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml index abd545ede67a..9b91b8332ba9 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental">experimental</link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>This ioctl allows applications to enumerate all frame sizes | 52 | <para>This ioctl allows applications to enumerate all frame sizes |
59 | supported by a sub-device on the given pad for the given media bus format. | 53 | supported by a sub-device on the given pad for the given media bus format. |
60 | Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE; | 54 | Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE; |
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml index 0bcb278fd062..c67256ada87a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental">experimental</link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>To enumerate media bus formats available at a given sub-device pad | 52 | <para>To enumerate media bus formats available at a given sub-device pad |
59 | applications initialize the <structfield>pad</structfield>, <structfield>which</structfield> | 53 | applications initialize the <structfield>pad</structfield>, <structfield>which</structfield> |
60 | and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and | 54 | and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and |
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml index a67cde6f8c54..781089cba453 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml | |||
@@ -50,12 +50,6 @@ | |||
50 | <refsect1> | 50 | <refsect1> |
51 | <title>Description</title> | 51 | <title>Description</title> |
52 | 52 | ||
53 | <note> | ||
54 | <title>Experimental</title> | ||
55 | <para>This is an <link linkend="experimental">experimental</link> | ||
56 | interface and may change in the future.</para> | ||
57 | </note> | ||
58 | |||
59 | <para>These ioctls are used to negotiate the frame format at specific | 53 | <para>These ioctls are used to negotiate the frame format at specific |
60 | subdev pads in the image pipeline.</para> | 54 | subdev pads in the image pipeline.</para> |
61 | 55 | ||
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml index 0bc3ea22d31f..848ec789ddaa 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml | |||
@@ -50,12 +50,6 @@ | |||
50 | <refsect1> | 50 | <refsect1> |
51 | <title>Description</title> | 51 | <title>Description</title> |
52 | 52 | ||
53 | <note> | ||
54 | <title>Experimental</title> | ||
55 | <para>This is an <link linkend="experimental">experimental</link> | ||
56 | interface and may change in the future.</para> | ||
57 | </note> | ||
58 | |||
59 | <para>These ioctls are used to get and set the frame interval at specific | 53 | <para>These ioctls are used to get and set the frame interval at specific |
60 | subdev pads in the image pipeline. The frame interval only makes sense for | 54 | subdev pads in the image pipeline. The frame interval only makes sense for |
61 | sub-devices that can control the frame period on their own. This includes, | 55 | sub-devices that can control the frame period on their own. This includes, |
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml index c62a7360719b..8346b2e4a703 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml | |||
@@ -49,12 +49,6 @@ | |||
49 | <refsect1> | 49 | <refsect1> |
50 | <title>Description</title> | 50 | <title>Description</title> |
51 | 51 | ||
52 | <note> | ||
53 | <title>Experimental</title> | ||
54 | <para>This is an <link linkend="experimental">experimental</link> | ||
55 | interface and may change in the future.</para> | ||
56 | </note> | ||
57 | |||
58 | <para>The selections are used to configure various image | 52 | <para>The selections are used to configure various image |
59 | processing functionality performed by the subdevs which affect the | 53 | processing functionality performed by the subdevs which affect the |
60 | image size. This currently includes cropping, scaling and | 54 | image size. This currently includes cropping, scaling and |
diff --git a/Documentation/Makefile b/Documentation/Makefile index 1207d7907650..f3b04d22957c 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | subdir-y := accounting auxdisplay blackfin connector \ | 1 | subdir-y := accounting auxdisplay blackfin connector \ |
2 | filesystems filesystems ia64 laptops mic misc-devices \ | 2 | filesystems filesystems ia64 laptops mic misc-devices \ |
3 | networking pcmcia prctl ptp timers vDSO video4linux \ | 3 | networking pcmcia prctl ptp timers vDSO watchdog |
4 | watchdog | ||
diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.txt b/Documentation/devicetree/bindings/media/i2c/adv7180.txt new file mode 100644 index 000000000000..0d501154dfb2 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | * Analog Devices ADV7180 analog video decoder family | ||
2 | |||
3 | The adv7180 family devices are used to capture analog video to different | ||
4 | digital interfaces like MIPI CSI-2 or parallel video. | ||
5 | |||
6 | Required Properties : | ||
7 | - compatible : value must be one of | ||
8 | "adi,adv7180" | ||
9 | "adi,adv7182" | ||
10 | "adi,adv7280" | ||
11 | "adi,adv7280-m" | ||
12 | "adi,adv7281" | ||
13 | "adi,adv7281-m" | ||
14 | "adi,adv7281-ma" | ||
15 | "adi,adv7282" | ||
16 | "adi,adv7282-m" | ||
17 | |||
18 | Example: | ||
19 | |||
20 | i2c0@1c22000 { | ||
21 | ... | ||
22 | ... | ||
23 | adv7180@21 { | ||
24 | compatible = "adi,adv7180"; | ||
25 | reg = <0x21>; | ||
26 | }; | ||
27 | ... | ||
28 | }; | ||
29 | |||
diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt index 619193ccf7ff..6a4e61cbe011 100644 --- a/Documentation/devicetree/bindings/media/rcar_vin.txt +++ b/Documentation/devicetree/bindings/media/rcar_vin.txt | |||
@@ -5,14 +5,22 @@ The rcar_vin device provides video input capabilities for the Renesas R-Car | |||
5 | family of devices. The current blocks are always slaves and suppot one input | 5 | family of devices. The current blocks are always slaves and suppot one input |
6 | channel which can be either RGB, YUYV or BT656. | 6 | channel which can be either RGB, YUYV or BT656. |
7 | 7 | ||
8 | - compatible: Must be one of the following | 8 | - compatible: Must be one or more of the following |
9 | - "renesas,vin-r8a7795" for the R8A7795 device | 9 | - "renesas,vin-r8a7795" for the R8A7795 device |
10 | - "renesas,vin-r8a7794" for the R8A7794 device | 10 | - "renesas,vin-r8a7794" for the R8A7794 device |
11 | - "renesas,vin-r8a7793" for the R8A7793 device | 11 | - "renesas,vin-r8a7793" for the R8A7793 device |
12 | - "renesas,vin-r8a7792" for the R8A7792 device | ||
12 | - "renesas,vin-r8a7791" for the R8A7791 device | 13 | - "renesas,vin-r8a7791" for the R8A7791 device |
13 | - "renesas,vin-r8a7790" for the R8A7790 device | 14 | - "renesas,vin-r8a7790" for the R8A7790 device |
14 | - "renesas,vin-r8a7779" for the R8A7779 device | 15 | - "renesas,vin-r8a7779" for the R8A7779 device |
15 | - "renesas,vin-r8a7778" for the R8A7778 device | 16 | - "renesas,vin-r8a7778" for the R8A7778 device |
17 | - "renesas,rcar-gen2-vin" for a generic R-Car Gen2 compatible device. | ||
18 | - "renesas,rcar-gen3-vin" for a generic R-Car Gen3 compatible device. | ||
19 | |||
20 | When compatible with the generic version nodes must list the | ||
21 | SoC-specific version corresponding to the platform first | ||
22 | followed by the generic version. | ||
23 | |||
16 | - reg: the register base and size for the device registers | 24 | - reg: the register base and size for the device registers |
17 | - interrupts: the interrupt for the device | 25 | - interrupts: the interrupt for the device |
18 | - clocks: Reference to the parent clock | 26 | - clocks: Reference to the parent clock |
@@ -37,7 +45,7 @@ Device node example | |||
37 | }; | 45 | }; |
38 | 46 | ||
39 | vin0: vin@0xe6ef0000 { | 47 | vin0: vin@0xe6ef0000 { |
40 | compatible = "renesas,vin-r8a7790"; | 48 | compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin"; |
41 | clocks = <&mstp8_clks R8A7790_CLK_VIN0>; | 49 | clocks = <&mstp8_clks R8A7790_CLK_VIN0>; |
42 | reg = <0 0xe6ef0000 0 0x1000>; | 50 | reg = <0 0xe6ef0000 0 0x1000>; |
43 | interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>; | 51 | interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>; |
diff --git a/Documentation/devicetree/bindings/media/xilinx/video.txt b/Documentation/devicetree/bindings/media/xilinx/video.txt index cbd46fa0988f..68ac210e688e 100644 --- a/Documentation/devicetree/bindings/media/xilinx/video.txt +++ b/Documentation/devicetree/bindings/media/xilinx/video.txt | |||
@@ -20,7 +20,7 @@ The following properties are common to all Xilinx video IP cores. | |||
20 | - xlnx,video-format: This property represents a video format transmitted on an | 20 | - xlnx,video-format: This property represents a video format transmitted on an |
21 | AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream | 21 | AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream |
22 | Video IP and System Design Guide" [UG934]. How the format relates to the IP | 22 | Video IP and System Design Guide" [UG934]. How the format relates to the IP |
23 | core is decribed in the IP core bindings documentation. | 23 | core is described in the IP core bindings documentation. |
24 | 24 | ||
25 | - xlnx,video-width: This property qualifies the video format with the sample | 25 | - xlnx,video-width: This property qualifies the video format with the sample |
26 | width expressed as a number of bits per pixel component. All components must | 26 | width expressed as a number of bits per pixel component. All components must |
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 44a4cfbfdc40..85a8fdcfcdaa 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 | |||
@@ -52,3 +52,5 @@ | |||
52 | 51 -> DVBSky T982 [4254:0982] | 52 | 51 -> DVBSky T982 [4254:0982] |
53 | 52 -> Hauppauge WinTV-HVR5525 [0070:f038] | 53 | 52 -> Hauppauge WinTV-HVR5525 [0070:f038] |
54 | 53 -> Hauppauge WinTV Starburst [0070:c12a] | 54 | 53 -> Hauppauge WinTV Starburst [0070:c12a] |
55 | 54 -> ViewCast 260e [1576:0260] | ||
56 | 55 -> ViewCast 460e [1576:0460] | ||
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 67209998a439..6784220c6a16 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx | |||
@@ -76,9 +76,9 @@ | |||
76 | 75 -> Dikom DK300 (em2882) | 76 | 75 -> Dikom DK300 (em2882) |
77 | 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] | 77 | 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] |
78 | 77 -> EM2874 Leadership ISDBT (em2874) | 78 | 77 -> EM2874 Leadership ISDBT (em2874) |
79 | 78 -> PCTV nanoStick T2 290e (em28174) | 79 | 78 -> PCTV nanoStick T2 290e (em28174) [2013:024f] |
80 | 79 -> Terratec Cinergy H5 (em2884) [eb1a:2885,0ccd:10a2,0ccd:10ad,0ccd:10b6] | 80 | 79 -> Terratec Cinergy H5 (em2884) [eb1a:2885,0ccd:10a2,0ccd:10ad,0ccd:10b6] |
81 | 80 -> PCTV DVB-S2 Stick (460e) (em28174) | 81 | 80 -> PCTV DVB-S2 Stick (460e) (em28174) [2013:024c] |
82 | 81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605] | 82 | 81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605] |
83 | 82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2] | 83 | 82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2] |
84 | 83 -> Honestech Vidbox NW03 (em2860) [eb1a:5006] | 84 | 83 -> Honestech Vidbox NW03 (em2860) [eb1a:5006] |
@@ -90,9 +90,11 @@ | |||
90 | 89 -> Delock 61959 (em2874) [1b80:e1cc] | 90 | 89 -> Delock 61959 (em2874) [1b80:e1cc] |
91 | 90 -> KWorld USB ATSC TV Stick UB435-Q V2 (em2874) [1b80:e346] | 91 | 90 -> KWorld USB ATSC TV Stick UB435-Q V2 (em2874) [1b80:e346] |
92 | 91 -> SpeedLink Vicious And Devine Laplace webcam (em2765) [1ae7:9003,1ae7:9004] | 92 | 91 -> SpeedLink Vicious And Devine Laplace webcam (em2765) [1ae7:9003,1ae7:9004] |
93 | 92 -> PCTV DVB-S2 Stick (461e) (em28178) | 93 | 92 -> PCTV DVB-S2 Stick (461e) (em28178) [2013:0258] |
94 | 93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c] | 94 | 93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c] |
95 | 94 -> PCTV tripleStick (292e) (em28178) | 95 | 94 -> PCTV tripleStick (292e) (em28178) [2013:025f,2040:0264] |
96 | 95 -> Leadtek VC100 (em2861) [0413:6f07] | 96 | 95 -> Leadtek VC100 (em2861) [0413:6f07] |
97 | 96 -> Terratec Cinergy T2 Stick HD (em28178) | 97 | 96 -> Terratec Cinergy T2 Stick HD (em28178) [eb1a:8179] |
98 | 97 -> Elgato EyeTV Hybrid 2008 INT (em2884) [0fd9:0018] | 98 | 97 -> Elgato EyeTV Hybrid 2008 INT (em2884) [0fd9:0018] |
99 | 98 -> PLEX PX-BCUD (em28178) [3275:0085] | ||
100 | 99 -> Hauppauge WinTV-dualHD DVB (em28174) [2040:0265] | ||
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index fa41608ab2b4..cbefc7902f5f 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt | |||
@@ -35,7 +35,7 @@ need and this same framework should make it much easier to refactor | |||
35 | common code into utility functions shared by all drivers. | 35 | common code into utility functions shared by all drivers. |
36 | 36 | ||
37 | A good example to look at as a reference is the v4l2-pci-skeleton.c | 37 | A good example to look at as a reference is the v4l2-pci-skeleton.c |
38 | source that is available in this directory. It is a skeleton driver for | 38 | source that is available in samples/v4l/. It is a skeleton driver for |
39 | a PCI capture card, and demonstrates how to use the V4L2 driver | 39 | a PCI capture card, and demonstrates how to use the V4L2 driver |
40 | framework. It can be used as a template for real PCI video capture driver. | 40 | framework. It can be used as a template for real PCI video capture driver. |
41 | 41 | ||
diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt index e35d376b7f64..8da5d2a576bc 100644 --- a/Documentation/video4linux/vivid.txt +++ b/Documentation/video4linux/vivid.txt | |||
@@ -294,7 +294,7 @@ the result will be. | |||
294 | 294 | ||
295 | These inputs support all combinations of the field setting. Special care has | 295 | These inputs support all combinations of the field setting. Special care has |
296 | been taken to faithfully reproduce how fields are handled for the different | 296 | been taken to faithfully reproduce how fields are handled for the different |
297 | TV standards. This is particularly noticable when generating a horizontally | 297 | TV standards. This is particularly noticeable when generating a horizontally |
298 | moving image so the temporal effect of using interlaced formats becomes clearly | 298 | moving image so the temporal effect of using interlaced formats becomes clearly |
299 | visible. For 50 Hz standards the top field is the oldest and the bottom field | 299 | visible. For 50 Hz standards the top field is the oldest and the bottom field |
300 | is the newest in time. For 60 Hz standards that is reversed: the bottom field | 300 | is the newest in time. For 60 Hz standards that is reversed: the bottom field |
@@ -313,7 +313,7 @@ will be SMPTE-170M. | |||
313 | The pixel aspect ratio will depend on the TV standard. The video aspect ratio | 313 | The pixel aspect ratio will depend on the TV standard. The video aspect ratio |
314 | can be selected through the 'Standard Aspect Ratio' Vivid control. | 314 | can be selected through the 'Standard Aspect Ratio' Vivid control. |
315 | Choices are '4x3', '16x9' which will give letterboxed widescreen video and | 315 | Choices are '4x3', '16x9' which will give letterboxed widescreen video and |
316 | '16x9 Anomorphic' which will give full screen squashed anamorphic widescreen | 316 | '16x9 Anamorphic' which will give full screen squashed anamorphic widescreen |
317 | video that will need to be scaled accordingly. | 317 | video that will need to be scaled accordingly. |
318 | 318 | ||
319 | The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available | 319 | The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available |
@@ -862,7 +862,7 @@ RDS Radio Text: | |||
862 | RDS Stereo: | 862 | RDS Stereo: |
863 | RDS Artificial Head: | 863 | RDS Artificial Head: |
864 | RDS Compressed: | 864 | RDS Compressed: |
865 | RDS Dymanic PTY: | 865 | RDS Dynamic PTY: |
866 | RDS Traffic Announcement: | 866 | RDS Traffic Announcement: |
867 | RDS Traffic Program: | 867 | RDS Traffic Program: |
868 | RDS Music: these are all controls that set the RDS data that is transmitted by | 868 | RDS Music: these are all controls that set the RDS data that is transmitted by |
diff --git a/MAINTAINERS b/MAINTAINERS index c7dd1a3401e5..add406a46231 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -11338,6 +11338,14 @@ W: https://linuxtv.org | |||
11338 | S: Odd Fixes | 11338 | S: Odd Fixes |
11339 | F: drivers/media/pci/tw68/ | 11339 | F: drivers/media/pci/tw68/ |
11340 | 11340 | ||
11341 | TW686X VIDEO4LINUX DRIVER | ||
11342 | M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> | ||
11343 | L: linux-media@vger.kernel.org | ||
11344 | T: git git://linuxtv.org/media_tree.git | ||
11345 | W: http://linuxtv.org | ||
11346 | S: Maintained | ||
11347 | F: drivers/media/pci/tw686x/ | ||
11348 | |||
11341 | TPM DEVICE DRIVER | 11349 | TPM DEVICE DRIVER |
11342 | M: Peter Huewe <peterhuewe@gmx.de> | 11350 | M: Peter Huewe <peterhuewe@gmx.de> |
11343 | M: Marcel Selhorst <tpmdd@selhorst.net> | 11351 | M: Marcel Selhorst <tpmdd@selhorst.net> |
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 21154dd87b0b..326df0ad75c0 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig | |||
@@ -19,3 +19,4 @@ config CYPRESS_FIRMWARE | |||
19 | source "drivers/media/common/b2c2/Kconfig" | 19 | source "drivers/media/common/b2c2/Kconfig" |
20 | source "drivers/media/common/saa7146/Kconfig" | 20 | source "drivers/media/common/saa7146/Kconfig" |
21 | source "drivers/media/common/siano/Kconfig" | 21 | source "drivers/media/common/siano/Kconfig" |
22 | source "drivers/media/common/v4l2-tpg/Kconfig" | ||
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 89b795df2cdd..2d1b0a025084 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y += b2c2/ saa7146/ siano/ | 1 | obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ |
2 | obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o | 2 | obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o |
3 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | 3 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o |
4 | obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o | 4 | obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o |
diff --git a/drivers/media/common/v4l2-tpg/Kconfig b/drivers/media/common/v4l2-tpg/Kconfig new file mode 100644 index 000000000000..7456fc1c41ed --- /dev/null +++ b/drivers/media/common/v4l2-tpg/Kconfig | |||
@@ -0,0 +1,2 @@ | |||
1 | config VIDEO_V4L2_TPG | ||
2 | tristate | ||
diff --git a/drivers/media/common/v4l2-tpg/Makefile b/drivers/media/common/v4l2-tpg/Makefile new file mode 100644 index 000000000000..f588df466ae3 --- /dev/null +++ b/drivers/media/common/v4l2-tpg/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | v4l2-tpg-objs := v4l2-tpg-core.o v4l2-tpg-colors.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_V4L2_TPG) += v4l2-tpg.o | ||
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c index 2299f0ce47c8..9bcbd318489b 100644 --- a/drivers/media/platform/vivid/vivid-tpg-colors.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * vivid-color.c - A table that converts colors to various colorspaces | 2 | * v4l2-tpg-colors.c - A table that converts colors to various colorspaces |
3 | * | 3 | * |
4 | * The test pattern generator uses the tpg_colors for its test patterns. | 4 | * The test pattern generator uses the tpg_colors for its test patterns. |
5 | * For testing colorspaces the first 8 colors of that table need to be | 5 | * For testing colorspaces the first 8 colors of that table need to be |
@@ -12,7 +12,7 @@ | |||
12 | * This source also contains the code used to generate the tpg_csc_colors | 12 | * This source also contains the code used to generate the tpg_csc_colors |
13 | * table. Run the following command to compile it: | 13 | * table. Run the following command to compile it: |
14 | * | 14 | * |
15 | * gcc vivid-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm | 15 | * gcc v4l2-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm |
16 | * | 16 | * |
17 | * and run the utility. | 17 | * and run the utility. |
18 | * | 18 | * |
@@ -36,8 +36,7 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/videodev2.h> | 38 | #include <linux/videodev2.h> |
39 | 39 | #include <media/v4l2-tpg-colors.h> | |
40 | #include "vivid-tpg-colors.h" | ||
41 | 40 | ||
42 | /* sRGB colors with range [0-255] */ | 41 | /* sRGB colors with range [0-255] */ |
43 | const struct color tpg_colors[TPG_COLOR_MAX] = { | 42 | const struct color tpg_colors[TPG_COLOR_MAX] = { |
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index da862bb2e5f8..cf1dadd0be9e 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * vivid-tpg.c - Test Pattern Generator | 2 | * v4l2-tpg-core.c - Test Pattern Generator |
3 | * | 3 | * |
4 | * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the | 4 | * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the |
5 | * vivi.c source for the copyright information of those functions. | 5 | * vivi.c source for the copyright information of those functions. |
@@ -20,7 +20,8 @@ | |||
20 | * SOFTWARE. | 20 | * SOFTWARE. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include "vivid-tpg.h" | 23 | #include <linux/module.h> |
24 | #include <media/v4l2-tpg.h> | ||
24 | 25 | ||
25 | /* Must remain in sync with enum tpg_pattern */ | 26 | /* Must remain in sync with enum tpg_pattern */ |
26 | const char * const tpg_pattern_strings[] = { | 27 | const char * const tpg_pattern_strings[] = { |
@@ -48,6 +49,7 @@ const char * const tpg_pattern_strings[] = { | |||
48 | "Noise", | 49 | "Noise", |
49 | NULL | 50 | NULL |
50 | }; | 51 | }; |
52 | EXPORT_SYMBOL_GPL(tpg_pattern_strings); | ||
51 | 53 | ||
52 | /* Must remain in sync with enum tpg_aspect */ | 54 | /* Must remain in sync with enum tpg_aspect */ |
53 | const char * const tpg_aspect_strings[] = { | 55 | const char * const tpg_aspect_strings[] = { |
@@ -58,6 +60,7 @@ const char * const tpg_aspect_strings[] = { | |||
58 | "16x9 Anamorphic", | 60 | "16x9 Anamorphic", |
59 | NULL | 61 | NULL |
60 | }; | 62 | }; |
63 | EXPORT_SYMBOL_GPL(tpg_aspect_strings); | ||
61 | 64 | ||
62 | /* | 65 | /* |
63 | * Sine table: sin[0] = 127 * sin(-180 degrees) | 66 | * Sine table: sin[0] = 127 * sin(-180 degrees) |
@@ -93,6 +96,7 @@ void tpg_set_font(const u8 *f) | |||
93 | { | 96 | { |
94 | font8x16 = f; | 97 | font8x16 = f; |
95 | } | 98 | } |
99 | EXPORT_SYMBOL_GPL(tpg_set_font); | ||
96 | 100 | ||
97 | void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h) | 101 | void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h) |
98 | { | 102 | { |
@@ -114,6 +118,7 @@ void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h) | |||
114 | tpg->colorspace = V4L2_COLORSPACE_SRGB; | 118 | tpg->colorspace = V4L2_COLORSPACE_SRGB; |
115 | tpg->perc_fill = 100; | 119 | tpg->perc_fill = 100; |
116 | } | 120 | } |
121 | EXPORT_SYMBOL_GPL(tpg_init); | ||
117 | 122 | ||
118 | int tpg_alloc(struct tpg_data *tpg, unsigned max_w) | 123 | int tpg_alloc(struct tpg_data *tpg, unsigned max_w) |
119 | { | 124 | { |
@@ -150,6 +155,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) | |||
150 | } | 155 | } |
151 | return 0; | 156 | return 0; |
152 | } | 157 | } |
158 | EXPORT_SYMBOL_GPL(tpg_alloc); | ||
153 | 159 | ||
154 | void tpg_free(struct tpg_data *tpg) | 160 | void tpg_free(struct tpg_data *tpg) |
155 | { | 161 | { |
@@ -174,6 +180,7 @@ void tpg_free(struct tpg_data *tpg) | |||
174 | tpg->random_line[plane] = NULL; | 180 | tpg->random_line[plane] = NULL; |
175 | } | 181 | } |
176 | } | 182 | } |
183 | EXPORT_SYMBOL_GPL(tpg_free); | ||
177 | 184 | ||
178 | bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) | 185 | bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) |
179 | { | 186 | { |
@@ -403,6 +410,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) | |||
403 | } | 410 | } |
404 | return true; | 411 | return true; |
405 | } | 412 | } |
413 | EXPORT_SYMBOL_GPL(tpg_s_fourcc); | ||
406 | 414 | ||
407 | void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, | 415 | void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, |
408 | const struct v4l2_rect *compose) | 416 | const struct v4l2_rect *compose) |
@@ -418,6 +426,7 @@ void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, | |||
418 | tpg->scaled_width = 2; | 426 | tpg->scaled_width = 2; |
419 | tpg->recalc_lines = true; | 427 | tpg->recalc_lines = true; |
420 | } | 428 | } |
429 | EXPORT_SYMBOL_GPL(tpg_s_crop_compose); | ||
421 | 430 | ||
422 | void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, | 431 | void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, |
423 | u32 field) | 432 | u32 field) |
@@ -442,6 +451,7 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, | |||
442 | (2 * tpg->hdownsampling[p]); | 451 | (2 * tpg->hdownsampling[p]); |
443 | tpg->recalc_square_border = true; | 452 | tpg->recalc_square_border = true; |
444 | } | 453 | } |
454 | EXPORT_SYMBOL_GPL(tpg_reset_source); | ||
445 | 455 | ||
446 | static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg) | 456 | static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg) |
447 | { | 457 | { |
@@ -1250,6 +1260,7 @@ unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line) | |||
1250 | return 0; | 1260 | return 0; |
1251 | } | 1261 | } |
1252 | } | 1262 | } |
1263 | EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane); | ||
1253 | 1264 | ||
1254 | /* Return how many pattern lines are used by the current pattern. */ | 1265 | /* Return how many pattern lines are used by the current pattern. */ |
1255 | static unsigned tpg_get_pat_lines(const struct tpg_data *tpg) | 1266 | static unsigned tpg_get_pat_lines(const struct tpg_data *tpg) |
@@ -1725,6 +1736,7 @@ void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | |||
1725 | } | 1736 | } |
1726 | } | 1737 | } |
1727 | } | 1738 | } |
1739 | EXPORT_SYMBOL_GPL(tpg_gen_text); | ||
1728 | 1740 | ||
1729 | void tpg_update_mv_step(struct tpg_data *tpg) | 1741 | void tpg_update_mv_step(struct tpg_data *tpg) |
1730 | { | 1742 | { |
@@ -1773,6 +1785,7 @@ void tpg_update_mv_step(struct tpg_data *tpg) | |||
1773 | if (factor < 0) | 1785 | if (factor < 0) |
1774 | tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step; | 1786 | tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step; |
1775 | } | 1787 | } |
1788 | EXPORT_SYMBOL_GPL(tpg_update_mv_step); | ||
1776 | 1789 | ||
1777 | /* Map the line number relative to the crop rectangle to a frame line number */ | 1790 | /* Map the line number relative to the crop rectangle to a frame line number */ |
1778 | static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y, | 1791 | static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y, |
@@ -1862,6 +1875,7 @@ void tpg_calc_text_basep(struct tpg_data *tpg, | |||
1862 | if (p == 0 && tpg->interleaved) | 1875 | if (p == 0 && tpg->interleaved) |
1863 | tpg_calc_text_basep(tpg, basep, 1, vbuf); | 1876 | tpg_calc_text_basep(tpg, basep, 1, vbuf); |
1864 | } | 1877 | } |
1878 | EXPORT_SYMBOL_GPL(tpg_calc_text_basep); | ||
1865 | 1879 | ||
1866 | static int tpg_pattern_avg(const struct tpg_data *tpg, | 1880 | static int tpg_pattern_avg(const struct tpg_data *tpg, |
1867 | unsigned pat1, unsigned pat2) | 1881 | unsigned pat1, unsigned pat2) |
@@ -1891,6 +1905,7 @@ void tpg_log_status(struct tpg_data *tpg) | |||
1891 | pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization); | 1905 | pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization); |
1892 | pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); | 1906 | pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); |
1893 | } | 1907 | } |
1908 | EXPORT_SYMBOL_GPL(tpg_log_status); | ||
1894 | 1909 | ||
1895 | /* | 1910 | /* |
1896 | * This struct contains common parameters used by both the drawing of the | 1911 | * This struct contains common parameters used by both the drawing of the |
@@ -2296,6 +2311,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, | |||
2296 | vbuf + buf_line * params.stride); | 2311 | vbuf + buf_line * params.stride); |
2297 | } | 2312 | } |
2298 | } | 2313 | } |
2314 | EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer); | ||
2299 | 2315 | ||
2300 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) | 2316 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) |
2301 | { | 2317 | { |
@@ -2312,3 +2328,8 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) | |||
2312 | offset += tpg_calc_plane_size(tpg, i); | 2328 | offset += tpg_calc_plane_size(tpg, i); |
2313 | } | 2329 | } |
2314 | } | 2330 | } |
2331 | EXPORT_SYMBOL_GPL(tpg_fillbuffer); | ||
2332 | |||
2333 | MODULE_DESCRIPTION("V4L2 Test Pattern Generator"); | ||
2334 | MODULE_AUTHOR("Hans Verkuil"); | ||
2335 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 0afad395ef97..a7a4674ccc40 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h | |||
@@ -58,6 +58,14 @@ | |||
58 | #define USB_VID_TELESTAR 0x10b9 | 58 | #define USB_VID_TELESTAR 0x10b9 |
59 | #define USB_VID_VISIONPLUS 0x13d3 | 59 | #define USB_VID_VISIONPLUS 0x13d3 |
60 | #define USB_VID_SONY 0x1415 | 60 | #define USB_VID_SONY 0x1415 |
61 | #define USB_PID_TEVII_S421 0xd421 | ||
62 | #define USB_PID_TEVII_S480_1 0xd481 | ||
63 | #define USB_PID_TEVII_S480_2 0xd482 | ||
64 | #define USB_PID_TEVII_S630 0xd630 | ||
65 | #define USB_PID_TEVII_S632 0xd632 | ||
66 | #define USB_PID_TEVII_S650 0xd650 | ||
67 | #define USB_PID_TEVII_S660 0xd660 | ||
68 | #define USB_PID_TEVII_S662 0xd662 | ||
61 | #define USB_VID_TWINHAN 0x1822 | 69 | #define USB_VID_TWINHAN 0x1822 |
62 | #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 | 70 | #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 |
63 | #define USB_VID_UNIWILL 0x1584 | 71 | #define USB_VID_UNIWILL 0x1584 |
@@ -141,6 +149,7 @@ | |||
141 | #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 | 149 | #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 |
142 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 | 150 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 |
143 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 | 151 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 |
152 | #define USB_PID_GOTVIEW_SAT_HD 0x5456 | ||
144 | #define USB_PID_INTEL_CE9500 0x9500 | 153 | #define USB_PID_INTEL_CE9500 0x9500 |
145 | #define USB_PID_ITETECH_IT9135 0x9135 | 154 | #define USB_PID_ITETECH_IT9135 0x9135 |
146 | #define USB_PID_ITETECH_IT9135_9005 0x9005 | 155 | #define USB_PID_ITETECH_IT9135_9005 0x9005 |
@@ -159,6 +168,8 @@ | |||
159 | #define USB_PID_KWORLD_UB499_2T_T09 0xe409 | 168 | #define USB_PID_KWORLD_UB499_2T_T09 0xe409 |
160 | #define USB_PID_KWORLD_VSTREAM_COLD 0x17de | 169 | #define USB_PID_KWORLD_VSTREAM_COLD 0x17de |
161 | #define USB_PID_KWORLD_VSTREAM_WARM 0x17df | 170 | #define USB_PID_KWORLD_VSTREAM_WARM 0x17df |
171 | #define USB_PID_PROF_1100 0xb012 | ||
172 | #define USB_PID_TERRATEC_CINERGY_S 0x0064 | ||
162 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 | 173 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 |
163 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 | 174 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 |
164 | #define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 | 175 | #define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 |
@@ -361,6 +372,8 @@ | |||
361 | #define USB_PID_YUAN_STK7700D 0x1efc | 372 | #define USB_PID_YUAN_STK7700D 0x1efc |
362 | #define USB_PID_YUAN_STK7700D_2 0x1e8c | 373 | #define USB_PID_YUAN_STK7700D_2 0x1e8c |
363 | #define USB_PID_DW2102 0x2102 | 374 | #define USB_PID_DW2102 0x2102 |
375 | #define USB_PID_DW2104 0x2104 | ||
376 | #define USB_PID_DW3101 0x3101 | ||
364 | #define USB_PID_XTENSIONS_XD_380 0x0381 | 377 | #define USB_PID_XTENSIONS_XD_380 0x0381 |
365 | #define USB_PID_TELESTAR_STARSTICK_2 0x8000 | 378 | #define USB_PID_TELESTAR_STARSTICK_2 0x8000 |
366 | #define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 | 379 | #define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 |
@@ -373,6 +386,7 @@ | |||
373 | #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 | 386 | #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 |
374 | #define USB_PID_ELGATO_EYETV_SAT 0x002a | 387 | #define USB_PID_ELGATO_EYETV_SAT 0x002a |
375 | #define USB_PID_ELGATO_EYETV_SAT_V2 0x0025 | 388 | #define USB_PID_ELGATO_EYETV_SAT_V2 0x0025 |
389 | #define USB_PID_ELGATO_EYETV_SAT_V3 0x0036 | ||
376 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 | 390 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 |
377 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 | 391 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 |
378 | #define USB_PID_FRIIO_WHITE 0x0001 | 392 | #define USB_PID_FRIIO_WHITE 0x0001 |
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index e1684c570e2f..75a3f4b57fd4 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c | |||
@@ -676,13 +676,13 @@ int dvb_create_media_graph(struct dvb_adapter *adap, | |||
676 | demux, 0, MEDIA_LNK_FL_ENABLED, | 676 | demux, 0, MEDIA_LNK_FL_ENABLED, |
677 | false); | 677 | false); |
678 | if (ret) | 678 | if (ret) |
679 | return -ENOMEM; | 679 | return ret; |
680 | } | 680 | } |
681 | if (demux && ca) { | 681 | if (demux && ca) { |
682 | ret = media_create_pad_link(demux, 1, ca, | 682 | ret = media_create_pad_link(demux, 1, ca, |
683 | 0, MEDIA_LNK_FL_ENABLED); | 683 | 0, MEDIA_LNK_FL_ENABLED); |
684 | if (ret) | 684 | if (ret) |
685 | return -ENOMEM; | 685 | return ret; |
686 | } | 686 | } |
687 | 687 | ||
688 | /* Create demux links for each ringbuffer/pad */ | 688 | /* Create demux links for each ringbuffer/pad */ |
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index dc2d41e144fd..d879dc0607f4 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c | |||
@@ -1121,7 +1121,7 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) | |||
1121 | (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", | 1121 | (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", |
1122 | state->identity.version & 0x1f); | 1122 | state->identity.version & 0x1f); |
1123 | 1123 | ||
1124 | if (rf_ramp && ((state->rf_ramp[0] == 0) || | 1124 | if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) || |
1125 | (state->current_band == BAND_CBAND && | 1125 | (state->current_band == BAND_CBAND && |
1126 | (state->identity.version & 0x1f) <= P1D_E_F))) { | 1126 | (state->identity.version & 0x1f) <= P1D_E_F))) { |
1127 | dprintk("DE-Engage mux for direct gain reg control"); | 1127 | dprintk("DE-Engage mux for direct gain reg control"); |
diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index e8fc0329ea64..addffc33993a 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c | |||
@@ -458,7 +458,7 @@ static int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status) | |||
458 | 458 | ||
459 | break; | 459 | break; |
460 | default: | 460 | default: |
461 | return 1; | 461 | return -EINVAL; |
462 | } | 462 | } |
463 | 463 | ||
464 | if (state->config->set_lock_led) | 464 | if (state->config->set_lock_led) |
@@ -528,7 +528,7 @@ static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber) | |||
528 | *ber = 0xffffffff; | 528 | *ber = 0xffffffff; |
529 | break; | 529 | break; |
530 | default: | 530 | default: |
531 | return 1; | 531 | return -EINVAL; |
532 | } | 532 | } |
533 | 533 | ||
534 | return 0; | 534 | return 0; |
@@ -623,7 +623,7 @@ static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr) | |||
623 | snr_reading, *snr); | 623 | snr_reading, *snr); |
624 | break; | 624 | break; |
625 | default: | 625 | default: |
626 | return 1; | 626 | return -EINVAL; |
627 | } | 627 | } |
628 | 628 | ||
629 | return 0; | 629 | return 0; |
@@ -661,7 +661,7 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |||
661 | state->prevUCBS2 = _ucblocks; | 661 | state->prevUCBS2 = _ucblocks; |
662 | break; | 662 | break; |
663 | default: | 663 | default: |
664 | return 1; | 664 | return -EINVAL; |
665 | } | 665 | } |
666 | 666 | ||
667 | return 0; | 667 | return 0; |
@@ -754,7 +754,7 @@ static int ds3000_send_diseqc_msg(struct dvb_frontend *fe, | |||
754 | data |= 0x80; | 754 | data |= 0x80; |
755 | ds3000_writereg(state, 0xa2, data); | 755 | ds3000_writereg(state, 0xa2, data); |
756 | 756 | ||
757 | return 1; | 757 | return -ETIMEDOUT; |
758 | } | 758 | } |
759 | 759 | ||
760 | data = ds3000_readreg(state, 0xa2); | 760 | data = ds3000_readreg(state, 0xa2); |
@@ -808,7 +808,7 @@ static int ds3000_diseqc_send_burst(struct dvb_frontend *fe, | |||
808 | data |= 0x80; | 808 | data |= 0x80; |
809 | ds3000_writereg(state, 0xa2, data); | 809 | ds3000_writereg(state, 0xa2, data); |
810 | 810 | ||
811 | return 1; | 811 | return -ETIMEDOUT; |
812 | } | 812 | } |
813 | 813 | ||
814 | data = ds3000_readreg(state, 0xa2); | 814 | data = ds3000_readreg(state, 0xa2); |
@@ -951,7 +951,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) | |||
951 | ds3000_writereg(state, 0xfe, 0x98); | 951 | ds3000_writereg(state, 0xfe, 0x98); |
952 | break; | 952 | break; |
953 | default: | 953 | default: |
954 | return 1; | 954 | return -EINVAL; |
955 | } | 955 | } |
956 | 956 | ||
957 | /* enable 27MHz clock output */ | 957 | /* enable 27MHz clock output */ |
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h index eee8c22c51ec..651e005146b2 100644 --- a/drivers/media/dvb-frontends/m88ds3103_priv.h +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h | |||
@@ -46,7 +46,7 @@ struct m88ds3103_dev { | |||
46 | /* auto detect chip id to do different config */ | 46 | /* auto detect chip id to do different config */ |
47 | u8 chip_id; | 47 | u8 chip_id; |
48 | /* main mclk is calculated for M88RS6000 dynamically */ | 48 | /* main mclk is calculated for M88RS6000 dynamically */ |
49 | u32 mclk_khz; | 49 | s32 mclk_khz; |
50 | u64 post_bit_error; | 50 | u64 post_bit_error; |
51 | u64 post_bit_count; | 51 | u64 post_bit_count; |
52 | }; | 52 | }; |
diff --git a/drivers/media/dvb-frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c index 1832c2f7695c..3b08176d7bec 100644 --- a/drivers/media/dvb-frontends/zl10353.c +++ b/drivers/media/dvb-frontends/zl10353.c | |||
@@ -135,8 +135,7 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, | |||
135 | 135 | ||
136 | value = (u64)10 * (1 << 23) / 7 * 125; | 136 | value = (u64)10 * (1 << 23) / 7 * 125; |
137 | value = (bw * value) + adc_clock / 2; | 137 | value = (bw * value) + adc_clock / 2; |
138 | do_div(value, adc_clock); | 138 | *nominal_rate = div_u64(value, adc_clock); |
139 | *nominal_rate = value; | ||
140 | 139 | ||
141 | dprintk("%s: bw %d, adc_clock %d => 0x%x\n", | 140 | dprintk("%s: bw %d, adc_clock %d => 0x%x\n", |
142 | __func__, bw, adc_clock, *nominal_rate); | 141 | __func__, bw, adc_clock, *nominal_rate); |
@@ -163,8 +162,7 @@ static void zl10353_calc_input_freq(struct dvb_frontend *fe, | |||
163 | if (ife > adc_clock / 2) | 162 | if (ife > adc_clock / 2) |
164 | ife = adc_clock - ife; | 163 | ife = adc_clock - ife; |
165 | } | 164 | } |
166 | value = (u64)65536 * ife + adc_clock / 2; | 165 | value = div_u64((u64)65536 * ife + adc_clock / 2, adc_clock); |
167 | do_div(value, adc_clock); | ||
168 | *input_freq = -value; | 166 | *input_freq = -value; |
169 | 167 | ||
170 | dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", | 168 | dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", |
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index 788967dadd29..0462f461e679 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c | |||
@@ -1130,8 +1130,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1130 | hdl = &state->hdl; | 1130 | hdl = &state->hdl; |
1131 | v4l2_ctrl_handler_init(hdl, 5); | 1131 | v4l2_ctrl_handler_init(hdl, 5); |
1132 | 1132 | ||
1133 | /* private controls */ | ||
1134 | |||
1135 | state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops, | 1133 | state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops, |
1136 | V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, | 1134 | V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, |
1137 | 0, V4L2_DV_TX_MODE_DVI_D); | 1135 | 0, V4L2_DV_TX_MODE_DVI_D); |
@@ -1151,12 +1149,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1151 | 1149 | ||
1152 | goto err_hdl; | 1150 | goto err_hdl; |
1153 | } | 1151 | } |
1154 | state->hdmi_mode_ctrl->is_private = true; | ||
1155 | state->hotplug_ctrl->is_private = true; | ||
1156 | state->rx_sense_ctrl->is_private = true; | ||
1157 | state->have_edid0_ctrl->is_private = true; | ||
1158 | state->rgb_quantization_range_ctrl->is_private = true; | ||
1159 | |||
1160 | state->pad.flags = MEDIA_PAD_FL_SINK; | 1152 | state->pad.flags = MEDIA_PAD_FL_SINK; |
1161 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); | 1153 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); |
1162 | if (err) | 1154 | if (err) |
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index fb7ed730d932..9e1731c565e7 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c | |||
@@ -466,9 +466,9 @@ static int adp1653_of_init(struct i2c_client *client, | |||
466 | of_node_put(child); | 466 | of_node_put(child); |
467 | 467 | ||
468 | pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); | 468 | pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); |
469 | if (!pd->enable_gpio) { | 469 | if (IS_ERR(pd->enable_gpio)) { |
470 | dev_err(&client->dev, "Error getting GPIO\n"); | 470 | dev_err(&client->dev, "Error getting GPIO\n"); |
471 | return -EINVAL; | 471 | return PTR_ERR(pd->enable_gpio); |
472 | } | 472 | } |
473 | 473 | ||
474 | return 0; | 474 | return 0; |
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index ff57c1dcb8af..b77b0a4dbf68 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c | |||
@@ -26,8 +26,9 @@ | |||
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/of.h> | 28 | #include <linux/of.h> |
29 | #include <media/v4l2-ioctl.h> | ||
30 | #include <linux/videodev2.h> | 29 | #include <linux/videodev2.h> |
30 | #include <media/v4l2-ioctl.h> | ||
31 | #include <media/v4l2-event.h> | ||
31 | #include <media/v4l2-device.h> | 32 | #include <media/v4l2-device.h> |
32 | #include <media/v4l2-ctrls.h> | 33 | #include <media/v4l2-ctrls.h> |
33 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
@@ -192,8 +193,8 @@ struct adv7180_state { | |||
192 | struct mutex mutex; /* mutual excl. when accessing chip */ | 193 | struct mutex mutex; /* mutual excl. when accessing chip */ |
193 | int irq; | 194 | int irq; |
194 | v4l2_std_id curr_norm; | 195 | v4l2_std_id curr_norm; |
195 | bool autodetect; | ||
196 | bool powered; | 196 | bool powered; |
197 | bool streaming; | ||
197 | u8 input; | 198 | u8 input; |
198 | 199 | ||
199 | struct i2c_client *client; | 200 | struct i2c_client *client; |
@@ -338,12 +339,26 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) | |||
338 | if (err) | 339 | if (err) |
339 | return err; | 340 | return err; |
340 | 341 | ||
341 | /* when we are interrupt driven we know the state */ | 342 | if (state->streaming) { |
342 | if (!state->autodetect || state->irq > 0) | 343 | err = -EBUSY; |
343 | *std = state->curr_norm; | 344 | goto unlock; |
344 | else | 345 | } |
345 | err = __adv7180_status(state, NULL, std); | 346 | |
347 | err = adv7180_set_video_standard(state, | ||
348 | ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); | ||
349 | if (err) | ||
350 | goto unlock; | ||
351 | |||
352 | msleep(100); | ||
353 | __adv7180_status(state, NULL, std); | ||
354 | |||
355 | err = v4l2_std_to_adv7180(state->curr_norm); | ||
356 | if (err < 0) | ||
357 | goto unlock; | ||
346 | 358 | ||
359 | err = adv7180_set_video_standard(state, err); | ||
360 | |||
361 | unlock: | ||
347 | mutex_unlock(&state->mutex); | 362 | mutex_unlock(&state->mutex); |
348 | return err; | 363 | return err; |
349 | } | 364 | } |
@@ -387,23 +402,13 @@ static int adv7180_program_std(struct adv7180_state *state) | |||
387 | { | 402 | { |
388 | int ret; | 403 | int ret; |
389 | 404 | ||
390 | if (state->autodetect) { | 405 | ret = v4l2_std_to_adv7180(state->curr_norm); |
391 | ret = adv7180_set_video_standard(state, | 406 | if (ret < 0) |
392 | ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); | 407 | return ret; |
393 | if (ret < 0) | ||
394 | return ret; | ||
395 | |||
396 | __adv7180_status(state, NULL, &state->curr_norm); | ||
397 | } else { | ||
398 | ret = v4l2_std_to_adv7180(state->curr_norm); | ||
399 | if (ret < 0) | ||
400 | return ret; | ||
401 | |||
402 | ret = adv7180_set_video_standard(state, ret); | ||
403 | if (ret < 0) | ||
404 | return ret; | ||
405 | } | ||
406 | 408 | ||
409 | ret = adv7180_set_video_standard(state, ret); | ||
410 | if (ret < 0) | ||
411 | return ret; | ||
407 | return 0; | 412 | return 0; |
408 | } | 413 | } |
409 | 414 | ||
@@ -415,18 +420,12 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | |||
415 | if (ret) | 420 | if (ret) |
416 | return ret; | 421 | return ret; |
417 | 422 | ||
418 | /* all standards -> autodetect */ | 423 | /* Make sure we can support this std */ |
419 | if (std == V4L2_STD_ALL) { | 424 | ret = v4l2_std_to_adv7180(std); |
420 | state->autodetect = true; | 425 | if (ret < 0) |
421 | } else { | 426 | goto out; |
422 | /* Make sure we can support this std */ | ||
423 | ret = v4l2_std_to_adv7180(std); | ||
424 | if (ret < 0) | ||
425 | goto out; | ||
426 | 427 | ||
427 | state->curr_norm = std; | 428 | state->curr_norm = std; |
428 | state->autodetect = false; | ||
429 | } | ||
430 | 429 | ||
431 | ret = adv7180_program_std(state); | 430 | ret = adv7180_program_std(state); |
432 | out: | 431 | out: |
@@ -434,6 +433,15 @@ out: | |||
434 | return ret; | 433 | return ret; |
435 | } | 434 | } |
436 | 435 | ||
436 | static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) | ||
437 | { | ||
438 | struct adv7180_state *state = to_state(sd); | ||
439 | |||
440 | *norm = state->curr_norm; | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
437 | static int adv7180_set_power(struct adv7180_state *state, bool on) | 445 | static int adv7180_set_power(struct adv7180_state *state, bool on) |
438 | { | 446 | { |
439 | u8 val; | 447 | u8 val; |
@@ -717,17 +725,77 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd, | |||
717 | return 0; | 725 | return 0; |
718 | } | 726 | } |
719 | 727 | ||
728 | static int adv7180_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cropcap) | ||
729 | { | ||
730 | struct adv7180_state *state = to_state(sd); | ||
731 | |||
732 | if (state->curr_norm & V4L2_STD_525_60) { | ||
733 | cropcap->pixelaspect.numerator = 11; | ||
734 | cropcap->pixelaspect.denominator = 10; | ||
735 | } else { | ||
736 | cropcap->pixelaspect.numerator = 54; | ||
737 | cropcap->pixelaspect.denominator = 59; | ||
738 | } | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) | ||
744 | { | ||
745 | *norm = V4L2_STD_ALL; | ||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) | ||
750 | { | ||
751 | struct adv7180_state *state = to_state(sd); | ||
752 | int ret; | ||
753 | |||
754 | /* It's always safe to stop streaming, no need to take the lock */ | ||
755 | if (!enable) { | ||
756 | state->streaming = enable; | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | /* Must wait until querystd released the lock */ | ||
761 | ret = mutex_lock_interruptible(&state->mutex); | ||
762 | if (ret) | ||
763 | return ret; | ||
764 | state->streaming = enable; | ||
765 | mutex_unlock(&state->mutex); | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int adv7180_subscribe_event(struct v4l2_subdev *sd, | ||
770 | struct v4l2_fh *fh, | ||
771 | struct v4l2_event_subscription *sub) | ||
772 | { | ||
773 | switch (sub->type) { | ||
774 | case V4L2_EVENT_SOURCE_CHANGE: | ||
775 | return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); | ||
776 | case V4L2_EVENT_CTRL: | ||
777 | return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); | ||
778 | default: | ||
779 | return -EINVAL; | ||
780 | } | ||
781 | } | ||
782 | |||
720 | static const struct v4l2_subdev_video_ops adv7180_video_ops = { | 783 | static const struct v4l2_subdev_video_ops adv7180_video_ops = { |
721 | .s_std = adv7180_s_std, | 784 | .s_std = adv7180_s_std, |
785 | .g_std = adv7180_g_std, | ||
722 | .querystd = adv7180_querystd, | 786 | .querystd = adv7180_querystd, |
723 | .g_input_status = adv7180_g_input_status, | 787 | .g_input_status = adv7180_g_input_status, |
724 | .s_routing = adv7180_s_routing, | 788 | .s_routing = adv7180_s_routing, |
725 | .g_mbus_config = adv7180_g_mbus_config, | 789 | .g_mbus_config = adv7180_g_mbus_config, |
790 | .cropcap = adv7180_cropcap, | ||
791 | .g_tvnorms = adv7180_g_tvnorms, | ||
792 | .s_stream = adv7180_s_stream, | ||
726 | }; | 793 | }; |
727 | 794 | ||
728 | |||
729 | static const struct v4l2_subdev_core_ops adv7180_core_ops = { | 795 | static const struct v4l2_subdev_core_ops adv7180_core_ops = { |
730 | .s_power = adv7180_s_power, | 796 | .s_power = adv7180_s_power, |
797 | .subscribe_event = adv7180_subscribe_event, | ||
798 | .unsubscribe_event = v4l2_event_subdev_unsubscribe, | ||
731 | }; | 799 | }; |
732 | 800 | ||
733 | static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { | 801 | static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { |
@@ -752,8 +820,14 @@ static irqreturn_t adv7180_irq(int irq, void *devid) | |||
752 | /* clear */ | 820 | /* clear */ |
753 | adv7180_write(state, ADV7180_REG_ICR3, isr3); | 821 | adv7180_write(state, ADV7180_REG_ICR3, isr3); |
754 | 822 | ||
755 | if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect) | 823 | if (isr3 & ADV7180_IRQ3_AD_CHANGE) { |
756 | __adv7180_status(state, NULL, &state->curr_norm); | 824 | static const struct v4l2_event src_ch = { |
825 | .type = V4L2_EVENT_SOURCE_CHANGE, | ||
826 | .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, | ||
827 | }; | ||
828 | |||
829 | v4l2_subdev_notify_event(&state->sd, &src_ch); | ||
830 | } | ||
757 | mutex_unlock(&state->mutex); | 831 | mutex_unlock(&state->mutex); |
758 | 832 | ||
759 | return IRQ_HANDLED; | 833 | return IRQ_HANDLED; |
@@ -1198,7 +1272,7 @@ static int adv7180_probe(struct i2c_client *client, | |||
1198 | 1272 | ||
1199 | state->irq = client->irq; | 1273 | state->irq = client->irq; |
1200 | mutex_init(&state->mutex); | 1274 | mutex_init(&state->mutex); |
1201 | state->autodetect = true; | 1275 | state->curr_norm = V4L2_STD_NTSC; |
1202 | if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) | 1276 | if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) |
1203 | state->powered = true; | 1277 | state->powered = true; |
1204 | else | 1278 | else |
@@ -1206,7 +1280,7 @@ static int adv7180_probe(struct i2c_client *client, | |||
1206 | state->input = 0; | 1280 | state->input = 0; |
1207 | sd = &state->sd; | 1281 | sd = &state->sd; |
1208 | v4l2_i2c_subdev_init(sd, client, &adv7180_ops); | 1282 | v4l2_i2c_subdev_init(sd, client, &adv7180_ops); |
1209 | sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; | 1283 | sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
1210 | 1284 | ||
1211 | ret = adv7180_init_controls(state); | 1285 | ret = adv7180_init_controls(state); |
1212 | if (ret) | 1286 | if (ret) |
@@ -1328,6 +1402,14 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); | |||
1328 | #ifdef CONFIG_OF | 1402 | #ifdef CONFIG_OF |
1329 | static const struct of_device_id adv7180_of_id[] = { | 1403 | static const struct of_device_id adv7180_of_id[] = { |
1330 | { .compatible = "adi,adv7180", }, | 1404 | { .compatible = "adi,adv7180", }, |
1405 | { .compatible = "adi,adv7182", }, | ||
1406 | { .compatible = "adi,adv7280", }, | ||
1407 | { .compatible = "adi,adv7280-m", }, | ||
1408 | { .compatible = "adi,adv7281", }, | ||
1409 | { .compatible = "adi,adv7281-m", }, | ||
1410 | { .compatible = "adi,adv7281-ma", }, | ||
1411 | { .compatible = "adi,adv7282", }, | ||
1412 | { .compatible = "adi,adv7282-m", }, | ||
1331 | { }, | 1413 | { }, |
1332 | }; | 1414 | }; |
1333 | 1415 | ||
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index bd822f032b08..39271c35da48 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c | |||
@@ -1502,12 +1502,6 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1502 | err = hdl->error; | 1502 | err = hdl->error; |
1503 | goto err_hdl; | 1503 | goto err_hdl; |
1504 | } | 1504 | } |
1505 | state->hdmi_mode_ctrl->is_private = true; | ||
1506 | state->hotplug_ctrl->is_private = true; | ||
1507 | state->rx_sense_ctrl->is_private = true; | ||
1508 | state->have_edid0_ctrl->is_private = true; | ||
1509 | state->rgb_quantization_range_ctrl->is_private = true; | ||
1510 | |||
1511 | state->pad.flags = MEDIA_PAD_FL_SINK; | 1505 | state->pad.flags = MEDIA_PAD_FL_SINK; |
1512 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); | 1506 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); |
1513 | if (err) | 1507 | if (err) |
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 41a1bfc5eaa7..beb2841ceae5 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c | |||
@@ -3141,7 +3141,6 @@ static int adv76xx_probe(struct i2c_client *client, | |||
3141 | if (ctrl) | 3141 | if (ctrl) |
3142 | ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; | 3142 | ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; |
3143 | 3143 | ||
3144 | /* private controls */ | ||
3145 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, | 3144 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, |
3146 | V4L2_CID_DV_RX_POWER_PRESENT, 0, | 3145 | V4L2_CID_DV_RX_POWER_PRESENT, 0, |
3147 | (1 << state->info->num_dv_ports) - 1, 0, 0); | 3146 | (1 << state->info->num_dv_ports) - 1, 0, 0); |
@@ -3164,13 +3163,6 @@ static int adv76xx_probe(struct i2c_client *client, | |||
3164 | err = hdl->error; | 3163 | err = hdl->error; |
3165 | goto err_hdl; | 3164 | goto err_hdl; |
3166 | } | 3165 | } |
3167 | state->detect_tx_5v_ctrl->is_private = true; | ||
3168 | state->rgb_quantization_range_ctrl->is_private = true; | ||
3169 | if (adv76xx_has_afe(state)) | ||
3170 | state->analog_sampling_phase_ctrl->is_private = true; | ||
3171 | state->free_run_color_manual_ctrl->is_private = true; | ||
3172 | state->free_run_color_ctrl->is_private = true; | ||
3173 | |||
3174 | if (adv76xx_s_detect_tx_5v_ctrl(sd)) { | 3166 | if (adv76xx_s_detect_tx_5v_ctrl(sd)) { |
3175 | err = -ENODEV; | 3167 | err = -ENODEV; |
3176 | goto err_hdl; | 3168 | goto err_hdl; |
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 7ccb85d45224..ecaacb0a6fa1 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c | |||
@@ -3300,12 +3300,6 @@ static int adv7842_probe(struct i2c_client *client, | |||
3300 | err = hdl->error; | 3300 | err = hdl->error; |
3301 | goto err_hdl; | 3301 | goto err_hdl; |
3302 | } | 3302 | } |
3303 | state->detect_tx_5v_ctrl->is_private = true; | ||
3304 | state->rgb_quantization_range_ctrl->is_private = true; | ||
3305 | state->analog_sampling_phase_ctrl->is_private = true; | ||
3306 | state->free_run_color_ctrl_manual->is_private = true; | ||
3307 | state->free_run_color_ctrl->is_private = true; | ||
3308 | |||
3309 | if (adv7842_s_detect_tx_5v_ctrl(sd)) { | 3303 | if (adv7842_s_detect_tx_5v_ctrl(sd)) { |
3310 | err = -ENODEV; | 3304 | err = -ENODEV; |
3311 | goto err_hdl; | 3305 | goto err_hdl; |
diff --git a/drivers/media/i2c/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c index a60931e66312..c2218c0a9e6f 100644 --- a/drivers/media/i2c/m5mols/m5mols_controls.c +++ b/drivers/media/i2c/m5mols/m5mols_controls.c | |||
@@ -405,7 +405,7 @@ static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |||
405 | struct v4l2_subdev *sd = to_sd(ctrl); | 405 | struct v4l2_subdev *sd = to_sd(ctrl); |
406 | struct m5mols_info *info = to_m5mols(sd); | 406 | struct m5mols_info *info = to_m5mols(sd); |
407 | int ret = 0; | 407 | int ret = 0; |
408 | u8 status; | 408 | u8 status = REG_ISO_AUTO; |
409 | 409 | ||
410 | v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n", | 410 | v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n", |
411 | __func__, ctrl->name, info->isp_ready); | 411 | __func__, ctrl->name, info->isp_ready); |
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index d2a1ce2bc7f5..bd3526bdd539 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c | |||
@@ -1798,6 +1798,21 @@ static int saa711x_detect_chip(struct i2c_client *client, | |||
1798 | return GM7113C; | 1798 | return GM7113C; |
1799 | } | 1799 | } |
1800 | 1800 | ||
1801 | /* Check if it is a CJC7113 */ | ||
1802 | if (!memcmp(name, "1111111111111111", CHIP_VER_SIZE)) { | ||
1803 | strlcpy(name, "cjc7113", CHIP_VER_SIZE); | ||
1804 | |||
1805 | if (!autodetect && strcmp(name, id->name)) | ||
1806 | return -EINVAL; | ||
1807 | |||
1808 | v4l_dbg(1, debug, client, | ||
1809 | "It seems to be a %s chip (%*ph) @ 0x%x.\n", | ||
1810 | name, 16, chip_ver, client->addr << 1); | ||
1811 | |||
1812 | /* CJC7113 seems to be SAA7113-compatible */ | ||
1813 | return SAA7113; | ||
1814 | } | ||
1815 | |||
1801 | /* Chip was not discovered. Return its ID and don't bind */ | 1816 | /* Chip was not discovered. Return its ID and don't bind */ |
1802 | v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n", | 1817 | v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n", |
1803 | 16, chip_ver, client->addr << 1); | 1818 | 16, chip_ver, client->addr << 1); |
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index a215efe7a8ba..3dfe387abf6e 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c | |||
@@ -188,6 +188,8 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) | |||
188 | embedded_end = 0; | 188 | embedded_end = 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | sensor->image_start = image_start; | ||
192 | |||
191 | dev_dbg(&client->dev, "embedded data from lines %d to %d\n", | 193 | dev_dbg(&client->dev, "embedded data from lines %d to %d\n", |
192 | embedded_start, embedded_end); | 194 | embedded_start, embedded_end); |
193 | dev_dbg(&client->dev, "image data starts at line %d\n", image_start); | 195 | dev_dbg(&client->dev, "image data starts at line %d\n", image_start); |
@@ -2280,6 +2282,15 @@ static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) | |||
2280 | return 0; | 2282 | return 0; |
2281 | } | 2283 | } |
2282 | 2284 | ||
2285 | static int smiapp_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) | ||
2286 | { | ||
2287 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2288 | |||
2289 | *lines = sensor->image_start; | ||
2290 | |||
2291 | return 0; | ||
2292 | } | ||
2293 | |||
2283 | /* ----------------------------------------------------------------------------- | 2294 | /* ----------------------------------------------------------------------------- |
2284 | * sysfs attributes | 2295 | * sysfs attributes |
2285 | */ | 2296 | */ |
@@ -2890,6 +2901,7 @@ static const struct v4l2_subdev_pad_ops smiapp_pad_ops = { | |||
2890 | 2901 | ||
2891 | static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { | 2902 | static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { |
2892 | .g_skip_frames = smiapp_get_skip_frames, | 2903 | .g_skip_frames = smiapp_get_skip_frames, |
2904 | .g_skip_top_lines = smiapp_get_skip_top_lines, | ||
2893 | }; | 2905 | }; |
2894 | 2906 | ||
2895 | static const struct v4l2_subdev_ops smiapp_ops = { | 2907 | static const struct v4l2_subdev_ops smiapp_ops = { |
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index f6af0cc4a256..2174f89a00db 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h | |||
@@ -217,6 +217,7 @@ struct smiapp_sensor { | |||
217 | 217 | ||
218 | u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ | 218 | u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ |
219 | u8 frame_skip; | 219 | u8 frame_skip; |
220 | u16 image_start; /* Offset to first line after metadata lines */ | ||
220 | 221 | ||
221 | int power_count; | 222 | int power_count; |
222 | 223 | ||
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 972e0d47259d..6cf6d06737a5 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c | |||
@@ -1551,6 +1551,8 @@ static int tc358743_g_edid(struct v4l2_subdev *sd, | |||
1551 | { | 1551 | { |
1552 | struct tc358743_state *state = to_state(sd); | 1552 | struct tc358743_state *state = to_state(sd); |
1553 | 1553 | ||
1554 | memset(edid->reserved, 0, sizeof(edid->reserved)); | ||
1555 | |||
1554 | if (edid->pad != 0) | 1556 | if (edid->pad != 0) |
1555 | return -EINVAL; | 1557 | return -EINVAL; |
1556 | 1558 | ||
@@ -1585,6 +1587,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd, | |||
1585 | v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", | 1587 | v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", |
1586 | __func__, edid->pad, edid->start_block, edid->blocks); | 1588 | __func__, edid->pad, edid->start_block, edid->blocks); |
1587 | 1589 | ||
1590 | memset(edid->reserved, 0, sizeof(edid->reserved)); | ||
1591 | |||
1588 | if (edid->pad != 0) | 1592 | if (edid->pad != 0) |
1589 | return -EINVAL; | 1593 | return -EINVAL; |
1590 | 1594 | ||
@@ -1859,7 +1863,6 @@ static int tc358743_probe(struct i2c_client *client, | |||
1859 | /* control handlers */ | 1863 | /* control handlers */ |
1860 | v4l2_ctrl_handler_init(&state->hdl, 3); | 1864 | v4l2_ctrl_handler_init(&state->hdl, 3); |
1861 | 1865 | ||
1862 | /* private controls */ | ||
1863 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, | 1866 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, |
1864 | V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); | 1867 | V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); |
1865 | 1868 | ||
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index 5bbfcab01c75..71a31352135c 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c | |||
@@ -285,7 +285,7 @@ static int ths7303_log_status(struct v4l2_subdev *sd) | |||
285 | v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off"); | 285 | v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off"); |
286 | 286 | ||
287 | if (state->bt.pixelclock) { | 287 | if (state->bt.pixelclock) { |
288 | struct v4l2_bt_timings *bt = bt = &state->bt; | 288 | struct v4l2_bt_timings *bt = &state->bt; |
289 | u32 frame_width, frame_height; | 289 | u32 frame_width, frame_height; |
290 | 290 | ||
291 | frame_width = V4L2_DV_BT_FRAME_WIDTH(bt); | 291 | frame_width = V4L2_DV_BT_FRAME_WIDTH(bt); |
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index ff18444e19e4..0b6d46c453bf 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c | |||
@@ -83,7 +83,7 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) | |||
83 | return rc; | 83 | return rc; |
84 | } | 84 | } |
85 | 85 | ||
86 | static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, | 86 | static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, |
87 | unsigned char value) | 87 | unsigned char value) |
88 | { | 88 | { |
89 | struct i2c_client *c = v4l2_get_subdevdata(sd); | 89 | struct i2c_client *c = v4l2_get_subdevdata(sd); |
@@ -92,7 +92,9 @@ static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, | |||
92 | v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); | 92 | v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); |
93 | rc = i2c_smbus_write_byte_data(c, addr, value); | 93 | rc = i2c_smbus_write_byte_data(c, addr, value); |
94 | if (rc < 0) | 94 | if (rc < 0) |
95 | v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc); | 95 | v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); |
96 | |||
97 | return rc; | ||
96 | } | 98 | } |
97 | 99 | ||
98 | static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, | 100 | static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, |
@@ -1159,8 +1161,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * | |||
1159 | 1161 | ||
1160 | static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) | 1162 | static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) |
1161 | { | 1163 | { |
1162 | tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); | 1164 | return tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); |
1163 | return 0; | ||
1164 | } | 1165 | } |
1165 | #endif | 1166 | #endif |
1166 | 1167 | ||
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 3cfd7af8c5ca..a1cd50f331f1 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c | |||
@@ -90,18 +90,13 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) | |||
90 | 90 | ||
91 | id &= ~MEDIA_ENT_ID_FLAG_NEXT; | 91 | id &= ~MEDIA_ENT_ID_FLAG_NEXT; |
92 | 92 | ||
93 | spin_lock(&mdev->lock); | ||
94 | |||
95 | media_device_for_each_entity(entity, mdev) { | 93 | media_device_for_each_entity(entity, mdev) { |
96 | if (((media_entity_id(entity) == id) && !next) || | 94 | if (((media_entity_id(entity) == id) && !next) || |
97 | ((media_entity_id(entity) > id) && next)) { | 95 | ((media_entity_id(entity) > id) && next)) { |
98 | spin_unlock(&mdev->lock); | ||
99 | return entity; | 96 | return entity; |
100 | } | 97 | } |
101 | } | 98 | } |
102 | 99 | ||
103 | spin_unlock(&mdev->lock); | ||
104 | |||
105 | return NULL; | 100 | return NULL; |
106 | } | 101 | } |
107 | 102 | ||
@@ -431,6 +426,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, | |||
431 | struct media_device *dev = to_media_device(devnode); | 426 | struct media_device *dev = to_media_device(devnode); |
432 | long ret; | 427 | long ret; |
433 | 428 | ||
429 | mutex_lock(&dev->graph_mutex); | ||
434 | switch (cmd) { | 430 | switch (cmd) { |
435 | case MEDIA_IOC_DEVICE_INFO: | 431 | case MEDIA_IOC_DEVICE_INFO: |
436 | ret = media_device_get_info(dev, | 432 | ret = media_device_get_info(dev, |
@@ -443,29 +439,24 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, | |||
443 | break; | 439 | break; |
444 | 440 | ||
445 | case MEDIA_IOC_ENUM_LINKS: | 441 | case MEDIA_IOC_ENUM_LINKS: |
446 | mutex_lock(&dev->graph_mutex); | ||
447 | ret = media_device_enum_links(dev, | 442 | ret = media_device_enum_links(dev, |
448 | (struct media_links_enum __user *)arg); | 443 | (struct media_links_enum __user *)arg); |
449 | mutex_unlock(&dev->graph_mutex); | ||
450 | break; | 444 | break; |
451 | 445 | ||
452 | case MEDIA_IOC_SETUP_LINK: | 446 | case MEDIA_IOC_SETUP_LINK: |
453 | mutex_lock(&dev->graph_mutex); | ||
454 | ret = media_device_setup_link(dev, | 447 | ret = media_device_setup_link(dev, |
455 | (struct media_link_desc __user *)arg); | 448 | (struct media_link_desc __user *)arg); |
456 | mutex_unlock(&dev->graph_mutex); | ||
457 | break; | 449 | break; |
458 | 450 | ||
459 | case MEDIA_IOC_G_TOPOLOGY: | 451 | case MEDIA_IOC_G_TOPOLOGY: |
460 | mutex_lock(&dev->graph_mutex); | ||
461 | ret = media_device_get_topology(dev, | 452 | ret = media_device_get_topology(dev, |
462 | (struct media_v2_topology __user *)arg); | 453 | (struct media_v2_topology __user *)arg); |
463 | mutex_unlock(&dev->graph_mutex); | ||
464 | break; | 454 | break; |
465 | 455 | ||
466 | default: | 456 | default: |
467 | ret = -ENOIOCTLCMD; | 457 | ret = -ENOIOCTLCMD; |
468 | } | 458 | } |
459 | mutex_unlock(&dev->graph_mutex); | ||
469 | 460 | ||
470 | return ret; | 461 | return ret; |
471 | } | 462 | } |
@@ -508,12 +499,6 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, | |||
508 | long ret; | 499 | long ret; |
509 | 500 | ||
510 | switch (cmd) { | 501 | switch (cmd) { |
511 | case MEDIA_IOC_DEVICE_INFO: | ||
512 | case MEDIA_IOC_ENUM_ENTITIES: | ||
513 | case MEDIA_IOC_SETUP_LINK: | ||
514 | case MEDIA_IOC_G_TOPOLOGY: | ||
515 | return media_device_ioctl(filp, cmd, arg); | ||
516 | |||
517 | case MEDIA_IOC_ENUM_LINKS32: | 502 | case MEDIA_IOC_ENUM_LINKS32: |
518 | mutex_lock(&dev->graph_mutex); | 503 | mutex_lock(&dev->graph_mutex); |
519 | ret = media_device_enum_links32(dev, | 504 | ret = media_device_enum_links32(dev, |
@@ -522,7 +507,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, | |||
522 | break; | 507 | break; |
523 | 508 | ||
524 | default: | 509 | default: |
525 | ret = -ENOIOCTLCMD; | 510 | return media_device_ioctl(filp, cmd, arg); |
526 | } | 511 | } |
527 | 512 | ||
528 | return ret; | 513 | return ret; |
@@ -590,12 +575,12 @@ int __must_check media_device_register_entity(struct media_device *mdev, | |||
590 | if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL)) | 575 | if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL)) |
591 | return -ENOMEM; | 576 | return -ENOMEM; |
592 | 577 | ||
593 | spin_lock(&mdev->lock); | 578 | mutex_lock(&mdev->graph_mutex); |
594 | 579 | ||
595 | ret = ida_get_new_above(&mdev->entity_internal_idx, 1, | 580 | ret = ida_get_new_above(&mdev->entity_internal_idx, 1, |
596 | &entity->internal_idx); | 581 | &entity->internal_idx); |
597 | if (ret < 0) { | 582 | if (ret < 0) { |
598 | spin_unlock(&mdev->lock); | 583 | mutex_unlock(&mdev->graph_mutex); |
599 | return ret; | 584 | return ret; |
600 | } | 585 | } |
601 | 586 | ||
@@ -615,9 +600,6 @@ int __must_check media_device_register_entity(struct media_device *mdev, | |||
615 | (notify)->notify(entity, notify->notify_data); | 600 | (notify)->notify(entity, notify->notify_data); |
616 | } | 601 | } |
617 | 602 | ||
618 | spin_unlock(&mdev->lock); | ||
619 | |||
620 | mutex_lock(&mdev->graph_mutex); | ||
621 | if (mdev->entity_internal_idx_max | 603 | if (mdev->entity_internal_idx_max |
622 | >= mdev->pm_count_walk.ent_enum.idx_max) { | 604 | >= mdev->pm_count_walk.ent_enum.idx_max) { |
623 | struct media_entity_graph new = { .top = 0 }; | 605 | struct media_entity_graph new = { .top = 0 }; |
@@ -680,9 +662,9 @@ void media_device_unregister_entity(struct media_entity *entity) | |||
680 | if (mdev == NULL) | 662 | if (mdev == NULL) |
681 | return; | 663 | return; |
682 | 664 | ||
683 | spin_lock(&mdev->lock); | 665 | mutex_lock(&mdev->graph_mutex); |
684 | __media_device_unregister_entity(entity); | 666 | __media_device_unregister_entity(entity); |
685 | spin_unlock(&mdev->lock); | 667 | mutex_unlock(&mdev->graph_mutex); |
686 | } | 668 | } |
687 | EXPORT_SYMBOL_GPL(media_device_unregister_entity); | 669 | EXPORT_SYMBOL_GPL(media_device_unregister_entity); |
688 | 670 | ||
@@ -703,7 +685,6 @@ void media_device_init(struct media_device *mdev) | |||
703 | INIT_LIST_HEAD(&mdev->pads); | 685 | INIT_LIST_HEAD(&mdev->pads); |
704 | INIT_LIST_HEAD(&mdev->links); | 686 | INIT_LIST_HEAD(&mdev->links); |
705 | INIT_LIST_HEAD(&mdev->entity_notify); | 687 | INIT_LIST_HEAD(&mdev->entity_notify); |
706 | spin_lock_init(&mdev->lock); | ||
707 | mutex_init(&mdev->graph_mutex); | 688 | mutex_init(&mdev->graph_mutex); |
708 | ida_init(&mdev->entity_internal_idx); | 689 | ida_init(&mdev->entity_internal_idx); |
709 | 690 | ||
@@ -752,9 +733,9 @@ EXPORT_SYMBOL_GPL(__media_device_register); | |||
752 | int __must_check media_device_register_entity_notify(struct media_device *mdev, | 733 | int __must_check media_device_register_entity_notify(struct media_device *mdev, |
753 | struct media_entity_notify *nptr) | 734 | struct media_entity_notify *nptr) |
754 | { | 735 | { |
755 | spin_lock(&mdev->lock); | 736 | mutex_lock(&mdev->graph_mutex); |
756 | list_add_tail(&nptr->list, &mdev->entity_notify); | 737 | list_add_tail(&nptr->list, &mdev->entity_notify); |
757 | spin_unlock(&mdev->lock); | 738 | mutex_unlock(&mdev->graph_mutex); |
758 | return 0; | 739 | return 0; |
759 | } | 740 | } |
760 | EXPORT_SYMBOL_GPL(media_device_register_entity_notify); | 741 | EXPORT_SYMBOL_GPL(media_device_register_entity_notify); |
@@ -771,9 +752,9 @@ static void __media_device_unregister_entity_notify(struct media_device *mdev, | |||
771 | void media_device_unregister_entity_notify(struct media_device *mdev, | 752 | void media_device_unregister_entity_notify(struct media_device *mdev, |
772 | struct media_entity_notify *nptr) | 753 | struct media_entity_notify *nptr) |
773 | { | 754 | { |
774 | spin_lock(&mdev->lock); | 755 | mutex_lock(&mdev->graph_mutex); |
775 | __media_device_unregister_entity_notify(mdev, nptr); | 756 | __media_device_unregister_entity_notify(mdev, nptr); |
776 | spin_unlock(&mdev->lock); | 757 | mutex_unlock(&mdev->graph_mutex); |
777 | } | 758 | } |
778 | EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); | 759 | EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); |
779 | 760 | ||
@@ -787,11 +768,11 @@ void media_device_unregister(struct media_device *mdev) | |||
787 | if (mdev == NULL) | 768 | if (mdev == NULL) |
788 | return; | 769 | return; |
789 | 770 | ||
790 | spin_lock(&mdev->lock); | 771 | mutex_lock(&mdev->graph_mutex); |
791 | 772 | ||
792 | /* Check if mdev was ever registered at all */ | 773 | /* Check if mdev was ever registered at all */ |
793 | if (!media_devnode_is_registered(&mdev->devnode)) { | 774 | if (!media_devnode_is_registered(&mdev->devnode)) { |
794 | spin_unlock(&mdev->lock); | 775 | mutex_unlock(&mdev->graph_mutex); |
795 | return; | 776 | return; |
796 | } | 777 | } |
797 | 778 | ||
@@ -811,12 +792,11 @@ void media_device_unregister(struct media_device *mdev) | |||
811 | kfree(intf); | 792 | kfree(intf); |
812 | } | 793 | } |
813 | 794 | ||
814 | spin_unlock(&mdev->lock); | 795 | mutex_unlock(&mdev->graph_mutex); |
815 | 796 | ||
816 | device_remove_file(&mdev->devnode.dev, &dev_attr_model); | 797 | device_remove_file(&mdev->devnode.dev, &dev_attr_model); |
798 | dev_dbg(mdev->dev, "Media device unregistering\n"); | ||
817 | media_devnode_unregister(&mdev->devnode); | 799 | media_devnode_unregister(&mdev->devnode); |
818 | |||
819 | dev_dbg(mdev->dev, "Media device unregistered\n"); | ||
820 | } | 800 | } |
821 | EXPORT_SYMBOL_GPL(media_device_unregister); | 801 | EXPORT_SYMBOL_GPL(media_device_unregister); |
822 | 802 | ||
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 29409f440f1c..b66dc9d0766b 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c | |||
@@ -197,10 +197,11 @@ static int media_release(struct inode *inode, struct file *filp) | |||
197 | if (mdev->fops->release) | 197 | if (mdev->fops->release) |
198 | mdev->fops->release(filp); | 198 | mdev->fops->release(filp); |
199 | 199 | ||
200 | filp->private_data = NULL; | ||
201 | |||
200 | /* decrease the refcount unconditionally since the release() | 202 | /* decrease the refcount unconditionally since the release() |
201 | return value is ignored. */ | 203 | return value is ignored. */ |
202 | put_device(&mdev->dev); | 204 | put_device(&mdev->dev); |
203 | filp->private_data = NULL; | ||
204 | return 0; | 205 | return 0; |
205 | } | 206 | } |
206 | 207 | ||
@@ -267,8 +268,11 @@ int __must_check media_devnode_register(struct media_devnode *mdev, | |||
267 | return 0; | 268 | return 0; |
268 | 269 | ||
269 | error: | 270 | error: |
271 | mutex_lock(&media_devnode_lock); | ||
270 | cdev_del(&mdev->cdev); | 272 | cdev_del(&mdev->cdev); |
271 | clear_bit(mdev->minor, media_devnode_nums); | 273 | clear_bit(mdev->minor, media_devnode_nums); |
274 | mutex_unlock(&media_devnode_lock); | ||
275 | |||
272 | return ret; | 276 | return ret; |
273 | } | 277 | } |
274 | 278 | ||
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index e95070b3a3d4..d8a2299f0c2a 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c | |||
@@ -219,7 +219,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, | |||
219 | entity->pads = pads; | 219 | entity->pads = pads; |
220 | 220 | ||
221 | if (mdev) | 221 | if (mdev) |
222 | spin_lock(&mdev->lock); | 222 | mutex_lock(&mdev->graph_mutex); |
223 | 223 | ||
224 | for (i = 0; i < num_pads; i++) { | 224 | for (i = 0; i < num_pads; i++) { |
225 | pads[i].entity = entity; | 225 | pads[i].entity = entity; |
@@ -230,7 +230,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, | |||
230 | } | 230 | } |
231 | 231 | ||
232 | if (mdev) | 232 | if (mdev) |
233 | spin_unlock(&mdev->lock); | 233 | mutex_unlock(&mdev->graph_mutex); |
234 | 234 | ||
235 | return 0; | 235 | return 0; |
236 | } | 236 | } |
@@ -445,7 +445,7 @@ __must_check int __media_entity_pipeline_start(struct media_entity *entity, | |||
445 | bitmap_or(active, active, has_no_links, entity->num_pads); | 445 | bitmap_or(active, active, has_no_links, entity->num_pads); |
446 | 446 | ||
447 | if (!bitmap_full(active, entity->num_pads)) { | 447 | if (!bitmap_full(active, entity->num_pads)) { |
448 | ret = -EPIPE; | 448 | ret = -ENOLINK; |
449 | dev_dbg(entity->graph_obj.mdev->dev, | 449 | dev_dbg(entity->graph_obj.mdev->dev, |
450 | "\"%s\":%u must be connected by an enabled link\n", | 450 | "\"%s\":%u must be connected by an enabled link\n", |
451 | entity->name, | 451 | entity->name, |
@@ -747,9 +747,9 @@ void media_entity_remove_links(struct media_entity *entity) | |||
747 | if (mdev == NULL) | 747 | if (mdev == NULL) |
748 | return; | 748 | return; |
749 | 749 | ||
750 | spin_lock(&mdev->lock); | 750 | mutex_lock(&mdev->graph_mutex); |
751 | __media_entity_remove_links(entity); | 751 | __media_entity_remove_links(entity); |
752 | spin_unlock(&mdev->lock); | 752 | mutex_unlock(&mdev->graph_mutex); |
753 | } | 753 | } |
754 | EXPORT_SYMBOL_GPL(media_entity_remove_links); | 754 | EXPORT_SYMBOL_GPL(media_entity_remove_links); |
755 | 755 | ||
@@ -951,9 +951,9 @@ void media_remove_intf_link(struct media_link *link) | |||
951 | if (mdev == NULL) | 951 | if (mdev == NULL) |
952 | return; | 952 | return; |
953 | 953 | ||
954 | spin_lock(&mdev->lock); | 954 | mutex_lock(&mdev->graph_mutex); |
955 | __media_remove_intf_link(link); | 955 | __media_remove_intf_link(link); |
956 | spin_unlock(&mdev->lock); | 956 | mutex_unlock(&mdev->graph_mutex); |
957 | } | 957 | } |
958 | EXPORT_SYMBOL_GPL(media_remove_intf_link); | 958 | EXPORT_SYMBOL_GPL(media_remove_intf_link); |
959 | 959 | ||
@@ -975,8 +975,8 @@ void media_remove_intf_links(struct media_interface *intf) | |||
975 | if (mdev == NULL) | 975 | if (mdev == NULL) |
976 | return; | 976 | return; |
977 | 977 | ||
978 | spin_lock(&mdev->lock); | 978 | mutex_lock(&mdev->graph_mutex); |
979 | __media_remove_intf_links(intf); | 979 | __media_remove_intf_links(intf); |
980 | spin_unlock(&mdev->lock); | 980 | mutex_unlock(&mdev->graph_mutex); |
981 | } | 981 | } |
982 | EXPORT_SYMBOL_GPL(media_remove_intf_links); | 982 | EXPORT_SYMBOL_GPL(media_remove_intf_links); |
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 48a611bc3e18..4f6467fbaeb4 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig | |||
@@ -14,6 +14,7 @@ source "drivers/media/pci/meye/Kconfig" | |||
14 | source "drivers/media/pci/solo6x10/Kconfig" | 14 | source "drivers/media/pci/solo6x10/Kconfig" |
15 | source "drivers/media/pci/sta2x11/Kconfig" | 15 | source "drivers/media/pci/sta2x11/Kconfig" |
16 | source "drivers/media/pci/tw68/Kconfig" | 16 | source "drivers/media/pci/tw68/Kconfig" |
17 | source "drivers/media/pci/tw686x/Kconfig" | ||
17 | source "drivers/media/pci/zoran/Kconfig" | 18 | source "drivers/media/pci/zoran/Kconfig" |
18 | endif | 19 | endif |
19 | 20 | ||
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 5f8aacb8b9b8..2e54c36441f7 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ | |||
25 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ | 25 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ |
26 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ | 26 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ |
27 | obj-$(CONFIG_VIDEO_TW68) += tw68/ | 27 | obj-$(CONFIG_VIDEO_TW68) += tw68/ |
28 | obj-$(CONFIG_VIDEO_TW686X) += tw686x/ | ||
28 | obj-$(CONFIG_VIDEO_DT3155) += dt3155/ | 29 | obj-$(CONFIG_VIDEO_DT3155) += dt3155/ |
29 | obj-$(CONFIG_VIDEO_MEYE) += meye/ | 30 | obj-$(CONFIG_VIDEO_MEYE) += meye/ |
30 | obj-$(CONFIG_STA2X11_VIP) += sta2x11/ | 31 | obj-$(CONFIG_STA2X11_VIP) += sta2x11/ |
diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index a01f0cc745cc..70343829a125 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig | |||
@@ -4,6 +4,7 @@ config VIDEO_COBALT | |||
4 | depends on PCI_MSI && MTD_COMPLEX_MAPPINGS | 4 | depends on PCI_MSI && MTD_COMPLEX_MAPPINGS |
5 | depends on GPIOLIB || COMPILE_TEST | 5 | depends on GPIOLIB || COMPILE_TEST |
6 | depends on SND | 6 | depends on SND |
7 | depends on MTD | ||
7 | select I2C_ALGOBIT | 8 | select I2C_ALGOBIT |
8 | select VIDEO_ADV7604 | 9 | select VIDEO_ADV7604 |
9 | select VIDEO_ADV7511 | 10 | select VIDEO_ADV7511 |
diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 7e31f2a2e085..47ce80fa73b9 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h | |||
@@ -707,11 +707,7 @@ static inline int cx18_raw_vbi(const struct cx18 *cx) | |||
707 | /* Call the specified callback for all subdevs with a grp_id bit matching the | 707 | /* Call the specified callback for all subdevs with a grp_id bit matching the |
708 | * mask in hw (if 0, then match them all). Ignore any errors. */ | 708 | * mask in hw (if 0, then match them all). Ignore any errors. */ |
709 | #define cx18_call_hw(cx, hw, o, f, args...) \ | 709 | #define cx18_call_hw(cx, hw, o, f, args...) \ |
710 | do { \ | 710 | v4l2_device_mask_call_all(&(cx)->v4l2_dev, hw, o, f, ##args) |
711 | struct v4l2_subdev *__sd; \ | ||
712 | __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \ | ||
713 | !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ | ||
714 | } while (0) | ||
715 | 711 | ||
716 | #define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) | 712 | #define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) |
717 | 713 | ||
@@ -719,12 +715,7 @@ static inline int cx18_raw_vbi(const struct cx18 *cx) | |||
719 | * mask in hw (if 0, then match them all). If the callback returns an error | 715 | * mask in hw (if 0, then match them all). If the callback returns an error |
720 | * other than 0 or -ENOIOCTLCMD, then return with that error code. */ | 716 | * other than 0 or -ENOIOCTLCMD, then return with that error code. */ |
721 | #define cx18_call_hw_err(cx, hw, o, f, args...) \ | 717 | #define cx18_call_hw_err(cx, hw, o, f, args...) \ |
722 | ({ \ | 718 | v4l2_device_mask_call_until_err(&(cx)->v4l2_dev, hw, o, f, ##args) |
723 | struct v4l2_subdev *__sd; \ | ||
724 | __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \ | ||
725 | __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \ | ||
726 | ##args); \ | ||
727 | }) | ||
728 | 719 | ||
729 | #define cx18_call_all_err(cx, o, f, args...) \ | 720 | #define cx18_call_all_err(cx, o, f, args...) \ |
730 | cx18_call_hw_err(cx, 0, o, f , ##args) | 721 | cx18_call_hw_err(cx, 0, o, f , ##args) |
diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c index 877dad89107e..e7d4406f9abd 100644 --- a/drivers/media/pci/cx23885/cx23885-av.c +++ b/drivers/media/pci/cx23885/cx23885-av.c | |||
@@ -24,7 +24,7 @@ void cx23885_av_work_handler(struct work_struct *work) | |||
24 | { | 24 | { |
25 | struct cx23885_dev *dev = | 25 | struct cx23885_dev *dev = |
26 | container_of(work, struct cx23885_dev, cx25840_work); | 26 | container_of(work, struct cx23885_dev, cx25840_work); |
27 | bool handled; | 27 | bool handled = false; |
28 | 28 | ||
29 | v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine, | 29 | v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine, |
30 | PCI_MSK_AV_CORE, &handled); | 30 | PCI_MSK_AV_CORE, &handled); |
diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index 6c08dae67a73..10cba305dbd2 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h | |||
@@ -827,12 +827,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv) | |||
827 | /* Call the specified callback for all subdevs matching hw (if 0, then | 827 | /* Call the specified callback for all subdevs matching hw (if 0, then |
828 | match them all). Ignore any errors. */ | 828 | match them all). Ignore any errors. */ |
829 | #define ivtv_call_hw(itv, hw, o, f, args...) \ | 829 | #define ivtv_call_hw(itv, hw, o, f, args...) \ |
830 | do { \ | 830 | v4l2_device_mask_call_all(&(itv)->v4l2_dev, hw, o, f, ##args) |
831 | struct v4l2_subdev *__sd; \ | ||
832 | __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \ | ||
833 | !(hw) ? true : (__sd->grp_id & (hw)), \ | ||
834 | o, f, ##args); \ | ||
835 | } while (0) | ||
836 | 831 | ||
837 | #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) | 832 | #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) |
838 | 833 | ||
@@ -840,11 +835,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv) | |||
840 | match them all). If the callback returns an error other than 0 or | 835 | match them all). If the callback returns an error other than 0 or |
841 | -ENOIOCTLCMD, then return with that error code. */ | 836 | -ENOIOCTLCMD, then return with that error code. */ |
842 | #define ivtv_call_hw_err(itv, hw, o, f, args...) \ | 837 | #define ivtv_call_hw_err(itv, hw, o, f, args...) \ |
843 | ({ \ | 838 | v4l2_device_mask_call_until_err(&(itv)->v4l2_dev, hw, o, f, ##args) |
844 | struct v4l2_subdev *__sd; \ | ||
845 | __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd, \ | ||
846 | !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ | ||
847 | }) | ||
848 | 839 | ||
849 | #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args) | 840 | #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args) |
850 | 841 | ||
diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c index d018673c71f6..826c7c75e64d 100644 --- a/drivers/media/pci/smipcie/smipcie-ir.c +++ b/drivers/media/pci/smipcie/smipcie-ir.c | |||
@@ -203,7 +203,7 @@ int smi_ir_init(struct smi_dev *dev) | |||
203 | rc_dev->dev.parent = &dev->pci_dev->dev; | 203 | rc_dev->dev.parent = &dev->pci_dev->dev; |
204 | 204 | ||
205 | rc_dev->driver_type = RC_DRIVER_SCANCODE; | 205 | rc_dev->driver_type = RC_DRIVER_SCANCODE; |
206 | rc_dev->map_name = RC_MAP_DVBSKY; | 206 | rc_dev->map_name = dev->info->rc_map; |
207 | 207 | ||
208 | ir->rc_dev = rc_dev; | 208 | ir->rc_dev = rc_dev; |
209 | ir->dev = dev; | 209 | ir->dev = dev; |
diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c index b039a229b7d2..83981d611a79 100644 --- a/drivers/media/pci/smipcie/smipcie-main.c +++ b/drivers/media/pci/smipcie/smipcie-main.c | |||
@@ -716,7 +716,8 @@ static int smi_fe_init(struct smi_port *port) | |||
716 | /* init MAC.*/ | 716 | /* init MAC.*/ |
717 | ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); | 717 | ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); |
718 | dev_info(&port->dev->pci_dev->dev, | 718 | dev_info(&port->dev->pci_dev->dev, |
719 | "DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8); | 719 | "%s port %d MAC: %pM\n", dev->info->name, |
720 | port->idx, mac_ee + (port->idx)*8); | ||
720 | memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); | 721 | memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); |
721 | return ret; | 722 | return ret; |
722 | } | 723 | } |
@@ -1066,6 +1067,7 @@ static struct smi_cfg_info dvbsky_s950_cfg = { | |||
1066 | .ts_1 = SMI_TS_DMA_BOTH, | 1067 | .ts_1 = SMI_TS_DMA_BOTH, |
1067 | .fe_0 = DVBSKY_FE_NULL, | 1068 | .fe_0 = DVBSKY_FE_NULL, |
1068 | .fe_1 = DVBSKY_FE_M88DS3103, | 1069 | .fe_1 = DVBSKY_FE_M88DS3103, |
1070 | .rc_map = RC_MAP_DVBSKY, | ||
1069 | }; | 1071 | }; |
1070 | 1072 | ||
1071 | static struct smi_cfg_info dvbsky_s952_cfg = { | 1073 | static struct smi_cfg_info dvbsky_s952_cfg = { |
@@ -1075,6 +1077,7 @@ static struct smi_cfg_info dvbsky_s952_cfg = { | |||
1075 | .ts_1 = SMI_TS_DMA_BOTH, | 1077 | .ts_1 = SMI_TS_DMA_BOTH, |
1076 | .fe_0 = DVBSKY_FE_M88RS6000, | 1078 | .fe_0 = DVBSKY_FE_M88RS6000, |
1077 | .fe_1 = DVBSKY_FE_M88RS6000, | 1079 | .fe_1 = DVBSKY_FE_M88RS6000, |
1080 | .rc_map = RC_MAP_DVBSKY, | ||
1078 | }; | 1081 | }; |
1079 | 1082 | ||
1080 | static struct smi_cfg_info dvbsky_t9580_cfg = { | 1083 | static struct smi_cfg_info dvbsky_t9580_cfg = { |
@@ -1084,6 +1087,17 @@ static struct smi_cfg_info dvbsky_t9580_cfg = { | |||
1084 | .ts_1 = SMI_TS_DMA_BOTH, | 1087 | .ts_1 = SMI_TS_DMA_BOTH, |
1085 | .fe_0 = DVBSKY_FE_SIT2, | 1088 | .fe_0 = DVBSKY_FE_SIT2, |
1086 | .fe_1 = DVBSKY_FE_M88DS3103, | 1089 | .fe_1 = DVBSKY_FE_M88DS3103, |
1090 | .rc_map = RC_MAP_DVBSKY, | ||
1091 | }; | ||
1092 | |||
1093 | static struct smi_cfg_info technotrend_s2_4200_cfg = { | ||
1094 | .type = SMI_TECHNOTREND_S2_4200, | ||
1095 | .name = "TechnoTrend TT-budget S2-4200 Twin", | ||
1096 | .ts_0 = SMI_TS_DMA_BOTH, | ||
1097 | .ts_1 = SMI_TS_DMA_BOTH, | ||
1098 | .fe_0 = DVBSKY_FE_M88RS6000, | ||
1099 | .fe_1 = DVBSKY_FE_M88RS6000, | ||
1100 | .rc_map = RC_MAP_TT_1500, | ||
1087 | }; | 1101 | }; |
1088 | 1102 | ||
1089 | /* PCI IDs */ | 1103 | /* PCI IDs */ |
@@ -1096,6 +1110,7 @@ static const struct pci_device_id smi_id_table[] = { | |||
1096 | SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), | 1110 | SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), |
1097 | SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), | 1111 | SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), |
1098 | SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), | 1112 | SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), |
1113 | SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg), | ||
1099 | {0} | 1114 | {0} |
1100 | }; | 1115 | }; |
1101 | MODULE_DEVICE_TABLE(pci, smi_id_table); | 1116 | MODULE_DEVICE_TABLE(pci, smi_id_table); |
diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 68cdda28fd98..611e4f02cadd 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h | |||
@@ -216,6 +216,7 @@ struct smi_cfg_info { | |||
216 | #define SMI_DVBSKY_S950 1 | 216 | #define SMI_DVBSKY_S950 1 |
217 | #define SMI_DVBSKY_T9580 2 | 217 | #define SMI_DVBSKY_T9580 2 |
218 | #define SMI_DVBSKY_T982 3 | 218 | #define SMI_DVBSKY_T982 3 |
219 | #define SMI_TECHNOTREND_S2_4200 4 | ||
219 | int type; | 220 | int type; |
220 | char *name; | 221 | char *name; |
221 | #define SMI_TS_NULL 0 | 222 | #define SMI_TS_NULL 0 |
@@ -232,6 +233,7 @@ struct smi_cfg_info { | |||
232 | #define DVBSKY_FE_SIT2 3 | 233 | #define DVBSKY_FE_SIT2 3 |
233 | int fe_0; | 234 | int fe_0; |
234 | int fe_1; | 235 | int fe_1; |
236 | char *rc_map; | ||
235 | }; | 237 | }; |
236 | 238 | ||
237 | struct smi_rc { | 239 | struct smi_rc { |
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 753411cbbc9a..1fc195f89686 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c | |||
@@ -444,27 +444,19 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
444 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) | 444 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) |
445 | { | 445 | { |
446 | struct sta2x11_vip *vip = video_drvdata(file); | 446 | struct sta2x11_vip *vip = video_drvdata(file); |
447 | v4l2_std_id oldstd = vip->std, newstd; | 447 | |
448 | int status; | 448 | /* |
449 | 449 | * This is here for backwards compatibility only. | |
450 | if (V4L2_STD_ALL == std) { | 450 | * The use of V4L2_STD_ALL to trigger a querystd is non-standard. |
451 | v4l2_subdev_call(vip->decoder, video, s_std, std); | 451 | */ |
452 | ssleep(2); | 452 | if (std == V4L2_STD_ALL) { |
453 | v4l2_subdev_call(vip->decoder, video, querystd, &newstd); | 453 | v4l2_subdev_call(vip->decoder, video, querystd, &std); |
454 | v4l2_subdev_call(vip->decoder, video, g_input_status, &status); | 454 | if (std == V4L2_STD_UNKNOWN) |
455 | if (status & V4L2_IN_ST_NO_SIGNAL) | ||
456 | return -EIO; | 455 | return -EIO; |
457 | std = vip->std = newstd; | ||
458 | if (oldstd != std) { | ||
459 | if (V4L2_STD_525_60 & std) | ||
460 | vip->format = formats_60[0]; | ||
461 | else | ||
462 | vip->format = formats_50[0]; | ||
463 | } | ||
464 | return 0; | ||
465 | } | 456 | } |
466 | 457 | ||
467 | if (oldstd != std) { | 458 | if (vip->std != std) { |
459 | vip->std = std; | ||
468 | if (V4L2_STD_525_60 & std) | 460 | if (V4L2_STD_525_60 & std) |
469 | vip->format = formats_60[0]; | 461 | vip->format = formats_60[0]; |
470 | else | 462 | else |
diff --git a/drivers/media/pci/tw686x/Kconfig b/drivers/media/pci/tw686x/Kconfig new file mode 100644 index 000000000000..fb8536974052 --- /dev/null +++ b/drivers/media/pci/tw686x/Kconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | config VIDEO_TW686X | ||
2 | tristate "Intersil/Techwell TW686x video capture cards" | ||
3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND | ||
4 | depends on HAS_DMA | ||
5 | select VIDEOBUF2_VMALLOC | ||
6 | select SND_PCM | ||
7 | help | ||
8 | Support for Intersil/Techwell TW686x-based frame grabber cards. | ||
9 | |||
10 | Currently supported chips: | ||
11 | - TW6864 (4 video channels), | ||
12 | - TW6865 (4 video channels, not tested, second generation chip), | ||
13 | - TW6868 (8 video channels but only 4 first channels using | ||
14 | built-in video decoder are supported, not tested), | ||
15 | - TW6869 (8 video channels, second generation chip). | ||
16 | |||
17 | To compile this driver as a module, choose M here: the module | ||
18 | will be named tw686x. | ||
diff --git a/drivers/media/pci/tw686x/Makefile b/drivers/media/pci/tw686x/Makefile new file mode 100644 index 000000000000..99819542b733 --- /dev/null +++ b/drivers/media/pci/tw686x/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | tw686x-objs := tw686x-core.o tw686x-video.o tw686x-audio.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_TW686X) += tw686x.o | ||
diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c new file mode 100644 index 000000000000..91459ab715b2 --- /dev/null +++ b/drivers/media/pci/tw686x/tw686x-audio.c | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar | ||
3 | * | ||
4 | * Based on the audio support from the tw6869 driver: | ||
5 | * Copyright 2015 www.starterkit.ru <info@starterkit.ru> | ||
6 | * | ||
7 | * Based on: | ||
8 | * Driver for Intersil|Techwell TW6869 based DVR cards | ||
9 | * (c) 2011-12 liran <jli11@intersil.com> [Intersil|Techwell China] | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of version 2 of the GNU General Public License | ||
13 | * as published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/types.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kmod.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <sound/core.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/control.h> | ||
29 | #include "tw686x.h" | ||
30 | #include "tw686x-regs.h" | ||
31 | |||
32 | #define AUDIO_CHANNEL_OFFSET 8 | ||
33 | |||
34 | void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests, | ||
35 | unsigned int pb_status) | ||
36 | { | ||
37 | unsigned long flags; | ||
38 | unsigned int ch, pb; | ||
39 | |||
40 | for_each_set_bit(ch, &requests, max_channels(dev)) { | ||
41 | struct tw686x_audio_channel *ac = &dev->audio_channels[ch]; | ||
42 | struct tw686x_audio_buf *done = NULL; | ||
43 | struct tw686x_audio_buf *next = NULL; | ||
44 | struct tw686x_dma_desc *desc; | ||
45 | |||
46 | pb = !!(pb_status & BIT(AUDIO_CHANNEL_OFFSET + ch)); | ||
47 | |||
48 | spin_lock_irqsave(&ac->lock, flags); | ||
49 | |||
50 | /* Sanity check */ | ||
51 | if (!ac->ss || !ac->curr_bufs[0] || !ac->curr_bufs[1]) { | ||
52 | spin_unlock_irqrestore(&ac->lock, flags); | ||
53 | continue; | ||
54 | } | ||
55 | |||
56 | if (!list_empty(&ac->buf_list)) { | ||
57 | next = list_first_entry(&ac->buf_list, | ||
58 | struct tw686x_audio_buf, list); | ||
59 | list_move_tail(&next->list, &ac->buf_list); | ||
60 | done = ac->curr_bufs[!pb]; | ||
61 | ac->curr_bufs[pb] = next; | ||
62 | } | ||
63 | spin_unlock_irqrestore(&ac->lock, flags); | ||
64 | |||
65 | desc = &ac->dma_descs[pb]; | ||
66 | if (done && next && desc->virt) { | ||
67 | memcpy(done->virt, desc->virt, desc->size); | ||
68 | ac->ptr = done->dma - ac->buf[0].dma; | ||
69 | snd_pcm_period_elapsed(ac->ss); | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static int tw686x_pcm_hw_params(struct snd_pcm_substream *ss, | ||
75 | struct snd_pcm_hw_params *hw_params) | ||
76 | { | ||
77 | return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); | ||
78 | } | ||
79 | |||
80 | static int tw686x_pcm_hw_free(struct snd_pcm_substream *ss) | ||
81 | { | ||
82 | return snd_pcm_lib_free_pages(ss); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * The audio device rate is global and shared among all | ||
87 | * capture channels. The driver makes no effort to prevent | ||
88 | * rate modifications. User is free change the rate, but it | ||
89 | * means changing the rate for all capture sub-devices. | ||
90 | */ | ||
91 | static const struct snd_pcm_hardware tw686x_capture_hw = { | ||
92 | .info = (SNDRV_PCM_INFO_MMAP | | ||
93 | SNDRV_PCM_INFO_INTERLEAVED | | ||
94 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
95 | SNDRV_PCM_INFO_MMAP_VALID), | ||
96 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
97 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
98 | .rate_min = 8000, | ||
99 | .rate_max = 48000, | ||
100 | .channels_min = 1, | ||
101 | .channels_max = 1, | ||
102 | .buffer_bytes_max = TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ, | ||
103 | .period_bytes_min = TW686X_AUDIO_PAGE_SZ, | ||
104 | .period_bytes_max = TW686X_AUDIO_PAGE_SZ, | ||
105 | .periods_min = TW686X_AUDIO_PERIODS_MIN, | ||
106 | .periods_max = TW686X_AUDIO_PERIODS_MAX, | ||
107 | }; | ||
108 | |||
109 | static int tw686x_pcm_open(struct snd_pcm_substream *ss) | ||
110 | { | ||
111 | struct tw686x_dev *dev = snd_pcm_substream_chip(ss); | ||
112 | struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number]; | ||
113 | struct snd_pcm_runtime *rt = ss->runtime; | ||
114 | int err; | ||
115 | |||
116 | ac->ss = ss; | ||
117 | rt->hw = tw686x_capture_hw; | ||
118 | |||
119 | err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); | ||
120 | if (err < 0) | ||
121 | return err; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int tw686x_pcm_close(struct snd_pcm_substream *ss) | ||
127 | { | ||
128 | struct tw686x_dev *dev = snd_pcm_substream_chip(ss); | ||
129 | struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number]; | ||
130 | |||
131 | ac->ss = NULL; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int tw686x_pcm_prepare(struct snd_pcm_substream *ss) | ||
136 | { | ||
137 | struct tw686x_dev *dev = snd_pcm_substream_chip(ss); | ||
138 | struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number]; | ||
139 | struct snd_pcm_runtime *rt = ss->runtime; | ||
140 | unsigned int period_size = snd_pcm_lib_period_bytes(ss); | ||
141 | struct tw686x_audio_buf *p_buf, *b_buf; | ||
142 | unsigned long flags; | ||
143 | int i; | ||
144 | |||
145 | spin_lock_irqsave(&dev->lock, flags); | ||
146 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); | ||
147 | spin_unlock_irqrestore(&dev->lock, flags); | ||
148 | |||
149 | if (dev->audio_rate != rt->rate) { | ||
150 | u32 reg; | ||
151 | |||
152 | dev->audio_rate = rt->rate; | ||
153 | reg = ((125000000 / rt->rate) << 16) + | ||
154 | ((125000000 % rt->rate) << 16) / rt->rate; | ||
155 | |||
156 | reg_write(dev, AUDIO_CONTROL2, reg); | ||
157 | } | ||
158 | |||
159 | if (period_size != TW686X_AUDIO_PAGE_SZ || | ||
160 | rt->periods < TW686X_AUDIO_PERIODS_MIN || | ||
161 | rt->periods > TW686X_AUDIO_PERIODS_MAX) { | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | spin_lock_irqsave(&ac->lock, flags); | ||
166 | INIT_LIST_HEAD(&ac->buf_list); | ||
167 | |||
168 | for (i = 0; i < rt->periods; i++) { | ||
169 | ac->buf[i].dma = rt->dma_addr + period_size * i; | ||
170 | ac->buf[i].virt = rt->dma_area + period_size * i; | ||
171 | INIT_LIST_HEAD(&ac->buf[i].list); | ||
172 | list_add_tail(&ac->buf[i].list, &ac->buf_list); | ||
173 | } | ||
174 | |||
175 | p_buf = list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list); | ||
176 | list_move_tail(&p_buf->list, &ac->buf_list); | ||
177 | |||
178 | b_buf = list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list); | ||
179 | list_move_tail(&b_buf->list, &ac->buf_list); | ||
180 | |||
181 | ac->curr_bufs[0] = p_buf; | ||
182 | ac->curr_bufs[1] = b_buf; | ||
183 | ac->ptr = 0; | ||
184 | spin_unlock_irqrestore(&ac->lock, flags); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd) | ||
190 | { | ||
191 | struct tw686x_dev *dev = snd_pcm_substream_chip(ss); | ||
192 | struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number]; | ||
193 | unsigned long flags; | ||
194 | int err = 0; | ||
195 | |||
196 | switch (cmd) { | ||
197 | case SNDRV_PCM_TRIGGER_START: | ||
198 | if (ac->curr_bufs[0] && ac->curr_bufs[1]) { | ||
199 | spin_lock_irqsave(&dev->lock, flags); | ||
200 | tw686x_enable_channel(dev, | ||
201 | AUDIO_CHANNEL_OFFSET + ac->ch); | ||
202 | spin_unlock_irqrestore(&dev->lock, flags); | ||
203 | |||
204 | mod_timer(&dev->dma_delay_timer, | ||
205 | jiffies + msecs_to_jiffies(100)); | ||
206 | } else { | ||
207 | err = -EIO; | ||
208 | } | ||
209 | break; | ||
210 | case SNDRV_PCM_TRIGGER_STOP: | ||
211 | spin_lock_irqsave(&dev->lock, flags); | ||
212 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); | ||
213 | spin_unlock_irqrestore(&dev->lock, flags); | ||
214 | |||
215 | spin_lock_irqsave(&ac->lock, flags); | ||
216 | ac->curr_bufs[0] = NULL; | ||
217 | ac->curr_bufs[1] = NULL; | ||
218 | spin_unlock_irqrestore(&ac->lock, flags); | ||
219 | break; | ||
220 | default: | ||
221 | err = -EINVAL; | ||
222 | } | ||
223 | return err; | ||
224 | } | ||
225 | |||
226 | static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss) | ||
227 | { | ||
228 | struct tw686x_dev *dev = snd_pcm_substream_chip(ss); | ||
229 | struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number]; | ||
230 | |||
231 | return bytes_to_frames(ss->runtime, ac->ptr); | ||
232 | } | ||
233 | |||
234 | static struct snd_pcm_ops tw686x_pcm_ops = { | ||
235 | .open = tw686x_pcm_open, | ||
236 | .close = tw686x_pcm_close, | ||
237 | .ioctl = snd_pcm_lib_ioctl, | ||
238 | .hw_params = tw686x_pcm_hw_params, | ||
239 | .hw_free = tw686x_pcm_hw_free, | ||
240 | .prepare = tw686x_pcm_prepare, | ||
241 | .trigger = tw686x_pcm_trigger, | ||
242 | .pointer = tw686x_pcm_pointer, | ||
243 | }; | ||
244 | |||
245 | static int tw686x_snd_pcm_init(struct tw686x_dev *dev) | ||
246 | { | ||
247 | struct snd_card *card = dev->snd_card; | ||
248 | struct snd_pcm *pcm; | ||
249 | struct snd_pcm_substream *ss; | ||
250 | unsigned int i; | ||
251 | int err; | ||
252 | |||
253 | err = snd_pcm_new(card, card->driver, 0, 0, max_channels(dev), &pcm); | ||
254 | if (err < 0) | ||
255 | return err; | ||
256 | |||
257 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw686x_pcm_ops); | ||
258 | snd_pcm_chip(pcm) = dev; | ||
259 | pcm->info_flags = 0; | ||
260 | strlcpy(pcm->name, "tw686x PCM", sizeof(pcm->name)); | ||
261 | |||
262 | for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; | ||
263 | ss; ss = ss->next, i++) | ||
264 | snprintf(ss->name, sizeof(ss->name), "vch%u audio", i); | ||
265 | |||
266 | return snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
267 | SNDRV_DMA_TYPE_DEV, | ||
268 | snd_dma_pci_data(dev->pci_dev), | ||
269 | TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ, | ||
270 | TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ); | ||
271 | } | ||
272 | |||
273 | static void tw686x_audio_dma_free(struct tw686x_dev *dev, | ||
274 | struct tw686x_audio_channel *ac) | ||
275 | { | ||
276 | int pb; | ||
277 | |||
278 | for (pb = 0; pb < 2; pb++) { | ||
279 | if (!ac->dma_descs[pb].virt) | ||
280 | continue; | ||
281 | pci_free_consistent(dev->pci_dev, ac->dma_descs[pb].size, | ||
282 | ac->dma_descs[pb].virt, | ||
283 | ac->dma_descs[pb].phys); | ||
284 | ac->dma_descs[pb].virt = NULL; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static int tw686x_audio_dma_alloc(struct tw686x_dev *dev, | ||
289 | struct tw686x_audio_channel *ac) | ||
290 | { | ||
291 | int pb; | ||
292 | |||
293 | for (pb = 0; pb < 2; pb++) { | ||
294 | u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch]; | ||
295 | void *virt; | ||
296 | |||
297 | virt = pci_alloc_consistent(dev->pci_dev, TW686X_AUDIO_PAGE_SZ, | ||
298 | &ac->dma_descs[pb].phys); | ||
299 | if (!virt) { | ||
300 | dev_err(&dev->pci_dev->dev, | ||
301 | "dma%d: unable to allocate audio DMA %s-buffer\n", | ||
302 | ac->ch, pb ? "B" : "P"); | ||
303 | return -ENOMEM; | ||
304 | } | ||
305 | ac->dma_descs[pb].virt = virt; | ||
306 | ac->dma_descs[pb].size = TW686X_AUDIO_PAGE_SZ; | ||
307 | reg_write(dev, reg, ac->dma_descs[pb].phys); | ||
308 | } | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | void tw686x_audio_free(struct tw686x_dev *dev) | ||
313 | { | ||
314 | unsigned long flags; | ||
315 | u32 dma_ch_mask; | ||
316 | u32 dma_cmd; | ||
317 | |||
318 | spin_lock_irqsave(&dev->lock, flags); | ||
319 | dma_cmd = reg_read(dev, DMA_CMD); | ||
320 | dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE); | ||
321 | reg_write(dev, DMA_CMD, dma_cmd & ~0xff00); | ||
322 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask & ~0xff00); | ||
323 | spin_unlock_irqrestore(&dev->lock, flags); | ||
324 | |||
325 | if (!dev->snd_card) | ||
326 | return; | ||
327 | snd_card_free(dev->snd_card); | ||
328 | dev->snd_card = NULL; | ||
329 | } | ||
330 | |||
331 | int tw686x_audio_init(struct tw686x_dev *dev) | ||
332 | { | ||
333 | struct pci_dev *pci_dev = dev->pci_dev; | ||
334 | struct snd_card *card; | ||
335 | int err, ch; | ||
336 | |||
337 | /* | ||
338 | * AUDIO_CONTROL1 | ||
339 | * DMA byte length [31:19] = 4096 (i.e. ALSA period) | ||
340 | * External audio enable [0] = enabled | ||
341 | */ | ||
342 | reg_write(dev, AUDIO_CONTROL1, 0x80000001); | ||
343 | |||
344 | err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1, | ||
345 | SNDRV_DEFAULT_STR1, | ||
346 | THIS_MODULE, 0, &card); | ||
347 | if (err < 0) | ||
348 | return err; | ||
349 | |||
350 | dev->snd_card = card; | ||
351 | strlcpy(card->driver, "tw686x", sizeof(card->driver)); | ||
352 | strlcpy(card->shortname, "tw686x", sizeof(card->shortname)); | ||
353 | strlcpy(card->longname, pci_name(pci_dev), sizeof(card->longname)); | ||
354 | snd_card_set_dev(card, &pci_dev->dev); | ||
355 | |||
356 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
357 | struct tw686x_audio_channel *ac; | ||
358 | |||
359 | ac = &dev->audio_channels[ch]; | ||
360 | spin_lock_init(&ac->lock); | ||
361 | ac->dev = dev; | ||
362 | ac->ch = ch; | ||
363 | |||
364 | err = tw686x_audio_dma_alloc(dev, ac); | ||
365 | if (err < 0) | ||
366 | goto err_cleanup; | ||
367 | } | ||
368 | |||
369 | err = tw686x_snd_pcm_init(dev); | ||
370 | if (err < 0) | ||
371 | goto err_cleanup; | ||
372 | |||
373 | err = snd_card_register(card); | ||
374 | if (!err) | ||
375 | return 0; | ||
376 | |||
377 | err_cleanup: | ||
378 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
379 | if (!dev->audio_channels[ch].dev) | ||
380 | continue; | ||
381 | tw686x_audio_dma_free(dev, &dev->audio_channels[ch]); | ||
382 | } | ||
383 | snd_card_free(card); | ||
384 | dev->snd_card = NULL; | ||
385 | return err; | ||
386 | } | ||
diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c new file mode 100644 index 000000000000..cf53b0e97be2 --- /dev/null +++ b/drivers/media/pci/tw686x/tw686x-core.c | |||
@@ -0,0 +1,415 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar | ||
3 | * | ||
4 | * Based on original driver by Krzysztof Ha?asa: | ||
5 | * Copyright (C) 2015 Industrial Research Institute for Automation | ||
6 | * and Measurements PIAP | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of version 2 of the GNU General Public License | ||
10 | * as published by the Free Software Foundation. | ||
11 | * | ||
12 | * Notes | ||
13 | * ----- | ||
14 | * | ||
15 | * 1. Under stress-testing, it has been observed that the PCIe link | ||
16 | * goes down, without reason. Therefore, the driver takes special care | ||
17 | * to allow device hot-unplugging. | ||
18 | * | ||
19 | * 2. TW686X devices are capable of setting a few different DMA modes, | ||
20 | * including: scatter-gather, field and frame modes. However, | ||
21 | * under stress testings it has been found that the machine can | ||
22 | * freeze completely if DMA registers are programmed while streaming | ||
23 | * is active. | ||
24 | * This driver tries to access hardware registers as infrequently | ||
25 | * as possible by: | ||
26 | * i. allocating fixed DMA buffers and memcpy'ing into | ||
27 | * vmalloc'ed buffers | ||
28 | * ii. using a timer to mitigate the rate of DMA reset operations, | ||
29 | * on DMA channels error. | ||
30 | */ | ||
31 | |||
32 | #include <linux/init.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/pci_ids.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/timer.h> | ||
40 | |||
41 | #include "tw686x.h" | ||
42 | #include "tw686x-regs.h" | ||
43 | |||
44 | /* | ||
45 | * This module parameter allows to control the DMA_TIMER_INTERVAL value. | ||
46 | * The DMA_TIMER_INTERVAL register controls the minimum DMA interrupt | ||
47 | * time span (iow, the maximum DMA interrupt rate) thus allowing for | ||
48 | * IRQ coalescing. | ||
49 | * | ||
50 | * The chip datasheet does not mention a time unit for this value, so | ||
51 | * users wanting fine-grain control over the interrupt rate should | ||
52 | * determine the desired value through testing. | ||
53 | */ | ||
54 | static u32 dma_interval = 0x00098968; | ||
55 | module_param(dma_interval, int, 0444); | ||
56 | MODULE_PARM_DESC(dma_interval, "Minimum time span for DMA interrupting host"); | ||
57 | |||
58 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel) | ||
59 | { | ||
60 | u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | ||
61 | u32 dma_cmd = reg_read(dev, DMA_CMD); | ||
62 | |||
63 | dma_en &= ~BIT(channel); | ||
64 | dma_cmd &= ~BIT(channel); | ||
65 | |||
66 | /* Must remove it from pending too */ | ||
67 | dev->pending_dma_en &= ~BIT(channel); | ||
68 | dev->pending_dma_cmd &= ~BIT(channel); | ||
69 | |||
70 | /* Stop DMA if no channels are enabled */ | ||
71 | if (!dma_en) | ||
72 | dma_cmd = 0; | ||
73 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_en); | ||
74 | reg_write(dev, DMA_CMD, dma_cmd); | ||
75 | } | ||
76 | |||
77 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel) | ||
78 | { | ||
79 | u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | ||
80 | u32 dma_cmd = reg_read(dev, DMA_CMD); | ||
81 | |||
82 | dev->pending_dma_en |= dma_en | BIT(channel); | ||
83 | dev->pending_dma_cmd |= dma_cmd | DMA_CMD_ENABLE | BIT(channel); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * The purpose of this awful hack is to avoid enabling the DMA | ||
88 | * channels "too fast" which makes some TW686x devices very | ||
89 | * angry and freeze the CPU (see note 1). | ||
90 | */ | ||
91 | static void tw686x_dma_delay(unsigned long data) | ||
92 | { | ||
93 | struct tw686x_dev *dev = (struct tw686x_dev *)data; | ||
94 | unsigned long flags; | ||
95 | |||
96 | spin_lock_irqsave(&dev->lock, flags); | ||
97 | |||
98 | reg_write(dev, DMA_CHANNEL_ENABLE, dev->pending_dma_en); | ||
99 | reg_write(dev, DMA_CMD, dev->pending_dma_cmd); | ||
100 | dev->pending_dma_en = 0; | ||
101 | dev->pending_dma_cmd = 0; | ||
102 | |||
103 | spin_unlock_irqrestore(&dev->lock, flags); | ||
104 | } | ||
105 | |||
106 | static void tw686x_reset_channels(struct tw686x_dev *dev, unsigned int ch_mask) | ||
107 | { | ||
108 | u32 dma_en, dma_cmd; | ||
109 | |||
110 | dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | ||
111 | dma_cmd = reg_read(dev, DMA_CMD); | ||
112 | |||
113 | /* | ||
114 | * Save pending register status, the timer will | ||
115 | * restore them. | ||
116 | */ | ||
117 | dev->pending_dma_en |= dma_en; | ||
118 | dev->pending_dma_cmd |= dma_cmd; | ||
119 | |||
120 | /* Disable the reset channels */ | ||
121 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_en & ~ch_mask); | ||
122 | |||
123 | if ((dma_en & ~ch_mask) == 0) { | ||
124 | dev_dbg(&dev->pci_dev->dev, "reset: stopping DMA\n"); | ||
125 | dma_cmd &= ~DMA_CMD_ENABLE; | ||
126 | } | ||
127 | reg_write(dev, DMA_CMD, dma_cmd & ~ch_mask); | ||
128 | } | ||
129 | |||
130 | static irqreturn_t tw686x_irq(int irq, void *dev_id) | ||
131 | { | ||
132 | struct tw686x_dev *dev = (struct tw686x_dev *)dev_id; | ||
133 | unsigned int video_requests, audio_requests, reset_ch; | ||
134 | u32 fifo_status, fifo_signal, fifo_ov, fifo_bad, fifo_errors; | ||
135 | u32 int_status, dma_en, video_en, pb_status; | ||
136 | unsigned long flags; | ||
137 | |||
138 | int_status = reg_read(dev, INT_STATUS); /* cleared on read */ | ||
139 | fifo_status = reg_read(dev, VIDEO_FIFO_STATUS); | ||
140 | |||
141 | /* INT_STATUS does not include FIFO_STATUS errors! */ | ||
142 | if (!int_status && !TW686X_FIFO_ERROR(fifo_status)) | ||
143 | return IRQ_NONE; | ||
144 | |||
145 | if (int_status & INT_STATUS_DMA_TOUT) { | ||
146 | dev_dbg(&dev->pci_dev->dev, | ||
147 | "DMA timeout. Resetting DMA for all channels\n"); | ||
148 | reset_ch = ~0; | ||
149 | goto reset_channels; | ||
150 | } | ||
151 | |||
152 | spin_lock_irqsave(&dev->lock, flags); | ||
153 | dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | ||
154 | spin_unlock_irqrestore(&dev->lock, flags); | ||
155 | |||
156 | video_en = dma_en & 0xff; | ||
157 | fifo_signal = ~(fifo_status & 0xff) & video_en; | ||
158 | fifo_ov = fifo_status >> 24; | ||
159 | fifo_bad = fifo_status >> 16; | ||
160 | |||
161 | /* Mask of channels with signal and FIFO errors */ | ||
162 | fifo_errors = fifo_signal & (fifo_ov | fifo_bad); | ||
163 | |||
164 | reset_ch = 0; | ||
165 | pb_status = reg_read(dev, PB_STATUS); | ||
166 | |||
167 | /* Coalesce video frame/error events */ | ||
168 | video_requests = (int_status & video_en) | fifo_errors; | ||
169 | audio_requests = (int_status & dma_en) >> 8; | ||
170 | |||
171 | if (video_requests) | ||
172 | tw686x_video_irq(dev, video_requests, pb_status, | ||
173 | fifo_status, &reset_ch); | ||
174 | if (audio_requests) | ||
175 | tw686x_audio_irq(dev, audio_requests, pb_status); | ||
176 | |||
177 | reset_channels: | ||
178 | if (reset_ch) { | ||
179 | spin_lock_irqsave(&dev->lock, flags); | ||
180 | tw686x_reset_channels(dev, reset_ch); | ||
181 | spin_unlock_irqrestore(&dev->lock, flags); | ||
182 | mod_timer(&dev->dma_delay_timer, | ||
183 | jiffies + msecs_to_jiffies(100)); | ||
184 | } | ||
185 | |||
186 | return IRQ_HANDLED; | ||
187 | } | ||
188 | |||
189 | static void tw686x_dev_release(struct v4l2_device *v4l2_dev) | ||
190 | { | ||
191 | struct tw686x_dev *dev = container_of(v4l2_dev, struct tw686x_dev, | ||
192 | v4l2_dev); | ||
193 | unsigned int ch; | ||
194 | |||
195 | for (ch = 0; ch < max_channels(dev); ch++) | ||
196 | v4l2_ctrl_handler_free(&dev->video_channels[ch].ctrl_handler); | ||
197 | |||
198 | v4l2_device_unregister(&dev->v4l2_dev); | ||
199 | |||
200 | kfree(dev->audio_channels); | ||
201 | kfree(dev->video_channels); | ||
202 | kfree(dev); | ||
203 | } | ||
204 | |||
205 | static int tw686x_probe(struct pci_dev *pci_dev, | ||
206 | const struct pci_device_id *pci_id) | ||
207 | { | ||
208 | struct tw686x_dev *dev; | ||
209 | int err; | ||
210 | |||
211 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
212 | if (!dev) | ||
213 | return -ENOMEM; | ||
214 | dev->type = pci_id->driver_data; | ||
215 | sprintf(dev->name, "tw%04X", pci_dev->device); | ||
216 | |||
217 | dev->video_channels = kcalloc(max_channels(dev), | ||
218 | sizeof(*dev->video_channels), GFP_KERNEL); | ||
219 | if (!dev->video_channels) { | ||
220 | err = -ENOMEM; | ||
221 | goto free_dev; | ||
222 | } | ||
223 | |||
224 | dev->audio_channels = kcalloc(max_channels(dev), | ||
225 | sizeof(*dev->audio_channels), GFP_KERNEL); | ||
226 | if (!dev->audio_channels) { | ||
227 | err = -ENOMEM; | ||
228 | goto free_video; | ||
229 | } | ||
230 | |||
231 | pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name, | ||
232 | pci_name(pci_dev), pci_dev->irq, | ||
233 | (unsigned long)pci_resource_start(pci_dev, 0)); | ||
234 | |||
235 | dev->pci_dev = pci_dev; | ||
236 | if (pci_enable_device(pci_dev)) { | ||
237 | err = -EIO; | ||
238 | goto free_audio; | ||
239 | } | ||
240 | |||
241 | pci_set_master(pci_dev); | ||
242 | err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); | ||
243 | if (err) { | ||
244 | dev_err(&pci_dev->dev, "32-bit PCI DMA not supported\n"); | ||
245 | err = -EIO; | ||
246 | goto disable_pci; | ||
247 | } | ||
248 | |||
249 | err = pci_request_regions(pci_dev, dev->name); | ||
250 | if (err) { | ||
251 | dev_err(&pci_dev->dev, "unable to request PCI region\n"); | ||
252 | goto disable_pci; | ||
253 | } | ||
254 | |||
255 | dev->mmio = pci_ioremap_bar(pci_dev, 0); | ||
256 | if (!dev->mmio) { | ||
257 | dev_err(&pci_dev->dev, "unable to remap PCI region\n"); | ||
258 | err = -ENOMEM; | ||
259 | goto free_region; | ||
260 | } | ||
261 | |||
262 | /* Reset all subsystems */ | ||
263 | reg_write(dev, SYS_SOFT_RST, 0x0f); | ||
264 | mdelay(1); | ||
265 | |||
266 | reg_write(dev, SRST[0], 0x3f); | ||
267 | if (max_channels(dev) > 4) | ||
268 | reg_write(dev, SRST[1], 0x3f); | ||
269 | |||
270 | /* Disable the DMA engine */ | ||
271 | reg_write(dev, DMA_CMD, 0); | ||
272 | reg_write(dev, DMA_CHANNEL_ENABLE, 0); | ||
273 | |||
274 | /* Enable DMA FIFO overflow and pointer check */ | ||
275 | reg_write(dev, DMA_CONFIG, 0xffffff04); | ||
276 | reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x140c8584); | ||
277 | reg_write(dev, DMA_TIMER_INTERVAL, dma_interval); | ||
278 | |||
279 | spin_lock_init(&dev->lock); | ||
280 | |||
281 | err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED, | ||
282 | dev->name, dev); | ||
283 | if (err < 0) { | ||
284 | dev_err(&pci_dev->dev, "unable to request interrupt\n"); | ||
285 | goto iounmap; | ||
286 | } | ||
287 | |||
288 | setup_timer(&dev->dma_delay_timer, | ||
289 | tw686x_dma_delay, (unsigned long) dev); | ||
290 | |||
291 | /* | ||
292 | * This must be set right before initializing v4l2_dev. | ||
293 | * It's used to release resources after the last handle | ||
294 | * held is released. | ||
295 | */ | ||
296 | dev->v4l2_dev.release = tw686x_dev_release; | ||
297 | err = tw686x_video_init(dev); | ||
298 | if (err) { | ||
299 | dev_err(&pci_dev->dev, "can't register video\n"); | ||
300 | goto free_irq; | ||
301 | } | ||
302 | |||
303 | err = tw686x_audio_init(dev); | ||
304 | if (err) | ||
305 | dev_warn(&pci_dev->dev, "can't register audio\n"); | ||
306 | |||
307 | pci_set_drvdata(pci_dev, dev); | ||
308 | return 0; | ||
309 | |||
310 | free_irq: | ||
311 | free_irq(pci_dev->irq, dev); | ||
312 | iounmap: | ||
313 | pci_iounmap(pci_dev, dev->mmio); | ||
314 | free_region: | ||
315 | pci_release_regions(pci_dev); | ||
316 | disable_pci: | ||
317 | pci_disable_device(pci_dev); | ||
318 | free_audio: | ||
319 | kfree(dev->audio_channels); | ||
320 | free_video: | ||
321 | kfree(dev->video_channels); | ||
322 | free_dev: | ||
323 | kfree(dev); | ||
324 | return err; | ||
325 | } | ||
326 | |||
327 | static void tw686x_remove(struct pci_dev *pci_dev) | ||
328 | { | ||
329 | struct tw686x_dev *dev = pci_get_drvdata(pci_dev); | ||
330 | unsigned long flags; | ||
331 | |||
332 | /* This guarantees the IRQ handler is no longer running, | ||
333 | * which means we can kiss good-bye some resources. | ||
334 | */ | ||
335 | free_irq(pci_dev->irq, dev); | ||
336 | |||
337 | tw686x_video_free(dev); | ||
338 | tw686x_audio_free(dev); | ||
339 | del_timer_sync(&dev->dma_delay_timer); | ||
340 | |||
341 | pci_iounmap(pci_dev, dev->mmio); | ||
342 | pci_release_regions(pci_dev); | ||
343 | pci_disable_device(pci_dev); | ||
344 | |||
345 | /* | ||
346 | * Setting pci_dev to NULL allows to detect hardware is no longer | ||
347 | * available and will be used by vb2_ops. This is required because | ||
348 | * the device sometimes hot-unplugs itself as the result of a PCIe | ||
349 | * link down. | ||
350 | * The lock is really important here. | ||
351 | */ | ||
352 | spin_lock_irqsave(&dev->lock, flags); | ||
353 | dev->pci_dev = NULL; | ||
354 | spin_unlock_irqrestore(&dev->lock, flags); | ||
355 | |||
356 | /* | ||
357 | * This calls tw686x_dev_release if it's the last reference. | ||
358 | * Otherwise, release is postponed until there are no users left. | ||
359 | */ | ||
360 | v4l2_device_put(&dev->v4l2_dev); | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * On TW6864 and TW6868, all channels share the pair of video DMA SG tables, | ||
365 | * with 10-bit start_idx and end_idx determining start and end of frame buffer | ||
366 | * for particular channel. | ||
367 | * TW6868 with all its 8 channels would be problematic (only 127 SG entries per | ||
368 | * channel) but we support only 4 channels on this chip anyway (the first | ||
369 | * 4 channels are driven with internal video decoder, the other 4 would require | ||
370 | * an external TW286x part). | ||
371 | * | ||
372 | * On TW6865 and TW6869, each channel has its own DMA SG table, with indexes | ||
373 | * starting with 0. Both chips have complete sets of internal video decoders | ||
374 | * (respectively 4 or 8-channel). | ||
375 | * | ||
376 | * All chips have separate SG tables for two video frames. | ||
377 | */ | ||
378 | |||
379 | /* driver_data is number of A/V channels */ | ||
380 | static const struct pci_device_id tw686x_pci_tbl[] = { | ||
381 | { | ||
382 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6864), | ||
383 | .driver_data = 4 | ||
384 | }, | ||
385 | { | ||
386 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6865), /* not tested */ | ||
387 | .driver_data = 4 | TYPE_SECOND_GEN | ||
388 | }, | ||
389 | /* | ||
390 | * TW6868 supports 8 A/V channels with an external TW2865 chip; | ||
391 | * not supported by the driver. | ||
392 | */ | ||
393 | { | ||
394 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6868), /* not tested */ | ||
395 | .driver_data = 4 | ||
396 | }, | ||
397 | { | ||
398 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6869), | ||
399 | .driver_data = 8 | TYPE_SECOND_GEN}, | ||
400 | {} | ||
401 | }; | ||
402 | MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl); | ||
403 | |||
404 | static struct pci_driver tw686x_pci_driver = { | ||
405 | .name = "tw686x", | ||
406 | .id_table = tw686x_pci_tbl, | ||
407 | .probe = tw686x_probe, | ||
408 | .remove = tw686x_remove, | ||
409 | }; | ||
410 | module_pci_driver(tw686x_pci_driver); | ||
411 | |||
412 | MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]"); | ||
413 | MODULE_AUTHOR("Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>"); | ||
414 | MODULE_AUTHOR("Krzysztof Ha?asa <khalasa@piap.pl>"); | ||
415 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/pci/tw686x/tw686x-regs.h b/drivers/media/pci/tw686x/tw686x-regs.h new file mode 100644 index 000000000000..fcef586a4c8c --- /dev/null +++ b/drivers/media/pci/tw686x/tw686x-regs.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* DMA controller registers */ | ||
2 | #define REG8_1(a0) ((const u16[8]) { a0, a0 + 1, a0 + 2, a0 + 3, \ | ||
3 | a0 + 4, a0 + 5, a0 + 6, a0 + 7}) | ||
4 | #define REG8_2(a0) ((const u16[8]) { a0, a0 + 2, a0 + 4, a0 + 6, \ | ||
5 | a0 + 8, a0 + 0xa, a0 + 0xc, a0 + 0xe}) | ||
6 | #define REG8_8(a0) ((const u16[8]) { a0, a0 + 8, a0 + 0x10, a0 + 0x18, \ | ||
7 | a0 + 0x20, a0 + 0x28, a0 + 0x30, \ | ||
8 | a0 + 0x38}) | ||
9 | #define INT_STATUS 0x00 | ||
10 | #define PB_STATUS 0x01 | ||
11 | #define DMA_CMD 0x02 | ||
12 | #define VIDEO_FIFO_STATUS 0x03 | ||
13 | #define VIDEO_CHANNEL_ID 0x04 | ||
14 | #define VIDEO_PARSER_STATUS 0x05 | ||
15 | #define SYS_SOFT_RST 0x06 | ||
16 | #define DMA_PAGE_TABLE0_ADDR ((const u16[8]) { 0x08, 0xd0, 0xd2, 0xd4, \ | ||
17 | 0xd6, 0xd8, 0xda, 0xdc }) | ||
18 | #define DMA_PAGE_TABLE1_ADDR ((const u16[8]) { 0x09, 0xd1, 0xd3, 0xd5, \ | ||
19 | 0xd7, 0xd9, 0xdb, 0xdd }) | ||
20 | #define DMA_CHANNEL_ENABLE 0x0a | ||
21 | #define DMA_CONFIG 0x0b | ||
22 | #define DMA_TIMER_INTERVAL 0x0c | ||
23 | #define DMA_CHANNEL_TIMEOUT 0x0d | ||
24 | #define VDMA_CHANNEL_CONFIG REG8_1(0x10) | ||
25 | #define ADMA_P_ADDR REG8_2(0x18) | ||
26 | #define ADMA_B_ADDR REG8_2(0x19) | ||
27 | #define DMA10_P_ADDR 0x28 | ||
28 | #define DMA10_B_ADDR 0x29 | ||
29 | #define VIDEO_CONTROL1 0x2a | ||
30 | #define VIDEO_CONTROL2 0x2b | ||
31 | #define AUDIO_CONTROL1 0x2c | ||
32 | #define AUDIO_CONTROL2 0x2d | ||
33 | #define PHASE_REF 0x2e | ||
34 | #define GPIO_REG 0x2f | ||
35 | #define INTL_HBAR_CTRL REG8_1(0x30) | ||
36 | #define AUDIO_CONTROL3 0x38 | ||
37 | #define VIDEO_FIELD_CTRL REG8_1(0x39) | ||
38 | #define HSCALER_CTRL REG8_1(0x42) | ||
39 | #define VIDEO_SIZE REG8_1(0x4A) | ||
40 | #define VIDEO_SIZE_F2 REG8_1(0x52) | ||
41 | #define MD_CONF REG8_1(0x60) | ||
42 | #define MD_INIT REG8_1(0x68) | ||
43 | #define MD_MAP0 REG8_1(0x70) | ||
44 | #define VDMA_P_ADDR REG8_8(0x80) /* not used in DMA SG mode */ | ||
45 | #define VDMA_WHP REG8_8(0x81) | ||
46 | #define VDMA_B_ADDR REG8_8(0x82) | ||
47 | #define VDMA_F2_P_ADDR REG8_8(0x84) | ||
48 | #define VDMA_F2_WHP REG8_8(0x85) | ||
49 | #define VDMA_F2_B_ADDR REG8_8(0x86) | ||
50 | #define EP_REG_ADDR 0xfe | ||
51 | #define EP_REG_DATA 0xff | ||
52 | |||
53 | /* Video decoder registers */ | ||
54 | #define VDREG8(a0) ((const u16[8]) { \ | ||
55 | a0 + 0x000, a0 + 0x010, a0 + 0x020, a0 + 0x030, \ | ||
56 | a0 + 0x100, a0 + 0x110, a0 + 0x120, a0 + 0x130}) | ||
57 | #define VIDSTAT VDREG8(0x100) | ||
58 | #define BRIGHT VDREG8(0x101) | ||
59 | #define CONTRAST VDREG8(0x102) | ||
60 | #define SHARPNESS VDREG8(0x103) | ||
61 | #define SAT_U VDREG8(0x104) | ||
62 | #define SAT_V VDREG8(0x105) | ||
63 | #define HUE VDREG8(0x106) | ||
64 | #define CROP_HI VDREG8(0x107) | ||
65 | #define VDELAY_LO VDREG8(0x108) | ||
66 | #define VACTIVE_LO VDREG8(0x109) | ||
67 | #define HDELAY_LO VDREG8(0x10a) | ||
68 | #define HACTIVE_LO VDREG8(0x10b) | ||
69 | #define MVSN VDREG8(0x10c) | ||
70 | #define STATUS2 VDREG8(0x10d) | ||
71 | #define SDT VDREG8(0x10e) | ||
72 | #define SDT_EN VDREG8(0x10f) | ||
73 | |||
74 | #define VSCALE_LO VDREG8(0x144) | ||
75 | #define SCALE_HI VDREG8(0x145) | ||
76 | #define HSCALE_LO VDREG8(0x146) | ||
77 | #define F2CROP_HI VDREG8(0x147) | ||
78 | #define F2VDELAY_LO VDREG8(0x148) | ||
79 | #define F2VACTIVE_LO VDREG8(0x149) | ||
80 | #define F2HDELAY_LO VDREG8(0x14a) | ||
81 | #define F2HACTIVE_LO VDREG8(0x14b) | ||
82 | #define F2VSCALE_LO VDREG8(0x14c) | ||
83 | #define F2SCALE_HI VDREG8(0x14d) | ||
84 | #define F2HSCALE_LO VDREG8(0x14e) | ||
85 | #define F2CNT VDREG8(0x14f) | ||
86 | |||
87 | #define VDREG2(a0) ((const u16[2]) { a0, a0 + 0x100 }) | ||
88 | #define SRST VDREG2(0x180) | ||
89 | #define ACNTL VDREG2(0x181) | ||
90 | #define ACNTL2 VDREG2(0x182) | ||
91 | #define CNTRL1 VDREG2(0x183) | ||
92 | #define CKHY VDREG2(0x184) | ||
93 | #define SHCOR VDREG2(0x185) | ||
94 | #define CORING VDREG2(0x186) | ||
95 | #define CLMPG VDREG2(0x187) | ||
96 | #define IAGC VDREG2(0x188) | ||
97 | #define VCTRL1 VDREG2(0x18f) | ||
98 | #define MISC1 VDREG2(0x194) | ||
99 | #define LOOP VDREG2(0x195) | ||
100 | #define MISC2 VDREG2(0x196) | ||
101 | |||
102 | #define CLMD VDREG2(0x197) | ||
103 | #define ANPWRDOWN VDREG2(0x1ce) | ||
104 | #define AIGAIN ((const u16[8]) { 0x1d0, 0x1d1, 0x1d2, 0x1d3, \ | ||
105 | 0x2d0, 0x2d1, 0x2d2, 0x2d3 }) | ||
106 | |||
107 | #define SYS_MODE_DMA_SHIFT 13 | ||
108 | |||
109 | #define DMA_CMD_ENABLE BIT(31) | ||
110 | #define INT_STATUS_DMA_TOUT BIT(17) | ||
111 | #define TW686X_VIDSTAT_HLOCK BIT(6) | ||
112 | #define TW686X_VIDSTAT_VDLOSS BIT(7) | ||
113 | |||
114 | #define TW686X_STD_NTSC_M 0 | ||
115 | #define TW686X_STD_PAL 1 | ||
116 | #define TW686X_STD_SECAM 2 | ||
117 | #define TW686X_STD_NTSC_443 3 | ||
118 | #define TW686X_STD_PAL_M 4 | ||
119 | #define TW686X_STD_PAL_CN 5 | ||
120 | #define TW686X_STD_PAL_60 6 | ||
121 | |||
122 | #define TW686X_FIFO_ERROR(x) (x & ~(0xff)) | ||
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c new file mode 100644 index 000000000000..253e10823ba3 --- /dev/null +++ b/drivers/media/pci/tw686x/tw686x-video.c | |||
@@ -0,0 +1,937 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar | ||
3 | * | ||
4 | * Based on original driver by Krzysztof Ha?asa: | ||
5 | * Copyright (C) 2015 Industrial Research Institute for Automation | ||
6 | * and Measurements PIAP | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of version 2 of the GNU General Public License | ||
10 | * as published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/list.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <media/v4l2-common.h> | ||
21 | #include <media/v4l2-event.h> | ||
22 | #include <media/videobuf2-vmalloc.h> | ||
23 | #include "tw686x.h" | ||
24 | #include "tw686x-regs.h" | ||
25 | |||
26 | #define TW686X_INPUTS_PER_CH 4 | ||
27 | #define TW686X_VIDEO_WIDTH 720 | ||
28 | #define TW686X_VIDEO_HEIGHT(id) ((id & V4L2_STD_525_60) ? 480 : 576) | ||
29 | |||
30 | static const struct tw686x_format formats[] = { | ||
31 | { | ||
32 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
33 | .mode = 0, | ||
34 | .depth = 16, | ||
35 | }, { | ||
36 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
37 | .mode = 5, | ||
38 | .depth = 16, | ||
39 | }, { | ||
40 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
41 | .mode = 6, | ||
42 | .depth = 16, | ||
43 | } | ||
44 | }; | ||
45 | |||
46 | static unsigned int tw686x_fields_map(v4l2_std_id std, unsigned int fps) | ||
47 | { | ||
48 | static const unsigned int map[15] = { | ||
49 | 0x00000000, 0x00000001, 0x00004001, 0x00104001, 0x00404041, | ||
50 | 0x01041041, 0x01104411, 0x01111111, 0x04444445, 0x04511445, | ||
51 | 0x05145145, 0x05151515, 0x05515455, 0x05551555, 0x05555555 | ||
52 | }; | ||
53 | |||
54 | static const unsigned int std_625_50[26] = { | ||
55 | 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, | ||
56 | 8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 0 | ||
57 | }; | ||
58 | |||
59 | static const unsigned int std_525_60[31] = { | ||
60 | 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, | ||
61 | 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 0, 0 | ||
62 | }; | ||
63 | |||
64 | unsigned int i; | ||
65 | |||
66 | if (std & V4L2_STD_525_60) { | ||
67 | if (fps >= ARRAY_SIZE(std_525_60)) | ||
68 | fps = 30; | ||
69 | i = std_525_60[fps]; | ||
70 | } else { | ||
71 | if (fps >= ARRAY_SIZE(std_625_50)) | ||
72 | fps = 25; | ||
73 | i = std_625_50[fps]; | ||
74 | } | ||
75 | |||
76 | return map[i]; | ||
77 | } | ||
78 | |||
79 | static void tw686x_set_framerate(struct tw686x_video_channel *vc, | ||
80 | unsigned int fps) | ||
81 | { | ||
82 | unsigned int map; | ||
83 | |||
84 | if (vc->fps == fps) | ||
85 | return; | ||
86 | |||
87 | map = tw686x_fields_map(vc->video_standard, fps) << 1; | ||
88 | map |= map << 1; | ||
89 | if (map > 0) | ||
90 | map |= BIT(31); | ||
91 | reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], map); | ||
92 | vc->fps = fps; | ||
93 | } | ||
94 | |||
95 | static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) | ||
96 | { | ||
97 | unsigned int cnt; | ||
98 | |||
99 | for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++) | ||
100 | if (formats[cnt].fourcc == fourcc) | ||
101 | return &formats[cnt]; | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | static int tw686x_queue_setup(struct vb2_queue *vq, | ||
106 | unsigned int *nbuffers, unsigned int *nplanes, | ||
107 | unsigned int sizes[], void *alloc_ctxs[]) | ||
108 | { | ||
109 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | ||
110 | unsigned int szimage = | ||
111 | (vc->width * vc->height * vc->format->depth) >> 3; | ||
112 | |||
113 | /* | ||
114 | * Let's request at least three buffers: two for the | ||
115 | * DMA engine and one for userspace. | ||
116 | */ | ||
117 | if (vq->num_buffers + *nbuffers < 3) | ||
118 | *nbuffers = 3 - vq->num_buffers; | ||
119 | |||
120 | if (*nplanes) { | ||
121 | if (*nplanes != 1 || sizes[0] < szimage) | ||
122 | return -EINVAL; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | sizes[0] = szimage; | ||
127 | *nplanes = 1; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void tw686x_buf_queue(struct vb2_buffer *vb) | ||
132 | { | ||
133 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue); | ||
134 | struct tw686x_dev *dev = vc->dev; | ||
135 | struct pci_dev *pci_dev; | ||
136 | unsigned long flags; | ||
137 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
138 | struct tw686x_v4l2_buf *buf = | ||
139 | container_of(vbuf, struct tw686x_v4l2_buf, vb); | ||
140 | |||
141 | /* Check device presence */ | ||
142 | spin_lock_irqsave(&dev->lock, flags); | ||
143 | pci_dev = dev->pci_dev; | ||
144 | spin_unlock_irqrestore(&dev->lock, flags); | ||
145 | if (!pci_dev) { | ||
146 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | spin_lock_irqsave(&vc->qlock, flags); | ||
151 | list_add_tail(&buf->list, &vc->vidq_queued); | ||
152 | spin_unlock_irqrestore(&vc->qlock, flags); | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * We can call this even when alloc_dma failed for the given channel | ||
157 | */ | ||
158 | static void tw686x_free_dma(struct tw686x_video_channel *vc, unsigned int pb) | ||
159 | { | ||
160 | struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | ||
161 | struct tw686x_dev *dev = vc->dev; | ||
162 | struct pci_dev *pci_dev; | ||
163 | unsigned long flags; | ||
164 | |||
165 | /* Check device presence. Shouldn't really happen! */ | ||
166 | spin_lock_irqsave(&dev->lock, flags); | ||
167 | pci_dev = dev->pci_dev; | ||
168 | spin_unlock_irqrestore(&dev->lock, flags); | ||
169 | if (!pci_dev) { | ||
170 | WARN(1, "trying to deallocate on missing device\n"); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | if (desc->virt) { | ||
175 | pci_free_consistent(dev->pci_dev, desc->size, | ||
176 | desc->virt, desc->phys); | ||
177 | desc->virt = NULL; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static int tw686x_alloc_dma(struct tw686x_video_channel *vc, unsigned int pb) | ||
182 | { | ||
183 | struct tw686x_dev *dev = vc->dev; | ||
184 | u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch]; | ||
185 | unsigned int len; | ||
186 | void *virt; | ||
187 | |||
188 | WARN(vc->dma_descs[pb].virt, | ||
189 | "Allocating buffer but previous still here\n"); | ||
190 | |||
191 | len = (vc->width * vc->height * vc->format->depth) >> 3; | ||
192 | virt = pci_alloc_consistent(dev->pci_dev, len, | ||
193 | &vc->dma_descs[pb].phys); | ||
194 | if (!virt) { | ||
195 | v4l2_err(&dev->v4l2_dev, | ||
196 | "dma%d: unable to allocate %s-buffer\n", | ||
197 | vc->ch, pb ? "B" : "P"); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | vc->dma_descs[pb].size = len; | ||
201 | vc->dma_descs[pb].virt = virt; | ||
202 | reg_write(dev, reg, vc->dma_descs[pb].phys); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static void tw686x_buffer_refill(struct tw686x_video_channel *vc, | ||
208 | unsigned int pb) | ||
209 | { | ||
210 | struct tw686x_v4l2_buf *buf; | ||
211 | |||
212 | while (!list_empty(&vc->vidq_queued)) { | ||
213 | |||
214 | buf = list_first_entry(&vc->vidq_queued, | ||
215 | struct tw686x_v4l2_buf, list); | ||
216 | list_del(&buf->list); | ||
217 | |||
218 | vc->curr_bufs[pb] = buf; | ||
219 | return; | ||
220 | } | ||
221 | vc->curr_bufs[pb] = NULL; | ||
222 | } | ||
223 | |||
224 | static void tw686x_clear_queue(struct tw686x_video_channel *vc, | ||
225 | enum vb2_buffer_state state) | ||
226 | { | ||
227 | unsigned int pb; | ||
228 | |||
229 | while (!list_empty(&vc->vidq_queued)) { | ||
230 | struct tw686x_v4l2_buf *buf; | ||
231 | |||
232 | buf = list_first_entry(&vc->vidq_queued, | ||
233 | struct tw686x_v4l2_buf, list); | ||
234 | list_del(&buf->list); | ||
235 | vb2_buffer_done(&buf->vb.vb2_buf, state); | ||
236 | } | ||
237 | |||
238 | for (pb = 0; pb < 2; pb++) { | ||
239 | if (vc->curr_bufs[pb]) | ||
240 | vb2_buffer_done(&vc->curr_bufs[pb]->vb.vb2_buf, state); | ||
241 | vc->curr_bufs[pb] = NULL; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
246 | { | ||
247 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | ||
248 | struct tw686x_dev *dev = vc->dev; | ||
249 | struct pci_dev *pci_dev; | ||
250 | unsigned long flags; | ||
251 | int pb, err; | ||
252 | |||
253 | /* Check device presence */ | ||
254 | spin_lock_irqsave(&dev->lock, flags); | ||
255 | pci_dev = dev->pci_dev; | ||
256 | spin_unlock_irqrestore(&dev->lock, flags); | ||
257 | if (!pci_dev) { | ||
258 | err = -ENODEV; | ||
259 | goto err_clear_queue; | ||
260 | } | ||
261 | |||
262 | spin_lock_irqsave(&vc->qlock, flags); | ||
263 | |||
264 | /* Sanity check */ | ||
265 | if (!vc->dma_descs[0].virt || !vc->dma_descs[1].virt) { | ||
266 | spin_unlock_irqrestore(&vc->qlock, flags); | ||
267 | v4l2_err(&dev->v4l2_dev, | ||
268 | "video%d: refusing to start without DMA buffers\n", | ||
269 | vc->num); | ||
270 | err = -ENOMEM; | ||
271 | goto err_clear_queue; | ||
272 | } | ||
273 | |||
274 | for (pb = 0; pb < 2; pb++) | ||
275 | tw686x_buffer_refill(vc, pb); | ||
276 | spin_unlock_irqrestore(&vc->qlock, flags); | ||
277 | |||
278 | vc->sequence = 0; | ||
279 | vc->pb = 0; | ||
280 | |||
281 | spin_lock_irqsave(&dev->lock, flags); | ||
282 | tw686x_enable_channel(dev, vc->ch); | ||
283 | spin_unlock_irqrestore(&dev->lock, flags); | ||
284 | |||
285 | mod_timer(&dev->dma_delay_timer, jiffies + msecs_to_jiffies(100)); | ||
286 | |||
287 | return 0; | ||
288 | |||
289 | err_clear_queue: | ||
290 | spin_lock_irqsave(&vc->qlock, flags); | ||
291 | tw686x_clear_queue(vc, VB2_BUF_STATE_QUEUED); | ||
292 | spin_unlock_irqrestore(&vc->qlock, flags); | ||
293 | return err; | ||
294 | } | ||
295 | |||
296 | static void tw686x_stop_streaming(struct vb2_queue *vq) | ||
297 | { | ||
298 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | ||
299 | struct tw686x_dev *dev = vc->dev; | ||
300 | struct pci_dev *pci_dev; | ||
301 | unsigned long flags; | ||
302 | |||
303 | /* Check device presence */ | ||
304 | spin_lock_irqsave(&dev->lock, flags); | ||
305 | pci_dev = dev->pci_dev; | ||
306 | spin_unlock_irqrestore(&dev->lock, flags); | ||
307 | if (pci_dev) | ||
308 | tw686x_disable_channel(dev, vc->ch); | ||
309 | |||
310 | spin_lock_irqsave(&vc->qlock, flags); | ||
311 | tw686x_clear_queue(vc, VB2_BUF_STATE_ERROR); | ||
312 | spin_unlock_irqrestore(&vc->qlock, flags); | ||
313 | } | ||
314 | |||
315 | static int tw686x_buf_prepare(struct vb2_buffer *vb) | ||
316 | { | ||
317 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue); | ||
318 | unsigned int size = | ||
319 | (vc->width * vc->height * vc->format->depth) >> 3; | ||
320 | |||
321 | if (vb2_plane_size(vb, 0) < size) | ||
322 | return -EINVAL; | ||
323 | vb2_set_plane_payload(vb, 0, size); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static struct vb2_ops tw686x_video_qops = { | ||
328 | .queue_setup = tw686x_queue_setup, | ||
329 | .buf_queue = tw686x_buf_queue, | ||
330 | .buf_prepare = tw686x_buf_prepare, | ||
331 | .start_streaming = tw686x_start_streaming, | ||
332 | .stop_streaming = tw686x_stop_streaming, | ||
333 | .wait_prepare = vb2_ops_wait_prepare, | ||
334 | .wait_finish = vb2_ops_wait_finish, | ||
335 | }; | ||
336 | |||
337 | static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl) | ||
338 | { | ||
339 | struct tw686x_video_channel *vc; | ||
340 | struct tw686x_dev *dev; | ||
341 | unsigned int ch; | ||
342 | |||
343 | vc = container_of(ctrl->handler, struct tw686x_video_channel, | ||
344 | ctrl_handler); | ||
345 | dev = vc->dev; | ||
346 | ch = vc->ch; | ||
347 | |||
348 | switch (ctrl->id) { | ||
349 | case V4L2_CID_BRIGHTNESS: | ||
350 | reg_write(dev, BRIGHT[ch], ctrl->val & 0xff); | ||
351 | return 0; | ||
352 | |||
353 | case V4L2_CID_CONTRAST: | ||
354 | reg_write(dev, CONTRAST[ch], ctrl->val); | ||
355 | return 0; | ||
356 | |||
357 | case V4L2_CID_SATURATION: | ||
358 | reg_write(dev, SAT_U[ch], ctrl->val); | ||
359 | reg_write(dev, SAT_V[ch], ctrl->val); | ||
360 | return 0; | ||
361 | |||
362 | case V4L2_CID_HUE: | ||
363 | reg_write(dev, HUE[ch], ctrl->val & 0xff); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | static const struct v4l2_ctrl_ops ctrl_ops = { | ||
371 | .s_ctrl = tw686x_s_ctrl, | ||
372 | }; | ||
373 | |||
374 | static int tw686x_g_fmt_vid_cap(struct file *file, void *priv, | ||
375 | struct v4l2_format *f) | ||
376 | { | ||
377 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
378 | |||
379 | f->fmt.pix.width = vc->width; | ||
380 | f->fmt.pix.height = vc->height; | ||
381 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
382 | f->fmt.pix.pixelformat = vc->format->fourcc; | ||
383 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
384 | f->fmt.pix.bytesperline = (f->fmt.pix.width * vc->format->depth) / 8; | ||
385 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, | ||
390 | struct v4l2_format *f) | ||
391 | { | ||
392 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
393 | unsigned int video_height = TW686X_VIDEO_HEIGHT(vc->video_standard); | ||
394 | const struct tw686x_format *format; | ||
395 | |||
396 | format = format_by_fourcc(f->fmt.pix.pixelformat); | ||
397 | if (!format) { | ||
398 | format = &formats[0]; | ||
399 | f->fmt.pix.pixelformat = format->fourcc; | ||
400 | } | ||
401 | |||
402 | if (f->fmt.pix.width <= TW686X_VIDEO_WIDTH / 2) | ||
403 | f->fmt.pix.width = TW686X_VIDEO_WIDTH / 2; | ||
404 | else | ||
405 | f->fmt.pix.width = TW686X_VIDEO_WIDTH; | ||
406 | |||
407 | if (f->fmt.pix.height <= video_height / 2) | ||
408 | f->fmt.pix.height = video_height / 2; | ||
409 | else | ||
410 | f->fmt.pix.height = video_height; | ||
411 | |||
412 | f->fmt.pix.bytesperline = (f->fmt.pix.width * format->depth) / 8; | ||
413 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
414 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
415 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, | ||
421 | struct v4l2_format *f) | ||
422 | { | ||
423 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
424 | u32 val, width, line_width, height; | ||
425 | unsigned long bitsperframe; | ||
426 | int err, pb; | ||
427 | |||
428 | if (vb2_is_busy(&vc->vidq)) | ||
429 | return -EBUSY; | ||
430 | |||
431 | bitsperframe = vc->width * vc->height * vc->format->depth; | ||
432 | err = tw686x_try_fmt_vid_cap(file, priv, f); | ||
433 | if (err) | ||
434 | return err; | ||
435 | |||
436 | vc->format = format_by_fourcc(f->fmt.pix.pixelformat); | ||
437 | vc->width = f->fmt.pix.width; | ||
438 | vc->height = f->fmt.pix.height; | ||
439 | |||
440 | /* We need new DMA buffers if the framesize has changed */ | ||
441 | if (bitsperframe != vc->width * vc->height * vc->format->depth) { | ||
442 | for (pb = 0; pb < 2; pb++) | ||
443 | tw686x_free_dma(vc, pb); | ||
444 | |||
445 | for (pb = 0; pb < 2; pb++) { | ||
446 | err = tw686x_alloc_dma(vc, pb); | ||
447 | if (err) { | ||
448 | if (pb > 0) | ||
449 | tw686x_free_dma(vc, 0); | ||
450 | return err; | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]); | ||
456 | |||
457 | if (vc->width <= TW686X_VIDEO_WIDTH / 2) | ||
458 | val |= BIT(23); | ||
459 | else | ||
460 | val &= ~BIT(23); | ||
461 | |||
462 | if (vc->height <= TW686X_VIDEO_HEIGHT(vc->video_standard) / 2) | ||
463 | val |= BIT(24); | ||
464 | else | ||
465 | val &= ~BIT(24); | ||
466 | |||
467 | val &= ~(0x7 << 20); | ||
468 | val |= vc->format->mode << 20; | ||
469 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); | ||
470 | |||
471 | /* Program the DMA frame size */ | ||
472 | width = (vc->width * 2) & 0x7ff; | ||
473 | height = vc->height / 2; | ||
474 | line_width = (vc->width * 2) & 0x7ff; | ||
475 | val = (height << 22) | (line_width << 11) | width; | ||
476 | reg_write(vc->dev, VDMA_WHP[vc->ch], val); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int tw686x_querycap(struct file *file, void *priv, | ||
481 | struct v4l2_capability *cap) | ||
482 | { | ||
483 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
484 | struct tw686x_dev *dev = vc->dev; | ||
485 | |||
486 | strlcpy(cap->driver, "tw686x", sizeof(cap->driver)); | ||
487 | strlcpy(cap->card, dev->name, sizeof(cap->card)); | ||
488 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ||
489 | "PCI:%s", pci_name(dev->pci_dev)); | ||
490 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
491 | V4L2_CAP_READWRITE; | ||
492 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) | ||
497 | { | ||
498 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
499 | struct v4l2_format f; | ||
500 | u32 val, ret; | ||
501 | |||
502 | if (vc->video_standard == id) | ||
503 | return 0; | ||
504 | |||
505 | if (vb2_is_busy(&vc->vidq)) | ||
506 | return -EBUSY; | ||
507 | |||
508 | if (id & V4L2_STD_NTSC) | ||
509 | val = 0; | ||
510 | else if (id & V4L2_STD_PAL) | ||
511 | val = 1; | ||
512 | else if (id & V4L2_STD_SECAM) | ||
513 | val = 2; | ||
514 | else if (id & V4L2_STD_NTSC_443) | ||
515 | val = 3; | ||
516 | else if (id & V4L2_STD_PAL_M) | ||
517 | val = 4; | ||
518 | else if (id & V4L2_STD_PAL_Nc) | ||
519 | val = 5; | ||
520 | else if (id & V4L2_STD_PAL_60) | ||
521 | val = 6; | ||
522 | else | ||
523 | return -EINVAL; | ||
524 | |||
525 | vc->video_standard = id; | ||
526 | reg_write(vc->dev, SDT[vc->ch], val); | ||
527 | |||
528 | val = reg_read(vc->dev, VIDEO_CONTROL1); | ||
529 | if (id & V4L2_STD_525_60) | ||
530 | val &= ~(1 << (SYS_MODE_DMA_SHIFT + vc->ch)); | ||
531 | else | ||
532 | val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch)); | ||
533 | reg_write(vc->dev, VIDEO_CONTROL1, val); | ||
534 | |||
535 | /* | ||
536 | * Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change, | ||
537 | * calling g_fmt and s_fmt will sanitize the height | ||
538 | * according to the standard. | ||
539 | */ | ||
540 | ret = tw686x_g_fmt_vid_cap(file, priv, &f); | ||
541 | if (!ret) | ||
542 | tw686x_s_fmt_vid_cap(file, priv, &f); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static int tw686x_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
547 | { | ||
548 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
549 | struct tw686x_dev *dev = vc->dev; | ||
550 | unsigned int old_std, detected_std = 0; | ||
551 | unsigned long end; | ||
552 | |||
553 | if (vb2_is_streaming(&vc->vidq)) | ||
554 | return -EBUSY; | ||
555 | |||
556 | /* Enable and start standard detection */ | ||
557 | old_std = reg_read(dev, SDT[vc->ch]); | ||
558 | reg_write(dev, SDT[vc->ch], 0x7); | ||
559 | reg_write(dev, SDT_EN[vc->ch], 0xff); | ||
560 | |||
561 | end = jiffies + msecs_to_jiffies(500); | ||
562 | while (time_is_after_jiffies(end)) { | ||
563 | |||
564 | detected_std = reg_read(dev, SDT[vc->ch]); | ||
565 | if (!(detected_std & BIT(7))) | ||
566 | break; | ||
567 | msleep(100); | ||
568 | } | ||
569 | reg_write(dev, SDT[vc->ch], old_std); | ||
570 | |||
571 | /* Exit if still busy */ | ||
572 | if (detected_std & BIT(7)) | ||
573 | return 0; | ||
574 | |||
575 | detected_std = (detected_std >> 4) & 0x7; | ||
576 | switch (detected_std) { | ||
577 | case TW686X_STD_NTSC_M: | ||
578 | *std &= V4L2_STD_NTSC; | ||
579 | break; | ||
580 | case TW686X_STD_NTSC_443: | ||
581 | *std &= V4L2_STD_NTSC_443; | ||
582 | break; | ||
583 | case TW686X_STD_PAL_M: | ||
584 | *std &= V4L2_STD_PAL_M; | ||
585 | break; | ||
586 | case TW686X_STD_PAL_60: | ||
587 | *std &= V4L2_STD_PAL_60; | ||
588 | break; | ||
589 | case TW686X_STD_PAL: | ||
590 | *std &= V4L2_STD_PAL; | ||
591 | break; | ||
592 | case TW686X_STD_PAL_CN: | ||
593 | *std &= V4L2_STD_PAL_Nc; | ||
594 | break; | ||
595 | case TW686X_STD_SECAM: | ||
596 | *std &= V4L2_STD_SECAM; | ||
597 | break; | ||
598 | default: | ||
599 | *std = 0; | ||
600 | } | ||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id) | ||
605 | { | ||
606 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
607 | |||
608 | *id = vc->video_standard; | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, | ||
613 | struct v4l2_fmtdesc *f) | ||
614 | { | ||
615 | if (f->index >= ARRAY_SIZE(formats)) | ||
616 | return -EINVAL; | ||
617 | f->pixelformat = formats[f->index].fourcc; | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static int tw686x_s_input(struct file *file, void *priv, unsigned int i) | ||
622 | { | ||
623 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
624 | u32 val; | ||
625 | |||
626 | if (i >= TW686X_INPUTS_PER_CH) | ||
627 | return -EINVAL; | ||
628 | if (i == vc->input) | ||
629 | return 0; | ||
630 | /* | ||
631 | * Not sure we are able to support on the fly input change | ||
632 | */ | ||
633 | if (vb2_is_busy(&vc->vidq)) | ||
634 | return -EBUSY; | ||
635 | |||
636 | vc->input = i; | ||
637 | |||
638 | val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]); | ||
639 | val &= ~(0x3 << 30); | ||
640 | val |= i << 30; | ||
641 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static int tw686x_g_input(struct file *file, void *priv, unsigned int *i) | ||
646 | { | ||
647 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
648 | |||
649 | *i = vc->input; | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int tw686x_enum_input(struct file *file, void *priv, | ||
654 | struct v4l2_input *i) | ||
655 | { | ||
656 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
657 | unsigned int vidstat; | ||
658 | |||
659 | if (i->index >= TW686X_INPUTS_PER_CH) | ||
660 | return -EINVAL; | ||
661 | |||
662 | snprintf(i->name, sizeof(i->name), "Composite%d", i->index); | ||
663 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
664 | i->std = vc->device->tvnorms; | ||
665 | i->capabilities = V4L2_IN_CAP_STD; | ||
666 | |||
667 | vidstat = reg_read(vc->dev, VIDSTAT[vc->ch]); | ||
668 | i->status = 0; | ||
669 | if (vidstat & TW686X_VIDSTAT_VDLOSS) | ||
670 | i->status |= V4L2_IN_ST_NO_SIGNAL; | ||
671 | if (!(vidstat & TW686X_VIDSTAT_HLOCK)) | ||
672 | i->status |= V4L2_IN_ST_NO_H_LOCK; | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static const struct v4l2_file_operations tw686x_video_fops = { | ||
678 | .owner = THIS_MODULE, | ||
679 | .open = v4l2_fh_open, | ||
680 | .unlocked_ioctl = video_ioctl2, | ||
681 | .release = vb2_fop_release, | ||
682 | .poll = vb2_fop_poll, | ||
683 | .read = vb2_fop_read, | ||
684 | .mmap = vb2_fop_mmap, | ||
685 | }; | ||
686 | |||
687 | static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { | ||
688 | .vidioc_querycap = tw686x_querycap, | ||
689 | .vidioc_g_fmt_vid_cap = tw686x_g_fmt_vid_cap, | ||
690 | .vidioc_s_fmt_vid_cap = tw686x_s_fmt_vid_cap, | ||
691 | .vidioc_enum_fmt_vid_cap = tw686x_enum_fmt_vid_cap, | ||
692 | .vidioc_try_fmt_vid_cap = tw686x_try_fmt_vid_cap, | ||
693 | |||
694 | .vidioc_querystd = tw686x_querystd, | ||
695 | .vidioc_g_std = tw686x_g_std, | ||
696 | .vidioc_s_std = tw686x_s_std, | ||
697 | |||
698 | .vidioc_enum_input = tw686x_enum_input, | ||
699 | .vidioc_g_input = tw686x_g_input, | ||
700 | .vidioc_s_input = tw686x_s_input, | ||
701 | |||
702 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
703 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
704 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
705 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
706 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
707 | .vidioc_streamon = vb2_ioctl_streamon, | ||
708 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
709 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
710 | |||
711 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
712 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
713 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
714 | }; | ||
715 | |||
716 | static void tw686x_buffer_copy(struct tw686x_video_channel *vc, | ||
717 | unsigned int pb, struct vb2_v4l2_buffer *vb) | ||
718 | { | ||
719 | struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | ||
720 | struct vb2_buffer *vb2_buf = &vb->vb2_buf; | ||
721 | |||
722 | vb->field = V4L2_FIELD_INTERLACED; | ||
723 | vb->sequence = vc->sequence++; | ||
724 | |||
725 | memcpy(vb2_plane_vaddr(vb2_buf, 0), desc->virt, desc->size); | ||
726 | vb2_buf->timestamp = ktime_get_ns(); | ||
727 | vb2_buffer_done(vb2_buf, VB2_BUF_STATE_DONE); | ||
728 | } | ||
729 | |||
730 | void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, | ||
731 | unsigned int pb_status, unsigned int fifo_status, | ||
732 | unsigned int *reset_ch) | ||
733 | { | ||
734 | struct tw686x_video_channel *vc; | ||
735 | struct vb2_v4l2_buffer *vb; | ||
736 | unsigned long flags; | ||
737 | unsigned int ch, pb; | ||
738 | |||
739 | for_each_set_bit(ch, &requests, max_channels(dev)) { | ||
740 | vc = &dev->video_channels[ch]; | ||
741 | |||
742 | /* | ||
743 | * This can either be a blue frame (with signal-lost bit set) | ||
744 | * or a good frame (with signal-lost bit clear). If we have just | ||
745 | * got signal, then this channel needs resetting. | ||
746 | */ | ||
747 | if (vc->no_signal && !(fifo_status & BIT(ch))) { | ||
748 | v4l2_printk(KERN_DEBUG, &dev->v4l2_dev, | ||
749 | "video%d: signal recovered\n", vc->num); | ||
750 | vc->no_signal = false; | ||
751 | *reset_ch |= BIT(ch); | ||
752 | vc->pb = 0; | ||
753 | continue; | ||
754 | } | ||
755 | vc->no_signal = !!(fifo_status & BIT(ch)); | ||
756 | |||
757 | /* Check FIFO errors only if there's signal */ | ||
758 | if (!vc->no_signal) { | ||
759 | u32 fifo_ov, fifo_bad; | ||
760 | |||
761 | fifo_ov = (fifo_status >> 24) & BIT(ch); | ||
762 | fifo_bad = (fifo_status >> 16) & BIT(ch); | ||
763 | if (fifo_ov || fifo_bad) { | ||
764 | /* Mark this channel for reset */ | ||
765 | v4l2_printk(KERN_DEBUG, &dev->v4l2_dev, | ||
766 | "video%d: FIFO error\n", vc->num); | ||
767 | *reset_ch |= BIT(ch); | ||
768 | vc->pb = 0; | ||
769 | continue; | ||
770 | } | ||
771 | } | ||
772 | |||
773 | pb = !!(pb_status & BIT(ch)); | ||
774 | if (vc->pb != pb) { | ||
775 | /* Mark this channel for reset */ | ||
776 | v4l2_printk(KERN_DEBUG, &dev->v4l2_dev, | ||
777 | "video%d: unexpected p-b buffer!\n", | ||
778 | vc->num); | ||
779 | *reset_ch |= BIT(ch); | ||
780 | vc->pb = 0; | ||
781 | continue; | ||
782 | } | ||
783 | |||
784 | /* handle video stream */ | ||
785 | spin_lock_irqsave(&vc->qlock, flags); | ||
786 | if (vc->curr_bufs[pb]) { | ||
787 | vb = &vc->curr_bufs[pb]->vb; | ||
788 | tw686x_buffer_copy(vc, pb, vb); | ||
789 | } | ||
790 | vc->pb = !pb; | ||
791 | tw686x_buffer_refill(vc, pb); | ||
792 | spin_unlock_irqrestore(&vc->qlock, flags); | ||
793 | } | ||
794 | } | ||
795 | |||
796 | void tw686x_video_free(struct tw686x_dev *dev) | ||
797 | { | ||
798 | unsigned int ch, pb; | ||
799 | |||
800 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
801 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; | ||
802 | |||
803 | if (vc->device) | ||
804 | video_unregister_device(vc->device); | ||
805 | |||
806 | for (pb = 0; pb < 2; pb++) | ||
807 | tw686x_free_dma(vc, pb); | ||
808 | } | ||
809 | } | ||
810 | |||
811 | int tw686x_video_init(struct tw686x_dev *dev) | ||
812 | { | ||
813 | unsigned int ch, val, pb; | ||
814 | int err; | ||
815 | |||
816 | err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev); | ||
817 | if (err) | ||
818 | return err; | ||
819 | |||
820 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
821 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; | ||
822 | struct video_device *vdev; | ||
823 | |||
824 | mutex_init(&vc->vb_mutex); | ||
825 | spin_lock_init(&vc->qlock); | ||
826 | INIT_LIST_HEAD(&vc->vidq_queued); | ||
827 | |||
828 | vc->dev = dev; | ||
829 | vc->ch = ch; | ||
830 | |||
831 | /* default settings */ | ||
832 | vc->format = &formats[0]; | ||
833 | vc->video_standard = V4L2_STD_NTSC; | ||
834 | vc->width = TW686X_VIDEO_WIDTH; | ||
835 | vc->height = TW686X_VIDEO_HEIGHT(vc->video_standard); | ||
836 | vc->input = 0; | ||
837 | |||
838 | reg_write(vc->dev, SDT[ch], 0); | ||
839 | tw686x_set_framerate(vc, 30); | ||
840 | |||
841 | reg_write(dev, VDELAY_LO[ch], 0x14); | ||
842 | reg_write(dev, HACTIVE_LO[ch], 0xd0); | ||
843 | reg_write(dev, VIDEO_SIZE[ch], 0); | ||
844 | |||
845 | for (pb = 0; pb < 2; pb++) { | ||
846 | err = tw686x_alloc_dma(vc, pb); | ||
847 | if (err) | ||
848 | goto error; | ||
849 | } | ||
850 | |||
851 | vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; | ||
852 | vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
853 | vc->vidq.drv_priv = vc; | ||
854 | vc->vidq.buf_struct_size = sizeof(struct tw686x_v4l2_buf); | ||
855 | vc->vidq.ops = &tw686x_video_qops; | ||
856 | vc->vidq.mem_ops = &vb2_vmalloc_memops; | ||
857 | vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
858 | vc->vidq.min_buffers_needed = 2; | ||
859 | vc->vidq.lock = &vc->vb_mutex; | ||
860 | vc->vidq.gfp_flags = GFP_DMA32; | ||
861 | |||
862 | err = vb2_queue_init(&vc->vidq); | ||
863 | if (err) { | ||
864 | v4l2_err(&dev->v4l2_dev, | ||
865 | "dma%d: cannot init vb2 queue\n", ch); | ||
866 | goto error; | ||
867 | } | ||
868 | |||
869 | err = v4l2_ctrl_handler_init(&vc->ctrl_handler, 4); | ||
870 | if (err) { | ||
871 | v4l2_err(&dev->v4l2_dev, | ||
872 | "dma%d: cannot init ctrl handler\n", ch); | ||
873 | goto error; | ||
874 | } | ||
875 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
876 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); | ||
877 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
878 | V4L2_CID_CONTRAST, 0, 255, 1, 100); | ||
879 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
880 | V4L2_CID_SATURATION, 0, 255, 1, 128); | ||
881 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
882 | V4L2_CID_HUE, -128, 127, 1, 0); | ||
883 | err = vc->ctrl_handler.error; | ||
884 | if (err) | ||
885 | goto error; | ||
886 | |||
887 | err = v4l2_ctrl_handler_setup(&vc->ctrl_handler); | ||
888 | if (err) | ||
889 | goto error; | ||
890 | |||
891 | vdev = video_device_alloc(); | ||
892 | if (!vdev) { | ||
893 | v4l2_err(&dev->v4l2_dev, | ||
894 | "dma%d: unable to allocate device\n", ch); | ||
895 | err = -ENOMEM; | ||
896 | goto error; | ||
897 | } | ||
898 | |||
899 | snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name); | ||
900 | vdev->fops = &tw686x_video_fops; | ||
901 | vdev->ioctl_ops = &tw686x_video_ioctl_ops; | ||
902 | vdev->release = video_device_release; | ||
903 | vdev->v4l2_dev = &dev->v4l2_dev; | ||
904 | vdev->queue = &vc->vidq; | ||
905 | vdev->tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50; | ||
906 | vdev->minor = -1; | ||
907 | vdev->lock = &vc->vb_mutex; | ||
908 | vdev->ctrl_handler = &vc->ctrl_handler; | ||
909 | vc->device = vdev; | ||
910 | video_set_drvdata(vdev, vc); | ||
911 | |||
912 | err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | ||
913 | if (err < 0) | ||
914 | goto error; | ||
915 | vc->num = vdev->num; | ||
916 | } | ||
917 | |||
918 | /* Set DMA frame mode on all channels. Only supported mode for now. */ | ||
919 | val = TW686X_DEF_PHASE_REF; | ||
920 | for (ch = 0; ch < max_channels(dev); ch++) | ||
921 | val |= TW686X_FRAME_MODE << (16 + ch * 2); | ||
922 | reg_write(dev, PHASE_REF, val); | ||
923 | |||
924 | reg_write(dev, MISC2[0], 0xe7); | ||
925 | reg_write(dev, VCTRL1[0], 0xcc); | ||
926 | reg_write(dev, LOOP[0], 0xa5); | ||
927 | if (max_channels(dev) > 4) { | ||
928 | reg_write(dev, VCTRL1[1], 0xcc); | ||
929 | reg_write(dev, LOOP[1], 0xa5); | ||
930 | reg_write(dev, MISC2[1], 0xe7); | ||
931 | } | ||
932 | return 0; | ||
933 | |||
934 | error: | ||
935 | tw686x_video_free(dev); | ||
936 | return err; | ||
937 | } | ||
diff --git a/drivers/media/pci/tw686x/tw686x.h b/drivers/media/pci/tw686x/tw686x.h new file mode 100644 index 000000000000..44b5755acf02 --- /dev/null +++ b/drivers/media/pci/tw686x/tw686x.h | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar | ||
3 | * | ||
4 | * Copyright (C) 2015 Industrial Research Institute for Automation | ||
5 | * and Measurements PIAP | ||
6 | * Written by Krzysztof Ha?asa | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of version 2 of the GNU General Public License | ||
10 | * as published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/mutex.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/timer.h> | ||
16 | #include <linux/videodev2.h> | ||
17 | #include <media/v4l2-common.h> | ||
18 | #include <media/v4l2-ctrls.h> | ||
19 | #include <media/v4l2-device.h> | ||
20 | #include <media/v4l2-ioctl.h> | ||
21 | #include <media/videobuf2-v4l2.h> | ||
22 | #include <sound/pcm.h> | ||
23 | |||
24 | #include "tw686x-regs.h" | ||
25 | |||
26 | #define TYPE_MAX_CHANNELS 0x0f | ||
27 | #define TYPE_SECOND_GEN 0x10 | ||
28 | #define TW686X_DEF_PHASE_REF 0x1518 | ||
29 | |||
30 | #define TW686X_FIELD_MODE 0x3 | ||
31 | #define TW686X_FRAME_MODE 0x2 | ||
32 | /* 0x1 is reserved */ | ||
33 | #define TW686X_SG_MODE 0x0 | ||
34 | |||
35 | #define TW686X_AUDIO_PAGE_SZ 4096 | ||
36 | #define TW686X_AUDIO_PAGE_MAX 16 | ||
37 | #define TW686X_AUDIO_PERIODS_MIN 2 | ||
38 | #define TW686X_AUDIO_PERIODS_MAX TW686X_AUDIO_PAGE_MAX | ||
39 | |||
40 | struct tw686x_format { | ||
41 | char *name; | ||
42 | unsigned int fourcc; | ||
43 | unsigned int depth; | ||
44 | unsigned int mode; | ||
45 | }; | ||
46 | |||
47 | struct tw686x_dma_desc { | ||
48 | dma_addr_t phys; | ||
49 | void *virt; | ||
50 | unsigned int size; | ||
51 | }; | ||
52 | |||
53 | struct tw686x_audio_buf { | ||
54 | dma_addr_t dma; | ||
55 | void *virt; | ||
56 | struct list_head list; | ||
57 | }; | ||
58 | |||
59 | struct tw686x_v4l2_buf { | ||
60 | struct vb2_v4l2_buffer vb; | ||
61 | struct list_head list; | ||
62 | }; | ||
63 | |||
64 | struct tw686x_audio_channel { | ||
65 | struct tw686x_dev *dev; | ||
66 | struct snd_pcm_substream *ss; | ||
67 | unsigned int ch; | ||
68 | struct tw686x_audio_buf *curr_bufs[2]; | ||
69 | struct tw686x_dma_desc dma_descs[2]; | ||
70 | dma_addr_t ptr; | ||
71 | |||
72 | struct tw686x_audio_buf buf[TW686X_AUDIO_PAGE_MAX]; | ||
73 | struct list_head buf_list; | ||
74 | spinlock_t lock; | ||
75 | }; | ||
76 | |||
77 | struct tw686x_video_channel { | ||
78 | struct tw686x_dev *dev; | ||
79 | |||
80 | struct vb2_queue vidq; | ||
81 | struct list_head vidq_queued; | ||
82 | struct video_device *device; | ||
83 | struct tw686x_v4l2_buf *curr_bufs[2]; | ||
84 | struct tw686x_dma_desc dma_descs[2]; | ||
85 | |||
86 | struct v4l2_ctrl_handler ctrl_handler; | ||
87 | const struct tw686x_format *format; | ||
88 | struct mutex vb_mutex; | ||
89 | spinlock_t qlock; | ||
90 | v4l2_std_id video_standard; | ||
91 | unsigned int width, height; | ||
92 | unsigned int h_halve, v_halve; | ||
93 | unsigned int ch; | ||
94 | unsigned int num; | ||
95 | unsigned int fps; | ||
96 | unsigned int input; | ||
97 | unsigned int sequence; | ||
98 | unsigned int pb; | ||
99 | bool no_signal; | ||
100 | }; | ||
101 | |||
102 | /** | ||
103 | * struct tw686x_dev - global device status | ||
104 | * @lock: spinlock controlling access to the | ||
105 | * shared device registers (DMA enable/disable). | ||
106 | */ | ||
107 | struct tw686x_dev { | ||
108 | spinlock_t lock; | ||
109 | |||
110 | struct v4l2_device v4l2_dev; | ||
111 | struct snd_card *snd_card; | ||
112 | |||
113 | char name[32]; | ||
114 | unsigned int type; | ||
115 | struct pci_dev *pci_dev; | ||
116 | __u32 __iomem *mmio; | ||
117 | |||
118 | void *alloc_ctx; | ||
119 | |||
120 | struct tw686x_video_channel *video_channels; | ||
121 | struct tw686x_audio_channel *audio_channels; | ||
122 | |||
123 | int audio_rate; /* per-device value */ | ||
124 | |||
125 | struct timer_list dma_delay_timer; | ||
126 | u32 pending_dma_en; /* must be protected by lock */ | ||
127 | u32 pending_dma_cmd; /* must be protected by lock */ | ||
128 | }; | ||
129 | |||
130 | static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg) | ||
131 | { | ||
132 | return readl(dev->mmio + reg); | ||
133 | } | ||
134 | |||
135 | static inline void reg_write(struct tw686x_dev *dev, unsigned int reg, | ||
136 | uint32_t value) | ||
137 | { | ||
138 | writel(value, dev->mmio + reg); | ||
139 | } | ||
140 | |||
141 | static inline unsigned int max_channels(struct tw686x_dev *dev) | ||
142 | { | ||
143 | return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */ | ||
144 | } | ||
145 | |||
146 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel); | ||
147 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel); | ||
148 | |||
149 | int tw686x_video_init(struct tw686x_dev *dev); | ||
150 | void tw686x_video_free(struct tw686x_dev *dev); | ||
151 | void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, | ||
152 | unsigned int pb_status, unsigned int fifo_status, | ||
153 | unsigned int *reset_ch); | ||
154 | |||
155 | int tw686x_audio_init(struct tw686x_dev *dev); | ||
156 | void tw686x_audio_free(struct tw686x_dev *dev); | ||
157 | void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests, | ||
158 | unsigned int pb_status); | ||
diff --git a/drivers/media/pci/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c index c01071635290..13a3c07cd259 100644 --- a/drivers/media/pci/zoran/videocodec.c +++ b/drivers/media/pci/zoran/videocodec.c | |||
@@ -116,8 +116,9 @@ videocodec_attach (struct videocodec_master *master) | |||
116 | goto out_module_put; | 116 | goto out_module_put; |
117 | } | 117 | } |
118 | 118 | ||
119 | snprintf(codec->name, sizeof(codec->name), | 119 | res = strlen(codec->name); |
120 | "%s[%d]", codec->name, h->attached); | 120 | snprintf(codec->name + res, sizeof(codec->name) - res, |
121 | "[%d]", h->attached); | ||
121 | codec->master_data = master; | 122 | codec->master_data = master; |
122 | res = codec->setup(codec); | 123 | res = codec->setup(codec); |
123 | if (res == 0) { | 124 | if (res == 0) { |
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 201f5c296a95..84e041c0a70e 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -238,7 +238,7 @@ config VIDEO_SH_VEU | |||
238 | config VIDEO_RENESAS_JPU | 238 | config VIDEO_RENESAS_JPU |
239 | tristate "Renesas JPEG Processing Unit" | 239 | tristate "Renesas JPEG Processing Unit" |
240 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | 240 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA |
241 | depends on ARCH_SHMOBILE || COMPILE_TEST | 241 | depends on ARCH_RENESAS || COMPILE_TEST |
242 | select VIDEOBUF2_DMA_CONTIG | 242 | select VIDEOBUF2_DMA_CONTIG |
243 | select V4L2_MEM2MEM_DEV | 243 | select V4L2_MEM2MEM_DEV |
244 | ---help--- | 244 | ---help--- |
@@ -250,7 +250,7 @@ config VIDEO_RENESAS_JPU | |||
250 | config VIDEO_RENESAS_VSP1 | 250 | config VIDEO_RENESAS_VSP1 |
251 | tristate "Renesas VSP1 Video Processing Engine" | 251 | tristate "Renesas VSP1 Video Processing Engine" |
252 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA | 252 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA |
253 | depends on (ARCH_SHMOBILE && OF) || COMPILE_TEST | 253 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST |
254 | select VIDEOBUF2_DMA_CONTIG | 254 | select VIDEOBUF2_DMA_CONTIG |
255 | ---help--- | 255 | ---help--- |
256 | This is a V4L2 driver for the Renesas VSP1 video processing engine. | 256 | This is a V4L2 driver for the Renesas VSP1 video processing engine. |
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index de32e3a3d4d1..e749eb7c3be9 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c | |||
@@ -1047,7 +1047,7 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe, | |||
1047 | static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) | 1047 | static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) |
1048 | { | 1048 | { |
1049 | enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; | 1049 | enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; |
1050 | int ret; | 1050 | int ret = 0; |
1051 | 1051 | ||
1052 | vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); | 1052 | vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); |
1053 | 1053 | ||
@@ -1706,7 +1706,7 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe, | |||
1706 | sdinfo = &cfg->sub_devs[i]; | 1706 | sdinfo = &cfg->sub_devs[i]; |
1707 | client = v4l2_get_subdevdata(sdinfo->sd); | 1707 | client = v4l2_get_subdevdata(sdinfo->sd); |
1708 | if (client->addr == curr_client->addr && | 1708 | if (client->addr == curr_client->addr && |
1709 | client->adapter->nr == client->adapter->nr) { | 1709 | client->adapter->nr == curr_client->adapter->nr) { |
1710 | if (vpfe->current_input >= 1) | 1710 | if (vpfe->current_input >= 1) |
1711 | return -1; | 1711 | return -1; |
1712 | *app_input_index = j + vpfe->current_input; | 1712 | *app_input_index = j + vpfe->current_input; |
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 9b9e423e4fc4..c04973669a47 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c | |||
@@ -967,15 +967,6 @@ static struct gsc_driverdata gsc_v_100_drvdata = { | |||
967 | .lclk_frequency = 266000000UL, | 967 | .lclk_frequency = 266000000UL, |
968 | }; | 968 | }; |
969 | 969 | ||
970 | static const struct platform_device_id gsc_driver_ids[] = { | ||
971 | { | ||
972 | .name = "exynos-gsc", | ||
973 | .driver_data = (unsigned long)&gsc_v_100_drvdata, | ||
974 | }, | ||
975 | {}, | ||
976 | }; | ||
977 | MODULE_DEVICE_TABLE(platform, gsc_driver_ids); | ||
978 | |||
979 | static const struct of_device_id exynos_gsc_match[] = { | 970 | static const struct of_device_id exynos_gsc_match[] = { |
980 | { | 971 | { |
981 | .compatible = "samsung,exynos5-gsc", | 972 | .compatible = "samsung,exynos5-gsc", |
@@ -988,17 +979,11 @@ MODULE_DEVICE_TABLE(of, exynos_gsc_match); | |||
988 | static void *gsc_get_drv_data(struct platform_device *pdev) | 979 | static void *gsc_get_drv_data(struct platform_device *pdev) |
989 | { | 980 | { |
990 | struct gsc_driverdata *driver_data = NULL; | 981 | struct gsc_driverdata *driver_data = NULL; |
982 | const struct of_device_id *match; | ||
991 | 983 | ||
992 | if (pdev->dev.of_node) { | 984 | match = of_match_node(exynos_gsc_match, pdev->dev.of_node); |
993 | const struct of_device_id *match; | 985 | if (match) |
994 | match = of_match_node(exynos_gsc_match, | 986 | driver_data = (struct gsc_driverdata *)match->data; |
995 | pdev->dev.of_node); | ||
996 | if (match) | ||
997 | driver_data = (struct gsc_driverdata *)match->data; | ||
998 | } else { | ||
999 | driver_data = (struct gsc_driverdata *) | ||
1000 | platform_get_device_id(pdev)->driver_data; | ||
1001 | } | ||
1002 | 987 | ||
1003 | return driver_data; | 988 | return driver_data; |
1004 | } | 989 | } |
@@ -1078,17 +1063,17 @@ static int gsc_probe(struct platform_device *pdev) | |||
1078 | struct resource *res; | 1063 | struct resource *res; |
1079 | struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev); | 1064 | struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev); |
1080 | struct device *dev = &pdev->dev; | 1065 | struct device *dev = &pdev->dev; |
1081 | int ret = 0; | 1066 | int ret; |
1082 | 1067 | ||
1083 | gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); | 1068 | gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); |
1084 | if (!gsc) | 1069 | if (!gsc) |
1085 | return -ENOMEM; | 1070 | return -ENOMEM; |
1086 | 1071 | ||
1087 | if (dev->of_node) | 1072 | ret = of_alias_get_id(pdev->dev.of_node, "gsc"); |
1088 | gsc->id = of_alias_get_id(pdev->dev.of_node, "gsc"); | 1073 | if (ret < 0) |
1089 | else | 1074 | return ret; |
1090 | gsc->id = pdev->id; | ||
1091 | 1075 | ||
1076 | gsc->id = ret; | ||
1092 | if (gsc->id >= drv_data->num_entities) { | 1077 | if (gsc->id >= drv_data->num_entities) { |
1093 | dev_err(dev, "Invalid platform device id: %d\n", gsc->id); | 1078 | dev_err(dev, "Invalid platform device id: %d\n", gsc->id); |
1094 | return -EINVAL; | 1079 | return -EINVAL; |
@@ -1096,7 +1081,6 @@ static int gsc_probe(struct platform_device *pdev) | |||
1096 | 1081 | ||
1097 | gsc->variant = drv_data->variant[gsc->id]; | 1082 | gsc->variant = drv_data->variant[gsc->id]; |
1098 | gsc->pdev = pdev; | 1083 | gsc->pdev = pdev; |
1099 | gsc->pdata = dev->platform_data; | ||
1100 | 1084 | ||
1101 | init_waitqueue_head(&gsc->irq_queue); | 1085 | init_waitqueue_head(&gsc->irq_queue); |
1102 | spin_lock_init(&gsc->slock); | 1086 | spin_lock_init(&gsc->slock); |
@@ -1253,7 +1237,6 @@ static const struct dev_pm_ops gsc_pm_ops = { | |||
1253 | static struct platform_driver gsc_driver = { | 1237 | static struct platform_driver gsc_driver = { |
1254 | .probe = gsc_probe, | 1238 | .probe = gsc_probe, |
1255 | .remove = gsc_remove, | 1239 | .remove = gsc_remove, |
1256 | .id_table = gsc_driver_ids, | ||
1257 | .driver = { | 1240 | .driver = { |
1258 | .name = GSC_MODULE_NAME, | 1241 | .name = GSC_MODULE_NAME, |
1259 | .pm = &gsc_pm_ops, | 1242 | .pm = &gsc_pm_ops, |
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index e93a2336cfa2..ec4000c72172 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h | |||
@@ -340,7 +340,6 @@ struct gsc_dev { | |||
340 | void __iomem *regs; | 340 | void __iomem *regs; |
341 | wait_queue_head_t irq_queue; | 341 | wait_queue_head_t irq_queue; |
342 | struct gsc_m2m_device m2m; | 342 | struct gsc_m2m_device m2m; |
343 | struct exynos_platform_gscaler *pdata; | ||
344 | unsigned long state; | 343 | unsigned long state; |
345 | struct vb2_alloc_ctx *alloc_ctx; | 344 | struct vb2_alloc_ctx *alloc_ctx; |
346 | struct video_device vdev; | 345 | struct video_device vdev; |
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index cef2a7f07cdb..b1c1cea82a27 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c | |||
@@ -1154,26 +1154,6 @@ static const struct fimc_pix_limit s5p_pix_limit[4] = { | |||
1154 | }, | 1154 | }, |
1155 | }; | 1155 | }; |
1156 | 1156 | ||
1157 | static const struct fimc_variant fimc0_variant_s5p = { | ||
1158 | .has_inp_rot = 1, | ||
1159 | .has_out_rot = 1, | ||
1160 | .has_cam_if = 1, | ||
1161 | .min_inp_pixsize = 16, | ||
1162 | .min_out_pixsize = 16, | ||
1163 | .hor_offs_align = 8, | ||
1164 | .min_vsize_align = 16, | ||
1165 | .pix_limit = &s5p_pix_limit[0], | ||
1166 | }; | ||
1167 | |||
1168 | static const struct fimc_variant fimc2_variant_s5p = { | ||
1169 | .has_cam_if = 1, | ||
1170 | .min_inp_pixsize = 16, | ||
1171 | .min_out_pixsize = 16, | ||
1172 | .hor_offs_align = 8, | ||
1173 | .min_vsize_align = 16, | ||
1174 | .pix_limit = &s5p_pix_limit[1], | ||
1175 | }; | ||
1176 | |||
1177 | static const struct fimc_variant fimc0_variant_s5pv210 = { | 1157 | static const struct fimc_variant fimc0_variant_s5pv210 = { |
1178 | .has_inp_rot = 1, | 1158 | .has_inp_rot = 1, |
1179 | .has_out_rot = 1, | 1159 | .has_out_rot = 1, |
@@ -1206,18 +1186,6 @@ static const struct fimc_variant fimc2_variant_s5pv210 = { | |||
1206 | .pix_limit = &s5p_pix_limit[2], | 1186 | .pix_limit = &s5p_pix_limit[2], |
1207 | }; | 1187 | }; |
1208 | 1188 | ||
1209 | /* S5PC100 */ | ||
1210 | static const struct fimc_drvdata fimc_drvdata_s5p = { | ||
1211 | .variant = { | ||
1212 | [0] = &fimc0_variant_s5p, | ||
1213 | [1] = &fimc0_variant_s5p, | ||
1214 | [2] = &fimc2_variant_s5p, | ||
1215 | }, | ||
1216 | .num_entities = 3, | ||
1217 | .lclk_frequency = 133000000UL, | ||
1218 | .out_buf_count = 4, | ||
1219 | }; | ||
1220 | |||
1221 | /* S5PV210, S5PC110 */ | 1189 | /* S5PV210, S5PC110 */ |
1222 | static const struct fimc_drvdata fimc_drvdata_s5pv210 = { | 1190 | static const struct fimc_drvdata fimc_drvdata_s5pv210 = { |
1223 | .variant = { | 1191 | .variant = { |
@@ -1251,23 +1219,6 @@ static const struct fimc_drvdata fimc_drvdata_exynos4x12 = { | |||
1251 | .out_buf_count = 32, | 1219 | .out_buf_count = 32, |
1252 | }; | 1220 | }; |
1253 | 1221 | ||
1254 | static const struct platform_device_id fimc_driver_ids[] = { | ||
1255 | { | ||
1256 | .name = "s5p-fimc", | ||
1257 | .driver_data = (unsigned long)&fimc_drvdata_s5p, | ||
1258 | }, { | ||
1259 | .name = "s5pv210-fimc", | ||
1260 | .driver_data = (unsigned long)&fimc_drvdata_s5pv210, | ||
1261 | }, { | ||
1262 | .name = "exynos4-fimc", | ||
1263 | .driver_data = (unsigned long)&fimc_drvdata_exynos4210, | ||
1264 | }, { | ||
1265 | .name = "exynos4x12-fimc", | ||
1266 | .driver_data = (unsigned long)&fimc_drvdata_exynos4x12, | ||
1267 | }, | ||
1268 | { }, | ||
1269 | }; | ||
1270 | |||
1271 | static const struct of_device_id fimc_of_match[] = { | 1222 | static const struct of_device_id fimc_of_match[] = { |
1272 | { | 1223 | { |
1273 | .compatible = "samsung,s5pv210-fimc", | 1224 | .compatible = "samsung,s5pv210-fimc", |
@@ -1290,7 +1241,6 @@ static const struct dev_pm_ops fimc_pm_ops = { | |||
1290 | static struct platform_driver fimc_driver = { | 1241 | static struct platform_driver fimc_driver = { |
1291 | .probe = fimc_probe, | 1242 | .probe = fimc_probe, |
1292 | .remove = fimc_remove, | 1243 | .remove = fimc_remove, |
1293 | .id_table = fimc_driver_ids, | ||
1294 | .driver = { | 1244 | .driver = { |
1295 | .of_match_table = fimc_of_match, | 1245 | .of_match_table = fimc_of_match, |
1296 | .name = FIMC_DRIVER_NAME, | 1246 | .name = FIMC_DRIVER_NAME, |
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 4f494acd8150..891625e77ef5 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c | |||
@@ -446,8 +446,10 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, | |||
446 | else | 446 | else |
447 | pd->fimc_bus_type = pd->sensor_bus_type; | 447 | pd->fimc_bus_type = pd->sensor_bus_type; |
448 | 448 | ||
449 | if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) | 449 | if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) { |
450 | of_node_put(rem); | ||
450 | return -EINVAL; | 451 | return -EINVAL; |
452 | } | ||
451 | 453 | ||
452 | fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF; | 454 | fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF; |
453 | fmd->sensor[index].asd.match.of.node = rem; | 455 | fmd->sensor[index].asd.match.of.node = rem; |
@@ -1130,7 +1132,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable, | |||
1130 | media_entity_graph_walk_start(graph, entity); | 1132 | media_entity_graph_walk_start(graph, entity); |
1131 | 1133 | ||
1132 | while ((entity = media_entity_graph_walk_next(graph))) { | 1134 | while ((entity = media_entity_graph_walk_next(graph))) { |
1133 | if (!is_media_entity_v4l2_io(entity)) | 1135 | if (!is_media_entity_v4l2_video_device(entity)) |
1134 | continue; | 1136 | continue; |
1135 | 1137 | ||
1136 | ret = __fimc_md_modify_pipeline(entity, enable); | 1138 | ret = __fimc_md_modify_pipeline(entity, enable); |
@@ -1145,7 +1147,7 @@ err: | |||
1145 | media_entity_graph_walk_start(graph, entity_err); | 1147 | media_entity_graph_walk_start(graph, entity_err); |
1146 | 1148 | ||
1147 | while ((entity_err = media_entity_graph_walk_next(graph))) { | 1149 | while ((entity_err = media_entity_graph_walk_next(graph))) { |
1148 | if (!is_media_entity_v4l2_io(entity_err)) | 1150 | if (!is_media_entity_v4l2_video_device(entity_err)) |
1149 | continue; | 1151 | continue; |
1150 | 1152 | ||
1151 | __fimc_md_modify_pipeline(entity_err, !enable); | 1153 | __fimc_md_modify_pipeline(entity_err, !enable); |
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index bd5c46c3d4b7..bf954424e7be 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c | |||
@@ -757,8 +757,10 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, | |||
757 | goto err; | 757 | goto err; |
758 | 758 | ||
759 | state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; | 759 | state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; |
760 | if (state->index >= CSIS_MAX_ENTITIES) | 760 | if (state->index >= CSIS_MAX_ENTITIES) { |
761 | return -ENXIO; | 761 | ret = -ENXIO; |
762 | goto err; | ||
763 | } | ||
762 | 764 | ||
763 | /* Get MIPI CSI-2 bus configration from the endpoint node. */ | 765 | /* Get MIPI CSI-2 bus configration from the endpoint node. */ |
764 | of_property_read_u32(node, "samsung,csis-hs-settle", | 766 | of_property_read_u32(node, "samsung,csis-hs-settle", |
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index ac76d2901501..1b1a95d546f6 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c | |||
@@ -251,7 +251,7 @@ static int isp_video_get_graph_data(struct isp_video *video, | |||
251 | if (entity == &video->video.entity) | 251 | if (entity == &video->video.entity) |
252 | continue; | 252 | continue; |
253 | 253 | ||
254 | if (!is_media_entity_v4l2_io(entity)) | 254 | if (!is_media_entity_v4l2_video_device(entity)) |
255 | continue; | 255 | continue; |
256 | 256 | ||
257 | __video = to_isp_video(media_entity_to_video_device(entity)); | 257 | __video = to_isp_video(media_entity_to_video_device(entity)); |
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 74bd46ca7942..612d1ea514f1 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c | |||
@@ -719,16 +719,12 @@ static int g2d_probe(struct platform_device *pdev) | |||
719 | 719 | ||
720 | def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; | 720 | def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; |
721 | 721 | ||
722 | if (!pdev->dev.of_node) { | 722 | of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); |
723 | dev->variant = g2d_get_drv_data(pdev); | 723 | if (!of_id) { |
724 | } else { | 724 | ret = -ENODEV; |
725 | of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); | 725 | goto unreg_video_dev; |
726 | if (!of_id) { | ||
727 | ret = -ENODEV; | ||
728 | goto unreg_video_dev; | ||
729 | } | ||
730 | dev->variant = (struct g2d_variant *)of_id->data; | ||
731 | } | 726 | } |
727 | dev->variant = (struct g2d_variant *)of_id->data; | ||
732 | 728 | ||
733 | return 0; | 729 | return 0; |
734 | 730 | ||
@@ -788,22 +784,9 @@ static const struct of_device_id exynos_g2d_match[] = { | |||
788 | }; | 784 | }; |
789 | MODULE_DEVICE_TABLE(of, exynos_g2d_match); | 785 | MODULE_DEVICE_TABLE(of, exynos_g2d_match); |
790 | 786 | ||
791 | static const struct platform_device_id g2d_driver_ids[] = { | ||
792 | { | ||
793 | .name = "s5p-g2d", | ||
794 | .driver_data = (unsigned long)&g2d_drvdata_v3x, | ||
795 | }, { | ||
796 | .name = "s5p-g2d-v4x", | ||
797 | .driver_data = (unsigned long)&g2d_drvdata_v4x, | ||
798 | }, | ||
799 | {}, | ||
800 | }; | ||
801 | MODULE_DEVICE_TABLE(platform, g2d_driver_ids); | ||
802 | |||
803 | static struct platform_driver g2d_pdrv = { | 787 | static struct platform_driver g2d_pdrv = { |
804 | .probe = g2d_probe, | 788 | .probe = g2d_probe, |
805 | .remove = g2d_remove, | 789 | .remove = g2d_remove, |
806 | .id_table = g2d_driver_ids, | ||
807 | .driver = { | 790 | .driver = { |
808 | .name = G2D_NAME, | 791 | .name = G2D_NAME, |
809 | .of_match_table = exynos_g2d_match, | 792 | .of_match_table = exynos_g2d_match, |
diff --git a/drivers/media/platform/s5p-g2d/g2d.h b/drivers/media/platform/s5p-g2d/g2d.h index b0e52ab7ecdb..e31df541aa62 100644 --- a/drivers/media/platform/s5p-g2d/g2d.h +++ b/drivers/media/platform/s5p-g2d/g2d.h | |||
@@ -89,8 +89,3 @@ void g2d_set_flip(struct g2d_dev *d, u32 r); | |||
89 | void g2d_set_v41_stretch(struct g2d_dev *d, | 89 | void g2d_set_v41_stretch(struct g2d_dev *d, |
90 | struct g2d_frame *src, struct g2d_frame *dst); | 90 | struct g2d_frame *src, struct g2d_frame *dst); |
91 | void g2d_set_cmd(struct g2d_dev *d, u32 c); | 91 | void g2d_set_cmd(struct g2d_dev *d, u32 c); |
92 | |||
93 | static inline struct g2d_variant *g2d_get_drv_data(struct platform_device *pdev) | ||
94 | { | ||
95 | return (struct g2d_variant *)platform_get_device_id(pdev)->driver_data; | ||
96 | } | ||
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index c3b13a630edf..caa19b408551 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c | |||
@@ -1548,8 +1548,10 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx, | |||
1548 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1548 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1549 | u32 pix_fmt = f->fmt.pix.pixelformat; | 1549 | u32 pix_fmt = f->fmt.pix.pixelformat; |
1550 | int w = pix->width, h = pix->height, wh_align; | 1550 | int w = pix->width, h = pix->height, wh_align; |
1551 | int padding = 0; | ||
1551 | 1552 | ||
1552 | if (pix_fmt == V4L2_PIX_FMT_RGB32 || | 1553 | if (pix_fmt == V4L2_PIX_FMT_RGB32 || |
1554 | pix_fmt == V4L2_PIX_FMT_RGB565 || | ||
1553 | pix_fmt == V4L2_PIX_FMT_NV24 || | 1555 | pix_fmt == V4L2_PIX_FMT_NV24 || |
1554 | pix_fmt == V4L2_PIX_FMT_NV42 || | 1556 | pix_fmt == V4L2_PIX_FMT_NV42 || |
1555 | pix_fmt == V4L2_PIX_FMT_NV12 || | 1557 | pix_fmt == V4L2_PIX_FMT_NV12 || |
@@ -1564,7 +1566,10 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx, | |||
1564 | &h, S5P_JPEG_MIN_HEIGHT, | 1566 | &h, S5P_JPEG_MIN_HEIGHT, |
1565 | S5P_JPEG_MAX_HEIGHT, wh_align); | 1567 | S5P_JPEG_MAX_HEIGHT, wh_align); |
1566 | 1568 | ||
1567 | return w * h * fmt_depth >> 3; | 1569 | if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) |
1570 | padding = PAGE_SIZE; | ||
1571 | |||
1572 | return (w * h * fmt_depth >> 3) + padding; | ||
1568 | } | 1573 | } |
1569 | 1574 | ||
1570 | static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx, | 1575 | static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx, |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 927ab4928779..b16466fe35ee 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -1489,27 +1489,6 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { | |||
1489 | .fw_name[0] = "s5p-mfc-v8.fw", | 1489 | .fw_name[0] = "s5p-mfc-v8.fw", |
1490 | }; | 1490 | }; |
1491 | 1491 | ||
1492 | static const struct platform_device_id mfc_driver_ids[] = { | ||
1493 | { | ||
1494 | .name = "s5p-mfc", | ||
1495 | .driver_data = (unsigned long)&mfc_drvdata_v5, | ||
1496 | }, { | ||
1497 | .name = "s5p-mfc-v5", | ||
1498 | .driver_data = (unsigned long)&mfc_drvdata_v5, | ||
1499 | }, { | ||
1500 | .name = "s5p-mfc-v6", | ||
1501 | .driver_data = (unsigned long)&mfc_drvdata_v6, | ||
1502 | }, { | ||
1503 | .name = "s5p-mfc-v7", | ||
1504 | .driver_data = (unsigned long)&mfc_drvdata_v7, | ||
1505 | }, { | ||
1506 | .name = "s5p-mfc-v8", | ||
1507 | .driver_data = (unsigned long)&mfc_drvdata_v8, | ||
1508 | }, | ||
1509 | {}, | ||
1510 | }; | ||
1511 | MODULE_DEVICE_TABLE(platform, mfc_driver_ids); | ||
1512 | |||
1513 | static const struct of_device_id exynos_mfc_match[] = { | 1492 | static const struct of_device_id exynos_mfc_match[] = { |
1514 | { | 1493 | { |
1515 | .compatible = "samsung,mfc-v5", | 1494 | .compatible = "samsung,mfc-v5", |
@@ -1531,24 +1510,18 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match); | |||
1531 | static void *mfc_get_drv_data(struct platform_device *pdev) | 1510 | static void *mfc_get_drv_data(struct platform_device *pdev) |
1532 | { | 1511 | { |
1533 | struct s5p_mfc_variant *driver_data = NULL; | 1512 | struct s5p_mfc_variant *driver_data = NULL; |
1513 | const struct of_device_id *match; | ||
1514 | |||
1515 | match = of_match_node(exynos_mfc_match, pdev->dev.of_node); | ||
1516 | if (match) | ||
1517 | driver_data = (struct s5p_mfc_variant *)match->data; | ||
1534 | 1518 | ||
1535 | if (pdev->dev.of_node) { | ||
1536 | const struct of_device_id *match; | ||
1537 | match = of_match_node(exynos_mfc_match, | ||
1538 | pdev->dev.of_node); | ||
1539 | if (match) | ||
1540 | driver_data = (struct s5p_mfc_variant *)match->data; | ||
1541 | } else { | ||
1542 | driver_data = (struct s5p_mfc_variant *) | ||
1543 | platform_get_device_id(pdev)->driver_data; | ||
1544 | } | ||
1545 | return driver_data; | 1519 | return driver_data; |
1546 | } | 1520 | } |
1547 | 1521 | ||
1548 | static struct platform_driver s5p_mfc_driver = { | 1522 | static struct platform_driver s5p_mfc_driver = { |
1549 | .probe = s5p_mfc_probe, | 1523 | .probe = s5p_mfc_probe, |
1550 | .remove = s5p_mfc_remove, | 1524 | .remove = s5p_mfc_remove, |
1551 | .id_table = mfc_driver_ids, | ||
1552 | .driver = { | 1525 | .driver = { |
1553 | .name = S5P_MFC_NAME, | 1526 | .name = S5P_MFC_NAME, |
1554 | .pm = &s5p_mfc_pm_ops, | 1527 | .pm = &s5p_mfc_pm_ops, |
diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h index 42cd2709c41c..4dd62a918fcf 100644 --- a/drivers/media/platform/s5p-tv/mixer.h +++ b/drivers/media/platform/s5p-tv/mixer.h | |||
@@ -300,7 +300,7 @@ void mxr_release_video(struct mxr_device *mdev); | |||
300 | struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx); | 300 | struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx); |
301 | struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx); | 301 | struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx); |
302 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, | 302 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, |
303 | int idx, char *name, struct mxr_layer_ops *ops); | 303 | int idx, char *name, const struct mxr_layer_ops *ops); |
304 | 304 | ||
305 | void mxr_base_layer_release(struct mxr_layer *layer); | 305 | void mxr_base_layer_release(struct mxr_layer *layer); |
306 | void mxr_layer_release(struct mxr_layer *layer); | 306 | void mxr_layer_release(struct mxr_layer *layer); |
diff --git a/drivers/media/platform/s5p-tv/mixer_grp_layer.c b/drivers/media/platform/s5p-tv/mixer_grp_layer.c index db3163b23ea0..d4d2564f7de7 100644 --- a/drivers/media/platform/s5p-tv/mixer_grp_layer.c +++ b/drivers/media/platform/s5p-tv/mixer_grp_layer.c | |||
@@ -235,7 +235,7 @@ struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx) | |||
235 | { | 235 | { |
236 | struct mxr_layer *layer; | 236 | struct mxr_layer *layer; |
237 | int ret; | 237 | int ret; |
238 | struct mxr_layer_ops ops = { | 238 | const struct mxr_layer_ops ops = { |
239 | .release = mxr_graph_layer_release, | 239 | .release = mxr_graph_layer_release, |
240 | .buffer_set = mxr_graph_buffer_set, | 240 | .buffer_set = mxr_graph_buffer_set, |
241 | .stream_set = mxr_graph_stream_set, | 241 | .stream_set = mxr_graph_stream_set, |
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index d9e7f030294c..7ab5578a0405 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c | |||
@@ -1070,7 +1070,7 @@ static void mxr_vfd_release(struct video_device *vdev) | |||
1070 | } | 1070 | } |
1071 | 1071 | ||
1072 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, | 1072 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, |
1073 | int idx, char *name, struct mxr_layer_ops *ops) | 1073 | int idx, char *name, const struct mxr_layer_ops *ops) |
1074 | { | 1074 | { |
1075 | struct mxr_layer *layer; | 1075 | struct mxr_layer *layer; |
1076 | 1076 | ||
diff --git a/drivers/media/platform/s5p-tv/mixer_vp_layer.c b/drivers/media/platform/s5p-tv/mixer_vp_layer.c index dd002a497dbb..6fa6f673f53b 100644 --- a/drivers/media/platform/s5p-tv/mixer_vp_layer.c +++ b/drivers/media/platform/s5p-tv/mixer_vp_layer.c | |||
@@ -207,7 +207,7 @@ struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx) | |||
207 | { | 207 | { |
208 | struct mxr_layer *layer; | 208 | struct mxr_layer *layer; |
209 | int ret; | 209 | int ret; |
210 | struct mxr_layer_ops ops = { | 210 | const struct mxr_layer_ops ops = { |
211 | .release = mxr_vp_layer_release, | 211 | .release = mxr_vp_layer_release, |
212 | .buffer_set = mxr_vp_buffer_set, | 212 | .buffer_set = mxr_vp_buffer_set, |
213 | .stream_set = mxr_vp_stream_set, | 213 | .stream_set = mxr_vp_stream_set, |
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 355298989dd8..83029a4854ae 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig | |||
@@ -28,7 +28,7 @@ config VIDEO_PXA27x | |||
28 | config VIDEO_RCAR_VIN | 28 | config VIDEO_RCAR_VIN |
29 | tristate "R-Car Video Input (VIN) support" | 29 | tristate "R-Car Video Input (VIN) support" |
30 | depends on VIDEO_DEV && SOC_CAMERA | 30 | depends on VIDEO_DEV && SOC_CAMERA |
31 | depends on ARCH_SHMOBILE || COMPILE_TEST | 31 | depends on ARCH_RENESAS || COMPILE_TEST |
32 | depends on HAS_DMA | 32 | depends on HAS_DMA |
33 | select VIDEOBUF2_DMA_CONTIG | 33 | select VIDEOBUF2_DMA_CONTIG |
34 | select SOC_CAMERA_SCALE_CROP | 34 | select SOC_CAMERA_SCALE_CROP |
@@ -45,7 +45,7 @@ config VIDEO_SH_MOBILE_CSI2 | |||
45 | config VIDEO_SH_MOBILE_CEU | 45 | config VIDEO_SH_MOBILE_CEU |
46 | tristate "SuperH Mobile CEU Interface driver" | 46 | tristate "SuperH Mobile CEU Interface driver" |
47 | depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK | 47 | depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK |
48 | depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST | 48 | depends on ARCH_SHMOBILE || COMPILE_TEST |
49 | depends on HAS_DMA | 49 | depends on HAS_DMA |
50 | select VIDEOBUF2_DMA_CONTIG | 50 | select VIDEOBUF2_DMA_CONTIG |
51 | select SOC_CAMERA_SCALE_CROP | 51 | select SOC_CAMERA_SCALE_CROP |
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 3b8edf458964..3f9c1b8456c3 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c | |||
@@ -1845,6 +1845,8 @@ static const struct of_device_id rcar_vin_of_table[] = { | |||
1845 | { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, | 1845 | { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, |
1846 | { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, | 1846 | { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, |
1847 | { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, | 1847 | { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, |
1848 | { .compatible = "renesas,rcar-gen3-vin", .data = (void *)RCAR_GEN3 }, | ||
1849 | { .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 }, | ||
1848 | { }, | 1850 | { }, |
1849 | }; | 1851 | }; |
1850 | MODULE_DEVICE_TABLE(of, rcar_vin_of_table); | 1852 | MODULE_DEVICE_TABLE(of, rcar_vin_of_table); |
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 78e3cb9a628f..7dddf77a62cf 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | |||
@@ -49,7 +49,7 @@ MODULE_FIRMWARE(FIRMWARE_MEMDMA); | |||
49 | #define PID_TABLE_SIZE 1024 | 49 | #define PID_TABLE_SIZE 1024 |
50 | #define POLL_MSECS 50 | 50 | #define POLL_MSECS 50 |
51 | 51 | ||
52 | static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei); | 52 | static int load_c8sectpfe_fw(struct c8sectpfei *fei); |
53 | 53 | ||
54 | #define TS_PKT_SIZE 188 | 54 | #define TS_PKT_SIZE 188 |
55 | #define HEADER_SIZE (4) | 55 | #define HEADER_SIZE (4) |
@@ -130,7 +130,7 @@ static void channel_swdemux_tsklet(unsigned long data) | |||
130 | writel(channel->back_buffer_busaddr, channel->irec + | 130 | writel(channel->back_buffer_busaddr, channel->irec + |
131 | DMA_PRDS_BUSRP_TP(0)); | 131 | DMA_PRDS_BUSRP_TP(0)); |
132 | else | 132 | else |
133 | writel(wp, channel->irec + DMA_PRDS_BUSWP_TP(0)); | 133 | writel(wp, channel->irec + DMA_PRDS_BUSRP_TP(0)); |
134 | } | 134 | } |
135 | 135 | ||
136 | static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) | 136 | static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) |
@@ -141,6 +141,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
141 | struct channel_info *channel; | 141 | struct channel_info *channel; |
142 | u32 tmp; | 142 | u32 tmp; |
143 | unsigned long *bitmap; | 143 | unsigned long *bitmap; |
144 | int ret; | ||
144 | 145 | ||
145 | switch (dvbdmxfeed->type) { | 146 | switch (dvbdmxfeed->type) { |
146 | case DMX_TYPE_TS: | 147 | case DMX_TYPE_TS: |
@@ -169,8 +170,9 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
169 | } | 170 | } |
170 | 171 | ||
171 | if (!atomic_read(&fei->fw_loaded)) { | 172 | if (!atomic_read(&fei->fw_loaded)) { |
172 | dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__); | 173 | ret = load_c8sectpfe_fw(fei); |
173 | return -EINVAL; | 174 | if (ret) |
175 | return ret; | ||
174 | } | 176 | } |
175 | 177 | ||
176 | mutex_lock(&fei->lock); | 178 | mutex_lock(&fei->lock); |
@@ -265,8 +267,9 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
265 | unsigned long *bitmap; | 267 | unsigned long *bitmap; |
266 | 268 | ||
267 | if (!atomic_read(&fei->fw_loaded)) { | 269 | if (!atomic_read(&fei->fw_loaded)) { |
268 | dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__); | 270 | ret = load_c8sectpfe_fw(fei); |
269 | return -EINVAL; | 271 | if (ret) |
272 | return ret; | ||
270 | } | 273 | } |
271 | 274 | ||
272 | mutex_lock(&fei->lock); | 275 | mutex_lock(&fei->lock); |
@@ -585,7 +588,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, | |||
585 | writel(tsin->pid_buffer_busaddr, | 588 | writel(tsin->pid_buffer_busaddr, |
586 | fei->io + PIDF_BASE(tsin->tsin_id)); | 589 | fei->io + PIDF_BASE(tsin->tsin_id)); |
587 | 590 | ||
588 | dev_info(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n", | 591 | dev_dbg(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n", |
589 | tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)), | 592 | tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)), |
590 | &tsin->pid_buffer_busaddr); | 593 | &tsin->pid_buffer_busaddr); |
591 | 594 | ||
@@ -880,13 +883,6 @@ static int c8sectpfe_probe(struct platform_device *pdev) | |||
880 | goto err_clk_disable; | 883 | goto err_clk_disable; |
881 | } | 884 | } |
882 | 885 | ||
883 | /* ensure all other init has been done before requesting firmware */ | ||
884 | ret = load_c8sectpfe_fw_step1(fei); | ||
885 | if (ret) { | ||
886 | dev_err(dev, "Couldn't load slim core firmware\n"); | ||
887 | goto err_clk_disable; | ||
888 | } | ||
889 | |||
890 | c8sectpfe_debugfs_init(fei); | 886 | c8sectpfe_debugfs_init(fei); |
891 | 887 | ||
892 | return 0; | 888 | return 0; |
@@ -1091,15 +1087,14 @@ static void load_dmem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr, | |||
1091 | phdr->p_memsz - phdr->p_filesz); | 1087 | phdr->p_memsz - phdr->p_filesz); |
1092 | } | 1088 | } |
1093 | 1089 | ||
1094 | static int load_slim_core_fw(const struct firmware *fw, void *context) | 1090 | static int load_slim_core_fw(const struct firmware *fw, struct c8sectpfei *fei) |
1095 | { | 1091 | { |
1096 | struct c8sectpfei *fei = context; | ||
1097 | Elf32_Ehdr *ehdr; | 1092 | Elf32_Ehdr *ehdr; |
1098 | Elf32_Phdr *phdr; | 1093 | Elf32_Phdr *phdr; |
1099 | u8 __iomem *dst; | 1094 | u8 __iomem *dst; |
1100 | int err = 0, i; | 1095 | int err = 0, i; |
1101 | 1096 | ||
1102 | if (!fw || !context) | 1097 | if (!fw || !fei) |
1103 | return -EINVAL; | 1098 | return -EINVAL; |
1104 | 1099 | ||
1105 | ehdr = (Elf32_Ehdr *)fw->data; | 1100 | ehdr = (Elf32_Ehdr *)fw->data; |
@@ -1151,29 +1146,35 @@ static int load_slim_core_fw(const struct firmware *fw, void *context) | |||
1151 | return err; | 1146 | return err; |
1152 | } | 1147 | } |
1153 | 1148 | ||
1154 | static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context) | 1149 | static int load_c8sectpfe_fw(struct c8sectpfei *fei) |
1155 | { | 1150 | { |
1156 | struct c8sectpfei *fei = context; | 1151 | const struct firmware *fw; |
1157 | int err; | 1152 | int err; |
1158 | 1153 | ||
1154 | dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA); | ||
1155 | |||
1156 | err = request_firmware(&fw, FIRMWARE_MEMDMA, fei->dev); | ||
1157 | if (err) | ||
1158 | return err; | ||
1159 | |||
1159 | err = c8sectpfe_elf_sanity_check(fei, fw); | 1160 | err = c8sectpfe_elf_sanity_check(fei, fw); |
1160 | if (err) { | 1161 | if (err) { |
1161 | dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n" | 1162 | dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n" |
1162 | , err); | 1163 | , err); |
1163 | goto err; | 1164 | return err; |
1164 | } | 1165 | } |
1165 | 1166 | ||
1166 | err = load_slim_core_fw(fw, context); | 1167 | err = load_slim_core_fw(fw, fei); |
1167 | if (err) { | 1168 | if (err) { |
1168 | dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err); | 1169 | dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err); |
1169 | goto err; | 1170 | return err; |
1170 | } | 1171 | } |
1171 | 1172 | ||
1172 | /* now the firmware is loaded configure the input blocks */ | 1173 | /* now the firmware is loaded configure the input blocks */ |
1173 | err = configure_channels(fei); | 1174 | err = configure_channels(fei); |
1174 | if (err) { | 1175 | if (err) { |
1175 | dev_err(fei->dev, "configure_channels failed err=(%d)\n", err); | 1176 | dev_err(fei->dev, "configure_channels failed err=(%d)\n", err); |
1176 | goto err; | 1177 | return err; |
1177 | } | 1178 | } |
1178 | 1179 | ||
1179 | /* | 1180 | /* |
@@ -1186,28 +1187,6 @@ static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context) | |||
1186 | writel(0x1, fei->io + DMA_CPU_RUN); | 1187 | writel(0x1, fei->io + DMA_CPU_RUN); |
1187 | 1188 | ||
1188 | atomic_set(&fei->fw_loaded, 1); | 1189 | atomic_set(&fei->fw_loaded, 1); |
1189 | err: | ||
1190 | complete_all(&fei->fw_ack); | ||
1191 | } | ||
1192 | |||
1193 | static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei) | ||
1194 | { | ||
1195 | int err; | ||
1196 | |||
1197 | dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA); | ||
1198 | |||
1199 | init_completion(&fei->fw_ack); | ||
1200 | atomic_set(&fei->fw_loaded, 0); | ||
1201 | |||
1202 | err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, | ||
1203 | FIRMWARE_MEMDMA, fei->dev, GFP_KERNEL, fei, | ||
1204 | load_c8sectpfe_fw_cb); | ||
1205 | |||
1206 | if (err) { | ||
1207 | dev_err(fei->dev, "request_firmware_nowait err: %d.\n", err); | ||
1208 | complete_all(&fei->fw_ack); | ||
1209 | return err; | ||
1210 | } | ||
1211 | 1190 | ||
1212 | return 0; | 1191 | return 0; |
1213 | } | 1192 | } |
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index 0885e93ad436..f535f576913d 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig | |||
@@ -7,6 +7,7 @@ config VIDEO_VIVID | |||
7 | select FB_CFB_COPYAREA | 7 | select FB_CFB_COPYAREA |
8 | select FB_CFB_IMAGEBLIT | 8 | select FB_CFB_IMAGEBLIT |
9 | select VIDEOBUF2_VMALLOC | 9 | select VIDEOBUF2_VMALLOC |
10 | select VIDEO_V4L2_TPG | ||
10 | default n | 11 | default n |
11 | ---help--- | 12 | ---help--- |
12 | Enables a virtual video driver. This driver emulates a webcam, | 13 | Enables a virtual video driver. This driver emulates a webcam, |
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile index 756fc12851df..633c8a1b2c27 100644 --- a/drivers/media/platform/vivid/Makefile +++ b/drivers/media/platform/vivid/Makefile | |||
@@ -2,5 +2,5 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ | |||
2 | vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ | 2 | vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ |
3 | vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ | 3 | vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ |
4 | vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ | 4 | vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ |
5 | vivid-osd.o vivid-tpg.o vivid-tpg-colors.o | 5 | vivid-osd.o |
6 | obj-$(CONFIG_VIDEO_VIVID) += vivid.o | 6 | obj-$(CONFIG_VIDEO_VIVID) += vivid.o |
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index ec125becb7af..c14da84af09b 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c | |||
@@ -200,27 +200,12 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
200 | struct v4l2_capability *cap) | 200 | struct v4l2_capability *cap) |
201 | { | 201 | { |
202 | struct vivid_dev *dev = video_drvdata(file); | 202 | struct vivid_dev *dev = video_drvdata(file); |
203 | struct video_device *vdev = video_devdata(file); | ||
204 | 203 | ||
205 | strcpy(cap->driver, "vivid"); | 204 | strcpy(cap->driver, "vivid"); |
206 | strcpy(cap->card, "vivid"); | 205 | strcpy(cap->card, "vivid"); |
207 | snprintf(cap->bus_info, sizeof(cap->bus_info), | 206 | snprintf(cap->bus_info, sizeof(cap->bus_info), |
208 | "platform:%s", dev->v4l2_dev.name); | 207 | "platform:%s", dev->v4l2_dev.name); |
209 | 208 | ||
210 | if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_RX) | ||
211 | cap->device_caps = dev->vid_cap_caps; | ||
212 | if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_TX) | ||
213 | cap->device_caps = dev->vid_out_caps; | ||
214 | else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_RX) | ||
215 | cap->device_caps = dev->vbi_cap_caps; | ||
216 | else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX) | ||
217 | cap->device_caps = dev->vbi_out_caps; | ||
218 | else if (vdev->vfl_type == VFL_TYPE_SDR) | ||
219 | cap->device_caps = dev->sdr_cap_caps; | ||
220 | else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX) | ||
221 | cap->device_caps = dev->radio_rx_caps; | ||
222 | else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX) | ||
223 | cap->device_caps = dev->radio_tx_caps; | ||
224 | cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | | 209 | cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | |
225 | dev->vbi_cap_caps | dev->vbi_out_caps | | 210 | dev->vbi_cap_caps | dev->vbi_out_caps | |
226 | dev->radio_rx_caps | dev->radio_tx_caps | | 211 | dev->radio_rx_caps | dev->radio_tx_caps | |
@@ -1135,6 +1120,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1135 | strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name)); | 1120 | strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name)); |
1136 | vfd->fops = &vivid_fops; | 1121 | vfd->fops = &vivid_fops; |
1137 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1122 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1123 | vfd->device_caps = dev->vid_cap_caps; | ||
1138 | vfd->release = video_device_release_empty; | 1124 | vfd->release = video_device_release_empty; |
1139 | vfd->v4l2_dev = &dev->v4l2_dev; | 1125 | vfd->v4l2_dev = &dev->v4l2_dev; |
1140 | vfd->queue = &dev->vb_vid_cap_q; | 1126 | vfd->queue = &dev->vb_vid_cap_q; |
@@ -1160,6 +1146,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1160 | vfd->vfl_dir = VFL_DIR_TX; | 1146 | vfd->vfl_dir = VFL_DIR_TX; |
1161 | vfd->fops = &vivid_fops; | 1147 | vfd->fops = &vivid_fops; |
1162 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1148 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1149 | vfd->device_caps = dev->vid_out_caps; | ||
1163 | vfd->release = video_device_release_empty; | 1150 | vfd->release = video_device_release_empty; |
1164 | vfd->v4l2_dev = &dev->v4l2_dev; | 1151 | vfd->v4l2_dev = &dev->v4l2_dev; |
1165 | vfd->queue = &dev->vb_vid_out_q; | 1152 | vfd->queue = &dev->vb_vid_out_q; |
@@ -1184,6 +1171,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1184 | strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name)); | 1171 | strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name)); |
1185 | vfd->fops = &vivid_fops; | 1172 | vfd->fops = &vivid_fops; |
1186 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1173 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1174 | vfd->device_caps = dev->vbi_cap_caps; | ||
1187 | vfd->release = video_device_release_empty; | 1175 | vfd->release = video_device_release_empty; |
1188 | vfd->v4l2_dev = &dev->v4l2_dev; | 1176 | vfd->v4l2_dev = &dev->v4l2_dev; |
1189 | vfd->queue = &dev->vb_vbi_cap_q; | 1177 | vfd->queue = &dev->vb_vbi_cap_q; |
@@ -1207,6 +1195,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1207 | vfd->vfl_dir = VFL_DIR_TX; | 1195 | vfd->vfl_dir = VFL_DIR_TX; |
1208 | vfd->fops = &vivid_fops; | 1196 | vfd->fops = &vivid_fops; |
1209 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1197 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1198 | vfd->device_caps = dev->vbi_out_caps; | ||
1210 | vfd->release = video_device_release_empty; | 1199 | vfd->release = video_device_release_empty; |
1211 | vfd->v4l2_dev = &dev->v4l2_dev; | 1200 | vfd->v4l2_dev = &dev->v4l2_dev; |
1212 | vfd->queue = &dev->vb_vbi_out_q; | 1201 | vfd->queue = &dev->vb_vbi_out_q; |
@@ -1229,6 +1218,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1229 | strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name)); | 1218 | strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name)); |
1230 | vfd->fops = &vivid_fops; | 1219 | vfd->fops = &vivid_fops; |
1231 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1220 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1221 | vfd->device_caps = dev->sdr_cap_caps; | ||
1232 | vfd->release = video_device_release_empty; | 1222 | vfd->release = video_device_release_empty; |
1233 | vfd->v4l2_dev = &dev->v4l2_dev; | 1223 | vfd->v4l2_dev = &dev->v4l2_dev; |
1234 | vfd->queue = &dev->vb_sdr_cap_q; | 1224 | vfd->queue = &dev->vb_sdr_cap_q; |
@@ -1247,6 +1237,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1247 | strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name)); | 1237 | strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name)); |
1248 | vfd->fops = &vivid_radio_fops; | 1238 | vfd->fops = &vivid_radio_fops; |
1249 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1239 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1240 | vfd->device_caps = dev->radio_rx_caps; | ||
1250 | vfd->release = video_device_release_empty; | 1241 | vfd->release = video_device_release_empty; |
1251 | vfd->v4l2_dev = &dev->v4l2_dev; | 1242 | vfd->v4l2_dev = &dev->v4l2_dev; |
1252 | vfd->lock = &dev->mutex; | 1243 | vfd->lock = &dev->mutex; |
@@ -1265,6 +1256,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1265 | vfd->vfl_dir = VFL_DIR_TX; | 1256 | vfd->vfl_dir = VFL_DIR_TX; |
1266 | vfd->fops = &vivid_radio_fops; | 1257 | vfd->fops = &vivid_radio_fops; |
1267 | vfd->ioctl_ops = &vivid_ioctl_ops; | 1258 | vfd->ioctl_ops = &vivid_ioctl_ops; |
1259 | vfd->device_caps = dev->radio_tx_caps; | ||
1268 | vfd->release = video_device_release_empty; | 1260 | vfd->release = video_device_release_empty; |
1269 | vfd->v4l2_dev = &dev->v4l2_dev; | 1261 | vfd->v4l2_dev = &dev->v4l2_dev; |
1270 | vfd->lock = &dev->mutex; | 1262 | vfd->lock = &dev->mutex; |
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 751c1ba391e9..776783bec227 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
26 | #include <media/v4l2-dev.h> | 26 | #include <media/v4l2-dev.h> |
27 | #include <media/v4l2-ctrls.h> | 27 | #include <media/v4l2-ctrls.h> |
28 | #include "vivid-tpg.h" | 28 | #include <media/v4l2-tpg.h> |
29 | #include "vivid-rds-gen.h" | 29 | #include "vivid-rds-gen.h" |
30 | #include "vivid-vbi-gen.h" | 30 | #include "vivid-vbi-gen.h" |
31 | 31 | ||
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 9034281944a4..3b8c10108dfa 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <media/v4l2-ioctl.h> | 36 | #include <media/v4l2-ioctl.h> |
37 | #include <media/v4l2-fh.h> | 37 | #include <media/v4l2-fh.h> |
38 | #include <media/v4l2-event.h> | 38 | #include <media/v4l2-event.h> |
39 | #include <media/v4l2-rect.h> | ||
39 | 40 | ||
40 | #include "vivid-core.h" | 41 | #include "vivid-core.h" |
41 | #include "vivid-vid-common.h" | 42 | #include "vivid-vid-common.h" |
@@ -184,15 +185,15 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev) | |||
184 | dev->compose_out.width, dev->compose_out.height | 185 | dev->compose_out.width, dev->compose_out.height |
185 | }; | 186 | }; |
186 | 187 | ||
187 | dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out); | 188 | v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out); |
188 | 189 | ||
189 | dev->loop_vid_out = dev->loop_vid_copy; | 190 | dev->loop_vid_out = dev->loop_vid_copy; |
190 | rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); | 191 | v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); |
191 | dev->loop_vid_out.left += dev->crop_out.left; | 192 | dev->loop_vid_out.left += dev->crop_out.left; |
192 | dev->loop_vid_out.top += dev->crop_out.top; | 193 | dev->loop_vid_out.top += dev->crop_out.top; |
193 | 194 | ||
194 | dev->loop_vid_cap = dev->loop_vid_copy; | 195 | dev->loop_vid_cap = dev->loop_vid_copy; |
195 | rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); | 196 | v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); |
196 | 197 | ||
197 | dprintk(dev, 1, | 198 | dprintk(dev, 1, |
198 | "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", | 199 | "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", |
@@ -203,13 +204,13 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev) | |||
203 | dev->loop_vid_cap.width, dev->loop_vid_cap.height, | 204 | dev->loop_vid_cap.width, dev->loop_vid_cap.height, |
204 | dev->loop_vid_cap.left, dev->loop_vid_cap.top); | 205 | dev->loop_vid_cap.left, dev->loop_vid_cap.top); |
205 | 206 | ||
206 | r_overlay = rect_intersect(&r_fb, &r_overlay); | 207 | v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay); |
207 | 208 | ||
208 | /* shift r_overlay to the same origin as compose_out */ | 209 | /* shift r_overlay to the same origin as compose_out */ |
209 | r_overlay.left += dev->compose_out.left - dev->overlay_out_left; | 210 | r_overlay.left += dev->compose_out.left - dev->overlay_out_left; |
210 | r_overlay.top += dev->compose_out.top - dev->overlay_out_top; | 211 | r_overlay.top += dev->compose_out.top - dev->overlay_out_top; |
211 | 212 | ||
212 | dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy); | 213 | v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy); |
213 | dev->loop_fb_copy = dev->loop_vid_overlay; | 214 | dev->loop_fb_copy = dev->loop_vid_overlay; |
214 | 215 | ||
215 | /* shift dev->loop_fb_copy back again to the fb origin */ | 216 | /* shift dev->loop_fb_copy back again to the fb origin */ |
@@ -217,7 +218,7 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev) | |||
217 | dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; | 218 | dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; |
218 | 219 | ||
219 | dev->loop_vid_overlay_cap = dev->loop_vid_overlay; | 220 | dev->loop_vid_overlay_cap = dev->loop_vid_overlay; |
220 | rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); | 221 | v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); |
221 | 222 | ||
222 | dprintk(dev, 1, | 223 | dprintk(dev, 1, |
223 | "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", | 224 | "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", |
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c index c382343fdb66..53c7777dc001 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.c +++ b/drivers/media/platform/vivid/vivid-rds-gen.c | |||
@@ -55,6 +55,7 @@ void vivid_rds_generate(struct vivid_rds_gen *rds) | |||
55 | { | 55 | { |
56 | struct v4l2_rds_data *data = rds->data; | 56 | struct v4l2_rds_data *data = rds->data; |
57 | unsigned grp; | 57 | unsigned grp; |
58 | unsigned idx; | ||
58 | struct tm tm; | 59 | struct tm tm; |
59 | unsigned date; | 60 | unsigned date; |
60 | unsigned time; | 61 | unsigned time; |
@@ -73,24 +74,26 @@ void vivid_rds_generate(struct vivid_rds_gen *rds) | |||
73 | case 0 ... 3: | 74 | case 0 ... 3: |
74 | case 22 ... 25: | 75 | case 22 ... 25: |
75 | case 44 ... 47: /* Group 0B */ | 76 | case 44 ... 47: /* Group 0B */ |
77 | idx = (grp % 22) % 4; | ||
76 | data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); | 78 | data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); |
77 | data[1].lsb |= vivid_get_di(rds, grp % 22); | 79 | data[1].lsb |= vivid_get_di(rds, idx); |
78 | data[1].msb |= 1 << 3; | 80 | data[1].msb |= 1 << 3; |
79 | data[2].lsb = rds->picode & 0xff; | 81 | data[2].lsb = rds->picode & 0xff; |
80 | data[2].msb = rds->picode >> 8; | 82 | data[2].msb = rds->picode >> 8; |
81 | data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); | 83 | data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); |
82 | data[3].lsb = rds->psname[2 * (grp % 22) + 1]; | 84 | data[3].lsb = rds->psname[2 * idx + 1]; |
83 | data[3].msb = rds->psname[2 * (grp % 22)]; | 85 | data[3].msb = rds->psname[2 * idx]; |
84 | break; | 86 | break; |
85 | case 4 ... 19: | 87 | case 4 ... 19: |
86 | case 26 ... 41: /* Group 2A */ | 88 | case 26 ... 41: /* Group 2A */ |
87 | data[1].lsb |= (grp - 4) % 22; | 89 | idx = ((grp - 4) % 22) % 16; |
90 | data[1].lsb |= idx; | ||
88 | data[1].msb |= 4 << 3; | 91 | data[1].msb |= 4 << 3; |
89 | data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)]; | 92 | data[2].msb = rds->radiotext[4 * idx]; |
90 | data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1]; | 93 | data[2].lsb = rds->radiotext[4 * idx + 1]; |
91 | data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); | 94 | data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); |
92 | data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2]; | 95 | data[3].msb = rds->radiotext[4 * idx + 2]; |
93 | data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3]; | 96 | data[3].lsb = rds->radiotext[4 * idx + 3]; |
94 | break; | 97 | break; |
95 | case 56: | 98 | case 56: |
96 | /* | 99 | /* |
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index b84f081c1b92..4f730f355a17 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <media/v4l2-common.h> | 26 | #include <media/v4l2-common.h> |
27 | #include <media/v4l2-event.h> | 27 | #include <media/v4l2-event.h> |
28 | #include <media/v4l2-dv-timings.h> | 28 | #include <media/v4l2-dv-timings.h> |
29 | #include <media/v4l2-rect.h> | ||
29 | 30 | ||
30 | #include "vivid-core.h" | 31 | #include "vivid-core.h" |
31 | #include "vivid-vid-common.h" | 32 | #include "vivid-vid-common.h" |
@@ -590,16 +591,16 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, | |||
590 | } else { | 591 | } else { |
591 | struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; | 592 | struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; |
592 | 593 | ||
593 | rect_set_min_size(&r, &vivid_min_rect); | 594 | v4l2_rect_set_min_size(&r, &vivid_min_rect); |
594 | rect_set_max_size(&r, &vivid_max_rect); | 595 | v4l2_rect_set_max_size(&r, &vivid_max_rect); |
595 | if (dev->has_scaler_cap && !dev->has_compose_cap) { | 596 | if (dev->has_scaler_cap && !dev->has_compose_cap) { |
596 | struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; | 597 | struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; |
597 | 598 | ||
598 | rect_set_max_size(&r, &max_r); | 599 | v4l2_rect_set_max_size(&r, &max_r); |
599 | } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { | 600 | } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { |
600 | rect_set_max_size(&r, &dev->src_rect); | 601 | v4l2_rect_set_max_size(&r, &dev->src_rect); |
601 | } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { | 602 | } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { |
602 | rect_set_min_size(&r, &dev->src_rect); | 603 | v4l2_rect_set_min_size(&r, &dev->src_rect); |
603 | } | 604 | } |
604 | mp->width = r.width; | 605 | mp->width = r.width; |
605 | mp->height = r.height / factor; | 606 | mp->height = r.height / factor; |
@@ -668,7 +669,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, | |||
668 | 669 | ||
669 | if (dev->has_scaler_cap) { | 670 | if (dev->has_scaler_cap) { |
670 | if (dev->has_compose_cap) | 671 | if (dev->has_compose_cap) |
671 | rect_map_inside(compose, &r); | 672 | v4l2_rect_map_inside(compose, &r); |
672 | else | 673 | else |
673 | *compose = r; | 674 | *compose = r; |
674 | if (dev->has_crop_cap && !dev->has_compose_cap) { | 675 | if (dev->has_crop_cap && !dev->has_compose_cap) { |
@@ -683,9 +684,9 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, | |||
683 | factor * r.height * MAX_ZOOM | 684 | factor * r.height * MAX_ZOOM |
684 | }; | 685 | }; |
685 | 686 | ||
686 | rect_set_min_size(crop, &min_r); | 687 | v4l2_rect_set_min_size(crop, &min_r); |
687 | rect_set_max_size(crop, &max_r); | 688 | v4l2_rect_set_max_size(crop, &max_r); |
688 | rect_map_inside(crop, &dev->crop_bounds_cap); | 689 | v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); |
689 | } else if (dev->has_crop_cap) { | 690 | } else if (dev->has_crop_cap) { |
690 | struct v4l2_rect min_r = { | 691 | struct v4l2_rect min_r = { |
691 | 0, 0, | 692 | 0, 0, |
@@ -698,27 +699,27 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, | |||
698 | factor * compose->height * MAX_ZOOM | 699 | factor * compose->height * MAX_ZOOM |
699 | }; | 700 | }; |
700 | 701 | ||
701 | rect_set_min_size(crop, &min_r); | 702 | v4l2_rect_set_min_size(crop, &min_r); |
702 | rect_set_max_size(crop, &max_r); | 703 | v4l2_rect_set_max_size(crop, &max_r); |
703 | rect_map_inside(crop, &dev->crop_bounds_cap); | 704 | v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); |
704 | } | 705 | } |
705 | } else if (dev->has_crop_cap && !dev->has_compose_cap) { | 706 | } else if (dev->has_crop_cap && !dev->has_compose_cap) { |
706 | r.height *= factor; | 707 | r.height *= factor; |
707 | rect_set_size_to(crop, &r); | 708 | v4l2_rect_set_size_to(crop, &r); |
708 | rect_map_inside(crop, &dev->crop_bounds_cap); | 709 | v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); |
709 | r = *crop; | 710 | r = *crop; |
710 | r.height /= factor; | 711 | r.height /= factor; |
711 | rect_set_size_to(compose, &r); | 712 | v4l2_rect_set_size_to(compose, &r); |
712 | } else if (!dev->has_crop_cap) { | 713 | } else if (!dev->has_crop_cap) { |
713 | rect_map_inside(compose, &r); | 714 | v4l2_rect_map_inside(compose, &r); |
714 | } else { | 715 | } else { |
715 | r.height *= factor; | 716 | r.height *= factor; |
716 | rect_set_max_size(crop, &r); | 717 | v4l2_rect_set_max_size(crop, &r); |
717 | rect_map_inside(crop, &dev->crop_bounds_cap); | 718 | v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); |
718 | compose->top *= factor; | 719 | compose->top *= factor; |
719 | compose->height *= factor; | 720 | compose->height *= factor; |
720 | rect_set_size_to(compose, crop); | 721 | v4l2_rect_set_size_to(compose, crop); |
721 | rect_map_inside(compose, &r); | 722 | v4l2_rect_map_inside(compose, &r); |
722 | compose->top /= factor; | 723 | compose->top /= factor; |
723 | compose->height /= factor; | 724 | compose->height /= factor; |
724 | } | 725 | } |
@@ -735,9 +736,9 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, | |||
735 | } else { | 736 | } else { |
736 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; | 737 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; |
737 | 738 | ||
738 | rect_set_size_to(compose, &r); | 739 | v4l2_rect_set_size_to(compose, &r); |
739 | r.height *= factor; | 740 | r.height *= factor; |
740 | rect_set_size_to(crop, &r); | 741 | v4l2_rect_set_size_to(crop, &r); |
741 | } | 742 | } |
742 | 743 | ||
743 | dev->fmt_cap_rect.width = mp->width; | 744 | dev->fmt_cap_rect.width = mp->width; |
@@ -886,9 +887,9 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
886 | ret = vivid_vid_adjust_sel(s->flags, &s->r); | 887 | ret = vivid_vid_adjust_sel(s->flags, &s->r); |
887 | if (ret) | 888 | if (ret) |
888 | return ret; | 889 | return ret; |
889 | rect_set_min_size(&s->r, &vivid_min_rect); | 890 | v4l2_rect_set_min_size(&s->r, &vivid_min_rect); |
890 | rect_set_max_size(&s->r, &dev->src_rect); | 891 | v4l2_rect_set_max_size(&s->r, &dev->src_rect); |
891 | rect_map_inside(&s->r, &dev->crop_bounds_cap); | 892 | v4l2_rect_map_inside(&s->r, &dev->crop_bounds_cap); |
892 | s->r.top /= factor; | 893 | s->r.top /= factor; |
893 | s->r.height /= factor; | 894 | s->r.height /= factor; |
894 | if (dev->has_scaler_cap) { | 895 | if (dev->has_scaler_cap) { |
@@ -904,36 +905,36 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
904 | s->r.height / MAX_ZOOM | 905 | s->r.height / MAX_ZOOM |
905 | }; | 906 | }; |
906 | 907 | ||
907 | rect_set_min_size(&fmt, &min_rect); | 908 | v4l2_rect_set_min_size(&fmt, &min_rect); |
908 | if (!dev->has_compose_cap) | 909 | if (!dev->has_compose_cap) |
909 | rect_set_max_size(&fmt, &max_rect); | 910 | v4l2_rect_set_max_size(&fmt, &max_rect); |
910 | if (!rect_same_size(&dev->fmt_cap_rect, &fmt) && | 911 | if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && |
911 | vb2_is_busy(&dev->vb_vid_cap_q)) | 912 | vb2_is_busy(&dev->vb_vid_cap_q)) |
912 | return -EBUSY; | 913 | return -EBUSY; |
913 | if (dev->has_compose_cap) { | 914 | if (dev->has_compose_cap) { |
914 | rect_set_min_size(compose, &min_rect); | 915 | v4l2_rect_set_min_size(compose, &min_rect); |
915 | rect_set_max_size(compose, &max_rect); | 916 | v4l2_rect_set_max_size(compose, &max_rect); |
916 | } | 917 | } |
917 | dev->fmt_cap_rect = fmt; | 918 | dev->fmt_cap_rect = fmt; |
918 | tpg_s_buf_height(&dev->tpg, fmt.height); | 919 | tpg_s_buf_height(&dev->tpg, fmt.height); |
919 | } else if (dev->has_compose_cap) { | 920 | } else if (dev->has_compose_cap) { |
920 | struct v4l2_rect fmt = dev->fmt_cap_rect; | 921 | struct v4l2_rect fmt = dev->fmt_cap_rect; |
921 | 922 | ||
922 | rect_set_min_size(&fmt, &s->r); | 923 | v4l2_rect_set_min_size(&fmt, &s->r); |
923 | if (!rect_same_size(&dev->fmt_cap_rect, &fmt) && | 924 | if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && |
924 | vb2_is_busy(&dev->vb_vid_cap_q)) | 925 | vb2_is_busy(&dev->vb_vid_cap_q)) |
925 | return -EBUSY; | 926 | return -EBUSY; |
926 | dev->fmt_cap_rect = fmt; | 927 | dev->fmt_cap_rect = fmt; |
927 | tpg_s_buf_height(&dev->tpg, fmt.height); | 928 | tpg_s_buf_height(&dev->tpg, fmt.height); |
928 | rect_set_size_to(compose, &s->r); | 929 | v4l2_rect_set_size_to(compose, &s->r); |
929 | rect_map_inside(compose, &dev->fmt_cap_rect); | 930 | v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); |
930 | } else { | 931 | } else { |
931 | if (!rect_same_size(&s->r, &dev->fmt_cap_rect) && | 932 | if (!v4l2_rect_same_size(&s->r, &dev->fmt_cap_rect) && |
932 | vb2_is_busy(&dev->vb_vid_cap_q)) | 933 | vb2_is_busy(&dev->vb_vid_cap_q)) |
933 | return -EBUSY; | 934 | return -EBUSY; |
934 | rect_set_size_to(&dev->fmt_cap_rect, &s->r); | 935 | v4l2_rect_set_size_to(&dev->fmt_cap_rect, &s->r); |
935 | rect_set_size_to(compose, &s->r); | 936 | v4l2_rect_set_size_to(compose, &s->r); |
936 | rect_map_inside(compose, &dev->fmt_cap_rect); | 937 | v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); |
937 | tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height); | 938 | tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height); |
938 | } | 939 | } |
939 | s->r.top *= factor; | 940 | s->r.top *= factor; |
@@ -946,8 +947,8 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
946 | ret = vivid_vid_adjust_sel(s->flags, &s->r); | 947 | ret = vivid_vid_adjust_sel(s->flags, &s->r); |
947 | if (ret) | 948 | if (ret) |
948 | return ret; | 949 | return ret; |
949 | rect_set_min_size(&s->r, &vivid_min_rect); | 950 | v4l2_rect_set_min_size(&s->r, &vivid_min_rect); |
950 | rect_set_max_size(&s->r, &dev->fmt_cap_rect); | 951 | v4l2_rect_set_max_size(&s->r, &dev->fmt_cap_rect); |
951 | if (dev->has_scaler_cap) { | 952 | if (dev->has_scaler_cap) { |
952 | struct v4l2_rect max_rect = { | 953 | struct v4l2_rect max_rect = { |
953 | 0, 0, | 954 | 0, 0, |
@@ -955,7 +956,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
955 | (dev->src_rect.height / factor) * MAX_ZOOM | 956 | (dev->src_rect.height / factor) * MAX_ZOOM |
956 | }; | 957 | }; |
957 | 958 | ||
958 | rect_set_max_size(&s->r, &max_rect); | 959 | v4l2_rect_set_max_size(&s->r, &max_rect); |
959 | if (dev->has_crop_cap) { | 960 | if (dev->has_crop_cap) { |
960 | struct v4l2_rect min_rect = { | 961 | struct v4l2_rect min_rect = { |
961 | 0, 0, | 962 | 0, 0, |
@@ -968,23 +969,23 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
968 | (s->r.height * factor) * MAX_ZOOM | 969 | (s->r.height * factor) * MAX_ZOOM |
969 | }; | 970 | }; |
970 | 971 | ||
971 | rect_set_min_size(crop, &min_rect); | 972 | v4l2_rect_set_min_size(crop, &min_rect); |
972 | rect_set_max_size(crop, &max_rect); | 973 | v4l2_rect_set_max_size(crop, &max_rect); |
973 | rect_map_inside(crop, &dev->crop_bounds_cap); | 974 | v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); |
974 | } | 975 | } |
975 | } else if (dev->has_crop_cap) { | 976 | } else if (dev->has_crop_cap) { |
976 | s->r.top *= factor; | 977 | s->r.top *= factor; |
977 | s->r.height *= factor; | 978 | s->r.height *= factor; |
978 | rect_set_max_size(&s->r, &dev->src_rect); | 979 | v4l2_rect_set_max_size(&s->r, &dev->src_rect); |
979 | rect_set_size_to(crop, &s->r); | 980 | v4l2_rect_set_size_to(crop, &s->r); |
980 | rect_map_inside(crop, &dev->crop_bounds_cap); | 981 | v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); |
981 | s->r.top /= factor; | 982 | s->r.top /= factor; |
982 | s->r.height /= factor; | 983 | s->r.height /= factor; |
983 | } else { | 984 | } else { |
984 | rect_set_size_to(&s->r, &dev->src_rect); | 985 | v4l2_rect_set_size_to(&s->r, &dev->src_rect); |
985 | s->r.height /= factor; | 986 | s->r.height /= factor; |
986 | } | 987 | } |
987 | rect_map_inside(&s->r, &dev->fmt_cap_rect); | 988 | v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); |
988 | if (dev->bitmap_cap && (compose->width != s->r.width || | 989 | if (dev->bitmap_cap && (compose->width != s->r.width || |
989 | compose->height != s->r.height)) { | 990 | compose->height != s->r.height)) { |
990 | kfree(dev->bitmap_cap); | 991 | kfree(dev->bitmap_cap); |
@@ -1124,7 +1125,7 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, | |||
1124 | for (j = i + 1; j < win->clipcount; j++) { | 1125 | for (j = i + 1; j < win->clipcount; j++) { |
1125 | struct v4l2_rect *r2 = &dev->try_clips_cap[j].c; | 1126 | struct v4l2_rect *r2 = &dev->try_clips_cap[j].c; |
1126 | 1127 | ||
1127 | if (rect_overlap(r1, r2)) | 1128 | if (v4l2_rect_overlap(r1, r2)) |
1128 | return -EINVAL; | 1129 | return -EINVAL; |
1129 | } | 1130 | } |
1130 | } | 1131 | } |
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index b0d4e3a0acf0..39ea2284789c 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c | |||
@@ -653,103 +653,6 @@ int fmt_sp2mp_func(struct file *file, void *priv, | |||
653 | return ret; | 653 | return ret; |
654 | } | 654 | } |
655 | 655 | ||
656 | /* v4l2_rect helper function: copy the width/height values */ | ||
657 | void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size) | ||
658 | { | ||
659 | r->width = size->width; | ||
660 | r->height = size->height; | ||
661 | } | ||
662 | |||
663 | /* v4l2_rect helper function: width and height of r should be >= min_size */ | ||
664 | void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size) | ||
665 | { | ||
666 | if (r->width < min_size->width) | ||
667 | r->width = min_size->width; | ||
668 | if (r->height < min_size->height) | ||
669 | r->height = min_size->height; | ||
670 | } | ||
671 | |||
672 | /* v4l2_rect helper function: width and height of r should be <= max_size */ | ||
673 | void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size) | ||
674 | { | ||
675 | if (r->width > max_size->width) | ||
676 | r->width = max_size->width; | ||
677 | if (r->height > max_size->height) | ||
678 | r->height = max_size->height; | ||
679 | } | ||
680 | |||
681 | /* v4l2_rect helper function: r should be inside boundary */ | ||
682 | void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary) | ||
683 | { | ||
684 | rect_set_max_size(r, boundary); | ||
685 | if (r->left < boundary->left) | ||
686 | r->left = boundary->left; | ||
687 | if (r->top < boundary->top) | ||
688 | r->top = boundary->top; | ||
689 | if (r->left + r->width > boundary->width) | ||
690 | r->left = boundary->width - r->width; | ||
691 | if (r->top + r->height > boundary->height) | ||
692 | r->top = boundary->height - r->height; | ||
693 | } | ||
694 | |||
695 | /* v4l2_rect helper function: return true if r1 has the same size as r2 */ | ||
696 | bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2) | ||
697 | { | ||
698 | return r1->width == r2->width && r1->height == r2->height; | ||
699 | } | ||
700 | |||
701 | /* v4l2_rect helper function: calculate the intersection of two rects */ | ||
702 | struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b) | ||
703 | { | ||
704 | struct v4l2_rect r; | ||
705 | int right, bottom; | ||
706 | |||
707 | r.top = max(a->top, b->top); | ||
708 | r.left = max(a->left, b->left); | ||
709 | bottom = min(a->top + a->height, b->top + b->height); | ||
710 | right = min(a->left + a->width, b->left + b->width); | ||
711 | r.height = max(0, bottom - r.top); | ||
712 | r.width = max(0, right - r.left); | ||
713 | return r; | ||
714 | } | ||
715 | |||
716 | /* | ||
717 | * v4l2_rect helper function: scale rect r by to->width / from->width and | ||
718 | * to->height / from->height. | ||
719 | */ | ||
720 | void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from, | ||
721 | const struct v4l2_rect *to) | ||
722 | { | ||
723 | if (from->width == 0 || from->height == 0) { | ||
724 | r->left = r->top = r->width = r->height = 0; | ||
725 | return; | ||
726 | } | ||
727 | r->left = (((r->left - from->left) * to->width) / from->width) & ~1; | ||
728 | r->width = ((r->width * to->width) / from->width) & ~1; | ||
729 | r->top = ((r->top - from->top) * to->height) / from->height; | ||
730 | r->height = (r->height * to->height) / from->height; | ||
731 | } | ||
732 | |||
733 | bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2) | ||
734 | { | ||
735 | /* | ||
736 | * IF the left side of r1 is to the right of the right side of r2 OR | ||
737 | * the left side of r2 is to the right of the right side of r1 THEN | ||
738 | * they do not overlap. | ||
739 | */ | ||
740 | if (r1->left >= r2->left + r2->width || | ||
741 | r2->left >= r1->left + r1->width) | ||
742 | return false; | ||
743 | /* | ||
744 | * IF the top side of r1 is below the bottom of r2 OR | ||
745 | * the top side of r2 is below the bottom of r1 THEN | ||
746 | * they do not overlap. | ||
747 | */ | ||
748 | if (r1->top >= r2->top + r2->height || | ||
749 | r2->top >= r1->top + r1->height) | ||
750 | return false; | ||
751 | return true; | ||
752 | } | ||
753 | int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) | 656 | int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) |
754 | { | 657 | { |
755 | unsigned w = r->width; | 658 | unsigned w = r->width; |
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 3ec4fa85c9b9..4b6175eab8a2 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h | |||
@@ -37,15 +37,6 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) | |||
37 | bool vivid_vid_can_loop(struct vivid_dev *dev); | 37 | bool vivid_vid_can_loop(struct vivid_dev *dev); |
38 | void vivid_send_source_change(struct vivid_dev *dev, unsigned type); | 38 | void vivid_send_source_change(struct vivid_dev *dev, unsigned type); |
39 | 39 | ||
40 | bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2); | ||
41 | void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size); | ||
42 | void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size); | ||
43 | void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size); | ||
44 | void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary); | ||
45 | bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2); | ||
46 | struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b); | ||
47 | void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from, | ||
48 | const struct v4l2_rect *to); | ||
49 | int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); | 40 | int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); |
50 | 41 | ||
51 | int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); | 42 | int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); |
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 64e4d66482c1..f92f4496d527 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-common.h> |
26 | #include <media/v4l2-event.h> | 26 | #include <media/v4l2-event.h> |
27 | #include <media/v4l2-dv-timings.h> | 27 | #include <media/v4l2-dv-timings.h> |
28 | #include <media/v4l2-rect.h> | ||
28 | 29 | ||
29 | #include "vivid-core.h" | 30 | #include "vivid-core.h" |
30 | #include "vivid-vid-common.h" | 31 | #include "vivid-vid-common.h" |
@@ -376,16 +377,16 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, | |||
376 | } else { | 377 | } else { |
377 | struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; | 378 | struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; |
378 | 379 | ||
379 | rect_set_min_size(&r, &vivid_min_rect); | 380 | v4l2_rect_set_min_size(&r, &vivid_min_rect); |
380 | rect_set_max_size(&r, &vivid_max_rect); | 381 | v4l2_rect_set_max_size(&r, &vivid_max_rect); |
381 | if (dev->has_scaler_out && !dev->has_crop_out) { | 382 | if (dev->has_scaler_out && !dev->has_crop_out) { |
382 | struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; | 383 | struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; |
383 | 384 | ||
384 | rect_set_max_size(&r, &max_r); | 385 | v4l2_rect_set_max_size(&r, &max_r); |
385 | } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { | 386 | } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { |
386 | rect_set_max_size(&r, &dev->sink_rect); | 387 | v4l2_rect_set_max_size(&r, &dev->sink_rect); |
387 | } else if (!dev->has_scaler_out && !dev->has_compose_out) { | 388 | } else if (!dev->has_scaler_out && !dev->has_compose_out) { |
388 | rect_set_min_size(&r, &dev->sink_rect); | 389 | v4l2_rect_set_min_size(&r, &dev->sink_rect); |
389 | } | 390 | } |
390 | mp->width = r.width; | 391 | mp->width = r.width; |
391 | mp->height = r.height / factor; | 392 | mp->height = r.height / factor; |
@@ -473,7 +474,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, | |||
473 | 474 | ||
474 | if (dev->has_scaler_out) { | 475 | if (dev->has_scaler_out) { |
475 | if (dev->has_crop_out) | 476 | if (dev->has_crop_out) |
476 | rect_map_inside(crop, &r); | 477 | v4l2_rect_map_inside(crop, &r); |
477 | else | 478 | else |
478 | *crop = r; | 479 | *crop = r; |
479 | if (dev->has_compose_out && !dev->has_crop_out) { | 480 | if (dev->has_compose_out && !dev->has_crop_out) { |
@@ -488,9 +489,9 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, | |||
488 | factor * r.height * MAX_ZOOM | 489 | factor * r.height * MAX_ZOOM |
489 | }; | 490 | }; |
490 | 491 | ||
491 | rect_set_min_size(compose, &min_r); | 492 | v4l2_rect_set_min_size(compose, &min_r); |
492 | rect_set_max_size(compose, &max_r); | 493 | v4l2_rect_set_max_size(compose, &max_r); |
493 | rect_map_inside(compose, &dev->compose_bounds_out); | 494 | v4l2_rect_map_inside(compose, &dev->compose_bounds_out); |
494 | } else if (dev->has_compose_out) { | 495 | } else if (dev->has_compose_out) { |
495 | struct v4l2_rect min_r = { | 496 | struct v4l2_rect min_r = { |
496 | 0, 0, | 497 | 0, 0, |
@@ -503,36 +504,36 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, | |||
503 | factor * crop->height * MAX_ZOOM | 504 | factor * crop->height * MAX_ZOOM |
504 | }; | 505 | }; |
505 | 506 | ||
506 | rect_set_min_size(compose, &min_r); | 507 | v4l2_rect_set_min_size(compose, &min_r); |
507 | rect_set_max_size(compose, &max_r); | 508 | v4l2_rect_set_max_size(compose, &max_r); |
508 | rect_map_inside(compose, &dev->compose_bounds_out); | 509 | v4l2_rect_map_inside(compose, &dev->compose_bounds_out); |
509 | } | 510 | } |
510 | } else if (dev->has_compose_out && !dev->has_crop_out) { | 511 | } else if (dev->has_compose_out && !dev->has_crop_out) { |
511 | rect_set_size_to(crop, &r); | 512 | v4l2_rect_set_size_to(crop, &r); |
512 | r.height *= factor; | 513 | r.height *= factor; |
513 | rect_set_size_to(compose, &r); | 514 | v4l2_rect_set_size_to(compose, &r); |
514 | rect_map_inside(compose, &dev->compose_bounds_out); | 515 | v4l2_rect_map_inside(compose, &dev->compose_bounds_out); |
515 | } else if (!dev->has_compose_out) { | 516 | } else if (!dev->has_compose_out) { |
516 | rect_map_inside(crop, &r); | 517 | v4l2_rect_map_inside(crop, &r); |
517 | r.height /= factor; | 518 | r.height /= factor; |
518 | rect_set_size_to(compose, &r); | 519 | v4l2_rect_set_size_to(compose, &r); |
519 | } else { | 520 | } else { |
520 | r.height *= factor; | 521 | r.height *= factor; |
521 | rect_set_max_size(compose, &r); | 522 | v4l2_rect_set_max_size(compose, &r); |
522 | rect_map_inside(compose, &dev->compose_bounds_out); | 523 | v4l2_rect_map_inside(compose, &dev->compose_bounds_out); |
523 | crop->top *= factor; | 524 | crop->top *= factor; |
524 | crop->height *= factor; | 525 | crop->height *= factor; |
525 | rect_set_size_to(crop, compose); | 526 | v4l2_rect_set_size_to(crop, compose); |
526 | rect_map_inside(crop, &r); | 527 | v4l2_rect_map_inside(crop, &r); |
527 | crop->top /= factor; | 528 | crop->top /= factor; |
528 | crop->height /= factor; | 529 | crop->height /= factor; |
529 | } | 530 | } |
530 | } else { | 531 | } else { |
531 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; | 532 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; |
532 | 533 | ||
533 | rect_set_size_to(crop, &r); | 534 | v4l2_rect_set_size_to(crop, &r); |
534 | r.height /= factor; | 535 | r.height /= factor; |
535 | rect_set_size_to(compose, &r); | 536 | v4l2_rect_set_size_to(compose, &r); |
536 | } | 537 | } |
537 | 538 | ||
538 | dev->fmt_out_rect.width = mp->width; | 539 | dev->fmt_out_rect.width = mp->width; |
@@ -683,8 +684,8 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
683 | ret = vivid_vid_adjust_sel(s->flags, &s->r); | 684 | ret = vivid_vid_adjust_sel(s->flags, &s->r); |
684 | if (ret) | 685 | if (ret) |
685 | return ret; | 686 | return ret; |
686 | rect_set_min_size(&s->r, &vivid_min_rect); | 687 | v4l2_rect_set_min_size(&s->r, &vivid_min_rect); |
687 | rect_set_max_size(&s->r, &dev->fmt_out_rect); | 688 | v4l2_rect_set_max_size(&s->r, &dev->fmt_out_rect); |
688 | if (dev->has_scaler_out) { | 689 | if (dev->has_scaler_out) { |
689 | struct v4l2_rect max_rect = { | 690 | struct v4l2_rect max_rect = { |
690 | 0, 0, | 691 | 0, 0, |
@@ -692,7 +693,7 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
692 | (dev->sink_rect.height / factor) * MAX_ZOOM | 693 | (dev->sink_rect.height / factor) * MAX_ZOOM |
693 | }; | 694 | }; |
694 | 695 | ||
695 | rect_set_max_size(&s->r, &max_rect); | 696 | v4l2_rect_set_max_size(&s->r, &max_rect); |
696 | if (dev->has_compose_out) { | 697 | if (dev->has_compose_out) { |
697 | struct v4l2_rect min_rect = { | 698 | struct v4l2_rect min_rect = { |
698 | 0, 0, | 699 | 0, 0, |
@@ -705,23 +706,23 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
705 | (s->r.height * factor) * MAX_ZOOM | 706 | (s->r.height * factor) * MAX_ZOOM |
706 | }; | 707 | }; |
707 | 708 | ||
708 | rect_set_min_size(compose, &min_rect); | 709 | v4l2_rect_set_min_size(compose, &min_rect); |
709 | rect_set_max_size(compose, &max_rect); | 710 | v4l2_rect_set_max_size(compose, &max_rect); |
710 | rect_map_inside(compose, &dev->compose_bounds_out); | 711 | v4l2_rect_map_inside(compose, &dev->compose_bounds_out); |
711 | } | 712 | } |
712 | } else if (dev->has_compose_out) { | 713 | } else if (dev->has_compose_out) { |
713 | s->r.top *= factor; | 714 | s->r.top *= factor; |
714 | s->r.height *= factor; | 715 | s->r.height *= factor; |
715 | rect_set_max_size(&s->r, &dev->sink_rect); | 716 | v4l2_rect_set_max_size(&s->r, &dev->sink_rect); |
716 | rect_set_size_to(compose, &s->r); | 717 | v4l2_rect_set_size_to(compose, &s->r); |
717 | rect_map_inside(compose, &dev->compose_bounds_out); | 718 | v4l2_rect_map_inside(compose, &dev->compose_bounds_out); |
718 | s->r.top /= factor; | 719 | s->r.top /= factor; |
719 | s->r.height /= factor; | 720 | s->r.height /= factor; |
720 | } else { | 721 | } else { |
721 | rect_set_size_to(&s->r, &dev->sink_rect); | 722 | v4l2_rect_set_size_to(&s->r, &dev->sink_rect); |
722 | s->r.height /= factor; | 723 | s->r.height /= factor; |
723 | } | 724 | } |
724 | rect_map_inside(&s->r, &dev->fmt_out_rect); | 725 | v4l2_rect_map_inside(&s->r, &dev->fmt_out_rect); |
725 | *crop = s->r; | 726 | *crop = s->r; |
726 | break; | 727 | break; |
727 | case V4L2_SEL_TGT_COMPOSE: | 728 | case V4L2_SEL_TGT_COMPOSE: |
@@ -730,9 +731,9 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
730 | ret = vivid_vid_adjust_sel(s->flags, &s->r); | 731 | ret = vivid_vid_adjust_sel(s->flags, &s->r); |
731 | if (ret) | 732 | if (ret) |
732 | return ret; | 733 | return ret; |
733 | rect_set_min_size(&s->r, &vivid_min_rect); | 734 | v4l2_rect_set_min_size(&s->r, &vivid_min_rect); |
734 | rect_set_max_size(&s->r, &dev->sink_rect); | 735 | v4l2_rect_set_max_size(&s->r, &dev->sink_rect); |
735 | rect_map_inside(&s->r, &dev->compose_bounds_out); | 736 | v4l2_rect_map_inside(&s->r, &dev->compose_bounds_out); |
736 | s->r.top /= factor; | 737 | s->r.top /= factor; |
737 | s->r.height /= factor; | 738 | s->r.height /= factor; |
738 | if (dev->has_scaler_out) { | 739 | if (dev->has_scaler_out) { |
@@ -748,35 +749,35 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
748 | s->r.height / MAX_ZOOM | 749 | s->r.height / MAX_ZOOM |
749 | }; | 750 | }; |
750 | 751 | ||
751 | rect_set_min_size(&fmt, &min_rect); | 752 | v4l2_rect_set_min_size(&fmt, &min_rect); |
752 | if (!dev->has_crop_out) | 753 | if (!dev->has_crop_out) |
753 | rect_set_max_size(&fmt, &max_rect); | 754 | v4l2_rect_set_max_size(&fmt, &max_rect); |
754 | if (!rect_same_size(&dev->fmt_out_rect, &fmt) && | 755 | if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && |
755 | vb2_is_busy(&dev->vb_vid_out_q)) | 756 | vb2_is_busy(&dev->vb_vid_out_q)) |
756 | return -EBUSY; | 757 | return -EBUSY; |
757 | if (dev->has_crop_out) { | 758 | if (dev->has_crop_out) { |
758 | rect_set_min_size(crop, &min_rect); | 759 | v4l2_rect_set_min_size(crop, &min_rect); |
759 | rect_set_max_size(crop, &max_rect); | 760 | v4l2_rect_set_max_size(crop, &max_rect); |
760 | } | 761 | } |
761 | dev->fmt_out_rect = fmt; | 762 | dev->fmt_out_rect = fmt; |
762 | } else if (dev->has_crop_out) { | 763 | } else if (dev->has_crop_out) { |
763 | struct v4l2_rect fmt = dev->fmt_out_rect; | 764 | struct v4l2_rect fmt = dev->fmt_out_rect; |
764 | 765 | ||
765 | rect_set_min_size(&fmt, &s->r); | 766 | v4l2_rect_set_min_size(&fmt, &s->r); |
766 | if (!rect_same_size(&dev->fmt_out_rect, &fmt) && | 767 | if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && |
767 | vb2_is_busy(&dev->vb_vid_out_q)) | 768 | vb2_is_busy(&dev->vb_vid_out_q)) |
768 | return -EBUSY; | 769 | return -EBUSY; |
769 | dev->fmt_out_rect = fmt; | 770 | dev->fmt_out_rect = fmt; |
770 | rect_set_size_to(crop, &s->r); | 771 | v4l2_rect_set_size_to(crop, &s->r); |
771 | rect_map_inside(crop, &dev->fmt_out_rect); | 772 | v4l2_rect_map_inside(crop, &dev->fmt_out_rect); |
772 | } else { | 773 | } else { |
773 | if (!rect_same_size(&s->r, &dev->fmt_out_rect) && | 774 | if (!v4l2_rect_same_size(&s->r, &dev->fmt_out_rect) && |
774 | vb2_is_busy(&dev->vb_vid_out_q)) | 775 | vb2_is_busy(&dev->vb_vid_out_q)) |
775 | return -EBUSY; | 776 | return -EBUSY; |
776 | rect_set_size_to(&dev->fmt_out_rect, &s->r); | 777 | v4l2_rect_set_size_to(&dev->fmt_out_rect, &s->r); |
777 | rect_set_size_to(crop, &s->r); | 778 | v4l2_rect_set_size_to(crop, &s->r); |
778 | crop->height /= factor; | 779 | crop->height /= factor; |
779 | rect_map_inside(crop, &dev->fmt_out_rect); | 780 | v4l2_rect_map_inside(crop, &dev->fmt_out_rect); |
780 | } | 781 | } |
781 | s->r.top *= factor; | 782 | s->r.top *= factor; |
782 | s->r.height *= factor; | 783 | s->r.height *= factor; |
@@ -901,7 +902,7 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, | |||
901 | for (j = i + 1; j < win->clipcount; j++) { | 902 | for (j = i + 1; j < win->clipcount; j++) { |
902 | struct v4l2_rect *r2 = &dev->try_clips_out[j].c; | 903 | struct v4l2_rect *r2 = &dev->try_clips_out[j].c; |
903 | 904 | ||
904 | if (rect_overlap(r1, r2)) | 905 | if (v4l2_rect_overlap(r1, r2)) |
905 | return -EINVAL; | 906 | return -EINVAL; |
906 | } | 907 | } |
907 | } | 908 | } |
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 910d6b8e8b50..46738b6c5f72 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h | |||
@@ -26,7 +26,6 @@ | |||
26 | struct clk; | 26 | struct clk; |
27 | struct device; | 27 | struct device; |
28 | 28 | ||
29 | struct vsp1_dl; | ||
30 | struct vsp1_drm; | 29 | struct vsp1_drm; |
31 | struct vsp1_entity; | 30 | struct vsp1_entity; |
32 | struct vsp1_platform_data; | 31 | struct vsp1_platform_data; |
@@ -49,6 +48,7 @@ struct vsp1_uds; | |||
49 | 48 | ||
50 | struct vsp1_device_info { | 49 | struct vsp1_device_info { |
51 | u32 version; | 50 | u32 version; |
51 | unsigned int gen; | ||
52 | unsigned int features; | 52 | unsigned int features; |
53 | unsigned int rpf_count; | 53 | unsigned int rpf_count; |
54 | unsigned int uds_count; | 54 | unsigned int uds_count; |
@@ -85,8 +85,6 @@ struct vsp1_device { | |||
85 | struct media_entity_operations media_ops; | 85 | struct media_entity_operations media_ops; |
86 | 86 | ||
87 | struct vsp1_drm *drm; | 87 | struct vsp1_drm *drm; |
88 | |||
89 | bool use_dl; | ||
90 | }; | 88 | }; |
91 | 89 | ||
92 | int vsp1_device_get(struct vsp1_device *vsp1); | 90 | int vsp1_device_get(struct vsp1_device *vsp1); |
@@ -104,14 +102,4 @@ static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data) | |||
104 | iowrite32(data, vsp1->mmio + reg); | 102 | iowrite32(data, vsp1->mmio + reg); |
105 | } | 103 | } |
106 | 104 | ||
107 | #include "vsp1_dl.h" | ||
108 | |||
109 | static inline void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data) | ||
110 | { | ||
111 | if (e->vsp1->use_dl) | ||
112 | vsp1_dl_add(e, reg, data); | ||
113 | else | ||
114 | vsp1_write(e->vsp1, reg, data); | ||
115 | } | ||
116 | |||
117 | #endif /* __VSP1_H__ */ | 105 | #endif /* __VSP1_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index cb0dbc15ddad..b1068c018011 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_bru.h" | 20 | #include "vsp1_bru.h" |
21 | #include "vsp1_dl.h" | ||
22 | #include "vsp1_pipe.h" | ||
21 | #include "vsp1_rwpf.h" | 23 | #include "vsp1_rwpf.h" |
22 | #include "vsp1_video.h" | 24 | #include "vsp1_video.h" |
23 | 25 | ||
@@ -28,9 +30,10 @@ | |||
28 | * Device Access | 30 | * Device Access |
29 | */ | 31 | */ |
30 | 32 | ||
31 | static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data) | 33 | static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl, |
34 | u32 reg, u32 data) | ||
32 | { | 35 | { |
33 | vsp1_mod_write(&bru->entity, reg, data); | 36 | vsp1_dl_list_write(dl, reg, data); |
34 | } | 37 | } |
35 | 38 | ||
36 | /* ----------------------------------------------------------------------------- | 39 | /* ----------------------------------------------------------------------------- |
@@ -42,13 +45,9 @@ static int bru_s_ctrl(struct v4l2_ctrl *ctrl) | |||
42 | struct vsp1_bru *bru = | 45 | struct vsp1_bru *bru = |
43 | container_of(ctrl->handler, struct vsp1_bru, ctrls); | 46 | container_of(ctrl->handler, struct vsp1_bru, ctrls); |
44 | 47 | ||
45 | if (!vsp1_entity_is_streaming(&bru->entity)) | ||
46 | return 0; | ||
47 | |||
48 | switch (ctrl->id) { | 48 | switch (ctrl->id) { |
49 | case V4L2_CID_BG_COLOR: | 49 | case V4L2_CID_BG_COLOR: |
50 | vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, ctrl->val | | 50 | bru->bgcolor = ctrl->val; |
51 | (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT)); | ||
52 | break; | 51 | break; |
53 | } | 52 | } |
54 | 53 | ||
@@ -60,116 +59,7 @@ static const struct v4l2_ctrl_ops bru_ctrl_ops = { | |||
60 | }; | 59 | }; |
61 | 60 | ||
62 | /* ----------------------------------------------------------------------------- | 61 | /* ----------------------------------------------------------------------------- |
63 | * V4L2 Subdevice Core Operations | 62 | * V4L2 Subdevice Operations |
64 | */ | ||
65 | |||
66 | static int bru_s_stream(struct v4l2_subdev *subdev, int enable) | ||
67 | { | ||
68 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity); | ||
69 | struct vsp1_bru *bru = to_bru(subdev); | ||
70 | struct v4l2_mbus_framefmt *format; | ||
71 | unsigned int flags; | ||
72 | unsigned int i; | ||
73 | int ret; | ||
74 | |||
75 | ret = vsp1_entity_set_streaming(&bru->entity, enable); | ||
76 | if (ret < 0) | ||
77 | return ret; | ||
78 | |||
79 | if (!enable) | ||
80 | return 0; | ||
81 | |||
82 | format = &bru->entity.formats[bru->entity.source_pad]; | ||
83 | |||
84 | /* The hardware is extremely flexible but we have no userspace API to | ||
85 | * expose all the parameters, nor is it clear whether we would have use | ||
86 | * cases for all the supported modes. Let's just harcode the parameters | ||
87 | * to sane default values for now. | ||
88 | */ | ||
89 | |||
90 | /* Disable dithering and enable color data normalization unless the | ||
91 | * format at the pipeline output is premultiplied. | ||
92 | */ | ||
93 | flags = pipe->output ? pipe->output->format.flags : 0; | ||
94 | vsp1_bru_write(bru, VI6_BRU_INCTRL, | ||
95 | flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ? | ||
96 | 0 : VI6_BRU_INCTRL_NRM); | ||
97 | |||
98 | /* Set the background position to cover the whole output image. */ | ||
99 | vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE, | ||
100 | (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | | ||
101 | (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); | ||
102 | vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0); | ||
103 | |||
104 | /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP | ||
105 | * unit with a NOP operation to make BRU input 1 available as the | ||
106 | * Blend/ROP unit B SRC input. | ||
107 | */ | ||
108 | vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | | ||
109 | VI6_BRU_ROP_CROP(VI6_ROP_NOP) | | ||
110 | VI6_BRU_ROP_AROP(VI6_ROP_NOP)); | ||
111 | |||
112 | for (i = 0; i < bru->entity.source_pad; ++i) { | ||
113 | bool premultiplied = false; | ||
114 | u32 ctrl = 0; | ||
115 | |||
116 | /* Configure all Blend/ROP units corresponding to an enabled BRU | ||
117 | * input for alpha blending. Blend/ROP units corresponding to | ||
118 | * disabled BRU inputs are used in ROP NOP mode to ignore the | ||
119 | * SRC input. | ||
120 | */ | ||
121 | if (bru->inputs[i].rpf) { | ||
122 | ctrl |= VI6_BRU_CTRL_RBC; | ||
123 | |||
124 | premultiplied = bru->inputs[i].rpf->format.flags | ||
125 | & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; | ||
126 | } else { | ||
127 | ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP) | ||
128 | | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); | ||
129 | } | ||
130 | |||
131 | /* Select the virtual RPF as the Blend/ROP unit A DST input to | ||
132 | * serve as a background color. | ||
133 | */ | ||
134 | if (i == 0) | ||
135 | ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; | ||
136 | |||
137 | /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to | ||
138 | * D in that order. The Blend/ROP unit B SRC is hardwired to the | ||
139 | * ROP unit output, the corresponding register bits must be set | ||
140 | * to 0. | ||
141 | */ | ||
142 | if (i != 1) | ||
143 | ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); | ||
144 | |||
145 | vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl); | ||
146 | |||
147 | /* Harcode the blending formula to | ||
148 | * | ||
149 | * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa | ||
150 | * DSTa = DSTa * (1 - SRCa) + SRCa | ||
151 | * | ||
152 | * when the SRC input isn't premultiplied, and to | ||
153 | * | ||
154 | * DSTc = DSTc * (1 - SRCa) + SRCc | ||
155 | * DSTa = DSTa * (1 - SRCa) + SRCa | ||
156 | * | ||
157 | * otherwise. | ||
158 | */ | ||
159 | vsp1_bru_write(bru, VI6_BRU_BLD(i), | ||
160 | VI6_BRU_BLD_CCMDX_255_SRC_A | | ||
161 | (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY : | ||
162 | VI6_BRU_BLD_CCMDY_SRC_A) | | ||
163 | VI6_BRU_BLD_ACMDX_255_SRC_A | | ||
164 | VI6_BRU_BLD_ACMDY_COEFY | | ||
165 | (0xff << VI6_BRU_BLD_COEFY_SHIFT)); | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /* ----------------------------------------------------------------------------- | ||
172 | * V4L2 Subdevice Pad Operations | ||
173 | */ | 63 | */ |
174 | 64 | ||
175 | /* | 65 | /* |
@@ -186,24 +76,9 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, | |||
186 | MEDIA_BUS_FMT_ARGB8888_1X32, | 76 | MEDIA_BUS_FMT_ARGB8888_1X32, |
187 | MEDIA_BUS_FMT_AYUV8_1X32, | 77 | MEDIA_BUS_FMT_AYUV8_1X32, |
188 | }; | 78 | }; |
189 | struct vsp1_bru *bru = to_bru(subdev); | ||
190 | struct v4l2_mbus_framefmt *format; | ||
191 | |||
192 | if (code->pad == BRU_PAD_SINK(0)) { | ||
193 | if (code->index >= ARRAY_SIZE(codes)) | ||
194 | return -EINVAL; | ||
195 | |||
196 | code->code = codes[code->index]; | ||
197 | } else { | ||
198 | if (code->index) | ||
199 | return -EINVAL; | ||
200 | |||
201 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, | ||
202 | BRU_PAD_SINK(0), code->which); | ||
203 | code->code = format->code; | ||
204 | } | ||
205 | 79 | ||
206 | return 0; | 80 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, |
81 | ARRAY_SIZE(codes)); | ||
207 | } | 82 | } |
208 | 83 | ||
209 | static int bru_enum_frame_size(struct v4l2_subdev *subdev, | 84 | static int bru_enum_frame_size(struct v4l2_subdev *subdev, |
@@ -227,32 +102,14 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev, | |||
227 | 102 | ||
228 | static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, | 103 | static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, |
229 | struct v4l2_subdev_pad_config *cfg, | 104 | struct v4l2_subdev_pad_config *cfg, |
230 | unsigned int pad, u32 which) | 105 | unsigned int pad) |
231 | { | ||
232 | switch (which) { | ||
233 | case V4L2_SUBDEV_FORMAT_TRY: | ||
234 | return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad); | ||
235 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
236 | return &bru->inputs[pad].compose; | ||
237 | default: | ||
238 | return NULL; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | ||
243 | struct v4l2_subdev_format *fmt) | ||
244 | { | 106 | { |
245 | struct vsp1_bru *bru = to_bru(subdev); | 107 | return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg, pad); |
246 | |||
247 | fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, | ||
248 | fmt->which); | ||
249 | |||
250 | return 0; | ||
251 | } | 108 | } |
252 | 109 | ||
253 | static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg, | 110 | static void bru_try_format(struct vsp1_bru *bru, |
254 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | 111 | struct v4l2_subdev_pad_config *config, |
255 | enum v4l2_subdev_format_whence which) | 112 | unsigned int pad, struct v4l2_mbus_framefmt *fmt) |
256 | { | 113 | { |
257 | struct v4l2_mbus_framefmt *format; | 114 | struct v4l2_mbus_framefmt *format; |
258 | 115 | ||
@@ -266,8 +123,8 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config * | |||
266 | 123 | ||
267 | default: | 124 | default: |
268 | /* The BRU can't perform format conversion. */ | 125 | /* The BRU can't perform format conversion. */ |
269 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, | 126 | format = vsp1_entity_get_pad_format(&bru->entity, config, |
270 | BRU_PAD_SINK(0), which); | 127 | BRU_PAD_SINK(0)); |
271 | fmt->code = format->code; | 128 | fmt->code = format->code; |
272 | break; | 129 | break; |
273 | } | 130 | } |
@@ -278,23 +135,28 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config * | |||
278 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 135 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
279 | } | 136 | } |
280 | 137 | ||
281 | static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 138 | static int bru_set_format(struct v4l2_subdev *subdev, |
139 | struct v4l2_subdev_pad_config *cfg, | ||
282 | struct v4l2_subdev_format *fmt) | 140 | struct v4l2_subdev_format *fmt) |
283 | { | 141 | { |
284 | struct vsp1_bru *bru = to_bru(subdev); | 142 | struct vsp1_bru *bru = to_bru(subdev); |
143 | struct v4l2_subdev_pad_config *config; | ||
285 | struct v4l2_mbus_framefmt *format; | 144 | struct v4l2_mbus_framefmt *format; |
286 | 145 | ||
287 | bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which); | 146 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which); |
147 | if (!config) | ||
148 | return -EINVAL; | ||
149 | |||
150 | bru_try_format(bru, config, fmt->pad, &fmt->format); | ||
288 | 151 | ||
289 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, | 152 | format = vsp1_entity_get_pad_format(&bru->entity, config, fmt->pad); |
290 | fmt->which); | ||
291 | *format = fmt->format; | 153 | *format = fmt->format; |
292 | 154 | ||
293 | /* Reset the compose rectangle */ | 155 | /* Reset the compose rectangle */ |
294 | if (fmt->pad != bru->entity.source_pad) { | 156 | if (fmt->pad != bru->entity.source_pad) { |
295 | struct v4l2_rect *compose; | 157 | struct v4l2_rect *compose; |
296 | 158 | ||
297 | compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which); | 159 | compose = bru_get_compose(bru, config, fmt->pad); |
298 | compose->left = 0; | 160 | compose->left = 0; |
299 | compose->top = 0; | 161 | compose->top = 0; |
300 | compose->width = format->width; | 162 | compose->width = format->width; |
@@ -306,8 +168,8 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con | |||
306 | unsigned int i; | 168 | unsigned int i; |
307 | 169 | ||
308 | for (i = 0; i <= bru->entity.source_pad; ++i) { | 170 | for (i = 0; i <= bru->entity.source_pad; ++i) { |
309 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, | 171 | format = vsp1_entity_get_pad_format(&bru->entity, |
310 | i, fmt->which); | 172 | config, i); |
311 | format->code = fmt->format.code; | 173 | format->code = fmt->format.code; |
312 | } | 174 | } |
313 | } | 175 | } |
@@ -320,6 +182,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, | |||
320 | struct v4l2_subdev_selection *sel) | 182 | struct v4l2_subdev_selection *sel) |
321 | { | 183 | { |
322 | struct vsp1_bru *bru = to_bru(subdev); | 184 | struct vsp1_bru *bru = to_bru(subdev); |
185 | struct v4l2_subdev_pad_config *config; | ||
323 | 186 | ||
324 | if (sel->pad == bru->entity.source_pad) | 187 | if (sel->pad == bru->entity.source_pad) |
325 | return -EINVAL; | 188 | return -EINVAL; |
@@ -333,7 +196,12 @@ static int bru_get_selection(struct v4l2_subdev *subdev, | |||
333 | return 0; | 196 | return 0; |
334 | 197 | ||
335 | case V4L2_SEL_TGT_COMPOSE: | 198 | case V4L2_SEL_TGT_COMPOSE: |
336 | sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which); | 199 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, |
200 | sel->which); | ||
201 | if (!config) | ||
202 | return -EINVAL; | ||
203 | |||
204 | sel->r = *bru_get_compose(bru, config, sel->pad); | ||
337 | return 0; | 205 | return 0; |
338 | 206 | ||
339 | default: | 207 | default: |
@@ -346,6 +214,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
346 | struct v4l2_subdev_selection *sel) | 214 | struct v4l2_subdev_selection *sel) |
347 | { | 215 | { |
348 | struct vsp1_bru *bru = to_bru(subdev); | 216 | struct vsp1_bru *bru = to_bru(subdev); |
217 | struct v4l2_subdev_pad_config *config; | ||
349 | struct v4l2_mbus_framefmt *format; | 218 | struct v4l2_mbus_framefmt *format; |
350 | struct v4l2_rect *compose; | 219 | struct v4l2_rect *compose; |
351 | 220 | ||
@@ -355,57 +224,161 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
355 | if (sel->target != V4L2_SEL_TGT_COMPOSE) | 224 | if (sel->target != V4L2_SEL_TGT_COMPOSE) |
356 | return -EINVAL; | 225 | return -EINVAL; |
357 | 226 | ||
227 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which); | ||
228 | if (!config) | ||
229 | return -EINVAL; | ||
230 | |||
358 | /* The compose rectangle top left corner must be inside the output | 231 | /* The compose rectangle top left corner must be inside the output |
359 | * frame. | 232 | * frame. |
360 | */ | 233 | */ |
361 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, | 234 | format = vsp1_entity_get_pad_format(&bru->entity, config, |
362 | bru->entity.source_pad, sel->which); | 235 | bru->entity.source_pad); |
363 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); | 236 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); |
364 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); | 237 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); |
365 | 238 | ||
366 | /* Scaling isn't supported, the compose rectangle size must be identical | 239 | /* Scaling isn't supported, the compose rectangle size must be identical |
367 | * to the sink format size. | 240 | * to the sink format size. |
368 | */ | 241 | */ |
369 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad, | 242 | format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad); |
370 | sel->which); | ||
371 | sel->r.width = format->width; | 243 | sel->r.width = format->width; |
372 | sel->r.height = format->height; | 244 | sel->r.height = format->height; |
373 | 245 | ||
374 | compose = bru_get_compose(bru, cfg, sel->pad, sel->which); | 246 | compose = bru_get_compose(bru, config, sel->pad); |
375 | *compose = sel->r; | 247 | *compose = sel->r; |
376 | 248 | ||
377 | return 0; | 249 | return 0; |
378 | } | 250 | } |
379 | 251 | ||
380 | /* ----------------------------------------------------------------------------- | ||
381 | * V4L2 Subdevice Operations | ||
382 | */ | ||
383 | |||
384 | static struct v4l2_subdev_video_ops bru_video_ops = { | ||
385 | .s_stream = bru_s_stream, | ||
386 | }; | ||
387 | |||
388 | static struct v4l2_subdev_pad_ops bru_pad_ops = { | 252 | static struct v4l2_subdev_pad_ops bru_pad_ops = { |
253 | .init_cfg = vsp1_entity_init_cfg, | ||
389 | .enum_mbus_code = bru_enum_mbus_code, | 254 | .enum_mbus_code = bru_enum_mbus_code, |
390 | .enum_frame_size = bru_enum_frame_size, | 255 | .enum_frame_size = bru_enum_frame_size, |
391 | .get_fmt = bru_get_format, | 256 | .get_fmt = vsp1_subdev_get_pad_format, |
392 | .set_fmt = bru_set_format, | 257 | .set_fmt = bru_set_format, |
393 | .get_selection = bru_get_selection, | 258 | .get_selection = bru_get_selection, |
394 | .set_selection = bru_set_selection, | 259 | .set_selection = bru_set_selection, |
395 | }; | 260 | }; |
396 | 261 | ||
397 | static struct v4l2_subdev_ops bru_ops = { | 262 | static struct v4l2_subdev_ops bru_ops = { |
398 | .video = &bru_video_ops, | ||
399 | .pad = &bru_pad_ops, | 263 | .pad = &bru_pad_ops, |
400 | }; | 264 | }; |
401 | 265 | ||
402 | /* ----------------------------------------------------------------------------- | 266 | /* ----------------------------------------------------------------------------- |
267 | * VSP1 Entity Operations | ||
268 | */ | ||
269 | |||
270 | static void bru_configure(struct vsp1_entity *entity, | ||
271 | struct vsp1_pipeline *pipe, | ||
272 | struct vsp1_dl_list *dl) | ||
273 | { | ||
274 | struct vsp1_bru *bru = to_bru(&entity->subdev); | ||
275 | struct v4l2_mbus_framefmt *format; | ||
276 | unsigned int flags; | ||
277 | unsigned int i; | ||
278 | |||
279 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, | ||
280 | bru->entity.source_pad); | ||
281 | |||
282 | /* The hardware is extremely flexible but we have no userspace API to | ||
283 | * expose all the parameters, nor is it clear whether we would have use | ||
284 | * cases for all the supported modes. Let's just harcode the parameters | ||
285 | * to sane default values for now. | ||
286 | */ | ||
287 | |||
288 | /* Disable dithering and enable color data normalization unless the | ||
289 | * format at the pipeline output is premultiplied. | ||
290 | */ | ||
291 | flags = pipe->output ? pipe->output->format.flags : 0; | ||
292 | vsp1_bru_write(bru, dl, VI6_BRU_INCTRL, | ||
293 | flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ? | ||
294 | 0 : VI6_BRU_INCTRL_NRM); | ||
295 | |||
296 | /* Set the background position to cover the whole output image and | ||
297 | * configure its color. | ||
298 | */ | ||
299 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE, | ||
300 | (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | | ||
301 | (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); | ||
302 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0); | ||
303 | |||
304 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor | | ||
305 | (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT)); | ||
306 | |||
307 | /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP | ||
308 | * unit with a NOP operation to make BRU input 1 available as the | ||
309 | * Blend/ROP unit B SRC input. | ||
310 | */ | ||
311 | vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | | ||
312 | VI6_BRU_ROP_CROP(VI6_ROP_NOP) | | ||
313 | VI6_BRU_ROP_AROP(VI6_ROP_NOP)); | ||
314 | |||
315 | for (i = 0; i < bru->entity.source_pad; ++i) { | ||
316 | bool premultiplied = false; | ||
317 | u32 ctrl = 0; | ||
318 | |||
319 | /* Configure all Blend/ROP units corresponding to an enabled BRU | ||
320 | * input for alpha blending. Blend/ROP units corresponding to | ||
321 | * disabled BRU inputs are used in ROP NOP mode to ignore the | ||
322 | * SRC input. | ||
323 | */ | ||
324 | if (bru->inputs[i].rpf) { | ||
325 | ctrl |= VI6_BRU_CTRL_RBC; | ||
326 | |||
327 | premultiplied = bru->inputs[i].rpf->format.flags | ||
328 | & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; | ||
329 | } else { | ||
330 | ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP) | ||
331 | | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); | ||
332 | } | ||
333 | |||
334 | /* Select the virtual RPF as the Blend/ROP unit A DST input to | ||
335 | * serve as a background color. | ||
336 | */ | ||
337 | if (i == 0) | ||
338 | ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; | ||
339 | |||
340 | /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to | ||
341 | * D in that order. The Blend/ROP unit B SRC is hardwired to the | ||
342 | * ROP unit output, the corresponding register bits must be set | ||
343 | * to 0. | ||
344 | */ | ||
345 | if (i != 1) | ||
346 | ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); | ||
347 | |||
348 | vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl); | ||
349 | |||
350 | /* Harcode the blending formula to | ||
351 | * | ||
352 | * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa | ||
353 | * DSTa = DSTa * (1 - SRCa) + SRCa | ||
354 | * | ||
355 | * when the SRC input isn't premultiplied, and to | ||
356 | * | ||
357 | * DSTc = DSTc * (1 - SRCa) + SRCc | ||
358 | * DSTa = DSTa * (1 - SRCa) + SRCa | ||
359 | * | ||
360 | * otherwise. | ||
361 | */ | ||
362 | vsp1_bru_write(bru, dl, VI6_BRU_BLD(i), | ||
363 | VI6_BRU_BLD_CCMDX_255_SRC_A | | ||
364 | (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY : | ||
365 | VI6_BRU_BLD_CCMDY_SRC_A) | | ||
366 | VI6_BRU_BLD_ACMDX_255_SRC_A | | ||
367 | VI6_BRU_BLD_ACMDY_COEFY | | ||
368 | (0xff << VI6_BRU_BLD_COEFY_SHIFT)); | ||
369 | } | ||
370 | } | ||
371 | |||
372 | static const struct vsp1_entity_operations bru_entity_ops = { | ||
373 | .configure = bru_configure, | ||
374 | }; | ||
375 | |||
376 | /* ----------------------------------------------------------------------------- | ||
403 | * Initialization and Cleanup | 377 | * Initialization and Cleanup |
404 | */ | 378 | */ |
405 | 379 | ||
406 | struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) | 380 | struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) |
407 | { | 381 | { |
408 | struct v4l2_subdev *subdev; | ||
409 | struct vsp1_bru *bru; | 382 | struct vsp1_bru *bru; |
410 | int ret; | 383 | int ret; |
411 | 384 | ||
@@ -413,31 +386,21 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) | |||
413 | if (bru == NULL) | 386 | if (bru == NULL) |
414 | return ERR_PTR(-ENOMEM); | 387 | return ERR_PTR(-ENOMEM); |
415 | 388 | ||
389 | bru->entity.ops = &bru_entity_ops; | ||
416 | bru->entity.type = VSP1_ENTITY_BRU; | 390 | bru->entity.type = VSP1_ENTITY_BRU; |
417 | 391 | ||
418 | ret = vsp1_entity_init(vsp1, &bru->entity, | 392 | ret = vsp1_entity_init(vsp1, &bru->entity, "bru", |
419 | vsp1->info->num_bru_inputs + 1); | 393 | vsp1->info->num_bru_inputs + 1, &bru_ops); |
420 | if (ret < 0) | 394 | if (ret < 0) |
421 | return ERR_PTR(ret); | 395 | return ERR_PTR(ret); |
422 | 396 | ||
423 | /* Initialize the V4L2 subdev. */ | ||
424 | subdev = &bru->entity.subdev; | ||
425 | v4l2_subdev_init(subdev, &bru_ops); | ||
426 | |||
427 | subdev->entity.ops = &vsp1->media_ops; | ||
428 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
429 | snprintf(subdev->name, sizeof(subdev->name), "%s bru", | ||
430 | dev_name(vsp1->dev)); | ||
431 | v4l2_set_subdevdata(subdev, bru); | ||
432 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
433 | |||
434 | vsp1_entity_init_formats(subdev, NULL); | ||
435 | |||
436 | /* Initialize the control handler. */ | 397 | /* Initialize the control handler. */ |
437 | v4l2_ctrl_handler_init(&bru->ctrls, 1); | 398 | v4l2_ctrl_handler_init(&bru->ctrls, 1); |
438 | v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR, | 399 | v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR, |
439 | 0, 0xffffff, 1, 0); | 400 | 0, 0xffffff, 1, 0); |
440 | 401 | ||
402 | bru->bgcolor = 0; | ||
403 | |||
441 | bru->entity.subdev.ctrl_handler = &bru->ctrls; | 404 | bru->entity.subdev.ctrl_handler = &bru->ctrls; |
442 | 405 | ||
443 | if (bru->ctrls.error) { | 406 | if (bru->ctrls.error) { |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h index dbac9686ea69..828a3fcadea8 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.h +++ b/drivers/media/platform/vsp1/vsp1_bru.h | |||
@@ -31,8 +31,9 @@ struct vsp1_bru { | |||
31 | 31 | ||
32 | struct { | 32 | struct { |
33 | struct vsp1_rwpf *rpf; | 33 | struct vsp1_rwpf *rpf; |
34 | struct v4l2_rect compose; | ||
35 | } inputs[VSP1_MAX_RPF]; | 34 | } inputs[VSP1_MAX_RPF]; |
35 | |||
36 | u32 bgcolor; | ||
36 | }; | 37 | }; |
37 | 38 | ||
38 | static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) | 39 | static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) |
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 1a9a58588f84..e238d9b9376b 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c | |||
@@ -18,139 +18,406 @@ | |||
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | 20 | #include "vsp1_dl.h" |
21 | #include "vsp1_pipe.h" | ||
22 | 21 | ||
23 | /* | 22 | #define VSP1_DL_NUM_ENTRIES 256 |
24 | * Global resources | ||
25 | * | ||
26 | * - Display-related interrupts (can be used for vblank evasion ?) | ||
27 | * - Display-list enable | ||
28 | * - Header-less for WPF0 | ||
29 | * - DL swap | ||
30 | */ | ||
31 | |||
32 | #define VSP1_DL_BODY_SIZE (2 * 4 * 256) | ||
33 | #define VSP1_DL_NUM_LISTS 3 | 23 | #define VSP1_DL_NUM_LISTS 3 |
34 | 24 | ||
25 | #define VSP1_DLH_INT_ENABLE (1 << 1) | ||
26 | #define VSP1_DLH_AUTO_START (1 << 0) | ||
27 | |||
28 | struct vsp1_dl_header_list { | ||
29 | u32 num_bytes; | ||
30 | u32 addr; | ||
31 | } __attribute__((__packed__)); | ||
32 | |||
33 | struct vsp1_dl_header { | ||
34 | u32 num_lists; | ||
35 | struct vsp1_dl_header_list lists[8]; | ||
36 | u32 next_header; | ||
37 | u32 flags; | ||
38 | } __attribute__((__packed__)); | ||
39 | |||
35 | struct vsp1_dl_entry { | 40 | struct vsp1_dl_entry { |
36 | u32 addr; | 41 | u32 addr; |
37 | u32 data; | 42 | u32 data; |
38 | } __attribute__((__packed__)); | 43 | } __attribute__((__packed__)); |
39 | 44 | ||
40 | struct vsp1_dl_list { | 45 | /** |
46 | * struct vsp1_dl_body - Display list body | ||
47 | * @list: entry in the display list list of bodies | ||
48 | * @vsp1: the VSP1 device | ||
49 | * @entries: array of entries | ||
50 | * @dma: DMA address of the entries | ||
51 | * @size: size of the DMA memory in bytes | ||
52 | * @num_entries: number of stored entries | ||
53 | */ | ||
54 | struct vsp1_dl_body { | ||
55 | struct list_head list; | ||
56 | struct vsp1_device *vsp1; | ||
57 | |||
58 | struct vsp1_dl_entry *entries; | ||
59 | dma_addr_t dma; | ||
41 | size_t size; | 60 | size_t size; |
42 | int reg_count; | ||
43 | 61 | ||
44 | bool in_use; | 62 | unsigned int num_entries; |
63 | }; | ||
45 | 64 | ||
46 | struct vsp1_dl_entry *body; | 65 | /** |
66 | * struct vsp1_dl_list - Display list | ||
67 | * @list: entry in the display list manager lists | ||
68 | * @dlm: the display list manager | ||
69 | * @header: display list header, NULL for headerless lists | ||
70 | * @dma: DMA address for the header | ||
71 | * @body0: first display list body | ||
72 | * @fragments: list of extra display list bodies | ||
73 | */ | ||
74 | struct vsp1_dl_list { | ||
75 | struct list_head list; | ||
76 | struct vsp1_dl_manager *dlm; | ||
77 | |||
78 | struct vsp1_dl_header *header; | ||
47 | dma_addr_t dma; | 79 | dma_addr_t dma; |
80 | |||
81 | struct vsp1_dl_body body0; | ||
82 | struct list_head fragments; | ||
83 | }; | ||
84 | |||
85 | enum vsp1_dl_mode { | ||
86 | VSP1_DL_MODE_HEADER, | ||
87 | VSP1_DL_MODE_HEADERLESS, | ||
48 | }; | 88 | }; |
49 | 89 | ||
50 | /** | 90 | /** |
51 | * struct vsp1_dl - Display List manager | 91 | * struct vsp1_dl_manager - Display List manager |
92 | * @index: index of the related WPF | ||
93 | * @mode: display list operation mode (header or headerless) | ||
52 | * @vsp1: the VSP1 device | 94 | * @vsp1: the VSP1 device |
53 | * @lock: protects the active, queued and pending lists | 95 | * @lock: protects the active, queued and pending lists |
54 | * @lists.all: array of all allocate display lists | 96 | * @free: array of all free display lists |
55 | * @lists.active: list currently being processed (loaded) by hardware | 97 | * @active: list currently being processed (loaded) by hardware |
56 | * @lists.queued: list queued to the hardware (written to the DL registers) | 98 | * @queued: list queued to the hardware (written to the DL registers) |
57 | * @lists.pending: list waiting to be queued to the hardware | 99 | * @pending: list waiting to be queued to the hardware |
58 | * @lists.write: list being written to by software | ||
59 | */ | 100 | */ |
60 | struct vsp1_dl { | 101 | struct vsp1_dl_manager { |
102 | unsigned int index; | ||
103 | enum vsp1_dl_mode mode; | ||
61 | struct vsp1_device *vsp1; | 104 | struct vsp1_device *vsp1; |
62 | 105 | ||
63 | spinlock_t lock; | 106 | spinlock_t lock; |
107 | struct list_head free; | ||
108 | struct vsp1_dl_list *active; | ||
109 | struct vsp1_dl_list *queued; | ||
110 | struct vsp1_dl_list *pending; | ||
111 | }; | ||
64 | 112 | ||
65 | size_t size; | 113 | /* ----------------------------------------------------------------------------- |
66 | dma_addr_t dma; | 114 | * Display List Body Management |
67 | void *mem; | 115 | */ |
116 | |||
117 | /* | ||
118 | * Initialize a display list body object and allocate DMA memory for the body | ||
119 | * data. The display list body object is expected to have been initialized to | ||
120 | * 0 when allocated. | ||
121 | */ | ||
122 | static int vsp1_dl_body_init(struct vsp1_device *vsp1, | ||
123 | struct vsp1_dl_body *dlb, unsigned int num_entries, | ||
124 | size_t extra_size) | ||
125 | { | ||
126 | size_t size = num_entries * sizeof(*dlb->entries) + extra_size; | ||
68 | 127 | ||
69 | struct { | 128 | dlb->vsp1 = vsp1; |
70 | struct vsp1_dl_list all[VSP1_DL_NUM_LISTS]; | 129 | dlb->size = size; |
71 | 130 | ||
72 | struct vsp1_dl_list *active; | 131 | dlb->entries = dma_alloc_wc(vsp1->dev, dlb->size, &dlb->dma, |
73 | struct vsp1_dl_list *queued; | 132 | GFP_KERNEL); |
74 | struct vsp1_dl_list *pending; | 133 | if (!dlb->entries) |
75 | struct vsp1_dl_list *write; | 134 | return -ENOMEM; |
76 | } lists; | 135 | |
77 | }; | 136 | return 0; |
137 | } | ||
138 | |||
139 | /* | ||
140 | * Cleanup a display list body and free allocated DMA memory allocated. | ||
141 | */ | ||
142 | static void vsp1_dl_body_cleanup(struct vsp1_dl_body *dlb) | ||
143 | { | ||
144 | dma_free_wc(dlb->vsp1->dev, dlb->size, dlb->entries, dlb->dma); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * vsp1_dl_fragment_alloc - Allocate a display list fragment | ||
149 | * @vsp1: The VSP1 device | ||
150 | * @num_entries: The maximum number of entries that the fragment can contain | ||
151 | * | ||
152 | * Allocate a display list fragment with enough memory to contain the requested | ||
153 | * number of entries. | ||
154 | * | ||
155 | * Return a pointer to a fragment on success or NULL if memory can't be | ||
156 | * allocated. | ||
157 | */ | ||
158 | struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1, | ||
159 | unsigned int num_entries) | ||
160 | { | ||
161 | struct vsp1_dl_body *dlb; | ||
162 | int ret; | ||
163 | |||
164 | dlb = kzalloc(sizeof(*dlb), GFP_KERNEL); | ||
165 | if (!dlb) | ||
166 | return NULL; | ||
167 | |||
168 | ret = vsp1_dl_body_init(vsp1, dlb, num_entries, 0); | ||
169 | if (ret < 0) { | ||
170 | kfree(dlb); | ||
171 | return NULL; | ||
172 | } | ||
173 | |||
174 | return dlb; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * vsp1_dl_fragment_free - Free a display list fragment | ||
179 | * @dlb: The fragment | ||
180 | * | ||
181 | * Free the given display list fragment and the associated DMA memory. | ||
182 | * | ||
183 | * Fragments must only be freed explicitly if they are not added to a display | ||
184 | * list, as the display list will take ownership of them and free them | ||
185 | * otherwise. Manual free typically happens at cleanup time for fragments that | ||
186 | * have been allocated but not used. | ||
187 | * | ||
188 | * Passing a NULL pointer to this function is safe, in that case no operation | ||
189 | * will be performed. | ||
190 | */ | ||
191 | void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb) | ||
192 | { | ||
193 | if (!dlb) | ||
194 | return; | ||
195 | |||
196 | vsp1_dl_body_cleanup(dlb); | ||
197 | kfree(dlb); | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * vsp1_dl_fragment_write - Write a register to a display list fragment | ||
202 | * @dlb: The fragment | ||
203 | * @reg: The register address | ||
204 | * @data: The register value | ||
205 | * | ||
206 | * Write the given register and value to the display list fragment. The maximum | ||
207 | * number of entries that can be written in a fragment is specified when the | ||
208 | * fragment is allocated by vsp1_dl_fragment_alloc(). | ||
209 | */ | ||
210 | void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data) | ||
211 | { | ||
212 | dlb->entries[dlb->num_entries].addr = reg; | ||
213 | dlb->entries[dlb->num_entries].data = data; | ||
214 | dlb->num_entries++; | ||
215 | } | ||
78 | 216 | ||
79 | /* ----------------------------------------------------------------------------- | 217 | /* ----------------------------------------------------------------------------- |
80 | * Display List Transaction Management | 218 | * Display List Transaction Management |
81 | */ | 219 | */ |
82 | 220 | ||
83 | static void vsp1_dl_free_list(struct vsp1_dl_list *list) | 221 | static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) |
84 | { | 222 | { |
85 | if (!list) | 223 | struct vsp1_dl_list *dl; |
86 | return; | 224 | size_t header_size; |
225 | int ret; | ||
226 | |||
227 | dl = kzalloc(sizeof(*dl), GFP_KERNEL); | ||
228 | if (!dl) | ||
229 | return NULL; | ||
87 | 230 | ||
88 | list->in_use = false; | 231 | INIT_LIST_HEAD(&dl->fragments); |
232 | dl->dlm = dlm; | ||
233 | |||
234 | /* Initialize the display list body and allocate DMA memory for the body | ||
235 | * and the optional header. Both are allocated together to avoid memory | ||
236 | * fragmentation, with the header located right after the body in | ||
237 | * memory. | ||
238 | */ | ||
239 | header_size = dlm->mode == VSP1_DL_MODE_HEADER | ||
240 | ? ALIGN(sizeof(struct vsp1_dl_header), 8) | ||
241 | : 0; | ||
242 | |||
243 | ret = vsp1_dl_body_init(dlm->vsp1, &dl->body0, VSP1_DL_NUM_ENTRIES, | ||
244 | header_size); | ||
245 | if (ret < 0) { | ||
246 | kfree(dl); | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | if (dlm->mode == VSP1_DL_MODE_HEADER) { | ||
251 | size_t header_offset = VSP1_DL_NUM_ENTRIES | ||
252 | * sizeof(*dl->body0.entries); | ||
253 | |||
254 | dl->header = ((void *)dl->body0.entries) + header_offset; | ||
255 | dl->dma = dl->body0.dma + header_offset; | ||
256 | |||
257 | memset(dl->header, 0, sizeof(*dl->header)); | ||
258 | dl->header->lists[0].addr = dl->body0.dma; | ||
259 | dl->header->flags = VSP1_DLH_INT_ENABLE; | ||
260 | } | ||
261 | |||
262 | return dl; | ||
89 | } | 263 | } |
90 | 264 | ||
91 | void vsp1_dl_reset(struct vsp1_dl *dl) | 265 | static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl) |
92 | { | 266 | { |
93 | unsigned int i; | 267 | struct vsp1_dl_body *dlb, *next; |
94 | 268 | ||
95 | dl->lists.active = NULL; | 269 | list_for_each_entry_safe(dlb, next, &dl->fragments, list) { |
96 | dl->lists.queued = NULL; | 270 | list_del(&dlb->list); |
97 | dl->lists.pending = NULL; | 271 | vsp1_dl_body_cleanup(dlb); |
98 | dl->lists.write = NULL; | 272 | kfree(dlb); |
273 | } | ||
274 | } | ||
99 | 275 | ||
100 | for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) | 276 | static void vsp1_dl_list_free(struct vsp1_dl_list *dl) |
101 | dl->lists.all[i].in_use = false; | 277 | { |
278 | vsp1_dl_body_cleanup(&dl->body0); | ||
279 | vsp1_dl_list_free_fragments(dl); | ||
280 | kfree(dl); | ||
102 | } | 281 | } |
103 | 282 | ||
104 | void vsp1_dl_begin(struct vsp1_dl *dl) | 283 | /** |
284 | * vsp1_dl_list_get - Get a free display list | ||
285 | * @dlm: The display list manager | ||
286 | * | ||
287 | * Get a display list from the pool of free lists and return it. | ||
288 | * | ||
289 | * This function must be called without the display list manager lock held. | ||
290 | */ | ||
291 | struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm) | ||
105 | { | 292 | { |
106 | struct vsp1_dl_list *list = NULL; | 293 | struct vsp1_dl_list *dl = NULL; |
107 | unsigned long flags; | 294 | unsigned long flags; |
108 | unsigned int i; | ||
109 | 295 | ||
110 | spin_lock_irqsave(&dl->lock, flags); | 296 | spin_lock_irqsave(&dlm->lock, flags); |
111 | 297 | ||
112 | for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) { | 298 | if (!list_empty(&dlm->free)) { |
113 | if (!dl->lists.all[i].in_use) { | 299 | dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list); |
114 | list = &dl->lists.all[i]; | 300 | list_del(&dl->list); |
115 | break; | ||
116 | } | ||
117 | } | 301 | } |
118 | 302 | ||
119 | if (!list) { | 303 | spin_unlock_irqrestore(&dlm->lock, flags); |
120 | list = dl->lists.pending; | 304 | |
121 | dl->lists.pending = NULL; | 305 | return dl; |
122 | } | 306 | } |
307 | |||
308 | /* This function must be called with the display list manager lock held.*/ | ||
309 | static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) | ||
310 | { | ||
311 | if (!dl) | ||
312 | return; | ||
313 | |||
314 | vsp1_dl_list_free_fragments(dl); | ||
315 | dl->body0.num_entries = 0; | ||
316 | |||
317 | list_add_tail(&dl->list, &dl->dlm->free); | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * vsp1_dl_list_put - Release a display list | ||
322 | * @dl: The display list | ||
323 | * | ||
324 | * Release the display list and return it to the pool of free lists. | ||
325 | * | ||
326 | * Passing a NULL pointer to this function is safe, in that case no operation | ||
327 | * will be performed. | ||
328 | */ | ||
329 | void vsp1_dl_list_put(struct vsp1_dl_list *dl) | ||
330 | { | ||
331 | unsigned long flags; | ||
123 | 332 | ||
124 | spin_unlock_irqrestore(&dl->lock, flags); | 333 | if (!dl) |
334 | return; | ||
125 | 335 | ||
126 | dl->lists.write = list; | 336 | spin_lock_irqsave(&dl->dlm->lock, flags); |
337 | __vsp1_dl_list_put(dl); | ||
338 | spin_unlock_irqrestore(&dl->dlm->lock, flags); | ||
339 | } | ||
127 | 340 | ||
128 | list->in_use = true; | 341 | /** |
129 | list->reg_count = 0; | 342 | * vsp1_dl_list_write - Write a register to the display list |
343 | * @dl: The display list | ||
344 | * @reg: The register address | ||
345 | * @data: The register value | ||
346 | * | ||
347 | * Write the given register and value to the display list. Up to 256 registers | ||
348 | * can be written per display list. | ||
349 | */ | ||
350 | void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data) | ||
351 | { | ||
352 | vsp1_dl_fragment_write(&dl->body0, reg, data); | ||
130 | } | 353 | } |
131 | 354 | ||
132 | void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data) | 355 | /** |
356 | * vsp1_dl_list_add_fragment - Add a fragment to the display list | ||
357 | * @dl: The display list | ||
358 | * @dlb: The fragment | ||
359 | * | ||
360 | * Add a display list body as a fragment to a display list. Registers contained | ||
361 | * in fragments are processed after registers contained in the main display | ||
362 | * list, in the order in which fragments are added. | ||
363 | * | ||
364 | * Adding a fragment to a display list passes ownership of the fragment to the | ||
365 | * list. The caller must not touch the fragment after this call, and must not | ||
366 | * free it explicitly with vsp1_dl_fragment_free(). | ||
367 | * | ||
368 | * Fragments are only usable for display lists in header mode. Attempt to | ||
369 | * add a fragment to a header-less display list will return an error. | ||
370 | */ | ||
371 | int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl, | ||
372 | struct vsp1_dl_body *dlb) | ||
133 | { | 373 | { |
134 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity); | 374 | /* Multi-body lists are only available in header mode. */ |
135 | struct vsp1_dl *dl = pipe->dl; | 375 | if (dl->dlm->mode != VSP1_DL_MODE_HEADER) |
136 | struct vsp1_dl_list *list = dl->lists.write; | 376 | return -EINVAL; |
137 | 377 | ||
138 | list->body[list->reg_count].addr = reg; | 378 | list_add_tail(&dlb->list, &dl->fragments); |
139 | list->body[list->reg_count].data = data; | 379 | return 0; |
140 | list->reg_count++; | ||
141 | } | 380 | } |
142 | 381 | ||
143 | void vsp1_dl_commit(struct vsp1_dl *dl) | 382 | void vsp1_dl_list_commit(struct vsp1_dl_list *dl) |
144 | { | 383 | { |
145 | struct vsp1_device *vsp1 = dl->vsp1; | 384 | struct vsp1_dl_manager *dlm = dl->dlm; |
146 | struct vsp1_dl_list *list; | 385 | struct vsp1_device *vsp1 = dlm->vsp1; |
147 | unsigned long flags; | 386 | unsigned long flags; |
148 | bool update; | 387 | bool update; |
149 | 388 | ||
150 | list = dl->lists.write; | 389 | spin_lock_irqsave(&dlm->lock, flags); |
151 | dl->lists.write = NULL; | 390 | |
391 | if (dl->dlm->mode == VSP1_DL_MODE_HEADER) { | ||
392 | struct vsp1_dl_header_list *hdr = dl->header->lists; | ||
393 | struct vsp1_dl_body *dlb; | ||
394 | unsigned int num_lists = 0; | ||
395 | |||
396 | /* Fill the header with the display list bodies addresses and | ||
397 | * sizes. The address of the first body has already been filled | ||
398 | * when the display list was allocated. | ||
399 | * | ||
400 | * In header mode the caller guarantees that the hardware is | ||
401 | * idle at this point. | ||
402 | */ | ||
403 | hdr->num_bytes = dl->body0.num_entries | ||
404 | * sizeof(*dl->header->lists); | ||
405 | |||
406 | list_for_each_entry(dlb, &dl->fragments, list) { | ||
407 | num_lists++; | ||
408 | hdr++; | ||
409 | |||
410 | hdr->addr = dlb->dma; | ||
411 | hdr->num_bytes = dlb->num_entries | ||
412 | * sizeof(*dl->header->lists); | ||
413 | } | ||
414 | |||
415 | dl->header->num_lists = num_lists; | ||
416 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma); | ||
152 | 417 | ||
153 | spin_lock_irqsave(&dl->lock, flags); | 418 | dlm->active = dl; |
419 | goto done; | ||
420 | } | ||
154 | 421 | ||
155 | /* Once the UPD bit has been set the hardware can start processing the | 422 | /* Once the UPD bit has been set the hardware can start processing the |
156 | * display list at any time and we can't touch the address and size | 423 | * display list at any time and we can't touch the address and size |
@@ -159,8 +426,8 @@ void vsp1_dl_commit(struct vsp1_dl *dl) | |||
159 | */ | 426 | */ |
160 | update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); | 427 | update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); |
161 | if (update) { | 428 | if (update) { |
162 | vsp1_dl_free_list(dl->lists.pending); | 429 | __vsp1_dl_list_put(dlm->pending); |
163 | dl->lists.pending = list; | 430 | dlm->pending = dl; |
164 | goto done; | 431 | goto done; |
165 | } | 432 | } |
166 | 433 | ||
@@ -168,42 +435,51 @@ void vsp1_dl_commit(struct vsp1_dl *dl) | |||
168 | * The UPD bit will be cleared by the device when the display list is | 435 | * The UPD bit will be cleared by the device when the display list is |
169 | * processed. | 436 | * processed. |
170 | */ | 437 | */ |
171 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma); | 438 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); |
172 | vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | | 439 | vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | |
173 | (list->reg_count * 8)); | 440 | (dl->body0.num_entries * sizeof(*dl->header->lists))); |
174 | 441 | ||
175 | vsp1_dl_free_list(dl->lists.queued); | 442 | __vsp1_dl_list_put(dlm->queued); |
176 | dl->lists.queued = list; | 443 | dlm->queued = dl; |
177 | 444 | ||
178 | done: | 445 | done: |
179 | spin_unlock_irqrestore(&dl->lock, flags); | 446 | spin_unlock_irqrestore(&dlm->lock, flags); |
180 | } | 447 | } |
181 | 448 | ||
182 | /* ----------------------------------------------------------------------------- | 449 | /* ----------------------------------------------------------------------------- |
183 | * Interrupt Handling | 450 | * Display List Manager |
184 | */ | 451 | */ |
185 | 452 | ||
186 | void vsp1_dl_irq_display_start(struct vsp1_dl *dl) | 453 | /* Interrupt Handling */ |
454 | void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm) | ||
187 | { | 455 | { |
188 | spin_lock(&dl->lock); | 456 | spin_lock(&dlm->lock); |
189 | 457 | ||
190 | /* The display start interrupt signals the end of the display list | 458 | /* The display start interrupt signals the end of the display list |
191 | * processing by the device. The active display list, if any, won't be | 459 | * processing by the device. The active display list, if any, won't be |
192 | * accessed anymore and can be reused. | 460 | * accessed anymore and can be reused. |
193 | */ | 461 | */ |
194 | if (dl->lists.active) { | 462 | __vsp1_dl_list_put(dlm->active); |
195 | vsp1_dl_free_list(dl->lists.active); | 463 | dlm->active = NULL; |
196 | dl->lists.active = NULL; | ||
197 | } | ||
198 | 464 | ||
199 | spin_unlock(&dl->lock); | 465 | spin_unlock(&dlm->lock); |
200 | } | 466 | } |
201 | 467 | ||
202 | void vsp1_dl_irq_frame_end(struct vsp1_dl *dl) | 468 | void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) |
203 | { | 469 | { |
204 | struct vsp1_device *vsp1 = dl->vsp1; | 470 | struct vsp1_device *vsp1 = dlm->vsp1; |
471 | |||
472 | spin_lock(&dlm->lock); | ||
473 | |||
474 | __vsp1_dl_list_put(dlm->active); | ||
475 | dlm->active = NULL; | ||
205 | 476 | ||
206 | spin_lock(&dl->lock); | 477 | /* Header mode is used for mem-to-mem pipelines only. We don't need to |
478 | * perform any operation as there can't be any new display list queued | ||
479 | * in that case. | ||
480 | */ | ||
481 | if (dlm->mode == VSP1_DL_MODE_HEADER) | ||
482 | goto done; | ||
207 | 483 | ||
208 | /* The UPD bit set indicates that the commit operation raced with the | 484 | /* The UPD bit set indicates that the commit operation raced with the |
209 | * interrupt and occurred after the frame end event and UPD clear but | 485 | * interrupt and occurred after the frame end event and UPD clear but |
@@ -216,42 +492,39 @@ void vsp1_dl_irq_frame_end(struct vsp1_dl *dl) | |||
216 | /* The device starts processing the queued display list right after the | 492 | /* The device starts processing the queued display list right after the |
217 | * frame end interrupt. The display list thus becomes active. | 493 | * frame end interrupt. The display list thus becomes active. |
218 | */ | 494 | */ |
219 | if (dl->lists.queued) { | 495 | if (dlm->queued) { |
220 | WARN_ON(dl->lists.active); | 496 | dlm->active = dlm->queued; |
221 | dl->lists.active = dl->lists.queued; | 497 | dlm->queued = NULL; |
222 | dl->lists.queued = NULL; | ||
223 | } | 498 | } |
224 | 499 | ||
225 | /* Now that the UPD bit has been cleared we can queue the next display | 500 | /* Now that the UPD bit has been cleared we can queue the next display |
226 | * list to the hardware if one has been prepared. | 501 | * list to the hardware if one has been prepared. |
227 | */ | 502 | */ |
228 | if (dl->lists.pending) { | 503 | if (dlm->pending) { |
229 | struct vsp1_dl_list *list = dl->lists.pending; | 504 | struct vsp1_dl_list *dl = dlm->pending; |
230 | 505 | ||
231 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma); | 506 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); |
232 | vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | | 507 | vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | |
233 | (list->reg_count * 8)); | 508 | (dl->body0.num_entries * |
509 | sizeof(*dl->header->lists))); | ||
234 | 510 | ||
235 | dl->lists.queued = list; | 511 | dlm->queued = dl; |
236 | dl->lists.pending = NULL; | 512 | dlm->pending = NULL; |
237 | } | 513 | } |
238 | 514 | ||
239 | done: | 515 | done: |
240 | spin_unlock(&dl->lock); | 516 | spin_unlock(&dlm->lock); |
241 | } | 517 | } |
242 | 518 | ||
243 | /* ----------------------------------------------------------------------------- | 519 | /* Hardware Setup */ |
244 | * Hardware Setup | 520 | void vsp1_dlm_setup(struct vsp1_device *vsp1) |
245 | */ | ||
246 | |||
247 | void vsp1_dl_setup(struct vsp1_device *vsp1) | ||
248 | { | 521 | { |
249 | u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT) | 522 | u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT) |
250 | | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 | 523 | | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 |
251 | | VI6_DL_CTRL_DLE; | 524 | | VI6_DL_CTRL_DLE; |
252 | 525 | ||
253 | /* The DRM pipeline operates with header-less display lists in | 526 | /* The DRM pipeline operates with display lists in Continuous Frame |
254 | * Continuous Frame Mode. | 527 | * Mode, all other pipelines use manual start. |
255 | */ | 528 | */ |
256 | if (vsp1->drm) | 529 | if (vsp1->drm) |
257 | ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0; | 530 | ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0; |
@@ -260,46 +533,64 @@ void vsp1_dl_setup(struct vsp1_device *vsp1) | |||
260 | vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS); | 533 | vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS); |
261 | } | 534 | } |
262 | 535 | ||
263 | /* ----------------------------------------------------------------------------- | 536 | void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) |
264 | * Initialization and Cleanup | 537 | { |
265 | */ | 538 | unsigned long flags; |
539 | |||
540 | spin_lock_irqsave(&dlm->lock, flags); | ||
266 | 541 | ||
267 | struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1) | 542 | __vsp1_dl_list_put(dlm->active); |
543 | __vsp1_dl_list_put(dlm->queued); | ||
544 | __vsp1_dl_list_put(dlm->pending); | ||
545 | |||
546 | spin_unlock_irqrestore(&dlm->lock, flags); | ||
547 | |||
548 | dlm->active = NULL; | ||
549 | dlm->queued = NULL; | ||
550 | dlm->pending = NULL; | ||
551 | } | ||
552 | |||
553 | struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, | ||
554 | unsigned int index, | ||
555 | unsigned int prealloc) | ||
268 | { | 556 | { |
269 | struct vsp1_dl *dl; | 557 | struct vsp1_dl_manager *dlm; |
270 | unsigned int i; | 558 | unsigned int i; |
271 | 559 | ||
272 | dl = kzalloc(sizeof(*dl), GFP_KERNEL); | 560 | dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL); |
273 | if (!dl) | 561 | if (!dlm) |
274 | return NULL; | 562 | return NULL; |
275 | 563 | ||
276 | spin_lock_init(&dl->lock); | 564 | dlm->index = index; |
565 | dlm->mode = index == 0 && !vsp1->info->uapi | ||
566 | ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER; | ||
567 | dlm->vsp1 = vsp1; | ||
277 | 568 | ||
278 | dl->vsp1 = vsp1; | 569 | spin_lock_init(&dlm->lock); |
279 | dl->size = VSP1_DL_BODY_SIZE * ARRAY_SIZE(dl->lists.all); | 570 | INIT_LIST_HEAD(&dlm->free); |
280 | 571 | ||
281 | dl->mem = dma_alloc_wc(vsp1->dev, dl->size, &dl->dma, | 572 | for (i = 0; i < prealloc; ++i) { |
282 | GFP_KERNEL); | 573 | struct vsp1_dl_list *dl; |
283 | if (!dl->mem) { | ||
284 | kfree(dl); | ||
285 | return NULL; | ||
286 | } | ||
287 | 574 | ||
288 | for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) { | 575 | dl = vsp1_dl_list_alloc(dlm); |
289 | struct vsp1_dl_list *list = &dl->lists.all[i]; | 576 | if (!dl) |
577 | return NULL; | ||
290 | 578 | ||
291 | list->size = VSP1_DL_BODY_SIZE; | 579 | list_add_tail(&dl->list, &dlm->free); |
292 | list->reg_count = 0; | ||
293 | list->in_use = false; | ||
294 | list->dma = dl->dma + VSP1_DL_BODY_SIZE * i; | ||
295 | list->body = dl->mem + VSP1_DL_BODY_SIZE * i; | ||
296 | } | 580 | } |
297 | 581 | ||
298 | return dl; | 582 | return dlm; |
299 | } | 583 | } |
300 | 584 | ||
301 | void vsp1_dl_destroy(struct vsp1_dl *dl) | 585 | void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm) |
302 | { | 586 | { |
303 | dma_free_wc(dl->vsp1->dev, dl->size, dl->mem, dl->dma); | 587 | struct vsp1_dl_list *dl, *next; |
304 | kfree(dl); | 588 | |
589 | if (!dlm) | ||
590 | return; | ||
591 | |||
592 | list_for_each_entry_safe(dl, next, &dlm->free, list) { | ||
593 | list_del(&dl->list); | ||
594 | vsp1_dl_list_free(dl); | ||
595 | } | ||
305 | } | 596 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h index 448c4250e54c..de387cd4d745 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.h +++ b/drivers/media/platform/vsp1/vsp1_dl.h | |||
@@ -13,30 +13,33 @@ | |||
13 | #ifndef __VSP1_DL_H__ | 13 | #ifndef __VSP1_DL_H__ |
14 | #define __VSP1_DL_H__ | 14 | #define __VSP1_DL_H__ |
15 | 15 | ||
16 | #include "vsp1_entity.h" | 16 | #include <linux/types.h> |
17 | 17 | ||
18 | struct vsp1_device; | 18 | struct vsp1_device; |
19 | struct vsp1_dl; | 19 | struct vsp1_dl_fragment; |
20 | 20 | struct vsp1_dl_list; | |
21 | struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1); | 21 | struct vsp1_dl_manager; |
22 | void vsp1_dl_destroy(struct vsp1_dl *dl); | 22 | |
23 | 23 | void vsp1_dlm_setup(struct vsp1_device *vsp1); | |
24 | void vsp1_dl_setup(struct vsp1_device *vsp1); | 24 | |
25 | 25 | struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, | |
26 | void vsp1_dl_reset(struct vsp1_dl *dl); | 26 | unsigned int index, |
27 | void vsp1_dl_begin(struct vsp1_dl *dl); | 27 | unsigned int prealloc); |
28 | void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data); | 28 | void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm); |
29 | void vsp1_dl_commit(struct vsp1_dl *dl); | 29 | void vsp1_dlm_reset(struct vsp1_dl_manager *dlm); |
30 | 30 | void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm); | |
31 | void vsp1_dl_irq_display_start(struct vsp1_dl *dl); | 31 | void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm); |
32 | void vsp1_dl_irq_frame_end(struct vsp1_dl *dl); | 32 | |
33 | 33 | struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm); | |
34 | static inline void vsp1_dl_mod_write(struct vsp1_entity *e, u32 reg, u32 data) | 34 | void vsp1_dl_list_put(struct vsp1_dl_list *dl); |
35 | { | 35 | void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data); |
36 | if (e->vsp1->use_dl) | 36 | void vsp1_dl_list_commit(struct vsp1_dl_list *dl); |
37 | vsp1_dl_add(e, reg, data); | 37 | |
38 | else | 38 | struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1, |
39 | vsp1_write(e->vsp1, reg, data); | 39 | unsigned int num_entries); |
40 | } | 40 | void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb); |
41 | void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data); | ||
42 | int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl, | ||
43 | struct vsp1_dl_body *dlb); | ||
41 | 44 | ||
42 | #endif /* __VSP1_DL_H__ */ | 45 | #endif /* __VSP1_DL_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 021fe5778cd1..fc4bbc401e67 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c | |||
@@ -13,10 +13,10 @@ | |||
13 | 13 | ||
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/vsp1.h> | ||
17 | 16 | ||
18 | #include <media/media-entity.h> | 17 | #include <media/media-entity.h> |
19 | #include <media/v4l2-subdev.h> | 18 | #include <media/v4l2-subdev.h> |
19 | #include <media/vsp1.h> | ||
20 | 20 | ||
21 | #include "vsp1.h" | 21 | #include "vsp1.h" |
22 | #include "vsp1_bru.h" | 22 | #include "vsp1_bru.h" |
@@ -26,18 +26,14 @@ | |||
26 | #include "vsp1_pipe.h" | 26 | #include "vsp1_pipe.h" |
27 | #include "vsp1_rwpf.h" | 27 | #include "vsp1_rwpf.h" |
28 | 28 | ||
29 | |||
29 | /* ----------------------------------------------------------------------------- | 30 | /* ----------------------------------------------------------------------------- |
30 | * Runtime Handling | 31 | * Interrupt Handling |
31 | */ | 32 | */ |
32 | 33 | ||
33 | static void vsp1_drm_pipeline_frame_end(struct vsp1_pipeline *pipe) | 34 | void vsp1_drm_display_start(struct vsp1_device *vsp1) |
34 | { | 35 | { |
35 | unsigned long flags; | 36 | vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm); |
36 | |||
37 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
38 | if (pipe->num_inputs) | ||
39 | vsp1_pipeline_run(pipe); | ||
40 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
41 | } | 37 | } |
42 | 38 | ||
43 | /* ----------------------------------------------------------------------------- | 39 | /* ----------------------------------------------------------------------------- |
@@ -97,12 +93,14 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width, | |||
97 | media_entity_pipeline_stop(&pipe->output->entity.subdev.entity); | 93 | media_entity_pipeline_stop(&pipe->output->entity.subdev.entity); |
98 | 94 | ||
99 | for (i = 0; i < bru->entity.source_pad; ++i) { | 95 | for (i = 0; i < bru->entity.source_pad; ++i) { |
96 | vsp1->drm->inputs[i].enabled = false; | ||
100 | bru->inputs[i].rpf = NULL; | 97 | bru->inputs[i].rpf = NULL; |
101 | pipe->inputs[i] = NULL; | 98 | pipe->inputs[i] = NULL; |
102 | } | 99 | } |
103 | 100 | ||
104 | pipe->num_inputs = 0; | 101 | pipe->num_inputs = 0; |
105 | 102 | ||
103 | vsp1_dlm_reset(pipe->output->dlm); | ||
106 | vsp1_device_put(vsp1); | 104 | vsp1_device_put(vsp1); |
107 | 105 | ||
108 | dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__); | 106 | dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__); |
@@ -110,8 +108,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width, | |||
110 | return 0; | 108 | return 0; |
111 | } | 109 | } |
112 | 110 | ||
113 | vsp1_dl_reset(vsp1->drm->dl); | ||
114 | |||
115 | /* Configure the format at the BRU sinks and propagate it through the | 111 | /* Configure the format at the BRU sinks and propagate it through the |
116 | * pipeline. | 112 | * pipeline. |
117 | */ | 113 | */ |
@@ -222,16 +218,11 @@ void vsp1_du_atomic_begin(struct device *dev) | |||
222 | { | 218 | { |
223 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | 219 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); |
224 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; | 220 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; |
225 | unsigned long flags; | ||
226 | |||
227 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
228 | 221 | ||
229 | vsp1->drm->num_inputs = pipe->num_inputs; | 222 | vsp1->drm->num_inputs = pipe->num_inputs; |
230 | 223 | ||
231 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
232 | |||
233 | /* Prepare the display list. */ | 224 | /* Prepare the display list. */ |
234 | vsp1_dl_begin(vsp1->drm->dl); | 225 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); |
235 | } | 226 | } |
236 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); | 227 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); |
237 | 228 | ||
@@ -244,10 +235,13 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); | |||
244 | * @mem: DMA addresses of the memory buffers (one per plane) | 235 | * @mem: DMA addresses of the memory buffers (one per plane) |
245 | * @src: the source crop rectangle for the RPF | 236 | * @src: the source crop rectangle for the RPF |
246 | * @dst: the destination compose rectangle for the BRU input | 237 | * @dst: the destination compose rectangle for the BRU input |
238 | * @alpha: global alpha value for the input | ||
239 | * @zpos: the Z-order position of the input | ||
247 | * | 240 | * |
248 | * Configure the VSP to perform composition of the image referenced by @mem | 241 | * Configure the VSP to perform composition of the image referenced by @mem |
249 | * through RPF @rpf_index, using the @src crop rectangle and the @dst | 242 | * through RPF @rpf_index, using the @src crop rectangle and the @dst |
250 | * composition rectangle. The Z-order is fixed with RPF 0 at the bottom. | 243 | * composition rectangle. The Z-order is configurable with higher @zpos values |
244 | * displayed on top. | ||
251 | * | 245 | * |
252 | * Image format as stored in memory is expressed as a V4L2 @pixelformat value. | 246 | * Image format as stored in memory is expressed as a V4L2 @pixelformat value. |
253 | * As a special case, setting the pixel format to 0 will disable the RPF. The | 247 | * As a special case, setting the pixel format to 0 will disable the RPF. The |
@@ -265,25 +259,17 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); | |||
265 | * | 259 | * |
266 | * This function isn't reentrant, the caller needs to serialize calls. | 260 | * This function isn't reentrant, the caller needs to serialize calls. |
267 | * | 261 | * |
268 | * TODO: Implement Z-order control by decoupling the RPF index from the BRU | ||
269 | * input index. | ||
270 | * | ||
271 | * Return 0 on success or a negative error code on failure. | 262 | * Return 0 on success or a negative error code on failure. |
272 | */ | 263 | */ |
273 | int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | 264 | int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, |
274 | u32 pixelformat, unsigned int pitch, | 265 | u32 pixelformat, unsigned int pitch, |
275 | dma_addr_t mem[2], const struct v4l2_rect *src, | 266 | dma_addr_t mem[2], const struct v4l2_rect *src, |
276 | const struct v4l2_rect *dst) | 267 | const struct v4l2_rect *dst, unsigned int alpha, |
268 | unsigned int zpos) | ||
277 | { | 269 | { |
278 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | 270 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); |
279 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; | ||
280 | const struct vsp1_format_info *fmtinfo; | 271 | const struct vsp1_format_info *fmtinfo; |
281 | struct v4l2_subdev_selection sel; | ||
282 | struct v4l2_subdev_format format; | ||
283 | struct vsp1_rwpf_memory memory; | ||
284 | struct vsp1_rwpf *rpf; | 272 | struct vsp1_rwpf *rpf; |
285 | unsigned long flags; | ||
286 | int ret; | ||
287 | 273 | ||
288 | if (rpf_index >= vsp1->info->rpf_count) | 274 | if (rpf_index >= vsp1->info->rpf_count) |
289 | return -EINVAL; | 275 | return -EINVAL; |
@@ -294,31 +280,20 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
294 | dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, | 280 | dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, |
295 | rpf_index); | 281 | rpf_index); |
296 | 282 | ||
297 | spin_lock_irqsave(&pipe->irqlock, flags); | 283 | vsp1->drm->inputs[rpf_index].enabled = false; |
298 | |||
299 | if (pipe->inputs[rpf_index]) { | ||
300 | /* Remove the RPF from the pipeline if it was previously | ||
301 | * enabled. | ||
302 | */ | ||
303 | vsp1->bru->inputs[rpf_index].rpf = NULL; | ||
304 | pipe->inputs[rpf_index] = NULL; | ||
305 | |||
306 | pipe->num_inputs--; | ||
307 | } | ||
308 | |||
309 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
310 | |||
311 | return 0; | 284 | return 0; |
312 | } | 285 | } |
313 | 286 | ||
314 | dev_dbg(vsp1->dev, | 287 | dev_dbg(vsp1->dev, |
315 | "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad }\n", | 288 | "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", |
316 | __func__, rpf_index, | 289 | __func__, rpf_index, |
317 | src->left, src->top, src->width, src->height, | 290 | src->left, src->top, src->width, src->height, |
318 | dst->left, dst->top, dst->width, dst->height, | 291 | dst->left, dst->top, dst->width, dst->height, |
319 | pixelformat, pitch, &mem[0], &mem[1]); | 292 | pixelformat, pitch, &mem[0], &mem[1], zpos); |
320 | 293 | ||
321 | /* Set the stride at the RPF input. */ | 294 | /* Store the format, stride, memory buffer address, crop and compose |
295 | * rectangles and Z-order position and for the input. | ||
296 | */ | ||
322 | fmtinfo = vsp1_get_format_info(pixelformat); | 297 | fmtinfo = vsp1_get_format_info(pixelformat); |
323 | if (!fmtinfo) { | 298 | if (!fmtinfo) { |
324 | dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", | 299 | dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", |
@@ -330,16 +305,40 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
330 | rpf->format.num_planes = fmtinfo->planes; | 305 | rpf->format.num_planes = fmtinfo->planes; |
331 | rpf->format.plane_fmt[0].bytesperline = pitch; | 306 | rpf->format.plane_fmt[0].bytesperline = pitch; |
332 | rpf->format.plane_fmt[1].bytesperline = pitch; | 307 | rpf->format.plane_fmt[1].bytesperline = pitch; |
308 | rpf->alpha = alpha; | ||
309 | |||
310 | rpf->mem.addr[0] = mem[0]; | ||
311 | rpf->mem.addr[1] = mem[1]; | ||
312 | rpf->mem.addr[2] = 0; | ||
313 | |||
314 | vsp1->drm->inputs[rpf_index].crop = *src; | ||
315 | vsp1->drm->inputs[rpf_index].compose = *dst; | ||
316 | vsp1->drm->inputs[rpf_index].zpos = zpos; | ||
317 | vsp1->drm->inputs[rpf_index].enabled = true; | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext); | ||
322 | |||
323 | static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, | ||
324 | struct vsp1_rwpf *rpf, unsigned int bru_input) | ||
325 | { | ||
326 | struct v4l2_subdev_selection sel; | ||
327 | struct v4l2_subdev_format format; | ||
328 | const struct v4l2_rect *crop; | ||
329 | int ret; | ||
333 | 330 | ||
334 | /* Configure the format on the RPF sink pad and propagate it up to the | 331 | /* Configure the format on the RPF sink pad and propagate it up to the |
335 | * BRU sink pad. | 332 | * BRU sink pad. |
336 | */ | 333 | */ |
334 | crop = &vsp1->drm->inputs[rpf->entity.index].crop; | ||
335 | |||
337 | memset(&format, 0, sizeof(format)); | 336 | memset(&format, 0, sizeof(format)); |
338 | format.which = V4L2_SUBDEV_FORMAT_ACTIVE; | 337 | format.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
339 | format.pad = RWPF_PAD_SINK; | 338 | format.pad = RWPF_PAD_SINK; |
340 | format.format.width = src->width + src->left; | 339 | format.format.width = crop->width + crop->left; |
341 | format.format.height = src->height + src->top; | 340 | format.format.height = crop->height + crop->top; |
342 | format.format.code = fmtinfo->mbus; | 341 | format.format.code = rpf->fmtinfo->mbus; |
343 | format.format.field = V4L2_FIELD_NONE; | 342 | format.format.field = V4L2_FIELD_NONE; |
344 | 343 | ||
345 | ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL, | 344 | ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL, |
@@ -356,7 +355,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
356 | sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; | 355 | sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
357 | sel.pad = RWPF_PAD_SINK; | 356 | sel.pad = RWPF_PAD_SINK; |
358 | sel.target = V4L2_SEL_TGT_CROP; | 357 | sel.target = V4L2_SEL_TGT_CROP; |
359 | sel.r = *src; | 358 | sel.r = *crop; |
360 | 359 | ||
361 | ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL, | 360 | ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL, |
362 | &sel); | 361 | &sel); |
@@ -391,7 +390,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
391 | return ret; | 390 | return ret; |
392 | 391 | ||
393 | /* BRU sink, propagate the format from the RPF source. */ | 392 | /* BRU sink, propagate the format from the RPF source. */ |
394 | format.pad = rpf->entity.index; | 393 | format.pad = bru_input; |
395 | 394 | ||
396 | ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL, | 395 | ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL, |
397 | &format); | 396 | &format); |
@@ -402,9 +401,9 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
402 | __func__, format.format.width, format.format.height, | 401 | __func__, format.format.width, format.format.height, |
403 | format.format.code, format.pad); | 402 | format.format.code, format.pad); |
404 | 403 | ||
405 | sel.pad = rpf->entity.index; | 404 | sel.pad = bru_input; |
406 | sel.target = V4L2_SEL_TGT_COMPOSE; | 405 | sel.target = V4L2_SEL_TGT_COMPOSE; |
407 | sel.r = *dst; | 406 | sel.r = vsp1->drm->inputs[rpf->entity.index].compose; |
408 | 407 | ||
409 | ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection, | 408 | ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection, |
410 | NULL, &sel); | 409 | NULL, &sel); |
@@ -416,33 +415,13 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
416 | __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, | 415 | __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, |
417 | sel.pad); | 416 | sel.pad); |
418 | 417 | ||
419 | /* Store the compose rectangle coordinates in the RPF. */ | ||
420 | rpf->location.left = dst->left; | ||
421 | rpf->location.top = dst->top; | ||
422 | |||
423 | /* Set the memory buffer address. */ | ||
424 | memory.num_planes = fmtinfo->planes; | ||
425 | memory.addr[0] = mem[0]; | ||
426 | memory.addr[1] = mem[1]; | ||
427 | |||
428 | rpf->ops->set_memory(rpf, &memory); | ||
429 | |||
430 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
431 | |||
432 | /* If the RPF was previously stopped set the BRU input to the RPF and | ||
433 | * store the RPF in the pipeline inputs array. | ||
434 | */ | ||
435 | if (!pipe->inputs[rpf->entity.index]) { | ||
436 | vsp1->bru->inputs[rpf_index].rpf = rpf; | ||
437 | pipe->inputs[rpf->entity.index] = rpf; | ||
438 | pipe->num_inputs++; | ||
439 | } | ||
440 | |||
441 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
442 | |||
443 | return 0; | 418 | return 0; |
444 | } | 419 | } |
445 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); | 420 | |
421 | static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf) | ||
422 | { | ||
423 | return vsp1->drm->inputs[rpf->entity.index].zpos; | ||
424 | } | ||
446 | 425 | ||
447 | /** | 426 | /** |
448 | * vsp1_du_atomic_flush - Commit an atomic update | 427 | * vsp1_du_atomic_flush - Commit an atomic update |
@@ -452,51 +431,96 @@ void vsp1_du_atomic_flush(struct device *dev) | |||
452 | { | 431 | { |
453 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | 432 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); |
454 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; | 433 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; |
434 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, }; | ||
455 | struct vsp1_entity *entity; | 435 | struct vsp1_entity *entity; |
456 | unsigned long flags; | 436 | unsigned long flags; |
457 | bool stop = false; | 437 | unsigned int i; |
458 | int ret; | 438 | int ret; |
459 | 439 | ||
440 | /* Count the number of enabled inputs and sort them by Z-order. */ | ||
441 | pipe->num_inputs = 0; | ||
442 | |||
443 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | ||
444 | struct vsp1_rwpf *rpf = vsp1->rpf[i]; | ||
445 | unsigned int j; | ||
446 | |||
447 | if (!vsp1->drm->inputs[i].enabled) { | ||
448 | pipe->inputs[i] = NULL; | ||
449 | continue; | ||
450 | } | ||
451 | |||
452 | pipe->inputs[i] = rpf; | ||
453 | |||
454 | /* Insert the RPF in the sorted RPFs array. */ | ||
455 | for (j = pipe->num_inputs++; j > 0; --j) { | ||
456 | if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf)) | ||
457 | break; | ||
458 | inputs[j] = inputs[j-1]; | ||
459 | } | ||
460 | |||
461 | inputs[j] = rpf; | ||
462 | } | ||
463 | |||
464 | /* Setup the RPF input pipeline for every enabled input. */ | ||
465 | for (i = 0; i < vsp1->info->num_bru_inputs; ++i) { | ||
466 | struct vsp1_rwpf *rpf = inputs[i]; | ||
467 | |||
468 | if (!rpf) { | ||
469 | vsp1->bru->inputs[i].rpf = NULL; | ||
470 | continue; | ||
471 | } | ||
472 | |||
473 | vsp1->bru->inputs[i].rpf = rpf; | ||
474 | rpf->bru_input = i; | ||
475 | rpf->entity.sink_pad = i; | ||
476 | |||
477 | dev_dbg(vsp1->dev, "%s: connecting RPF.%u to BRU:%u\n", | ||
478 | __func__, rpf->entity.index, i); | ||
479 | |||
480 | ret = vsp1_du_setup_rpf_pipe(vsp1, rpf, i); | ||
481 | if (ret < 0) | ||
482 | dev_err(vsp1->dev, | ||
483 | "%s: failed to setup RPF.%u\n", | ||
484 | __func__, rpf->entity.index); | ||
485 | } | ||
486 | |||
487 | /* Configure all entities in the pipeline. */ | ||
460 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | 488 | list_for_each_entry(entity, &pipe->entities, list_pipe) { |
461 | /* Disconnect unused RPFs from the pipeline. */ | 489 | /* Disconnect unused RPFs from the pipeline. */ |
462 | if (entity->type == VSP1_ENTITY_RPF) { | 490 | if (entity->type == VSP1_ENTITY_RPF) { |
463 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); | 491 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); |
464 | 492 | ||
465 | if (!pipe->inputs[rpf->entity.index]) { | 493 | if (!pipe->inputs[rpf->entity.index]) { |
466 | vsp1_mod_write(entity, entity->route->reg, | 494 | vsp1_dl_list_write(pipe->dl, entity->route->reg, |
467 | VI6_DPR_NODE_UNUSED); | 495 | VI6_DPR_NODE_UNUSED); |
468 | continue; | 496 | continue; |
469 | } | 497 | } |
470 | } | 498 | } |
471 | 499 | ||
472 | vsp1_entity_route_setup(entity); | 500 | vsp1_entity_route_setup(entity, pipe->dl); |
473 | 501 | ||
474 | ret = v4l2_subdev_call(&entity->subdev, video, | 502 | if (entity->ops->configure) |
475 | s_stream, 1); | 503 | entity->ops->configure(entity, pipe, pipe->dl); |
476 | if (ret < 0) { | ||
477 | dev_err(vsp1->dev, | ||
478 | "DRM pipeline start failure on entity %s\n", | ||
479 | entity->subdev.name); | ||
480 | return; | ||
481 | } | ||
482 | } | ||
483 | 504 | ||
484 | vsp1_dl_commit(vsp1->drm->dl); | 505 | /* The memory buffer address must be applied after configuring |
506 | * the RPF to make sure the crop offset are computed. | ||
507 | */ | ||
508 | if (entity->type == VSP1_ENTITY_RPF) | ||
509 | vsp1_rwpf_set_memory(to_rwpf(&entity->subdev), | ||
510 | pipe->dl); | ||
511 | } | ||
485 | 512 | ||
486 | spin_lock_irqsave(&pipe->irqlock, flags); | 513 | vsp1_dl_list_commit(pipe->dl); |
514 | pipe->dl = NULL; | ||
487 | 515 | ||
488 | /* Start or stop the pipeline if needed. */ | 516 | /* Start or stop the pipeline if needed. */ |
489 | if (!vsp1->drm->num_inputs && pipe->num_inputs) { | 517 | if (!vsp1->drm->num_inputs && pipe->num_inputs) { |
490 | vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0); | 518 | vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0); |
491 | vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE); | 519 | vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE); |
520 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
492 | vsp1_pipeline_run(pipe); | 521 | vsp1_pipeline_run(pipe); |
522 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
493 | } else if (vsp1->drm->num_inputs && !pipe->num_inputs) { | 523 | } else if (vsp1->drm->num_inputs && !pipe->num_inputs) { |
494 | stop = true; | ||
495 | } | ||
496 | |||
497 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
498 | |||
499 | if (stop) { | ||
500 | vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0); | 524 | vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0); |
501 | vsp1_pipeline_stop(pipe); | 525 | vsp1_pipeline_stop(pipe); |
502 | } | 526 | } |
@@ -562,14 +586,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1) | |||
562 | if (!vsp1->drm) | 586 | if (!vsp1->drm) |
563 | return -ENOMEM; | 587 | return -ENOMEM; |
564 | 588 | ||
565 | vsp1->drm->dl = vsp1_dl_create(vsp1); | ||
566 | if (!vsp1->drm->dl) | ||
567 | return -ENOMEM; | ||
568 | |||
569 | pipe = &vsp1->drm->pipe; | 589 | pipe = &vsp1->drm->pipe; |
570 | 590 | ||
571 | vsp1_pipeline_init(pipe); | 591 | vsp1_pipeline_init(pipe); |
572 | pipe->frame_end = vsp1_drm_pipeline_frame_end; | ||
573 | 592 | ||
574 | /* The DRM pipeline is static, add entities manually. */ | 593 | /* The DRM pipeline is static, add entities manually. */ |
575 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | 594 | for (i = 0; i < vsp1->info->rpf_count; ++i) { |
@@ -586,12 +605,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1) | |||
586 | pipe->lif = &vsp1->lif->entity; | 605 | pipe->lif = &vsp1->lif->entity; |
587 | pipe->output = vsp1->wpf[0]; | 606 | pipe->output = vsp1->wpf[0]; |
588 | 607 | ||
589 | pipe->dl = vsp1->drm->dl; | ||
590 | |||
591 | return 0; | 608 | return 0; |
592 | } | 609 | } |
593 | 610 | ||
594 | void vsp1_drm_cleanup(struct vsp1_device *vsp1) | 611 | void vsp1_drm_cleanup(struct vsp1_device *vsp1) |
595 | { | 612 | { |
596 | vsp1_dl_destroy(vsp1->drm->dl); | ||
597 | } | 613 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h index f68056838319..9e28ab9254ba 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.h +++ b/drivers/media/platform/vsp1/vsp1_drm.h | |||
@@ -13,37 +13,32 @@ | |||
13 | #ifndef __VSP1_DRM_H__ | 13 | #ifndef __VSP1_DRM_H__ |
14 | #define __VSP1_DRM_H__ | 14 | #define __VSP1_DRM_H__ |
15 | 15 | ||
16 | #include "vsp1_pipe.h" | 16 | #include <linux/videodev2.h> |
17 | 17 | ||
18 | struct vsp1_dl; | 18 | #include "vsp1_pipe.h" |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * vsp1_drm - State for the API exposed to the DRM driver | 21 | * vsp1_drm - State for the API exposed to the DRM driver |
22 | * @dl: display list for DRM pipeline operation | ||
23 | * @pipe: the VSP1 pipeline used for display | 22 | * @pipe: the VSP1 pipeline used for display |
24 | * @num_inputs: number of active pipeline inputs at the beginning of an update | 23 | * @num_inputs: number of active pipeline inputs at the beginning of an update |
25 | * @update: the pipeline configuration has been updated | 24 | * @planes: source crop rectangle, destination compose rectangle and z-order |
25 | * position for every input | ||
26 | */ | 26 | */ |
27 | struct vsp1_drm { | 27 | struct vsp1_drm { |
28 | struct vsp1_dl *dl; | ||
29 | struct vsp1_pipeline pipe; | 28 | struct vsp1_pipeline pipe; |
30 | unsigned int num_inputs; | 29 | unsigned int num_inputs; |
31 | bool update; | 30 | struct { |
31 | bool enabled; | ||
32 | struct v4l2_rect crop; | ||
33 | struct v4l2_rect compose; | ||
34 | unsigned int zpos; | ||
35 | } inputs[VSP1_MAX_RPF]; | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | int vsp1_drm_init(struct vsp1_device *vsp1); | 38 | int vsp1_drm_init(struct vsp1_device *vsp1); |
35 | void vsp1_drm_cleanup(struct vsp1_device *vsp1); | 39 | void vsp1_drm_cleanup(struct vsp1_device *vsp1); |
36 | int vsp1_drm_create_links(struct vsp1_device *vsp1); | 40 | int vsp1_drm_create_links(struct vsp1_device *vsp1); |
37 | 41 | ||
38 | int vsp1_du_init(struct device *dev); | 42 | void vsp1_drm_display_start(struct vsp1_device *vsp1); |
39 | int vsp1_du_setup_lif(struct device *dev, unsigned int width, | ||
40 | unsigned int height); | ||
41 | void vsp1_du_atomic_begin(struct device *dev); | ||
42 | int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | ||
43 | u32 pixelformat, unsigned int pitch, | ||
44 | dma_addr_t mem[2], const struct v4l2_rect *src, | ||
45 | const struct v4l2_rect *dst); | ||
46 | void vsp1_du_atomic_flush(struct device *dev); | ||
47 | |||
48 | 43 | ||
49 | #endif /* __VSP1_DRM_H__ */ | 44 | #endif /* __VSP1_DRM_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 25750a0e4631..e2d779fac0eb 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "vsp1_hsit.h" | 30 | #include "vsp1_hsit.h" |
31 | #include "vsp1_lif.h" | 31 | #include "vsp1_lif.h" |
32 | #include "vsp1_lut.h" | 32 | #include "vsp1_lut.h" |
33 | #include "vsp1_pipe.h" | ||
33 | #include "vsp1_rwpf.h" | 34 | #include "vsp1_rwpf.h" |
34 | #include "vsp1_sru.h" | 35 | #include "vsp1_sru.h" |
35 | #include "vsp1_uds.h" | 36 | #include "vsp1_uds.h" |
@@ -49,17 +50,15 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) | |||
49 | 50 | ||
50 | for (i = 0; i < vsp1->info->wpf_count; ++i) { | 51 | for (i = 0; i < vsp1->info->wpf_count; ++i) { |
51 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; | 52 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; |
52 | struct vsp1_pipeline *pipe; | ||
53 | 53 | ||
54 | if (wpf == NULL) | 54 | if (wpf == NULL) |
55 | continue; | 55 | continue; |
56 | 56 | ||
57 | pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); | ||
58 | status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); | 57 | status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); |
59 | vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); | 58 | vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); |
60 | 59 | ||
61 | if (status & VI6_WFP_IRQ_STA_FRE) { | 60 | if (status & VI6_WFP_IRQ_STA_FRE) { |
62 | vsp1_pipeline_frame_end(pipe); | 61 | vsp1_pipeline_frame_end(wpf->pipe); |
63 | ret = IRQ_HANDLED; | 62 | ret = IRQ_HANDLED; |
64 | } | 63 | } |
65 | } | 64 | } |
@@ -68,14 +67,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) | |||
68 | vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST); | 67 | vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST); |
69 | 68 | ||
70 | if (status & VI6_DISP_IRQ_STA_DST) { | 69 | if (status & VI6_DISP_IRQ_STA_DST) { |
71 | struct vsp1_rwpf *wpf = vsp1->wpf[0]; | 70 | vsp1_drm_display_start(vsp1); |
72 | struct vsp1_pipeline *pipe; | ||
73 | |||
74 | if (wpf) { | ||
75 | pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); | ||
76 | vsp1_pipeline_display_start(pipe); | ||
77 | } | ||
78 | |||
79 | ret = IRQ_HANDLED; | 71 | ret = IRQ_HANDLED; |
80 | } | 72 | } |
81 | 73 | ||
@@ -387,13 +379,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
387 | /* Register subdev nodes if the userspace API is enabled or initialize | 379 | /* Register subdev nodes if the userspace API is enabled or initialize |
388 | * the DRM pipeline otherwise. | 380 | * the DRM pipeline otherwise. |
389 | */ | 381 | */ |
390 | if (vsp1->info->uapi) { | 382 | if (vsp1->info->uapi) |
391 | vsp1->use_dl = false; | ||
392 | ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); | 383 | ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); |
393 | } else { | 384 | else |
394 | vsp1->use_dl = true; | ||
395 | ret = vsp1_drm_init(vsp1); | 385 | ret = vsp1_drm_init(vsp1); |
396 | } | ||
397 | if (ret < 0) | 386 | if (ret < 0) |
398 | goto done; | 387 | goto done; |
399 | 388 | ||
@@ -465,8 +454,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1) | |||
465 | vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | | 454 | vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | |
466 | (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); | 455 | (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); |
467 | 456 | ||
468 | if (vsp1->use_dl) | 457 | vsp1_dlm_setup(vsp1); |
469 | vsp1_dl_setup(vsp1); | ||
470 | 458 | ||
471 | return 0; | 459 | return 0; |
472 | } | 460 | } |
@@ -570,6 +558,7 @@ static const struct dev_pm_ops vsp1_pm_ops = { | |||
570 | static const struct vsp1_device_info vsp1_device_infos[] = { | 558 | static const struct vsp1_device_info vsp1_device_infos[] = { |
571 | { | 559 | { |
572 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, | 560 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, |
561 | .gen = 2, | ||
573 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, | 562 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, |
574 | .rpf_count = 5, | 563 | .rpf_count = 5, |
575 | .uds_count = 3, | 564 | .uds_count = 3, |
@@ -578,6 +567,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
578 | .uapi = true, | 567 | .uapi = true, |
579 | }, { | 568 | }, { |
580 | .version = VI6_IP_VERSION_MODEL_VSPR_H2, | 569 | .version = VI6_IP_VERSION_MODEL_VSPR_H2, |
570 | .gen = 2, | ||
581 | .features = VSP1_HAS_BRU | VSP1_HAS_SRU, | 571 | .features = VSP1_HAS_BRU | VSP1_HAS_SRU, |
582 | .rpf_count = 5, | 572 | .rpf_count = 5, |
583 | .uds_count = 1, | 573 | .uds_count = 1, |
@@ -586,6 +576,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
586 | .uapi = true, | 576 | .uapi = true, |
587 | }, { | 577 | }, { |
588 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, | 578 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, |
579 | .gen = 2, | ||
589 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, | 580 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, |
590 | .rpf_count = 4, | 581 | .rpf_count = 4, |
591 | .uds_count = 1, | 582 | .uds_count = 1, |
@@ -594,6 +585,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
594 | .uapi = true, | 585 | .uapi = true, |
595 | }, { | 586 | }, { |
596 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, | 587 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, |
588 | .gen = 2, | ||
597 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, | 589 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, |
598 | .rpf_count = 5, | 590 | .rpf_count = 5, |
599 | .uds_count = 3, | 591 | .uds_count = 3, |
@@ -602,6 +594,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
602 | .uapi = true, | 594 | .uapi = true, |
603 | }, { | 595 | }, { |
604 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, | 596 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, |
597 | .gen = 3, | ||
605 | .features = VSP1_HAS_LUT | VSP1_HAS_SRU, | 598 | .features = VSP1_HAS_LUT | VSP1_HAS_SRU, |
606 | .rpf_count = 1, | 599 | .rpf_count = 1, |
607 | .uds_count = 1, | 600 | .uds_count = 1, |
@@ -609,6 +602,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
609 | .uapi = true, | 602 | .uapi = true, |
610 | }, { | 603 | }, { |
611 | .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, | 604 | .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, |
605 | .gen = 3, | ||
612 | .features = VSP1_HAS_BRU, | 606 | .features = VSP1_HAS_BRU, |
613 | .rpf_count = 5, | 607 | .rpf_count = 5, |
614 | .wpf_count = 1, | 608 | .wpf_count = 1, |
@@ -616,6 +610,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
616 | .uapi = true, | 610 | .uapi = true, |
617 | }, { | 611 | }, { |
618 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, | 612 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, |
613 | .gen = 3, | ||
619 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT, | 614 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT, |
620 | .rpf_count = 5, | 615 | .rpf_count = 5, |
621 | .wpf_count = 1, | 616 | .wpf_count = 1, |
@@ -623,7 +618,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
623 | .uapi = true, | 618 | .uapi = true, |
624 | }, { | 619 | }, { |
625 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, | 620 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, |
626 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, | 621 | .gen = 3, |
622 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF, | ||
627 | .rpf_count = 5, | 623 | .rpf_count = 5, |
628 | .wpf_count = 2, | 624 | .wpf_count = 2, |
629 | .num_bru_inputs = 5, | 625 | .num_bru_inputs = 5, |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 20a78fbd3691..3d070bcc6053 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
@@ -19,46 +19,11 @@ | |||
19 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
20 | 20 | ||
21 | #include "vsp1.h" | 21 | #include "vsp1.h" |
22 | #include "vsp1_dl.h" | ||
22 | #include "vsp1_entity.h" | 23 | #include "vsp1_entity.h" |
23 | 24 | ||
24 | bool vsp1_entity_is_streaming(struct vsp1_entity *entity) | 25 | void vsp1_entity_route_setup(struct vsp1_entity *source, |
25 | { | 26 | struct vsp1_dl_list *dl) |
26 | unsigned long flags; | ||
27 | bool streaming; | ||
28 | |||
29 | spin_lock_irqsave(&entity->lock, flags); | ||
30 | streaming = entity->streaming; | ||
31 | spin_unlock_irqrestore(&entity->lock, flags); | ||
32 | |||
33 | return streaming; | ||
34 | } | ||
35 | |||
36 | int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) | ||
37 | { | ||
38 | unsigned long flags; | ||
39 | int ret; | ||
40 | |||
41 | spin_lock_irqsave(&entity->lock, flags); | ||
42 | entity->streaming = streaming; | ||
43 | spin_unlock_irqrestore(&entity->lock, flags); | ||
44 | |||
45 | if (!streaming) | ||
46 | return 0; | ||
47 | |||
48 | if (!entity->vsp1->info->uapi || !entity->subdev.ctrl_handler) | ||
49 | return 0; | ||
50 | |||
51 | ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler); | ||
52 | if (ret < 0) { | ||
53 | spin_lock_irqsave(&entity->lock, flags); | ||
54 | entity->streaming = false; | ||
55 | spin_unlock_irqrestore(&entity->lock, flags); | ||
56 | } | ||
57 | |||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | void vsp1_entity_route_setup(struct vsp1_entity *source) | ||
62 | { | 27 | { |
63 | struct vsp1_entity *sink; | 28 | struct vsp1_entity *sink; |
64 | 29 | ||
@@ -66,40 +31,74 @@ void vsp1_entity_route_setup(struct vsp1_entity *source) | |||
66 | return; | 31 | return; |
67 | 32 | ||
68 | sink = container_of(source->sink, struct vsp1_entity, subdev.entity); | 33 | sink = container_of(source->sink, struct vsp1_entity, subdev.entity); |
69 | vsp1_mod_write(source, source->route->reg, | 34 | vsp1_dl_list_write(dl, source->route->reg, |
70 | sink->route->inputs[source->sink_pad]); | 35 | sink->route->inputs[source->sink_pad]); |
71 | } | 36 | } |
72 | 37 | ||
73 | /* ----------------------------------------------------------------------------- | 38 | /* ----------------------------------------------------------------------------- |
74 | * V4L2 Subdevice Operations | 39 | * V4L2 Subdevice Operations |
75 | */ | 40 | */ |
76 | 41 | ||
77 | struct v4l2_mbus_framefmt * | 42 | /** |
78 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, | 43 | * vsp1_entity_get_pad_config - Get the pad configuration for an entity |
44 | * @entity: the entity | ||
45 | * @cfg: the TRY pad configuration | ||
46 | * @which: configuration selector (ACTIVE or TRY) | ||
47 | * | ||
48 | * Return the pad configuration requested by the which argument. The TRY | ||
49 | * configuration is passed explicitly to the function through the cfg argument | ||
50 | * and simply returned when requested. The ACTIVE configuration comes from the | ||
51 | * entity structure. | ||
52 | */ | ||
53 | struct v4l2_subdev_pad_config * | ||
54 | vsp1_entity_get_pad_config(struct vsp1_entity *entity, | ||
79 | struct v4l2_subdev_pad_config *cfg, | 55 | struct v4l2_subdev_pad_config *cfg, |
80 | unsigned int pad, u32 which) | 56 | enum v4l2_subdev_format_whence which) |
81 | { | 57 | { |
82 | switch (which) { | 58 | switch (which) { |
83 | case V4L2_SUBDEV_FORMAT_TRY: | ||
84 | return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); | ||
85 | case V4L2_SUBDEV_FORMAT_ACTIVE: | 59 | case V4L2_SUBDEV_FORMAT_ACTIVE: |
86 | return &entity->formats[pad]; | 60 | return entity->config; |
61 | case V4L2_SUBDEV_FORMAT_TRY: | ||
87 | default: | 62 | default: |
88 | return NULL; | 63 | return cfg; |
89 | } | 64 | } |
90 | } | 65 | } |
91 | 66 | ||
67 | /** | ||
68 | * vsp1_entity_get_pad_format - Get a pad format from storage for an entity | ||
69 | * @entity: the entity | ||
70 | * @cfg: the configuration storage | ||
71 | * @pad: the pad number | ||
72 | * | ||
73 | * Return the format stored in the given configuration for an entity's pad. The | ||
74 | * configuration can be an ACTIVE or TRY configuration. | ||
75 | */ | ||
76 | struct v4l2_mbus_framefmt * | ||
77 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, | ||
78 | struct v4l2_subdev_pad_config *cfg, | ||
79 | unsigned int pad) | ||
80 | { | ||
81 | return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); | ||
82 | } | ||
83 | |||
84 | struct v4l2_rect * | ||
85 | vsp1_entity_get_pad_compose(struct vsp1_entity *entity, | ||
86 | struct v4l2_subdev_pad_config *cfg, | ||
87 | unsigned int pad) | ||
88 | { | ||
89 | return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad); | ||
90 | } | ||
91 | |||
92 | /* | 92 | /* |
93 | * vsp1_entity_init_formats - Initialize formats on all pads | 93 | * vsp1_entity_init_cfg - Initialize formats on all pads |
94 | * @subdev: V4L2 subdevice | 94 | * @subdev: V4L2 subdevice |
95 | * @cfg: V4L2 subdev pad configuration | 95 | * @cfg: V4L2 subdev pad configuration |
96 | * | 96 | * |
97 | * Initialize all pad formats with default values. If cfg is not NULL, try | 97 | * Initialize all pad formats with default values in the given pad config. This |
98 | * formats are initialized on the file handle. Otherwise active formats are | 98 | * function can be used as a handler for the subdev pad::init_cfg operation. |
99 | * initialized on the device. | ||
100 | */ | 99 | */ |
101 | void vsp1_entity_init_formats(struct v4l2_subdev *subdev, | 100 | int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, |
102 | struct v4l2_subdev_pad_config *cfg) | 101 | struct v4l2_subdev_pad_config *cfg) |
103 | { | 102 | { |
104 | struct v4l2_subdev_format format; | 103 | struct v4l2_subdev_format format; |
105 | unsigned int pad; | 104 | unsigned int pad; |
@@ -113,19 +112,132 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev, | |||
113 | 112 | ||
114 | v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format); | 113 | v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format); |
115 | } | 114 | } |
115 | |||
116 | return 0; | ||
116 | } | 117 | } |
117 | 118 | ||
118 | static int vsp1_entity_open(struct v4l2_subdev *subdev, | 119 | /* |
119 | struct v4l2_subdev_fh *fh) | 120 | * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler |
121 | * @subdev: V4L2 subdevice | ||
122 | * @cfg: V4L2 subdev pad configuration | ||
123 | * @fmt: V4L2 subdev format | ||
124 | * | ||
125 | * This function implements the subdev get_fmt pad operation. It can be used as | ||
126 | * a direct drop-in for the operation handler. | ||
127 | */ | ||
128 | int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, | ||
129 | struct v4l2_subdev_pad_config *cfg, | ||
130 | struct v4l2_subdev_format *fmt) | ||
120 | { | 131 | { |
121 | vsp1_entity_init_formats(subdev, fh->pad); | 132 | struct vsp1_entity *entity = to_vsp1_entity(subdev); |
133 | struct v4l2_subdev_pad_config *config; | ||
134 | |||
135 | config = vsp1_entity_get_pad_config(entity, cfg, fmt->which); | ||
136 | if (!config) | ||
137 | return -EINVAL; | ||
138 | |||
139 | fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad); | ||
122 | 140 | ||
123 | return 0; | 141 | return 0; |
124 | } | 142 | } |
125 | 143 | ||
126 | const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = { | 144 | /* |
127 | .open = vsp1_entity_open, | 145 | * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler |
128 | }; | 146 | * @subdev: V4L2 subdevice |
147 | * @cfg: V4L2 subdev pad configuration | ||
148 | * @code: Media bus code enumeration | ||
149 | * @codes: Array of supported media bus codes | ||
150 | * @ncodes: Number of supported media bus codes | ||
151 | * | ||
152 | * This function implements the subdev enum_mbus_code pad operation for entities | ||
153 | * that do not support format conversion. It enumerates the given supported | ||
154 | * media bus codes on the sink pad and reports a source pad format identical to | ||
155 | * the sink pad. | ||
156 | */ | ||
157 | int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, | ||
158 | struct v4l2_subdev_pad_config *cfg, | ||
159 | struct v4l2_subdev_mbus_code_enum *code, | ||
160 | const unsigned int *codes, unsigned int ncodes) | ||
161 | { | ||
162 | struct vsp1_entity *entity = to_vsp1_entity(subdev); | ||
163 | |||
164 | if (code->pad == 0) { | ||
165 | if (code->index >= ncodes) | ||
166 | return -EINVAL; | ||
167 | |||
168 | code->code = codes[code->index]; | ||
169 | } else { | ||
170 | struct v4l2_subdev_pad_config *config; | ||
171 | struct v4l2_mbus_framefmt *format; | ||
172 | |||
173 | /* The entity can't perform format conversion, the sink format | ||
174 | * is always identical to the source format. | ||
175 | */ | ||
176 | if (code->index) | ||
177 | return -EINVAL; | ||
178 | |||
179 | config = vsp1_entity_get_pad_config(entity, cfg, code->which); | ||
180 | if (!config) | ||
181 | return -EINVAL; | ||
182 | |||
183 | format = vsp1_entity_get_pad_format(entity, config, 0); | ||
184 | code->code = format->code; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler | ||
192 | * @subdev: V4L2 subdevice | ||
193 | * @cfg: V4L2 subdev pad configuration | ||
194 | * @fse: Frame size enumeration | ||
195 | * @min_width: Minimum image width | ||
196 | * @min_height: Minimum image height | ||
197 | * @max_width: Maximum image width | ||
198 | * @max_height: Maximum image height | ||
199 | * | ||
200 | * This function implements the subdev enum_frame_size pad operation for | ||
201 | * entities that do not support scaling or cropping. It reports the given | ||
202 | * minimum and maximum frame width and height on the sink pad, and a fixed | ||
203 | * source pad size identical to the sink pad. | ||
204 | */ | ||
205 | int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, | ||
206 | struct v4l2_subdev_pad_config *cfg, | ||
207 | struct v4l2_subdev_frame_size_enum *fse, | ||
208 | unsigned int min_width, unsigned int min_height, | ||
209 | unsigned int max_width, unsigned int max_height) | ||
210 | { | ||
211 | struct vsp1_entity *entity = to_vsp1_entity(subdev); | ||
212 | struct v4l2_subdev_pad_config *config; | ||
213 | struct v4l2_mbus_framefmt *format; | ||
214 | |||
215 | config = vsp1_entity_get_pad_config(entity, cfg, fse->which); | ||
216 | if (!config) | ||
217 | return -EINVAL; | ||
218 | |||
219 | format = vsp1_entity_get_pad_format(entity, config, fse->pad); | ||
220 | |||
221 | if (fse->index || fse->code != format->code) | ||
222 | return -EINVAL; | ||
223 | |||
224 | if (fse->pad == 0) { | ||
225 | fse->min_width = min_width; | ||
226 | fse->max_width = max_width; | ||
227 | fse->min_height = min_height; | ||
228 | fse->max_height = max_height; | ||
229 | } else { | ||
230 | /* The size on the source pad are fixed and always identical to | ||
231 | * the size on the sink pad. | ||
232 | */ | ||
233 | fse->min_width = format->width; | ||
234 | fse->max_width = format->width; | ||
235 | fse->min_height = format->height; | ||
236 | fse->max_height = format->height; | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
129 | 241 | ||
130 | /* ----------------------------------------------------------------------------- | 242 | /* ----------------------------------------------------------------------------- |
131 | * Media Operations | 243 | * Media Operations |
@@ -171,11 +283,11 @@ static const struct vsp1_route vsp1_routes[] = { | |||
171 | { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, | 283 | { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, |
172 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, | 284 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, |
173 | { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, | 285 | { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, |
174 | { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } }, | 286 | { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { 0, } }, |
175 | { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } }, | 287 | { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { 0, } }, |
176 | { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } }, | 288 | { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { 0, } }, |
177 | { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } }, | 289 | { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { 0, } }, |
178 | { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } }, | 290 | { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { 0, } }, |
179 | { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, | 291 | { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, |
180 | { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, | 292 | { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, |
181 | { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, | 293 | { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, |
@@ -187,9 +299,12 @@ static const struct vsp1_route vsp1_routes[] = { | |||
187 | }; | 299 | }; |
188 | 300 | ||
189 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | 301 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, |
190 | unsigned int num_pads) | 302 | const char *name, unsigned int num_pads, |
303 | const struct v4l2_subdev_ops *ops) | ||
191 | { | 304 | { |
305 | struct v4l2_subdev *subdev; | ||
192 | unsigned int i; | 306 | unsigned int i; |
307 | int ret; | ||
193 | 308 | ||
194 | for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) { | 309 | for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) { |
195 | if (vsp1_routes[i].type == entity->type && | 310 | if (vsp1_routes[i].type == entity->type && |
@@ -202,37 +317,56 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
202 | if (i == ARRAY_SIZE(vsp1_routes)) | 317 | if (i == ARRAY_SIZE(vsp1_routes)) |
203 | return -EINVAL; | 318 | return -EINVAL; |
204 | 319 | ||
205 | spin_lock_init(&entity->lock); | ||
206 | |||
207 | entity->vsp1 = vsp1; | 320 | entity->vsp1 = vsp1; |
208 | entity->source_pad = num_pads - 1; | 321 | entity->source_pad = num_pads - 1; |
209 | 322 | ||
210 | /* Allocate formats and pads. */ | 323 | /* Allocate and initialize pads. */ |
211 | entity->formats = devm_kzalloc(vsp1->dev, | ||
212 | num_pads * sizeof(*entity->formats), | ||
213 | GFP_KERNEL); | ||
214 | if (entity->formats == NULL) | ||
215 | return -ENOMEM; | ||
216 | |||
217 | entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads), | 324 | entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads), |
218 | GFP_KERNEL); | 325 | GFP_KERNEL); |
219 | if (entity->pads == NULL) | 326 | if (entity->pads == NULL) |
220 | return -ENOMEM; | 327 | return -ENOMEM; |
221 | 328 | ||
222 | /* Initialize pads. */ | ||
223 | for (i = 0; i < num_pads - 1; ++i) | 329 | for (i = 0; i < num_pads - 1; ++i) |
224 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; | 330 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; |
225 | 331 | ||
226 | entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE; | 332 | entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE; |
227 | 333 | ||
228 | /* Initialize the media entity. */ | 334 | /* Initialize the media entity. */ |
229 | return media_entity_pads_init(&entity->subdev.entity, num_pads, | 335 | ret = media_entity_pads_init(&entity->subdev.entity, num_pads, |
230 | entity->pads); | 336 | entity->pads); |
337 | if (ret < 0) | ||
338 | return ret; | ||
339 | |||
340 | /* Initialize the V4L2 subdev. */ | ||
341 | subdev = &entity->subdev; | ||
342 | v4l2_subdev_init(subdev, ops); | ||
343 | |||
344 | subdev->entity.ops = &vsp1->media_ops; | ||
345 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
346 | |||
347 | snprintf(subdev->name, sizeof(subdev->name), "%s %s", | ||
348 | dev_name(vsp1->dev), name); | ||
349 | |||
350 | vsp1_entity_init_cfg(subdev, NULL); | ||
351 | |||
352 | /* Allocate the pad configuration to store formats and selection | ||
353 | * rectangles. | ||
354 | */ | ||
355 | entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev); | ||
356 | if (entity->config == NULL) { | ||
357 | media_entity_cleanup(&entity->subdev.entity); | ||
358 | return -ENOMEM; | ||
359 | } | ||
360 | |||
361 | return 0; | ||
231 | } | 362 | } |
232 | 363 | ||
233 | void vsp1_entity_destroy(struct vsp1_entity *entity) | 364 | void vsp1_entity_destroy(struct vsp1_entity *entity) |
234 | { | 365 | { |
366 | if (entity->ops && entity->ops->destroy) | ||
367 | entity->ops->destroy(entity); | ||
235 | if (entity->subdev.ctrl_handler) | 368 | if (entity->subdev.ctrl_handler) |
236 | v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); | 369 | v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); |
370 | v4l2_subdev_free_pad_config(entity->config); | ||
237 | media_entity_cleanup(&entity->subdev.entity); | 371 | media_entity_cleanup(&entity->subdev.entity); |
238 | } | 372 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 83570dfde8ec..69eff4e17350 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
20 | 20 | ||
21 | struct vsp1_device; | 21 | struct vsp1_device; |
22 | struct vsp1_dl_list; | ||
23 | struct vsp1_pipeline; | ||
22 | 24 | ||
23 | enum vsp1_entity_type { | 25 | enum vsp1_entity_type { |
24 | VSP1_ENTITY_BRU, | 26 | VSP1_ENTITY_BRU, |
@@ -53,9 +55,27 @@ struct vsp1_route { | |||
53 | unsigned int inputs[VSP1_ENTITY_MAX_INPUTS]; | 55 | unsigned int inputs[VSP1_ENTITY_MAX_INPUTS]; |
54 | }; | 56 | }; |
55 | 57 | ||
58 | /** | ||
59 | * struct vsp1_entity_operations - Entity operations | ||
60 | * @destroy: Destroy the entity. | ||
61 | * @set_memory: Setup memory buffer access. This operation applies the settings | ||
62 | * stored in the rwpf mem field to the display list. Valid for RPF | ||
63 | * and WPF only. | ||
64 | * @configure: Setup the hardware based on the entity state (pipeline, formats, | ||
65 | * selection rectangles, ...) | ||
66 | */ | ||
67 | struct vsp1_entity_operations { | ||
68 | void (*destroy)(struct vsp1_entity *); | ||
69 | void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl); | ||
70 | void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, | ||
71 | struct vsp1_dl_list *); | ||
72 | }; | ||
73 | |||
56 | struct vsp1_entity { | 74 | struct vsp1_entity { |
57 | struct vsp1_device *vsp1; | 75 | struct vsp1_device *vsp1; |
58 | 76 | ||
77 | const struct vsp1_entity_operations *ops; | ||
78 | |||
59 | enum vsp1_entity_type type; | 79 | enum vsp1_entity_type type; |
60 | unsigned int index; | 80 | unsigned int index; |
61 | const struct vsp1_route *route; | 81 | const struct vsp1_route *route; |
@@ -70,10 +90,7 @@ struct vsp1_entity { | |||
70 | unsigned int sink_pad; | 90 | unsigned int sink_pad; |
71 | 91 | ||
72 | struct v4l2_subdev subdev; | 92 | struct v4l2_subdev subdev; |
73 | struct v4l2_mbus_framefmt *formats; | 93 | struct v4l2_subdev_pad_config *config; |
74 | |||
75 | spinlock_t lock; /* Protects the streaming field */ | ||
76 | bool streaming; | ||
77 | }; | 94 | }; |
78 | 95 | ||
79 | static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) | 96 | static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) |
@@ -82,7 +99,8 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) | |||
82 | } | 99 | } |
83 | 100 | ||
84 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | 101 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, |
85 | unsigned int num_pads); | 102 | const char *name, unsigned int num_pads, |
103 | const struct v4l2_subdev_ops *ops); | ||
86 | void vsp1_entity_destroy(struct vsp1_entity *entity); | 104 | void vsp1_entity_destroy(struct vsp1_entity *entity); |
87 | 105 | ||
88 | extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops; | 106 | extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops; |
@@ -91,16 +109,35 @@ int vsp1_entity_link_setup(struct media_entity *entity, | |||
91 | const struct media_pad *local, | 109 | const struct media_pad *local, |
92 | const struct media_pad *remote, u32 flags); | 110 | const struct media_pad *remote, u32 flags); |
93 | 111 | ||
112 | struct v4l2_subdev_pad_config * | ||
113 | vsp1_entity_get_pad_config(struct vsp1_entity *entity, | ||
114 | struct v4l2_subdev_pad_config *cfg, | ||
115 | enum v4l2_subdev_format_whence which); | ||
94 | struct v4l2_mbus_framefmt * | 116 | struct v4l2_mbus_framefmt * |
95 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, | 117 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, |
96 | struct v4l2_subdev_pad_config *cfg, | 118 | struct v4l2_subdev_pad_config *cfg, |
97 | unsigned int pad, u32 which); | 119 | unsigned int pad); |
98 | void vsp1_entity_init_formats(struct v4l2_subdev *subdev, | 120 | struct v4l2_rect * |
99 | struct v4l2_subdev_pad_config *cfg); | 121 | vsp1_entity_get_pad_compose(struct vsp1_entity *entity, |
100 | 122 | struct v4l2_subdev_pad_config *cfg, | |
101 | bool vsp1_entity_is_streaming(struct vsp1_entity *entity); | 123 | unsigned int pad); |
102 | int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming); | 124 | int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, |
103 | 125 | struct v4l2_subdev_pad_config *cfg); | |
104 | void vsp1_entity_route_setup(struct vsp1_entity *source); | 126 | |
127 | void vsp1_entity_route_setup(struct vsp1_entity *source, | ||
128 | struct vsp1_dl_list *dl); | ||
129 | |||
130 | int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, | ||
131 | struct v4l2_subdev_pad_config *cfg, | ||
132 | struct v4l2_subdev_format *fmt); | ||
133 | int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, | ||
134 | struct v4l2_subdev_pad_config *cfg, | ||
135 | struct v4l2_subdev_mbus_code_enum *code, | ||
136 | const unsigned int *codes, unsigned int ncodes); | ||
137 | int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, | ||
138 | struct v4l2_subdev_pad_config *cfg, | ||
139 | struct v4l2_subdev_frame_size_enum *fse, | ||
140 | unsigned int min_w, unsigned int min_h, | ||
141 | unsigned int max_w, unsigned int max_h); | ||
105 | 142 | ||
106 | #endif /* __VSP1_ENTITY_H__ */ | 143 | #endif /* __VSP1_ENTITY_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index c1087cff31a0..68b8567b374d 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <media/v4l2-subdev.h> | 17 | #include <media/v4l2-subdev.h> |
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | ||
20 | #include "vsp1_hsit.h" | 21 | #include "vsp1_hsit.h" |
21 | 22 | ||
22 | #define HSIT_MIN_SIZE 4U | 23 | #define HSIT_MIN_SIZE 4U |
@@ -26,32 +27,14 @@ | |||
26 | * Device Access | 27 | * Device Access |
27 | */ | 28 | */ |
28 | 29 | ||
29 | static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data) | 30 | static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, |
31 | struct vsp1_dl_list *dl, u32 reg, u32 data) | ||
30 | { | 32 | { |
31 | vsp1_write(hsit->entity.vsp1, reg, data); | 33 | vsp1_dl_list_write(dl, reg, data); |
32 | } | 34 | } |
33 | 35 | ||
34 | /* ----------------------------------------------------------------------------- | 36 | /* ----------------------------------------------------------------------------- |
35 | * V4L2 Subdevice Core Operations | 37 | * V4L2 Subdevice Operations |
36 | */ | ||
37 | |||
38 | static int hsit_s_stream(struct v4l2_subdev *subdev, int enable) | ||
39 | { | ||
40 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
41 | |||
42 | if (!enable) | ||
43 | return 0; | ||
44 | |||
45 | if (hsit->inverse) | ||
46 | vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); | ||
47 | else | ||
48 | vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN); | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* ----------------------------------------------------------------------------- | ||
54 | * V4L2 Subdevice Pad Operations | ||
55 | */ | 38 | */ |
56 | 39 | ||
57 | static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, | 40 | static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, |
@@ -76,43 +59,9 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev, | |||
76 | struct v4l2_subdev_pad_config *cfg, | 59 | struct v4l2_subdev_pad_config *cfg, |
77 | struct v4l2_subdev_frame_size_enum *fse) | 60 | struct v4l2_subdev_frame_size_enum *fse) |
78 | { | 61 | { |
79 | struct vsp1_hsit *hsit = to_hsit(subdev); | 62 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HSIT_MIN_SIZE, |
80 | struct v4l2_mbus_framefmt *format; | 63 | HSIT_MIN_SIZE, HSIT_MAX_SIZE, |
81 | 64 | HSIT_MAX_SIZE); | |
82 | format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad, | ||
83 | fse->which); | ||
84 | |||
85 | if (fse->index || fse->code != format->code) | ||
86 | return -EINVAL; | ||
87 | |||
88 | if (fse->pad == HSIT_PAD_SINK) { | ||
89 | fse->min_width = HSIT_MIN_SIZE; | ||
90 | fse->max_width = HSIT_MAX_SIZE; | ||
91 | fse->min_height = HSIT_MIN_SIZE; | ||
92 | fse->max_height = HSIT_MAX_SIZE; | ||
93 | } else { | ||
94 | /* The size on the source pad are fixed and always identical to | ||
95 | * the size on the sink pad. | ||
96 | */ | ||
97 | fse->min_width = format->width; | ||
98 | fse->max_width = format->width; | ||
99 | fse->min_height = format->height; | ||
100 | fse->max_height = format->height; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int hsit_get_format(struct v4l2_subdev *subdev, | ||
107 | struct v4l2_subdev_pad_config *cfg, | ||
108 | struct v4l2_subdev_format *fmt) | ||
109 | { | ||
110 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
111 | |||
112 | fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, | ||
113 | fmt->which); | ||
114 | |||
115 | return 0; | ||
116 | } | 65 | } |
117 | 66 | ||
118 | static int hsit_set_format(struct v4l2_subdev *subdev, | 67 | static int hsit_set_format(struct v4l2_subdev *subdev, |
@@ -120,10 +69,14 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
120 | struct v4l2_subdev_format *fmt) | 69 | struct v4l2_subdev_format *fmt) |
121 | { | 70 | { |
122 | struct vsp1_hsit *hsit = to_hsit(subdev); | 71 | struct vsp1_hsit *hsit = to_hsit(subdev); |
72 | struct v4l2_subdev_pad_config *config; | ||
123 | struct v4l2_mbus_framefmt *format; | 73 | struct v4l2_mbus_framefmt *format; |
124 | 74 | ||
125 | format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, | 75 | config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which); |
126 | fmt->which); | 76 | if (!config) |
77 | return -EINVAL; | ||
78 | |||
79 | format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); | ||
127 | 80 | ||
128 | if (fmt->pad == HSIT_PAD_SOURCE) { | 81 | if (fmt->pad == HSIT_PAD_SOURCE) { |
129 | /* The HST and HSI output format code and resolution can't be | 82 | /* The HST and HSI output format code and resolution can't be |
@@ -145,8 +98,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
145 | fmt->format = *format; | 98 | fmt->format = *format; |
146 | 99 | ||
147 | /* Propagate the format to the source pad. */ | 100 | /* Propagate the format to the source pad. */ |
148 | format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE, | 101 | format = vsp1_entity_get_pad_format(&hsit->entity, config, |
149 | fmt->which); | 102 | HSIT_PAD_SOURCE); |
150 | *format = fmt->format; | 103 | *format = fmt->format; |
151 | format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 | 104 | format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 |
152 | : MEDIA_BUS_FMT_AHSV8888_1X32; | 105 | : MEDIA_BUS_FMT_AHSV8888_1X32; |
@@ -154,33 +107,44 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
154 | return 0; | 107 | return 0; |
155 | } | 108 | } |
156 | 109 | ||
157 | /* ----------------------------------------------------------------------------- | ||
158 | * V4L2 Subdevice Operations | ||
159 | */ | ||
160 | |||
161 | static struct v4l2_subdev_video_ops hsit_video_ops = { | ||
162 | .s_stream = hsit_s_stream, | ||
163 | }; | ||
164 | |||
165 | static struct v4l2_subdev_pad_ops hsit_pad_ops = { | 110 | static struct v4l2_subdev_pad_ops hsit_pad_ops = { |
111 | .init_cfg = vsp1_entity_init_cfg, | ||
166 | .enum_mbus_code = hsit_enum_mbus_code, | 112 | .enum_mbus_code = hsit_enum_mbus_code, |
167 | .enum_frame_size = hsit_enum_frame_size, | 113 | .enum_frame_size = hsit_enum_frame_size, |
168 | .get_fmt = hsit_get_format, | 114 | .get_fmt = vsp1_subdev_get_pad_format, |
169 | .set_fmt = hsit_set_format, | 115 | .set_fmt = hsit_set_format, |
170 | }; | 116 | }; |
171 | 117 | ||
172 | static struct v4l2_subdev_ops hsit_ops = { | 118 | static struct v4l2_subdev_ops hsit_ops = { |
173 | .video = &hsit_video_ops, | ||
174 | .pad = &hsit_pad_ops, | 119 | .pad = &hsit_pad_ops, |
175 | }; | 120 | }; |
176 | 121 | ||
177 | /* ----------------------------------------------------------------------------- | 122 | /* ----------------------------------------------------------------------------- |
123 | * VSP1 Entity Operations | ||
124 | */ | ||
125 | |||
126 | static void hsit_configure(struct vsp1_entity *entity, | ||
127 | struct vsp1_pipeline *pipe, | ||
128 | struct vsp1_dl_list *dl) | ||
129 | { | ||
130 | struct vsp1_hsit *hsit = to_hsit(&entity->subdev); | ||
131 | |||
132 | if (hsit->inverse) | ||
133 | vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); | ||
134 | else | ||
135 | vsp1_hsit_write(hsit, dl, VI6_HST_CTRL, VI6_HST_CTRL_EN); | ||
136 | } | ||
137 | |||
138 | static const struct vsp1_entity_operations hsit_entity_ops = { | ||
139 | .configure = hsit_configure, | ||
140 | }; | ||
141 | |||
142 | /* ----------------------------------------------------------------------------- | ||
178 | * Initialization and Cleanup | 143 | * Initialization and Cleanup |
179 | */ | 144 | */ |
180 | 145 | ||
181 | struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) | 146 | struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) |
182 | { | 147 | { |
183 | struct v4l2_subdev *subdev; | ||
184 | struct vsp1_hsit *hsit; | 148 | struct vsp1_hsit *hsit; |
185 | int ret; | 149 | int ret; |
186 | 150 | ||
@@ -190,27 +154,17 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) | |||
190 | 154 | ||
191 | hsit->inverse = inverse; | 155 | hsit->inverse = inverse; |
192 | 156 | ||
157 | hsit->entity.ops = &hsit_entity_ops; | ||
158 | |||
193 | if (inverse) | 159 | if (inverse) |
194 | hsit->entity.type = VSP1_ENTITY_HSI; | 160 | hsit->entity.type = VSP1_ENTITY_HSI; |
195 | else | 161 | else |
196 | hsit->entity.type = VSP1_ENTITY_HST; | 162 | hsit->entity.type = VSP1_ENTITY_HST; |
197 | 163 | ||
198 | ret = vsp1_entity_init(vsp1, &hsit->entity, 2); | 164 | ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2, |
165 | &hsit_ops); | ||
199 | if (ret < 0) | 166 | if (ret < 0) |
200 | return ERR_PTR(ret); | 167 | return ERR_PTR(ret); |
201 | 168 | ||
202 | /* Initialize the V4L2 subdev. */ | ||
203 | subdev = &hsit->entity.subdev; | ||
204 | v4l2_subdev_init(subdev, &hsit_ops); | ||
205 | |||
206 | subdev->entity.ops = &vsp1->media_ops; | ||
207 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
208 | snprintf(subdev->name, sizeof(subdev->name), "%s %s", | ||
209 | dev_name(vsp1->dev), inverse ? "hsi" : "hst"); | ||
210 | v4l2_set_subdevdata(subdev, hsit); | ||
211 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
212 | |||
213 | vsp1_entity_init_formats(subdev, NULL); | ||
214 | |||
215 | return hsit; | 169 | return hsit; |
216 | } | 170 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 433853ce8dbf..0217393f22df 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c | |||
@@ -17,55 +17,24 @@ | |||
17 | #include <media/v4l2-subdev.h> | 17 | #include <media/v4l2-subdev.h> |
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | ||
20 | #include "vsp1_lif.h" | 21 | #include "vsp1_lif.h" |
21 | 22 | ||
22 | #define LIF_MIN_SIZE 2U | 23 | #define LIF_MIN_SIZE 2U |
23 | #define LIF_MAX_SIZE 2048U | 24 | #define LIF_MAX_SIZE 8190U |
24 | 25 | ||
25 | /* ----------------------------------------------------------------------------- | 26 | /* ----------------------------------------------------------------------------- |
26 | * Device Access | 27 | * Device Access |
27 | */ | 28 | */ |
28 | 29 | ||
29 | static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data) | 30 | static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl, |
31 | u32 reg, u32 data) | ||
30 | { | 32 | { |
31 | vsp1_mod_write(&lif->entity, reg, data); | 33 | vsp1_dl_list_write(dl, reg, data); |
32 | } | 34 | } |
33 | 35 | ||
34 | /* ----------------------------------------------------------------------------- | 36 | /* ----------------------------------------------------------------------------- |
35 | * V4L2 Subdevice Core Operations | 37 | * V4L2 Subdevice Operations |
36 | */ | ||
37 | |||
38 | static int lif_s_stream(struct v4l2_subdev *subdev, int enable) | ||
39 | { | ||
40 | const struct v4l2_mbus_framefmt *format; | ||
41 | struct vsp1_lif *lif = to_lif(subdev); | ||
42 | unsigned int hbth = 1300; | ||
43 | unsigned int obth = 400; | ||
44 | unsigned int lbth = 200; | ||
45 | |||
46 | if (!enable) { | ||
47 | vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0); | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | format = &lif->entity.formats[LIF_PAD_SOURCE]; | ||
52 | |||
53 | obth = min(obth, (format->width + 1) / 2 * format->height - 4); | ||
54 | |||
55 | vsp1_lif_write(lif, VI6_LIF_CSBTH, | ||
56 | (hbth << VI6_LIF_CSBTH_HBTH_SHIFT) | | ||
57 | (lbth << VI6_LIF_CSBTH_LBTH_SHIFT)); | ||
58 | |||
59 | vsp1_lif_write(lif, VI6_LIF_CTRL, | ||
60 | (obth << VI6_LIF_CTRL_OBTH_SHIFT) | | ||
61 | (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | | ||
62 | VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | /* ----------------------------------------------------------------------------- | ||
68 | * V4L2 Subdevice Pad Operations | ||
69 | */ | 38 | */ |
70 | 39 | ||
71 | static int lif_enum_mbus_code(struct v4l2_subdev *subdev, | 40 | static int lif_enum_mbus_code(struct v4l2_subdev *subdev, |
@@ -76,82 +45,38 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, | |||
76 | MEDIA_BUS_FMT_ARGB8888_1X32, | 45 | MEDIA_BUS_FMT_ARGB8888_1X32, |
77 | MEDIA_BUS_FMT_AYUV8_1X32, | 46 | MEDIA_BUS_FMT_AYUV8_1X32, |
78 | }; | 47 | }; |
79 | struct vsp1_lif *lif = to_lif(subdev); | ||
80 | 48 | ||
81 | if (code->pad == LIF_PAD_SINK) { | 49 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, |
82 | if (code->index >= ARRAY_SIZE(codes)) | 50 | ARRAY_SIZE(codes)); |
83 | return -EINVAL; | ||
84 | |||
85 | code->code = codes[code->index]; | ||
86 | } else { | ||
87 | struct v4l2_mbus_framefmt *format; | ||
88 | |||
89 | /* The LIF can't perform format conversion, the sink format is | ||
90 | * always identical to the source format. | ||
91 | */ | ||
92 | if (code->index) | ||
93 | return -EINVAL; | ||
94 | |||
95 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, | ||
96 | LIF_PAD_SINK, code->which); | ||
97 | code->code = format->code; | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | 51 | } |
102 | 52 | ||
103 | static int lif_enum_frame_size(struct v4l2_subdev *subdev, | 53 | static int lif_enum_frame_size(struct v4l2_subdev *subdev, |
104 | struct v4l2_subdev_pad_config *cfg, | 54 | struct v4l2_subdev_pad_config *cfg, |
105 | struct v4l2_subdev_frame_size_enum *fse) | 55 | struct v4l2_subdev_frame_size_enum *fse) |
106 | { | 56 | { |
107 | struct vsp1_lif *lif = to_lif(subdev); | 57 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE, |
108 | struct v4l2_mbus_framefmt *format; | 58 | LIF_MIN_SIZE, LIF_MAX_SIZE, |
109 | 59 | LIF_MAX_SIZE); | |
110 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK, | ||
111 | fse->which); | ||
112 | |||
113 | if (fse->index || fse->code != format->code) | ||
114 | return -EINVAL; | ||
115 | |||
116 | if (fse->pad == LIF_PAD_SINK) { | ||
117 | fse->min_width = LIF_MIN_SIZE; | ||
118 | fse->max_width = LIF_MAX_SIZE; | ||
119 | fse->min_height = LIF_MIN_SIZE; | ||
120 | fse->max_height = LIF_MAX_SIZE; | ||
121 | } else { | ||
122 | fse->min_width = format->width; | ||
123 | fse->max_width = format->width; | ||
124 | fse->min_height = format->height; | ||
125 | fse->max_height = format->height; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | 60 | } |
130 | 61 | ||
131 | static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 62 | static int lif_set_format(struct v4l2_subdev *subdev, |
132 | struct v4l2_subdev_format *fmt) | 63 | struct v4l2_subdev_pad_config *cfg, |
133 | { | ||
134 | struct vsp1_lif *lif = to_lif(subdev); | ||
135 | |||
136 | fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, | ||
137 | fmt->which); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | ||
143 | struct v4l2_subdev_format *fmt) | 64 | struct v4l2_subdev_format *fmt) |
144 | { | 65 | { |
145 | struct vsp1_lif *lif = to_lif(subdev); | 66 | struct vsp1_lif *lif = to_lif(subdev); |
67 | struct v4l2_subdev_pad_config *config; | ||
146 | struct v4l2_mbus_framefmt *format; | 68 | struct v4l2_mbus_framefmt *format; |
147 | 69 | ||
70 | config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which); | ||
71 | if (!config) | ||
72 | return -EINVAL; | ||
73 | |||
148 | /* Default to YUV if the requested format is not supported. */ | 74 | /* Default to YUV if the requested format is not supported. */ |
149 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 75 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
150 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | 76 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) |
151 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | 77 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; |
152 | 78 | ||
153 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, | 79 | format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad); |
154 | fmt->which); | ||
155 | 80 | ||
156 | if (fmt->pad == LIF_PAD_SOURCE) { | 81 | if (fmt->pad == LIF_PAD_SOURCE) { |
157 | /* The LIF source format is always identical to its sink | 82 | /* The LIF source format is always identical to its sink |
@@ -172,40 +97,64 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con | |||
172 | fmt->format = *format; | 97 | fmt->format = *format; |
173 | 98 | ||
174 | /* Propagate the format to the source pad. */ | 99 | /* Propagate the format to the source pad. */ |
175 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE, | 100 | format = vsp1_entity_get_pad_format(&lif->entity, config, |
176 | fmt->which); | 101 | LIF_PAD_SOURCE); |
177 | *format = fmt->format; | 102 | *format = fmt->format; |
178 | 103 | ||
179 | return 0; | 104 | return 0; |
180 | } | 105 | } |
181 | 106 | ||
182 | /* ----------------------------------------------------------------------------- | ||
183 | * V4L2 Subdevice Operations | ||
184 | */ | ||
185 | |||
186 | static struct v4l2_subdev_video_ops lif_video_ops = { | ||
187 | .s_stream = lif_s_stream, | ||
188 | }; | ||
189 | |||
190 | static struct v4l2_subdev_pad_ops lif_pad_ops = { | 107 | static struct v4l2_subdev_pad_ops lif_pad_ops = { |
108 | .init_cfg = vsp1_entity_init_cfg, | ||
191 | .enum_mbus_code = lif_enum_mbus_code, | 109 | .enum_mbus_code = lif_enum_mbus_code, |
192 | .enum_frame_size = lif_enum_frame_size, | 110 | .enum_frame_size = lif_enum_frame_size, |
193 | .get_fmt = lif_get_format, | 111 | .get_fmt = vsp1_subdev_get_pad_format, |
194 | .set_fmt = lif_set_format, | 112 | .set_fmt = lif_set_format, |
195 | }; | 113 | }; |
196 | 114 | ||
197 | static struct v4l2_subdev_ops lif_ops = { | 115 | static struct v4l2_subdev_ops lif_ops = { |
198 | .video = &lif_video_ops, | ||
199 | .pad = &lif_pad_ops, | 116 | .pad = &lif_pad_ops, |
200 | }; | 117 | }; |
201 | 118 | ||
202 | /* ----------------------------------------------------------------------------- | 119 | /* ----------------------------------------------------------------------------- |
120 | * VSP1 Entity Operations | ||
121 | */ | ||
122 | |||
123 | static void lif_configure(struct vsp1_entity *entity, | ||
124 | struct vsp1_pipeline *pipe, | ||
125 | struct vsp1_dl_list *dl) | ||
126 | { | ||
127 | const struct v4l2_mbus_framefmt *format; | ||
128 | struct vsp1_lif *lif = to_lif(&entity->subdev); | ||
129 | unsigned int hbth = 1300; | ||
130 | unsigned int obth = 400; | ||
131 | unsigned int lbth = 200; | ||
132 | |||
133 | format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, | ||
134 | LIF_PAD_SOURCE); | ||
135 | |||
136 | obth = min(obth, (format->width + 1) / 2 * format->height - 4); | ||
137 | |||
138 | vsp1_lif_write(lif, dl, VI6_LIF_CSBTH, | ||
139 | (hbth << VI6_LIF_CSBTH_HBTH_SHIFT) | | ||
140 | (lbth << VI6_LIF_CSBTH_LBTH_SHIFT)); | ||
141 | |||
142 | vsp1_lif_write(lif, dl, VI6_LIF_CTRL, | ||
143 | (obth << VI6_LIF_CTRL_OBTH_SHIFT) | | ||
144 | (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | | ||
145 | VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); | ||
146 | } | ||
147 | |||
148 | static const struct vsp1_entity_operations lif_entity_ops = { | ||
149 | .configure = lif_configure, | ||
150 | }; | ||
151 | |||
152 | /* ----------------------------------------------------------------------------- | ||
203 | * Initialization and Cleanup | 153 | * Initialization and Cleanup |
204 | */ | 154 | */ |
205 | 155 | ||
206 | struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) | 156 | struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) |
207 | { | 157 | { |
208 | struct v4l2_subdev *subdev; | ||
209 | struct vsp1_lif *lif; | 158 | struct vsp1_lif *lif; |
210 | int ret; | 159 | int ret; |
211 | 160 | ||
@@ -213,24 +162,12 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) | |||
213 | if (lif == NULL) | 162 | if (lif == NULL) |
214 | return ERR_PTR(-ENOMEM); | 163 | return ERR_PTR(-ENOMEM); |
215 | 164 | ||
165 | lif->entity.ops = &lif_entity_ops; | ||
216 | lif->entity.type = VSP1_ENTITY_LIF; | 166 | lif->entity.type = VSP1_ENTITY_LIF; |
217 | 167 | ||
218 | ret = vsp1_entity_init(vsp1, &lif->entity, 2); | 168 | ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops); |
219 | if (ret < 0) | 169 | if (ret < 0) |
220 | return ERR_PTR(ret); | 170 | return ERR_PTR(ret); |
221 | 171 | ||
222 | /* Initialize the V4L2 subdev. */ | ||
223 | subdev = &lif->entity.subdev; | ||
224 | v4l2_subdev_init(subdev, &lif_ops); | ||
225 | |||
226 | subdev->entity.ops = &vsp1->media_ops; | ||
227 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
228 | snprintf(subdev->name, sizeof(subdev->name), "%s lif", | ||
229 | dev_name(vsp1->dev)); | ||
230 | v4l2_set_subdevdata(subdev, lif); | ||
231 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
232 | |||
233 | vsp1_entity_init_formats(subdev, NULL); | ||
234 | |||
235 | return lif; | 172 | return lif; |
236 | } | 173 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4b89095e7b5f..aa09e59f0ab8 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <media/v4l2-subdev.h> | 18 | #include <media/v4l2-subdev.h> |
19 | 19 | ||
20 | #include "vsp1.h" | 20 | #include "vsp1.h" |
21 | #include "vsp1_dl.h" | ||
21 | #include "vsp1_lut.h" | 22 | #include "vsp1_lut.h" |
22 | 23 | ||
23 | #define LUT_MIN_SIZE 4U | 24 | #define LUT_MIN_SIZE 4U |
@@ -27,19 +28,35 @@ | |||
27 | * Device Access | 28 | * Device Access |
28 | */ | 29 | */ |
29 | 30 | ||
30 | static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data) | 31 | static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl, |
32 | u32 reg, u32 data) | ||
31 | { | 33 | { |
32 | vsp1_write(lut->entity.vsp1, reg, data); | 34 | vsp1_dl_list_write(dl, reg, data); |
33 | } | 35 | } |
34 | 36 | ||
35 | /* ----------------------------------------------------------------------------- | 37 | /* ----------------------------------------------------------------------------- |
36 | * V4L2 Subdevice Core Operations | 38 | * V4L2 Subdevice Core Operations |
37 | */ | 39 | */ |
38 | 40 | ||
39 | static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config) | 41 | static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config) |
40 | { | 42 | { |
41 | memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut, | 43 | struct vsp1_dl_body *dlb; |
42 | sizeof(config->lut)); | 44 | unsigned int i; |
45 | |||
46 | dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut)); | ||
47 | if (!dlb) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | for (i = 0; i < ARRAY_SIZE(config->lut); ++i) | ||
51 | vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, | ||
52 | config->lut[i]); | ||
53 | |||
54 | mutex_lock(&lut->lock); | ||
55 | swap(lut->lut, dlb); | ||
56 | mutex_unlock(&lut->lock); | ||
57 | |||
58 | vsp1_dl_fragment_free(dlb); | ||
59 | return 0; | ||
43 | } | 60 | } |
44 | 61 | ||
45 | static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) | 62 | static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) |
@@ -48,8 +65,7 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) | |||
48 | 65 | ||
49 | switch (cmd) { | 66 | switch (cmd) { |
50 | case VIDIOC_VSP1_LUT_CONFIG: | 67 | case VIDIOC_VSP1_LUT_CONFIG: |
51 | lut_configure(lut, arg); | 68 | return lut_set_table(lut, arg); |
52 | return 0; | ||
53 | 69 | ||
54 | default: | 70 | default: |
55 | return -ENOIOCTLCMD; | 71 | return -ENOIOCTLCMD; |
@@ -57,22 +73,6 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) | |||
57 | } | 73 | } |
58 | 74 | ||
59 | /* ----------------------------------------------------------------------------- | 75 | /* ----------------------------------------------------------------------------- |
60 | * V4L2 Subdevice Video Operations | ||
61 | */ | ||
62 | |||
63 | static int lut_s_stream(struct v4l2_subdev *subdev, int enable) | ||
64 | { | ||
65 | struct vsp1_lut *lut = to_lut(subdev); | ||
66 | |||
67 | if (!enable) | ||
68 | return 0; | ||
69 | |||
70 | vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* ----------------------------------------------------------------------------- | ||
76 | * V4L2 Subdevice Pad Operations | 76 | * V4L2 Subdevice Pad Operations |
77 | */ | 77 | */ |
78 | 78 | ||
@@ -85,85 +85,39 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, | |||
85 | MEDIA_BUS_FMT_AHSV8888_1X32, | 85 | MEDIA_BUS_FMT_AHSV8888_1X32, |
86 | MEDIA_BUS_FMT_AYUV8_1X32, | 86 | MEDIA_BUS_FMT_AYUV8_1X32, |
87 | }; | 87 | }; |
88 | struct vsp1_lut *lut = to_lut(subdev); | ||
89 | struct v4l2_mbus_framefmt *format; | ||
90 | |||
91 | if (code->pad == LUT_PAD_SINK) { | ||
92 | if (code->index >= ARRAY_SIZE(codes)) | ||
93 | return -EINVAL; | ||
94 | |||
95 | code->code = codes[code->index]; | ||
96 | } else { | ||
97 | /* The LUT can't perform format conversion, the sink format is | ||
98 | * always identical to the source format. | ||
99 | */ | ||
100 | if (code->index) | ||
101 | return -EINVAL; | ||
102 | |||
103 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, | ||
104 | LUT_PAD_SINK, code->which); | ||
105 | code->code = format->code; | ||
106 | } | ||
107 | 88 | ||
108 | return 0; | 89 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, |
90 | ARRAY_SIZE(codes)); | ||
109 | } | 91 | } |
110 | 92 | ||
111 | static int lut_enum_frame_size(struct v4l2_subdev *subdev, | 93 | static int lut_enum_frame_size(struct v4l2_subdev *subdev, |
112 | struct v4l2_subdev_pad_config *cfg, | 94 | struct v4l2_subdev_pad_config *cfg, |
113 | struct v4l2_subdev_frame_size_enum *fse) | 95 | struct v4l2_subdev_frame_size_enum *fse) |
114 | { | 96 | { |
115 | struct vsp1_lut *lut = to_lut(subdev); | 97 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE, |
116 | struct v4l2_mbus_framefmt *format; | 98 | LUT_MIN_SIZE, LUT_MAX_SIZE, |
117 | 99 | LUT_MAX_SIZE); | |
118 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, | ||
119 | fse->pad, fse->which); | ||
120 | |||
121 | if (fse->index || fse->code != format->code) | ||
122 | return -EINVAL; | ||
123 | |||
124 | if (fse->pad == LUT_PAD_SINK) { | ||
125 | fse->min_width = LUT_MIN_SIZE; | ||
126 | fse->max_width = LUT_MAX_SIZE; | ||
127 | fse->min_height = LUT_MIN_SIZE; | ||
128 | fse->max_height = LUT_MAX_SIZE; | ||
129 | } else { | ||
130 | /* The size on the source pad are fixed and always identical to | ||
131 | * the size on the sink pad. | ||
132 | */ | ||
133 | fse->min_width = format->width; | ||
134 | fse->max_width = format->width; | ||
135 | fse->min_height = format->height; | ||
136 | fse->max_height = format->height; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | ||
143 | struct v4l2_subdev_format *fmt) | ||
144 | { | ||
145 | struct vsp1_lut *lut = to_lut(subdev); | ||
146 | |||
147 | fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, | ||
148 | fmt->which); | ||
149 | |||
150 | return 0; | ||
151 | } | 100 | } |
152 | 101 | ||
153 | static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 102 | static int lut_set_format(struct v4l2_subdev *subdev, |
103 | struct v4l2_subdev_pad_config *cfg, | ||
154 | struct v4l2_subdev_format *fmt) | 104 | struct v4l2_subdev_format *fmt) |
155 | { | 105 | { |
156 | struct vsp1_lut *lut = to_lut(subdev); | 106 | struct vsp1_lut *lut = to_lut(subdev); |
107 | struct v4l2_subdev_pad_config *config; | ||
157 | struct v4l2_mbus_framefmt *format; | 108 | struct v4l2_mbus_framefmt *format; |
158 | 109 | ||
110 | config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which); | ||
111 | if (!config) | ||
112 | return -EINVAL; | ||
113 | |||
159 | /* Default to YUV if the requested format is not supported. */ | 114 | /* Default to YUV if the requested format is not supported. */ |
160 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 115 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
161 | fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && | 116 | fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && |
162 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | 117 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) |
163 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | 118 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; |
164 | 119 | ||
165 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, | 120 | format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad); |
166 | fmt->which); | ||
167 | 121 | ||
168 | if (fmt->pad == LUT_PAD_SOURCE) { | 122 | if (fmt->pad == LUT_PAD_SOURCE) { |
169 | /* The LUT output format can't be modified. */ | 123 | /* The LUT output format can't be modified. */ |
@@ -171,6 +125,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con | |||
171 | return 0; | 125 | return 0; |
172 | } | 126 | } |
173 | 127 | ||
128 | format->code = fmt->format.code; | ||
174 | format->width = clamp_t(unsigned int, fmt->format.width, | 129 | format->width = clamp_t(unsigned int, fmt->format.width, |
175 | LUT_MIN_SIZE, LUT_MAX_SIZE); | 130 | LUT_MIN_SIZE, LUT_MAX_SIZE); |
176 | format->height = clamp_t(unsigned int, fmt->format.height, | 131 | format->height = clamp_t(unsigned int, fmt->format.height, |
@@ -181,8 +136,8 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con | |||
181 | fmt->format = *format; | 136 | fmt->format = *format; |
182 | 137 | ||
183 | /* Propagate the format to the source pad. */ | 138 | /* Propagate the format to the source pad. */ |
184 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE, | 139 | format = vsp1_entity_get_pad_format(&lut->entity, config, |
185 | fmt->which); | 140 | LUT_PAD_SOURCE); |
186 | *format = fmt->format; | 141 | *format = fmt->format; |
187 | 142 | ||
188 | return 0; | 143 | return 0; |
@@ -196,30 +151,49 @@ static struct v4l2_subdev_core_ops lut_core_ops = { | |||
196 | .ioctl = lut_ioctl, | 151 | .ioctl = lut_ioctl, |
197 | }; | 152 | }; |
198 | 153 | ||
199 | static struct v4l2_subdev_video_ops lut_video_ops = { | ||
200 | .s_stream = lut_s_stream, | ||
201 | }; | ||
202 | |||
203 | static struct v4l2_subdev_pad_ops lut_pad_ops = { | 154 | static struct v4l2_subdev_pad_ops lut_pad_ops = { |
155 | .init_cfg = vsp1_entity_init_cfg, | ||
204 | .enum_mbus_code = lut_enum_mbus_code, | 156 | .enum_mbus_code = lut_enum_mbus_code, |
205 | .enum_frame_size = lut_enum_frame_size, | 157 | .enum_frame_size = lut_enum_frame_size, |
206 | .get_fmt = lut_get_format, | 158 | .get_fmt = vsp1_subdev_get_pad_format, |
207 | .set_fmt = lut_set_format, | 159 | .set_fmt = lut_set_format, |
208 | }; | 160 | }; |
209 | 161 | ||
210 | static struct v4l2_subdev_ops lut_ops = { | 162 | static struct v4l2_subdev_ops lut_ops = { |
211 | .core = &lut_core_ops, | 163 | .core = &lut_core_ops, |
212 | .video = &lut_video_ops, | ||
213 | .pad = &lut_pad_ops, | 164 | .pad = &lut_pad_ops, |
214 | }; | 165 | }; |
215 | 166 | ||
216 | /* ----------------------------------------------------------------------------- | 167 | /* ----------------------------------------------------------------------------- |
168 | * VSP1 Entity Operations | ||
169 | */ | ||
170 | |||
171 | static void lut_configure(struct vsp1_entity *entity, | ||
172 | struct vsp1_pipeline *pipe, | ||
173 | struct vsp1_dl_list *dl) | ||
174 | { | ||
175 | struct vsp1_lut *lut = to_lut(&entity->subdev); | ||
176 | |||
177 | vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); | ||
178 | |||
179 | mutex_lock(&lut->lock); | ||
180 | if (lut->lut) { | ||
181 | vsp1_dl_list_add_fragment(dl, lut->lut); | ||
182 | lut->lut = NULL; | ||
183 | } | ||
184 | mutex_unlock(&lut->lock); | ||
185 | } | ||
186 | |||
187 | static const struct vsp1_entity_operations lut_entity_ops = { | ||
188 | .configure = lut_configure, | ||
189 | }; | ||
190 | |||
191 | /* ----------------------------------------------------------------------------- | ||
217 | * Initialization and Cleanup | 192 | * Initialization and Cleanup |
218 | */ | 193 | */ |
219 | 194 | ||
220 | struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) | 195 | struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) |
221 | { | 196 | { |
222 | struct v4l2_subdev *subdev; | ||
223 | struct vsp1_lut *lut; | 197 | struct vsp1_lut *lut; |
224 | int ret; | 198 | int ret; |
225 | 199 | ||
@@ -227,24 +201,12 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) | |||
227 | if (lut == NULL) | 201 | if (lut == NULL) |
228 | return ERR_PTR(-ENOMEM); | 202 | return ERR_PTR(-ENOMEM); |
229 | 203 | ||
204 | lut->entity.ops = &lut_entity_ops; | ||
230 | lut->entity.type = VSP1_ENTITY_LUT; | 205 | lut->entity.type = VSP1_ENTITY_LUT; |
231 | 206 | ||
232 | ret = vsp1_entity_init(vsp1, &lut->entity, 2); | 207 | ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops); |
233 | if (ret < 0) | 208 | if (ret < 0) |
234 | return ERR_PTR(ret); | 209 | return ERR_PTR(ret); |
235 | 210 | ||
236 | /* Initialize the V4L2 subdev. */ | ||
237 | subdev = &lut->entity.subdev; | ||
238 | v4l2_subdev_init(subdev, &lut_ops); | ||
239 | |||
240 | subdev->entity.ops = &vsp1->media_ops; | ||
241 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
242 | snprintf(subdev->name, sizeof(subdev->name), "%s lut", | ||
243 | dev_name(vsp1->dev)); | ||
244 | v4l2_set_subdevdata(subdev, lut); | ||
245 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
246 | |||
247 | vsp1_entity_init_formats(subdev, NULL); | ||
248 | |||
249 | return lut; | 211 | return lut; |
250 | } | 212 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h index f92ffb867350..cef874f22b6a 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.h +++ b/drivers/media/platform/vsp1/vsp1_lut.h | |||
@@ -13,6 +13,8 @@ | |||
13 | #ifndef __VSP1_LUT_H__ | 13 | #ifndef __VSP1_LUT_H__ |
14 | #define __VSP1_LUT_H__ | 14 | #define __VSP1_LUT_H__ |
15 | 15 | ||
16 | #include <linux/mutex.h> | ||
17 | |||
16 | #include <media/media-entity.h> | 18 | #include <media/media-entity.h> |
17 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
18 | 20 | ||
@@ -25,7 +27,9 @@ struct vsp1_device; | |||
25 | 27 | ||
26 | struct vsp1_lut { | 28 | struct vsp1_lut { |
27 | struct vsp1_entity entity; | 29 | struct vsp1_entity entity; |
28 | u32 lut[256]; | 30 | |
31 | struct mutex lock; | ||
32 | struct vsp1_dl_body *lut; | ||
29 | }; | 33 | }; |
30 | 34 | ||
31 | static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev) | 35 | static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev) |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 6659f06b1643..4f3b4a1d028a 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c | |||
@@ -43,7 +43,7 @@ static const struct vsp1_format_info vsp1_video_formats[] = { | |||
43 | { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32, | 43 | { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32, |
44 | VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | | 44 | VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | |
45 | VI6_RPF_DSWAP_P_WDS, | 45 | VI6_RPF_DSWAP_P_WDS, |
46 | 1, { 16, 0, 0 }, false, false, 1, 1, true }, | 46 | 1, { 16, 0, 0 }, false, false, 1, 1, false }, |
47 | { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, | 47 | { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, |
48 | VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | | 48 | VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | |
49 | VI6_RPF_DSWAP_P_WDS, | 49 | VI6_RPF_DSWAP_P_WDS, |
@@ -172,14 +172,18 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) | |||
172 | bru->inputs[i].rpf = NULL; | 172 | bru->inputs[i].rpf = NULL; |
173 | } | 173 | } |
174 | 174 | ||
175 | for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) | 175 | for (i = 0; i < pipe->num_inputs; ++i) { |
176 | pipe->inputs[i]->pipe = NULL; | ||
176 | pipe->inputs[i] = NULL; | 177 | pipe->inputs[i] = NULL; |
178 | } | ||
179 | |||
180 | pipe->output->pipe = NULL; | ||
181 | pipe->output = NULL; | ||
177 | 182 | ||
178 | INIT_LIST_HEAD(&pipe->entities); | 183 | INIT_LIST_HEAD(&pipe->entities); |
179 | pipe->state = VSP1_PIPELINE_STOPPED; | 184 | pipe->state = VSP1_PIPELINE_STOPPED; |
180 | pipe->buffers_ready = 0; | 185 | pipe->buffers_ready = 0; |
181 | pipe->num_inputs = 0; | 186 | pipe->num_inputs = 0; |
182 | pipe->output = NULL; | ||
183 | pipe->bru = NULL; | 187 | pipe->bru = NULL; |
184 | pipe->lif = NULL; | 188 | pipe->lif = NULL; |
185 | pipe->uds = NULL; | 189 | pipe->uds = NULL; |
@@ -190,11 +194,13 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe) | |||
190 | mutex_init(&pipe->lock); | 194 | mutex_init(&pipe->lock); |
191 | spin_lock_init(&pipe->irqlock); | 195 | spin_lock_init(&pipe->irqlock); |
192 | init_waitqueue_head(&pipe->wq); | 196 | init_waitqueue_head(&pipe->wq); |
197 | kref_init(&pipe->kref); | ||
193 | 198 | ||
194 | INIT_LIST_HEAD(&pipe->entities); | 199 | INIT_LIST_HEAD(&pipe->entities); |
195 | pipe->state = VSP1_PIPELINE_STOPPED; | 200 | pipe->state = VSP1_PIPELINE_STOPPED; |
196 | } | 201 | } |
197 | 202 | ||
203 | /* Must be called with the pipe irqlock held. */ | ||
198 | void vsp1_pipeline_run(struct vsp1_pipeline *pipe) | 204 | void vsp1_pipeline_run(struct vsp1_pipeline *pipe) |
199 | { | 205 | { |
200 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | 206 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; |
@@ -226,7 +232,7 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) | |||
226 | unsigned long flags; | 232 | unsigned long flags; |
227 | int ret; | 233 | int ret; |
228 | 234 | ||
229 | if (pipe->dl) { | 235 | if (pipe->lif) { |
230 | /* When using display lists in continuous frame mode the only | 236 | /* When using display lists in continuous frame mode the only |
231 | * way to stop the pipeline is to reset the hardware. | 237 | * way to stop the pipeline is to reset the hardware. |
232 | */ | 238 | */ |
@@ -253,10 +259,10 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) | |||
253 | if (entity->route && entity->route->reg) | 259 | if (entity->route && entity->route->reg) |
254 | vsp1_write(entity->vsp1, entity->route->reg, | 260 | vsp1_write(entity->vsp1, entity->route->reg, |
255 | VI6_DPR_NODE_UNUSED); | 261 | VI6_DPR_NODE_UNUSED); |
256 | |||
257 | v4l2_subdev_call(&entity->subdev, video, s_stream, 0); | ||
258 | } | 262 | } |
259 | 263 | ||
264 | v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0); | ||
265 | |||
260 | return ret; | 266 | return ret; |
261 | } | 267 | } |
262 | 268 | ||
@@ -271,50 +277,15 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe) | |||
271 | return pipe->buffers_ready == mask; | 277 | return pipe->buffers_ready == mask; |
272 | } | 278 | } |
273 | 279 | ||
274 | void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe) | ||
275 | { | ||
276 | if (pipe->dl) | ||
277 | vsp1_dl_irq_display_start(pipe->dl); | ||
278 | } | ||
279 | |||
280 | void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) | 280 | void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) |
281 | { | 281 | { |
282 | enum vsp1_pipeline_state state; | ||
283 | unsigned long flags; | ||
284 | |||
285 | if (pipe == NULL) | 282 | if (pipe == NULL) |
286 | return; | 283 | return; |
287 | 284 | ||
288 | if (pipe->dl) | 285 | vsp1_dlm_irq_frame_end(pipe->output->dlm); |
289 | vsp1_dl_irq_frame_end(pipe->dl); | ||
290 | 286 | ||
291 | /* Signal frame end to the pipeline handler. */ | 287 | if (pipe->frame_end) |
292 | pipe->frame_end(pipe); | 288 | pipe->frame_end(pipe); |
293 | |||
294 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
295 | |||
296 | state = pipe->state; | ||
297 | |||
298 | /* When using display lists in continuous frame mode the pipeline is | ||
299 | * automatically restarted by the hardware. | ||
300 | */ | ||
301 | if (!pipe->dl) | ||
302 | pipe->state = VSP1_PIPELINE_STOPPED; | ||
303 | |||
304 | /* If a stop has been requested, mark the pipeline as stopped and | ||
305 | * return. | ||
306 | */ | ||
307 | if (state == VSP1_PIPELINE_STOPPING) { | ||
308 | wake_up(&pipe->wq); | ||
309 | goto done; | ||
310 | } | ||
311 | |||
312 | /* Restart the pipeline if ready. */ | ||
313 | if (vsp1_pipeline_ready(pipe)) | ||
314 | vsp1_pipeline_run(pipe); | ||
315 | |||
316 | done: | ||
317 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
318 | } | 289 | } |
319 | 290 | ||
320 | /* | 291 | /* |
@@ -324,9 +295,13 @@ done: | |||
324 | * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha | 295 | * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha |
325 | * value. The UDS then outputs a fixed alpha value which needs to be programmed | 296 | * value. The UDS then outputs a fixed alpha value which needs to be programmed |
326 | * from the input RPF alpha. | 297 | * from the input RPF alpha. |
298 | * | ||
299 | * This function can only be called from a subdev s_stream handler as it | ||
300 | * requires a valid display list context. | ||
327 | */ | 301 | */ |
328 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | 302 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, |
329 | struct vsp1_entity *input, | 303 | struct vsp1_entity *input, |
304 | struct vsp1_dl_list *dl, | ||
330 | unsigned int alpha) | 305 | unsigned int alpha) |
331 | { | 306 | { |
332 | struct vsp1_entity *entity; | 307 | struct vsp1_entity *entity; |
@@ -349,7 +324,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | |||
349 | if (entity->type == VSP1_ENTITY_UDS) { | 324 | if (entity->type == VSP1_ENTITY_UDS) { |
350 | struct vsp1_uds *uds = to_uds(&entity->subdev); | 325 | struct vsp1_uds *uds = to_uds(&entity->subdev); |
351 | 326 | ||
352 | vsp1_uds_set_alpha(uds, alpha); | 327 | vsp1_uds_set_alpha(uds, dl, alpha); |
353 | break; | 328 | break; |
354 | } | 329 | } |
355 | 330 | ||
@@ -375,7 +350,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1) | |||
375 | if (wpf == NULL) | 350 | if (wpf == NULL) |
376 | continue; | 351 | continue; |
377 | 352 | ||
378 | pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); | 353 | pipe = wpf->pipe; |
379 | if (pipe == NULL) | 354 | if (pipe == NULL) |
380 | continue; | 355 | continue; |
381 | 356 | ||
@@ -392,7 +367,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1) | |||
392 | if (wpf == NULL) | 367 | if (wpf == NULL) |
393 | continue; | 368 | continue; |
394 | 369 | ||
395 | pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); | 370 | pipe = wpf->pipe; |
396 | if (pipe == NULL) | 371 | if (pipe == NULL) |
397 | continue; | 372 | continue; |
398 | 373 | ||
@@ -416,7 +391,7 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1) | |||
416 | if (wpf == NULL) | 391 | if (wpf == NULL) |
417 | continue; | 392 | continue; |
418 | 393 | ||
419 | pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); | 394 | pipe = wpf->pipe; |
420 | if (pipe == NULL) | 395 | if (pipe == NULL) |
421 | continue; | 396 | continue; |
422 | 397 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index b2f3a8a896c9..7b56113511dd 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h | |||
@@ -13,13 +13,14 @@ | |||
13 | #ifndef __VSP1_PIPE_H__ | 13 | #ifndef __VSP1_PIPE_H__ |
14 | #define __VSP1_PIPE_H__ | 14 | #define __VSP1_PIPE_H__ |
15 | 15 | ||
16 | #include <linux/kref.h> | ||
16 | #include <linux/list.h> | 17 | #include <linux/list.h> |
17 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
18 | #include <linux/wait.h> | 19 | #include <linux/wait.h> |
19 | 20 | ||
20 | #include <media/media-entity.h> | 21 | #include <media/media-entity.h> |
21 | 22 | ||
22 | struct vsp1_dl; | 23 | struct vsp1_dl_list; |
23 | struct vsp1_rwpf; | 24 | struct vsp1_rwpf; |
24 | 25 | ||
25 | /* | 26 | /* |
@@ -63,7 +64,7 @@ enum vsp1_pipeline_state { | |||
63 | * @wq: work queue to wait for state change completion | 64 | * @wq: work queue to wait for state change completion |
64 | * @frame_end: frame end interrupt handler | 65 | * @frame_end: frame end interrupt handler |
65 | * @lock: protects the pipeline use count and stream count | 66 | * @lock: protects the pipeline use count and stream count |
66 | * @use_count: number of video nodes using the pipeline | 67 | * @kref: pipeline reference count |
67 | * @stream_count: number of streaming video nodes | 68 | * @stream_count: number of streaming video nodes |
68 | * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available | 69 | * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available |
69 | * @num_inputs: number of RPFs | 70 | * @num_inputs: number of RPFs |
@@ -86,7 +87,7 @@ struct vsp1_pipeline { | |||
86 | void (*frame_end)(struct vsp1_pipeline *pipe); | 87 | void (*frame_end)(struct vsp1_pipeline *pipe); |
87 | 88 | ||
88 | struct mutex lock; | 89 | struct mutex lock; |
89 | unsigned int use_count; | 90 | struct kref kref; |
90 | unsigned int stream_count; | 91 | unsigned int stream_count; |
91 | unsigned int buffers_ready; | 92 | unsigned int buffers_ready; |
92 | 93 | ||
@@ -100,17 +101,9 @@ struct vsp1_pipeline { | |||
100 | 101 | ||
101 | struct list_head entities; | 102 | struct list_head entities; |
102 | 103 | ||
103 | struct vsp1_dl *dl; | 104 | struct vsp1_dl_list *dl; |
104 | }; | 105 | }; |
105 | 106 | ||
106 | static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e) | ||
107 | { | ||
108 | if (likely(e->pipe)) | ||
109 | return container_of(e->pipe, struct vsp1_pipeline, pipe); | ||
110 | else | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); | 107 | void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); |
115 | void vsp1_pipeline_init(struct vsp1_pipeline *pipe); | 108 | void vsp1_pipeline_init(struct vsp1_pipeline *pipe); |
116 | 109 | ||
@@ -119,11 +112,11 @@ bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe); | |||
119 | int vsp1_pipeline_stop(struct vsp1_pipeline *pipe); | 112 | int vsp1_pipeline_stop(struct vsp1_pipeline *pipe); |
120 | bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe); | 113 | bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe); |
121 | 114 | ||
122 | void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe); | ||
123 | void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); | 115 | void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); |
124 | 116 | ||
125 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | 117 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, |
126 | struct vsp1_entity *input, | 118 | struct vsp1_entity *input, |
119 | struct vsp1_dl_list *dl, | ||
127 | unsigned int alpha); | 120 | unsigned int alpha); |
128 | 121 | ||
129 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1); | 122 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1); |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 069216f0eb44..927b5fb94c48 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h | |||
@@ -217,6 +217,16 @@ | |||
217 | #define VI6_RPF_SRCM_ADDR_C1 0x0344 | 217 | #define VI6_RPF_SRCM_ADDR_C1 0x0344 |
218 | #define VI6_RPF_SRCM_ADDR_AI 0x0348 | 218 | #define VI6_RPF_SRCM_ADDR_AI 0x0348 |
219 | 219 | ||
220 | #define VI6_RPF_MULT_ALPHA 0x036c | ||
221 | #define VI6_RPF_MULT_ALPHA_A_MMD_NONE (0 << 12) | ||
222 | #define VI6_RPF_MULT_ALPHA_A_MMD_RATIO (1 << 12) | ||
223 | #define VI6_RPF_MULT_ALPHA_P_MMD_NONE (0 << 8) | ||
224 | #define VI6_RPF_MULT_ALPHA_P_MMD_RATIO (1 << 8) | ||
225 | #define VI6_RPF_MULT_ALPHA_P_MMD_IMAGE (2 << 8) | ||
226 | #define VI6_RPF_MULT_ALPHA_P_MMD_BOTH (3 << 8) | ||
227 | #define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff < 0) | ||
228 | #define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0 | ||
229 | |||
220 | /* ----------------------------------------------------------------------------- | 230 | /* ----------------------------------------------------------------------------- |
221 | * WPF Control Registers | 231 | * WPF Control Registers |
222 | */ | 232 | */ |
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 5bc1d1574a43..49168db3f529 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <media/v4l2-subdev.h> | 16 | #include <media/v4l2-subdev.h> |
17 | 17 | ||
18 | #include "vsp1.h" | 18 | #include "vsp1.h" |
19 | #include "vsp1_dl.h" | ||
20 | #include "vsp1_pipe.h" | ||
19 | #include "vsp1_rwpf.h" | 21 | #include "vsp1_rwpf.h" |
20 | #include "vsp1_video.h" | 22 | #include "vsp1_video.h" |
21 | 23 | ||
@@ -26,64 +28,50 @@ | |||
26 | * Device Access | 28 | * Device Access |
27 | */ | 29 | */ |
28 | 30 | ||
29 | static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data) | 31 | static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, |
32 | struct vsp1_dl_list *dl, u32 reg, u32 data) | ||
30 | { | 33 | { |
31 | vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET, | 34 | vsp1_dl_list_write(dl, reg + rpf->entity.index * VI6_RPF_OFFSET, data); |
32 | data); | ||
33 | } | 35 | } |
34 | 36 | ||
35 | /* ----------------------------------------------------------------------------- | 37 | /* ----------------------------------------------------------------------------- |
36 | * Controls | 38 | * V4L2 Subdevice Operations |
37 | */ | 39 | */ |
38 | 40 | ||
39 | static int rpf_s_ctrl(struct v4l2_ctrl *ctrl) | 41 | static struct v4l2_subdev_ops rpf_ops = { |
40 | { | 42 | .pad = &vsp1_rwpf_pad_ops, |
41 | struct vsp1_rwpf *rpf = | ||
42 | container_of(ctrl->handler, struct vsp1_rwpf, ctrls); | ||
43 | struct vsp1_pipeline *pipe; | ||
44 | |||
45 | if (!vsp1_entity_is_streaming(&rpf->entity)) | ||
46 | return 0; | ||
47 | |||
48 | switch (ctrl->id) { | ||
49 | case V4L2_CID_ALPHA_COMPONENT: | ||
50 | vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET, | ||
51 | ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); | ||
52 | |||
53 | pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity); | ||
54 | vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val); | ||
55 | break; | ||
56 | } | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static const struct v4l2_ctrl_ops rpf_ctrl_ops = { | ||
62 | .s_ctrl = rpf_s_ctrl, | ||
63 | }; | 43 | }; |
64 | 44 | ||
65 | /* ----------------------------------------------------------------------------- | 45 | /* ----------------------------------------------------------------------------- |
66 | * V4L2 Subdevice Core Operations | 46 | * VSP1 Entity Operations |
67 | */ | 47 | */ |
68 | 48 | ||
69 | static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) | 49 | static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) |
50 | { | ||
51 | struct vsp1_rwpf *rpf = entity_to_rwpf(entity); | ||
52 | |||
53 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y, | ||
54 | rpf->mem.addr[0] + rpf->offsets[0]); | ||
55 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0, | ||
56 | rpf->mem.addr[1] + rpf->offsets[1]); | ||
57 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1, | ||
58 | rpf->mem.addr[2] + rpf->offsets[1]); | ||
59 | } | ||
60 | |||
61 | static void rpf_configure(struct vsp1_entity *entity, | ||
62 | struct vsp1_pipeline *pipe, | ||
63 | struct vsp1_dl_list *dl) | ||
70 | { | 64 | { |
71 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity); | 65 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); |
72 | struct vsp1_rwpf *rpf = to_rwpf(subdev); | ||
73 | struct vsp1_device *vsp1 = rpf->entity.vsp1; | ||
74 | const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; | 66 | const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; |
75 | const struct v4l2_pix_format_mplane *format = &rpf->format; | 67 | const struct v4l2_pix_format_mplane *format = &rpf->format; |
76 | const struct v4l2_rect *crop = &rpf->crop; | 68 | const struct v4l2_mbus_framefmt *source_format; |
69 | const struct v4l2_mbus_framefmt *sink_format; | ||
70 | const struct v4l2_rect *crop; | ||
71 | unsigned int left = 0; | ||
72 | unsigned int top = 0; | ||
77 | u32 pstride; | 73 | u32 pstride; |
78 | u32 infmt; | 74 | u32 infmt; |
79 | int ret; | ||
80 | |||
81 | ret = vsp1_entity_set_streaming(&rpf->entity, enable); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | |||
85 | if (!enable) | ||
86 | return 0; | ||
87 | 75 | ||
88 | /* Source size, stride and crop offsets. | 76 | /* Source size, stride and crop offsets. |
89 | * | 77 | * |
@@ -91,10 +79,12 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
91 | * left corner in the plane buffer. Only two offsets are needed, as | 79 | * left corner in the plane buffer. Only two offsets are needed, as |
92 | * planes 2 and 3 always have identical strides. | 80 | * planes 2 and 3 always have identical strides. |
93 | */ | 81 | */ |
94 | vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE, | 82 | crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config); |
83 | |||
84 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, | ||
95 | (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | | 85 | (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | |
96 | (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); | 86 | (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); |
97 | vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE, | 87 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE, |
98 | (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | | 88 | (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | |
99 | (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); | 89 | (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); |
100 | 90 | ||
@@ -103,26 +93,25 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
103 | pstride = format->plane_fmt[0].bytesperline | 93 | pstride = format->plane_fmt[0].bytesperline |
104 | << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; | 94 | << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; |
105 | 95 | ||
106 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, | ||
107 | rpf->buf_addr[0] + rpf->offsets[0]); | ||
108 | |||
109 | if (format->num_planes > 1) { | 96 | if (format->num_planes > 1) { |
110 | rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline | 97 | rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline |
111 | + crop->left * fmtinfo->bpp[1] / 8; | 98 | + crop->left * fmtinfo->bpp[1] / 8; |
112 | pstride |= format->plane_fmt[1].bytesperline | 99 | pstride |= format->plane_fmt[1].bytesperline |
113 | << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; | 100 | << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; |
114 | 101 | } else { | |
115 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, | 102 | rpf->offsets[1] = 0; |
116 | rpf->buf_addr[1] + rpf->offsets[1]); | ||
117 | |||
118 | if (format->num_planes > 2) | ||
119 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, | ||
120 | rpf->buf_addr[2] + rpf->offsets[1]); | ||
121 | } | 103 | } |
122 | 104 | ||
123 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride); | 105 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride); |
124 | 106 | ||
125 | /* Format */ | 107 | /* Format */ |
108 | sink_format = vsp1_entity_get_pad_format(&rpf->entity, | ||
109 | rpf->entity.config, | ||
110 | RWPF_PAD_SINK); | ||
111 | source_format = vsp1_entity_get_pad_format(&rpf->entity, | ||
112 | rpf->entity.config, | ||
113 | RWPF_PAD_SOURCE); | ||
114 | |||
126 | infmt = VI6_RPF_INFMT_CIPM | 115 | infmt = VI6_RPF_INFMT_CIPM |
127 | | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); | 116 | | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); |
128 | 117 | ||
@@ -131,88 +120,98 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
131 | if (fmtinfo->swap_uv) | 120 | if (fmtinfo->swap_uv) |
132 | infmt |= VI6_RPF_INFMT_SPUVS; | 121 | infmt |= VI6_RPF_INFMT_SPUVS; |
133 | 122 | ||
134 | if (rpf->entity.formats[RWPF_PAD_SINK].code != | 123 | if (sink_format->code != source_format->code) |
135 | rpf->entity.formats[RWPF_PAD_SOURCE].code) | ||
136 | infmt |= VI6_RPF_INFMT_CSC; | 124 | infmt |= VI6_RPF_INFMT_CSC; |
137 | 125 | ||
138 | vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); | 126 | vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt); |
139 | vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); | 127 | vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap); |
140 | 128 | ||
141 | /* Output location */ | 129 | /* Output location */ |
142 | vsp1_rpf_write(rpf, VI6_RPF_LOC, | 130 | if (pipe->bru) { |
143 | (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) | | 131 | const struct v4l2_rect *compose; |
144 | (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT)); | 132 | |
133 | compose = vsp1_entity_get_pad_compose(pipe->bru, | ||
134 | pipe->bru->config, | ||
135 | rpf->bru_input); | ||
136 | left = compose->left; | ||
137 | top = compose->top; | ||
138 | } | ||
145 | 139 | ||
146 | /* Use the alpha channel (extended to 8 bits) when available or an | 140 | vsp1_rpf_write(rpf, dl, VI6_RPF_LOC, |
147 | * alpha value set through the V4L2_CID_ALPHA_COMPONENT control | 141 | (left << VI6_RPF_LOC_HCOORD_SHIFT) | |
148 | * otherwise. Disable color keying. | 142 | (top << VI6_RPF_LOC_VCOORD_SHIFT)); |
143 | |||
144 | /* On Gen2 use the alpha channel (extended to 8 bits) when available or | ||
145 | * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control | ||
146 | * otherwise. | ||
147 | * | ||
148 | * The Gen3 RPF has extended alpha capability and can both multiply the | ||
149 | * alpha channel by a fixed global alpha value, and multiply the pixel | ||
150 | * components to convert the input to premultiplied alpha. | ||
151 | * | ||
152 | * As alpha premultiplication is available in the BRU for both Gen2 and | ||
153 | * Gen3 we handle it there and use the Gen3 alpha multiplier for global | ||
154 | * alpha multiplication only. This however prevents conversion to | ||
155 | * premultiplied alpha if no BRU is present in the pipeline. If that use | ||
156 | * case turns out to be useful we will revisit the implementation (for | ||
157 | * Gen3 only). | ||
158 | * | ||
159 | * We enable alpha multiplication on Gen3 using the fixed alpha value | ||
160 | * set through the V4L2_CID_ALPHA_COMPONENT control when the input | ||
161 | * contains an alpha channel. On Gen2 the global alpha is ignored in | ||
162 | * that case. | ||
163 | * | ||
164 | * In all cases, disable color keying. | ||
149 | */ | 165 | */ |
150 | vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | | 166 | vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | |
151 | (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED | 167 | (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED |
152 | : VI6_RPF_ALPH_SEL_ASEL_FIXED)); | 168 | : VI6_RPF_ALPH_SEL_ASEL_FIXED)); |
153 | 169 | ||
154 | if (vsp1->info->uapi) | 170 | vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, |
155 | mutex_lock(rpf->ctrls.lock); | 171 | rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); |
156 | vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET, | 172 | |
157 | rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); | 173 | if (entity->vsp1->info->gen == 3) { |
158 | vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val); | 174 | u32 mult; |
159 | if (vsp1->info->uapi) | 175 | |
160 | mutex_unlock(rpf->ctrls.lock); | 176 | if (fmtinfo->alpha) { |
161 | 177 | /* When the input contains an alpha channel enable the | |
162 | vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0); | 178 | * alpha multiplier. If the input is premultiplied we |
163 | vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0); | 179 | * need to multiply both the alpha channel and the pixel |
164 | 180 | * components by the global alpha value to keep them | |
165 | return 0; | 181 | * premultiplied. Otherwise multiply the alpha channel |
166 | } | 182 | * only. |
167 | 183 | */ | |
168 | /* ----------------------------------------------------------------------------- | 184 | bool premultiplied = format->flags |
169 | * V4L2 Subdevice Operations | 185 | & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; |
170 | */ | 186 | |
171 | 187 | mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO | |
172 | static struct v4l2_subdev_video_ops rpf_video_ops = { | 188 | | (premultiplied ? |
173 | .s_stream = rpf_s_stream, | 189 | VI6_RPF_MULT_ALPHA_P_MMD_RATIO : |
174 | }; | 190 | VI6_RPF_MULT_ALPHA_P_MMD_NONE) |
175 | 191 | | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT); | |
176 | static struct v4l2_subdev_pad_ops rpf_pad_ops = { | 192 | } else { |
177 | .enum_mbus_code = vsp1_rwpf_enum_mbus_code, | 193 | /* When the input doesn't contain an alpha channel the |
178 | .enum_frame_size = vsp1_rwpf_enum_frame_size, | 194 | * global alpha value is applied in the unpacking unit, |
179 | .get_fmt = vsp1_rwpf_get_format, | 195 | * the alpha multiplier isn't needed and must be |
180 | .set_fmt = vsp1_rwpf_set_format, | 196 | * disabled. |
181 | .get_selection = vsp1_rwpf_get_selection, | 197 | */ |
182 | .set_selection = vsp1_rwpf_set_selection, | 198 | mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE |
183 | }; | 199 | | VI6_RPF_MULT_ALPHA_P_MMD_NONE; |
200 | } | ||
201 | |||
202 | vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult); | ||
203 | } | ||
184 | 204 | ||
185 | static struct v4l2_subdev_ops rpf_ops = { | 205 | vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha); |
186 | .video = &rpf_video_ops, | ||
187 | .pad = &rpf_pad_ops, | ||
188 | }; | ||
189 | 206 | ||
190 | /* ----------------------------------------------------------------------------- | 207 | vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); |
191 | * Video Device Operations | 208 | vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); |
192 | */ | ||
193 | 209 | ||
194 | static void rpf_set_memory(struct vsp1_rwpf *rpf, struct vsp1_rwpf_memory *mem) | ||
195 | { | ||
196 | unsigned int i; | ||
197 | |||
198 | for (i = 0; i < 3; ++i) | ||
199 | rpf->buf_addr[i] = mem->addr[i]; | ||
200 | |||
201 | if (!vsp1_entity_is_streaming(&rpf->entity)) | ||
202 | return; | ||
203 | |||
204 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, | ||
205 | mem->addr[0] + rpf->offsets[0]); | ||
206 | if (mem->num_planes > 1) | ||
207 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, | ||
208 | mem->addr[1] + rpf->offsets[1]); | ||
209 | if (mem->num_planes > 2) | ||
210 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, | ||
211 | mem->addr[2] + rpf->offsets[1]); | ||
212 | } | 210 | } |
213 | 211 | ||
214 | static const struct vsp1_rwpf_operations rpf_vdev_ops = { | 212 | static const struct vsp1_entity_operations rpf_entity_ops = { |
215 | .set_memory = rpf_set_memory, | 213 | .set_memory = rpf_set_memory, |
214 | .configure = rpf_configure, | ||
216 | }; | 215 | }; |
217 | 216 | ||
218 | /* ----------------------------------------------------------------------------- | 217 | /* ----------------------------------------------------------------------------- |
@@ -221,51 +220,31 @@ static const struct vsp1_rwpf_operations rpf_vdev_ops = { | |||
221 | 220 | ||
222 | struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) | 221 | struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) |
223 | { | 222 | { |
224 | struct v4l2_subdev *subdev; | ||
225 | struct vsp1_rwpf *rpf; | 223 | struct vsp1_rwpf *rpf; |
224 | char name[6]; | ||
226 | int ret; | 225 | int ret; |
227 | 226 | ||
228 | rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL); | 227 | rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL); |
229 | if (rpf == NULL) | 228 | if (rpf == NULL) |
230 | return ERR_PTR(-ENOMEM); | 229 | return ERR_PTR(-ENOMEM); |
231 | 230 | ||
232 | rpf->ops = &rpf_vdev_ops; | ||
233 | |||
234 | rpf->max_width = RPF_MAX_WIDTH; | 231 | rpf->max_width = RPF_MAX_WIDTH; |
235 | rpf->max_height = RPF_MAX_HEIGHT; | 232 | rpf->max_height = RPF_MAX_HEIGHT; |
236 | 233 | ||
234 | rpf->entity.ops = &rpf_entity_ops; | ||
237 | rpf->entity.type = VSP1_ENTITY_RPF; | 235 | rpf->entity.type = VSP1_ENTITY_RPF; |
238 | rpf->entity.index = index; | 236 | rpf->entity.index = index; |
239 | 237 | ||
240 | ret = vsp1_entity_init(vsp1, &rpf->entity, 2); | 238 | sprintf(name, "rpf.%u", index); |
239 | ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops); | ||
241 | if (ret < 0) | 240 | if (ret < 0) |
242 | return ERR_PTR(ret); | 241 | return ERR_PTR(ret); |
243 | 242 | ||
244 | /* Initialize the V4L2 subdev. */ | ||
245 | subdev = &rpf->entity.subdev; | ||
246 | v4l2_subdev_init(subdev, &rpf_ops); | ||
247 | |||
248 | subdev->entity.ops = &vsp1->media_ops; | ||
249 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
250 | snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u", | ||
251 | dev_name(vsp1->dev), index); | ||
252 | v4l2_set_subdevdata(subdev, rpf); | ||
253 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
254 | |||
255 | vsp1_entity_init_formats(subdev, NULL); | ||
256 | |||
257 | /* Initialize the control handler. */ | 243 | /* Initialize the control handler. */ |
258 | v4l2_ctrl_handler_init(&rpf->ctrls, 1); | 244 | ret = vsp1_rwpf_init_ctrls(rpf); |
259 | rpf->alpha = v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops, | 245 | if (ret < 0) { |
260 | V4L2_CID_ALPHA_COMPONENT, | ||
261 | 0, 255, 1, 255); | ||
262 | |||
263 | rpf->entity.subdev.ctrl_handler = &rpf->ctrls; | ||
264 | |||
265 | if (rpf->ctrls.error) { | ||
266 | dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", | 246 | dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", |
267 | index); | 247 | index); |
268 | ret = rpf->ctrls.error; | ||
269 | goto error; | 248 | goto error; |
270 | } | 249 | } |
271 | 250 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 9688c219b30e..3b6e032e7806 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c | |||
@@ -20,13 +20,20 @@ | |||
20 | #define RWPF_MIN_WIDTH 1 | 20 | #define RWPF_MIN_WIDTH 1 |
21 | #define RWPF_MIN_HEIGHT 1 | 21 | #define RWPF_MIN_HEIGHT 1 |
22 | 22 | ||
23 | struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, | ||
24 | struct v4l2_subdev_pad_config *config) | ||
25 | { | ||
26 | return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config, | ||
27 | RWPF_PAD_SINK); | ||
28 | } | ||
29 | |||
23 | /* ----------------------------------------------------------------------------- | 30 | /* ----------------------------------------------------------------------------- |
24 | * V4L2 Subdevice Pad Operations | 31 | * V4L2 Subdevice Pad Operations |
25 | */ | 32 | */ |
26 | 33 | ||
27 | int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, | 34 | static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, |
28 | struct v4l2_subdev_pad_config *cfg, | 35 | struct v4l2_subdev_pad_config *cfg, |
29 | struct v4l2_subdev_mbus_code_enum *code) | 36 | struct v4l2_subdev_mbus_code_enum *code) |
30 | { | 37 | { |
31 | static const unsigned int codes[] = { | 38 | static const unsigned int codes[] = { |
32 | MEDIA_BUS_FMT_ARGB8888_1X32, | 39 | MEDIA_BUS_FMT_ARGB8888_1X32, |
@@ -41,75 +48,36 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, | |||
41 | return 0; | 48 | return 0; |
42 | } | 49 | } |
43 | 50 | ||
44 | int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, | 51 | static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, |
45 | struct v4l2_subdev_pad_config *cfg, | 52 | struct v4l2_subdev_pad_config *cfg, |
46 | struct v4l2_subdev_frame_size_enum *fse) | 53 | struct v4l2_subdev_frame_size_enum *fse) |
47 | { | ||
48 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | ||
49 | struct v4l2_mbus_framefmt *format; | ||
50 | |||
51 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad, | ||
52 | fse->which); | ||
53 | |||
54 | if (fse->index || fse->code != format->code) | ||
55 | return -EINVAL; | ||
56 | |||
57 | if (fse->pad == RWPF_PAD_SINK) { | ||
58 | fse->min_width = RWPF_MIN_WIDTH; | ||
59 | fse->max_width = rwpf->max_width; | ||
60 | fse->min_height = RWPF_MIN_HEIGHT; | ||
61 | fse->max_height = rwpf->max_height; | ||
62 | } else { | ||
63 | /* The size on the source pad are fixed and always identical to | ||
64 | * the size on the sink pad. | ||
65 | */ | ||
66 | fse->min_width = format->width; | ||
67 | fse->max_width = format->width; | ||
68 | fse->min_height = format->height; | ||
69 | fse->max_height = format->height; | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static struct v4l2_rect * | ||
76 | vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which) | ||
77 | { | ||
78 | switch (which) { | ||
79 | case V4L2_SUBDEV_FORMAT_TRY: | ||
80 | return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK); | ||
81 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
82 | return &rwpf->crop; | ||
83 | default: | ||
84 | return NULL; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | ||
89 | struct v4l2_subdev_format *fmt) | ||
90 | { | 54 | { |
91 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 55 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
92 | 56 | ||
93 | fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, | 57 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, RWPF_MIN_WIDTH, |
94 | fmt->which); | 58 | RWPF_MIN_HEIGHT, rwpf->max_width, |
95 | 59 | rwpf->max_height); | |
96 | return 0; | ||
97 | } | 60 | } |
98 | 61 | ||
99 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 62 | static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, |
100 | struct v4l2_subdev_format *fmt) | 63 | struct v4l2_subdev_pad_config *cfg, |
64 | struct v4l2_subdev_format *fmt) | ||
101 | { | 65 | { |
102 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 66 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
67 | struct v4l2_subdev_pad_config *config; | ||
103 | struct v4l2_mbus_framefmt *format; | 68 | struct v4l2_mbus_framefmt *format; |
104 | struct v4l2_rect *crop; | 69 | struct v4l2_rect *crop; |
105 | 70 | ||
71 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which); | ||
72 | if (!config) | ||
73 | return -EINVAL; | ||
74 | |||
106 | /* Default to YUV if the requested format is not supported. */ | 75 | /* Default to YUV if the requested format is not supported. */ |
107 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 76 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
108 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | 77 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) |
109 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | 78 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; |
110 | 79 | ||
111 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, | 80 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad); |
112 | fmt->which); | ||
113 | 81 | ||
114 | if (fmt->pad == RWPF_PAD_SOURCE) { | 82 | if (fmt->pad == RWPF_PAD_SOURCE) { |
115 | /* The RWPF performs format conversion but can't scale, only the | 83 | /* The RWPF performs format conversion but can't scale, only the |
@@ -131,39 +99,44 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_conf | |||
131 | fmt->format = *format; | 99 | fmt->format = *format; |
132 | 100 | ||
133 | /* Update the sink crop rectangle. */ | 101 | /* Update the sink crop rectangle. */ |
134 | crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); | 102 | crop = vsp1_rwpf_get_crop(rwpf, config); |
135 | crop->left = 0; | 103 | crop->left = 0; |
136 | crop->top = 0; | 104 | crop->top = 0; |
137 | crop->width = fmt->format.width; | 105 | crop->width = fmt->format.width; |
138 | crop->height = fmt->format.height; | 106 | crop->height = fmt->format.height; |
139 | 107 | ||
140 | /* Propagate the format to the source pad. */ | 108 | /* Propagate the format to the source pad. */ |
141 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, | 109 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
142 | fmt->which); | 110 | RWPF_PAD_SOURCE); |
143 | *format = fmt->format; | 111 | *format = fmt->format; |
144 | 112 | ||
145 | return 0; | 113 | return 0; |
146 | } | 114 | } |
147 | 115 | ||
148 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | 116 | static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, |
149 | struct v4l2_subdev_pad_config *cfg, | 117 | struct v4l2_subdev_pad_config *cfg, |
150 | struct v4l2_subdev_selection *sel) | 118 | struct v4l2_subdev_selection *sel) |
151 | { | 119 | { |
152 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 120 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
121 | struct v4l2_subdev_pad_config *config; | ||
153 | struct v4l2_mbus_framefmt *format; | 122 | struct v4l2_mbus_framefmt *format; |
154 | 123 | ||
155 | /* Cropping is implemented on the sink pad. */ | 124 | /* Cropping is implemented on the sink pad. */ |
156 | if (sel->pad != RWPF_PAD_SINK) | 125 | if (sel->pad != RWPF_PAD_SINK) |
157 | return -EINVAL; | 126 | return -EINVAL; |
158 | 127 | ||
128 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); | ||
129 | if (!config) | ||
130 | return -EINVAL; | ||
131 | |||
159 | switch (sel->target) { | 132 | switch (sel->target) { |
160 | case V4L2_SEL_TGT_CROP: | 133 | case V4L2_SEL_TGT_CROP: |
161 | sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); | 134 | sel->r = *vsp1_rwpf_get_crop(rwpf, config); |
162 | break; | 135 | break; |
163 | 136 | ||
164 | case V4L2_SEL_TGT_CROP_BOUNDS: | 137 | case V4L2_SEL_TGT_CROP_BOUNDS: |
165 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, | 138 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
166 | RWPF_PAD_SINK, sel->which); | 139 | RWPF_PAD_SINK); |
167 | sel->r.left = 0; | 140 | sel->r.left = 0; |
168 | sel->r.top = 0; | 141 | sel->r.top = 0; |
169 | sel->r.width = format->width; | 142 | sel->r.width = format->width; |
@@ -177,11 +150,12 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | |||
177 | return 0; | 150 | return 0; |
178 | } | 151 | } |
179 | 152 | ||
180 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | 153 | static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, |
181 | struct v4l2_subdev_pad_config *cfg, | 154 | struct v4l2_subdev_pad_config *cfg, |
182 | struct v4l2_subdev_selection *sel) | 155 | struct v4l2_subdev_selection *sel) |
183 | { | 156 | { |
184 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 157 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
158 | struct v4l2_subdev_pad_config *config; | ||
185 | struct v4l2_mbus_framefmt *format; | 159 | struct v4l2_mbus_framefmt *format; |
186 | struct v4l2_rect *crop; | 160 | struct v4l2_rect *crop; |
187 | 161 | ||
@@ -192,11 +166,15 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
192 | if (sel->target != V4L2_SEL_TGT_CROP) | 166 | if (sel->target != V4L2_SEL_TGT_CROP) |
193 | return -EINVAL; | 167 | return -EINVAL; |
194 | 168 | ||
169 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); | ||
170 | if (!config) | ||
171 | return -EINVAL; | ||
172 | |||
195 | /* Make sure the crop rectangle is entirely contained in the image. The | 173 | /* Make sure the crop rectangle is entirely contained in the image. The |
196 | * WPF top and left offsets are limited to 255. | 174 | * WPF top and left offsets are limited to 255. |
197 | */ | 175 | */ |
198 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, | 176 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
199 | sel->which); | 177 | RWPF_PAD_SINK); |
200 | 178 | ||
201 | /* Restrict the crop rectangle coordinates to multiples of 2 to avoid | 179 | /* Restrict the crop rectangle coordinates to multiples of 2 to avoid |
202 | * shifting the color plane. | 180 | * shifting the color plane. |
@@ -219,14 +197,59 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
219 | sel->r.height = min_t(unsigned int, sel->r.height, | 197 | sel->r.height = min_t(unsigned int, sel->r.height, |
220 | format->height - sel->r.top); | 198 | format->height - sel->r.top); |
221 | 199 | ||
222 | crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); | 200 | crop = vsp1_rwpf_get_crop(rwpf, config); |
223 | *crop = sel->r; | 201 | *crop = sel->r; |
224 | 202 | ||
225 | /* Propagate the format to the source pad. */ | 203 | /* Propagate the format to the source pad. */ |
226 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, | 204 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
227 | sel->which); | 205 | RWPF_PAD_SOURCE); |
228 | format->width = crop->width; | 206 | format->width = crop->width; |
229 | format->height = crop->height; | 207 | format->height = crop->height; |
230 | 208 | ||
231 | return 0; | 209 | return 0; |
232 | } | 210 | } |
211 | |||
212 | const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { | ||
213 | .init_cfg = vsp1_entity_init_cfg, | ||
214 | .enum_mbus_code = vsp1_rwpf_enum_mbus_code, | ||
215 | .enum_frame_size = vsp1_rwpf_enum_frame_size, | ||
216 | .get_fmt = vsp1_subdev_get_pad_format, | ||
217 | .set_fmt = vsp1_rwpf_set_format, | ||
218 | .get_selection = vsp1_rwpf_get_selection, | ||
219 | .set_selection = vsp1_rwpf_set_selection, | ||
220 | }; | ||
221 | |||
222 | /* ----------------------------------------------------------------------------- | ||
223 | * Controls | ||
224 | */ | ||
225 | |||
226 | static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl) | ||
227 | { | ||
228 | struct vsp1_rwpf *rwpf = | ||
229 | container_of(ctrl->handler, struct vsp1_rwpf, ctrls); | ||
230 | |||
231 | switch (ctrl->id) { | ||
232 | case V4L2_CID_ALPHA_COMPONENT: | ||
233 | rwpf->alpha = ctrl->val; | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = { | ||
241 | .s_ctrl = vsp1_rwpf_s_ctrl, | ||
242 | }; | ||
243 | |||
244 | int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf) | ||
245 | { | ||
246 | rwpf->alpha = 255; | ||
247 | |||
248 | v4l2_ctrl_handler_init(&rwpf->ctrls, 1); | ||
249 | v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, | ||
250 | V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); | ||
251 | |||
252 | rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls; | ||
253 | |||
254 | return rwpf->ctrls.error; | ||
255 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 8e8235682ada..9ff7c78f239e 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
@@ -24,42 +24,35 @@ | |||
24 | #define RWPF_PAD_SOURCE 1 | 24 | #define RWPF_PAD_SOURCE 1 |
25 | 25 | ||
26 | struct v4l2_ctrl; | 26 | struct v4l2_ctrl; |
27 | struct vsp1_dl_manager; | ||
28 | struct vsp1_pipeline; | ||
27 | struct vsp1_rwpf; | 29 | struct vsp1_rwpf; |
28 | struct vsp1_video; | 30 | struct vsp1_video; |
29 | 31 | ||
30 | struct vsp1_rwpf_memory { | 32 | struct vsp1_rwpf_memory { |
31 | unsigned int num_planes; | ||
32 | dma_addr_t addr[3]; | 33 | dma_addr_t addr[3]; |
33 | unsigned int length[3]; | ||
34 | }; | ||
35 | |||
36 | struct vsp1_rwpf_operations { | ||
37 | void (*set_memory)(struct vsp1_rwpf *rwpf, | ||
38 | struct vsp1_rwpf_memory *mem); | ||
39 | }; | 34 | }; |
40 | 35 | ||
41 | struct vsp1_rwpf { | 36 | struct vsp1_rwpf { |
42 | struct vsp1_entity entity; | 37 | struct vsp1_entity entity; |
43 | struct v4l2_ctrl_handler ctrls; | 38 | struct v4l2_ctrl_handler ctrls; |
44 | struct v4l2_ctrl *alpha; | ||
45 | 39 | ||
40 | struct vsp1_pipeline *pipe; | ||
46 | struct vsp1_video *video; | 41 | struct vsp1_video *video; |
47 | 42 | ||
48 | const struct vsp1_rwpf_operations *ops; | ||
49 | |||
50 | unsigned int max_width; | 43 | unsigned int max_width; |
51 | unsigned int max_height; | 44 | unsigned int max_height; |
52 | 45 | ||
53 | struct v4l2_pix_format_mplane format; | 46 | struct v4l2_pix_format_mplane format; |
54 | const struct vsp1_format_info *fmtinfo; | 47 | const struct vsp1_format_info *fmtinfo; |
55 | struct { | 48 | unsigned int bru_input; |
56 | unsigned int left; | 49 | |
57 | unsigned int top; | 50 | unsigned int alpha; |
58 | } location; | ||
59 | struct v4l2_rect crop; | ||
60 | 51 | ||
61 | unsigned int offsets[2]; | 52 | unsigned int offsets[2]; |
62 | dma_addr_t buf_addr[3]; | 53 | struct vsp1_rwpf_memory mem; |
54 | |||
55 | struct vsp1_dl_manager *dlm; | ||
63 | }; | 56 | }; |
64 | 57 | ||
65 | static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) | 58 | static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) |
@@ -67,24 +60,31 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) | |||
67 | return container_of(subdev, struct vsp1_rwpf, entity.subdev); | 60 | return container_of(subdev, struct vsp1_rwpf, entity.subdev); |
68 | } | 61 | } |
69 | 62 | ||
63 | static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity) | ||
64 | { | ||
65 | return container_of(entity, struct vsp1_rwpf, entity); | ||
66 | } | ||
67 | |||
70 | struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); | 68 | struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); |
71 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); | 69 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); |
72 | 70 | ||
73 | int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, | 71 | int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf); |
74 | struct v4l2_subdev_pad_config *cfg, | 72 | |
75 | struct v4l2_subdev_mbus_code_enum *code); | 73 | extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; |
76 | int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, | 74 | |
77 | struct v4l2_subdev_pad_config *cfg, | 75 | struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, |
78 | struct v4l2_subdev_frame_size_enum *fse); | 76 | struct v4l2_subdev_pad_config *config); |
79 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 77 | /** |
80 | struct v4l2_subdev_format *fmt); | 78 | * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF |
81 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 79 | * @rwpf: the [RW]PF instance |
82 | struct v4l2_subdev_format *fmt); | 80 | * @dl: the display list |
83 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | 81 | * |
84 | struct v4l2_subdev_pad_config *cfg, | 82 | * This function applies the cached memory buffer address to the display list. |
85 | struct v4l2_subdev_selection *sel); | 83 | */ |
86 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | 84 | static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, |
87 | struct v4l2_subdev_pad_config *cfg, | 85 | struct vsp1_dl_list *dl) |
88 | struct v4l2_subdev_selection *sel); | 86 | { |
87 | rwpf->entity.ops->set_memory(&rwpf->entity, dl); | ||
88 | } | ||
89 | 89 | ||
90 | #endif /* __VSP1_RWPF_H__ */ | 90 | #endif /* __VSP1_RWPF_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index cc09efbfb24f..97ef997ae735 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <media/v4l2-subdev.h> | 17 | #include <media/v4l2-subdev.h> |
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | ||
20 | #include "vsp1_sru.h" | 21 | #include "vsp1_sru.h" |
21 | 22 | ||
22 | #define SRU_MIN_SIZE 4U | 23 | #define SRU_MIN_SIZE 4U |
@@ -26,14 +27,10 @@ | |||
26 | * Device Access | 27 | * Device Access |
27 | */ | 28 | */ |
28 | 29 | ||
29 | static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg) | 30 | static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl, |
31 | u32 reg, u32 data) | ||
30 | { | 32 | { |
31 | return vsp1_read(sru->entity.vsp1, reg); | 33 | vsp1_dl_list_write(dl, reg, data); |
32 | } | ||
33 | |||
34 | static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data) | ||
35 | { | ||
36 | vsp1_write(sru->entity.vsp1, reg, data); | ||
37 | } | 34 | } |
38 | 35 | ||
39 | /* ----------------------------------------------------------------------------- | 36 | /* ----------------------------------------------------------------------------- |
@@ -82,20 +79,10 @@ static int sru_s_ctrl(struct v4l2_ctrl *ctrl) | |||
82 | { | 79 | { |
83 | struct vsp1_sru *sru = | 80 | struct vsp1_sru *sru = |
84 | container_of(ctrl->handler, struct vsp1_sru, ctrls); | 81 | container_of(ctrl->handler, struct vsp1_sru, ctrls); |
85 | const struct vsp1_sru_param *param; | ||
86 | u32 value; | ||
87 | 82 | ||
88 | switch (ctrl->id) { | 83 | switch (ctrl->id) { |
89 | case V4L2_CID_VSP1_SRU_INTENSITY: | 84 | case V4L2_CID_VSP1_SRU_INTENSITY: |
90 | param = &vsp1_sru_params[ctrl->val - 1]; | 85 | sru->intensity = ctrl->val; |
91 | |||
92 | value = vsp1_sru_read(sru, VI6_SRU_CTRL0); | ||
93 | value &= ~(VI6_SRU_CTRL0_PARAM0_MASK | | ||
94 | VI6_SRU_CTRL0_PARAM1_MASK); | ||
95 | value |= param->ctrl0; | ||
96 | vsp1_sru_write(sru, VI6_SRU_CTRL0, value); | ||
97 | |||
98 | vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2); | ||
99 | break; | 86 | break; |
100 | } | 87 | } |
101 | 88 | ||
@@ -118,54 +105,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = { | |||
118 | }; | 105 | }; |
119 | 106 | ||
120 | /* ----------------------------------------------------------------------------- | 107 | /* ----------------------------------------------------------------------------- |
121 | * V4L2 Subdevice Core Operations | 108 | * V4L2 Subdevice Operations |
122 | */ | ||
123 | |||
124 | static int sru_s_stream(struct v4l2_subdev *subdev, int enable) | ||
125 | { | ||
126 | struct vsp1_sru *sru = to_sru(subdev); | ||
127 | struct v4l2_mbus_framefmt *input; | ||
128 | struct v4l2_mbus_framefmt *output; | ||
129 | u32 ctrl0; | ||
130 | int ret; | ||
131 | |||
132 | ret = vsp1_entity_set_streaming(&sru->entity, enable); | ||
133 | if (ret < 0) | ||
134 | return ret; | ||
135 | |||
136 | if (!enable) | ||
137 | return 0; | ||
138 | |||
139 | input = &sru->entity.formats[SRU_PAD_SINK]; | ||
140 | output = &sru->entity.formats[SRU_PAD_SOURCE]; | ||
141 | |||
142 | if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) | ||
143 | ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 | ||
144 | | VI6_SRU_CTRL0_PARAM4; | ||
145 | else | ||
146 | ctrl0 = VI6_SRU_CTRL0_PARAM3; | ||
147 | |||
148 | if (input->width != output->width) | ||
149 | ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE; | ||
150 | |||
151 | /* Take the control handler lock to ensure that the CTRL0 value won't be | ||
152 | * changed behind our back by a set control operation. | ||
153 | */ | ||
154 | if (sru->entity.vsp1->info->uapi) | ||
155 | mutex_lock(sru->ctrls.lock); | ||
156 | ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0) | ||
157 | & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK); | ||
158 | vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0); | ||
159 | if (sru->entity.vsp1->info->uapi) | ||
160 | mutex_unlock(sru->ctrls.lock); | ||
161 | |||
162 | vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | /* ----------------------------------------------------------------------------- | ||
168 | * V4L2 Subdevice Pad Operations | ||
169 | */ | 109 | */ |
170 | 110 | ||
171 | static int sru_enum_mbus_code(struct v4l2_subdev *subdev, | 111 | static int sru_enum_mbus_code(struct v4l2_subdev *subdev, |
@@ -176,27 +116,9 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, | |||
176 | MEDIA_BUS_FMT_ARGB8888_1X32, | 116 | MEDIA_BUS_FMT_ARGB8888_1X32, |
177 | MEDIA_BUS_FMT_AYUV8_1X32, | 117 | MEDIA_BUS_FMT_AYUV8_1X32, |
178 | }; | 118 | }; |
179 | struct vsp1_sru *sru = to_sru(subdev); | ||
180 | struct v4l2_mbus_framefmt *format; | ||
181 | |||
182 | if (code->pad == SRU_PAD_SINK) { | ||
183 | if (code->index >= ARRAY_SIZE(codes)) | ||
184 | return -EINVAL; | ||
185 | |||
186 | code->code = codes[code->index]; | ||
187 | } else { | ||
188 | /* The SRU can't perform format conversion, the sink format is | ||
189 | * always identical to the source format. | ||
190 | */ | ||
191 | if (code->index) | ||
192 | return -EINVAL; | ||
193 | 119 | ||
194 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, | 120 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, |
195 | SRU_PAD_SINK, code->which); | 121 | ARRAY_SIZE(codes)); |
196 | code->code = format->code; | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | 122 | } |
201 | 123 | ||
202 | static int sru_enum_frame_size(struct v4l2_subdev *subdev, | 124 | static int sru_enum_frame_size(struct v4l2_subdev *subdev, |
@@ -204,10 +126,14 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, | |||
204 | struct v4l2_subdev_frame_size_enum *fse) | 126 | struct v4l2_subdev_frame_size_enum *fse) |
205 | { | 127 | { |
206 | struct vsp1_sru *sru = to_sru(subdev); | 128 | struct vsp1_sru *sru = to_sru(subdev); |
129 | struct v4l2_subdev_pad_config *config; | ||
207 | struct v4l2_mbus_framefmt *format; | 130 | struct v4l2_mbus_framefmt *format; |
208 | 131 | ||
209 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, | 132 | config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which); |
210 | SRU_PAD_SINK, fse->which); | 133 | if (!config) |
134 | return -EINVAL; | ||
135 | |||
136 | format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK); | ||
211 | 137 | ||
212 | if (fse->index || fse->code != format->code) | 138 | if (fse->index || fse->code != format->code) |
213 | return -EINVAL; | 139 | return -EINVAL; |
@@ -233,20 +159,9 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, | |||
233 | return 0; | 159 | return 0; |
234 | } | 160 | } |
235 | 161 | ||
236 | static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 162 | static void sru_try_format(struct vsp1_sru *sru, |
237 | struct v4l2_subdev_format *fmt) | 163 | struct v4l2_subdev_pad_config *config, |
238 | { | 164 | unsigned int pad, struct v4l2_mbus_framefmt *fmt) |
239 | struct vsp1_sru *sru = to_sru(subdev); | ||
240 | |||
241 | fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, | ||
242 | fmt->which); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg, | ||
248 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | ||
249 | enum v4l2_subdev_format_whence which) | ||
250 | { | 165 | { |
251 | struct v4l2_mbus_framefmt *format; | 166 | struct v4l2_mbus_framefmt *format; |
252 | unsigned int input_area; | 167 | unsigned int input_area; |
@@ -265,8 +180,8 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config * | |||
265 | 180 | ||
266 | case SRU_PAD_SOURCE: | 181 | case SRU_PAD_SOURCE: |
267 | /* The SRU can't perform format conversion. */ | 182 | /* The SRU can't perform format conversion. */ |
268 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, | 183 | format = vsp1_entity_get_pad_format(&sru->entity, config, |
269 | SRU_PAD_SINK, which); | 184 | SRU_PAD_SINK); |
270 | fmt->code = format->code; | 185 | fmt->code = format->code; |
271 | 186 | ||
272 | /* We can upscale by 2 in both direction, but not independently. | 187 | /* We can upscale by 2 in both direction, but not independently. |
@@ -295,57 +210,94 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config * | |||
295 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 210 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
296 | } | 211 | } |
297 | 212 | ||
298 | static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 213 | static int sru_set_format(struct v4l2_subdev *subdev, |
214 | struct v4l2_subdev_pad_config *cfg, | ||
299 | struct v4l2_subdev_format *fmt) | 215 | struct v4l2_subdev_format *fmt) |
300 | { | 216 | { |
301 | struct vsp1_sru *sru = to_sru(subdev); | 217 | struct vsp1_sru *sru = to_sru(subdev); |
218 | struct v4l2_subdev_pad_config *config; | ||
302 | struct v4l2_mbus_framefmt *format; | 219 | struct v4l2_mbus_framefmt *format; |
303 | 220 | ||
304 | sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which); | 221 | config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which); |
222 | if (!config) | ||
223 | return -EINVAL; | ||
224 | |||
225 | sru_try_format(sru, config, fmt->pad, &fmt->format); | ||
305 | 226 | ||
306 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, | 227 | format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad); |
307 | fmt->which); | ||
308 | *format = fmt->format; | 228 | *format = fmt->format; |
309 | 229 | ||
310 | if (fmt->pad == SRU_PAD_SINK) { | 230 | if (fmt->pad == SRU_PAD_SINK) { |
311 | /* Propagate the format to the source pad. */ | 231 | /* Propagate the format to the source pad. */ |
312 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, | 232 | format = vsp1_entity_get_pad_format(&sru->entity, config, |
313 | SRU_PAD_SOURCE, fmt->which); | 233 | SRU_PAD_SOURCE); |
314 | *format = fmt->format; | 234 | *format = fmt->format; |
315 | 235 | ||
316 | sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which); | 236 | sru_try_format(sru, config, SRU_PAD_SOURCE, format); |
317 | } | 237 | } |
318 | 238 | ||
319 | return 0; | 239 | return 0; |
320 | } | 240 | } |
321 | 241 | ||
322 | /* ----------------------------------------------------------------------------- | ||
323 | * V4L2 Subdevice Operations | ||
324 | */ | ||
325 | |||
326 | static struct v4l2_subdev_video_ops sru_video_ops = { | ||
327 | .s_stream = sru_s_stream, | ||
328 | }; | ||
329 | |||
330 | static struct v4l2_subdev_pad_ops sru_pad_ops = { | 242 | static struct v4l2_subdev_pad_ops sru_pad_ops = { |
243 | .init_cfg = vsp1_entity_init_cfg, | ||
331 | .enum_mbus_code = sru_enum_mbus_code, | 244 | .enum_mbus_code = sru_enum_mbus_code, |
332 | .enum_frame_size = sru_enum_frame_size, | 245 | .enum_frame_size = sru_enum_frame_size, |
333 | .get_fmt = sru_get_format, | 246 | .get_fmt = vsp1_subdev_get_pad_format, |
334 | .set_fmt = sru_set_format, | 247 | .set_fmt = sru_set_format, |
335 | }; | 248 | }; |
336 | 249 | ||
337 | static struct v4l2_subdev_ops sru_ops = { | 250 | static struct v4l2_subdev_ops sru_ops = { |
338 | .video = &sru_video_ops, | ||
339 | .pad = &sru_pad_ops, | 251 | .pad = &sru_pad_ops, |
340 | }; | 252 | }; |
341 | 253 | ||
342 | /* ----------------------------------------------------------------------------- | 254 | /* ----------------------------------------------------------------------------- |
255 | * VSP1 Entity Operations | ||
256 | */ | ||
257 | |||
258 | static void sru_configure(struct vsp1_entity *entity, | ||
259 | struct vsp1_pipeline *pipe, | ||
260 | struct vsp1_dl_list *dl) | ||
261 | { | ||
262 | const struct vsp1_sru_param *param; | ||
263 | struct vsp1_sru *sru = to_sru(&entity->subdev); | ||
264 | struct v4l2_mbus_framefmt *input; | ||
265 | struct v4l2_mbus_framefmt *output; | ||
266 | u32 ctrl0; | ||
267 | |||
268 | input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | ||
269 | SRU_PAD_SINK); | ||
270 | output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | ||
271 | SRU_PAD_SOURCE); | ||
272 | |||
273 | if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) | ||
274 | ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 | ||
275 | | VI6_SRU_CTRL0_PARAM4; | ||
276 | else | ||
277 | ctrl0 = VI6_SRU_CTRL0_PARAM3; | ||
278 | |||
279 | if (input->width != output->width) | ||
280 | ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE; | ||
281 | |||
282 | param = &vsp1_sru_params[sru->intensity - 1]; | ||
283 | |||
284 | ctrl0 |= param->ctrl0; | ||
285 | |||
286 | vsp1_sru_write(sru, dl, VI6_SRU_CTRL0, ctrl0); | ||
287 | vsp1_sru_write(sru, dl, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5); | ||
288 | vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2); | ||
289 | } | ||
290 | |||
291 | static const struct vsp1_entity_operations sru_entity_ops = { | ||
292 | .configure = sru_configure, | ||
293 | }; | ||
294 | |||
295 | /* ----------------------------------------------------------------------------- | ||
343 | * Initialization and Cleanup | 296 | * Initialization and Cleanup |
344 | */ | 297 | */ |
345 | 298 | ||
346 | struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) | 299 | struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) |
347 | { | 300 | { |
348 | struct v4l2_subdev *subdev; | ||
349 | struct vsp1_sru *sru; | 301 | struct vsp1_sru *sru; |
350 | int ret; | 302 | int ret; |
351 | 303 | ||
@@ -353,29 +305,19 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) | |||
353 | if (sru == NULL) | 305 | if (sru == NULL) |
354 | return ERR_PTR(-ENOMEM); | 306 | return ERR_PTR(-ENOMEM); |
355 | 307 | ||
308 | sru->entity.ops = &sru_entity_ops; | ||
356 | sru->entity.type = VSP1_ENTITY_SRU; | 309 | sru->entity.type = VSP1_ENTITY_SRU; |
357 | 310 | ||
358 | ret = vsp1_entity_init(vsp1, &sru->entity, 2); | 311 | ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops); |
359 | if (ret < 0) | 312 | if (ret < 0) |
360 | return ERR_PTR(ret); | 313 | return ERR_PTR(ret); |
361 | 314 | ||
362 | /* Initialize the V4L2 subdev. */ | ||
363 | subdev = &sru->entity.subdev; | ||
364 | v4l2_subdev_init(subdev, &sru_ops); | ||
365 | |||
366 | subdev->entity.ops = &vsp1->media_ops; | ||
367 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
368 | snprintf(subdev->name, sizeof(subdev->name), "%s sru", | ||
369 | dev_name(vsp1->dev)); | ||
370 | v4l2_set_subdevdata(subdev, sru); | ||
371 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
372 | |||
373 | vsp1_entity_init_formats(subdev, NULL); | ||
374 | |||
375 | /* Initialize the control handler. */ | 315 | /* Initialize the control handler. */ |
376 | v4l2_ctrl_handler_init(&sru->ctrls, 1); | 316 | v4l2_ctrl_handler_init(&sru->ctrls, 1); |
377 | v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL); | 317 | v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL); |
378 | 318 | ||
319 | sru->intensity = 1; | ||
320 | |||
379 | sru->entity.subdev.ctrl_handler = &sru->ctrls; | 321 | sru->entity.subdev.ctrl_handler = &sru->ctrls; |
380 | 322 | ||
381 | if (sru->ctrls.error) { | 323 | if (sru->ctrls.error) { |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h index b6768bf3dc47..85e241457af2 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.h +++ b/drivers/media/platform/vsp1/vsp1_sru.h | |||
@@ -28,6 +28,8 @@ struct vsp1_sru { | |||
28 | struct vsp1_entity entity; | 28 | struct vsp1_entity entity; |
29 | 29 | ||
30 | struct v4l2_ctrl_handler ctrls; | 30 | struct v4l2_ctrl_handler ctrls; |
31 | |||
32 | unsigned int intensity; | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev) | 35 | static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev) |
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index bba67770cf95..1875e29da184 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <media/v4l2-subdev.h> | 17 | #include <media/v4l2-subdev.h> |
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | ||
20 | #include "vsp1_uds.h" | 21 | #include "vsp1_uds.h" |
21 | 22 | ||
22 | #define UDS_MIN_SIZE 4U | 23 | #define UDS_MIN_SIZE 4U |
@@ -29,19 +30,21 @@ | |||
29 | * Device Access | 30 | * Device Access |
30 | */ | 31 | */ |
31 | 32 | ||
32 | static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data) | 33 | static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl, |
34 | u32 reg, u32 data) | ||
33 | { | 35 | { |
34 | vsp1_write(uds->entity.vsp1, | 36 | vsp1_dl_list_write(dl, reg + uds->entity.index * VI6_UDS_OFFSET, data); |
35 | reg + uds->entity.index * VI6_UDS_OFFSET, data); | ||
36 | } | 37 | } |
37 | 38 | ||
38 | /* ----------------------------------------------------------------------------- | 39 | /* ----------------------------------------------------------------------------- |
39 | * Scaling Computation | 40 | * Scaling Computation |
40 | */ | 41 | */ |
41 | 42 | ||
42 | void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha) | 43 | void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, |
44 | unsigned int alpha) | ||
43 | { | 45 | { |
44 | vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); | 46 | vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, |
47 | alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); | ||
45 | } | 48 | } |
46 | 49 | ||
47 | /* | 50 | /* |
@@ -105,60 +108,6 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output) | |||
105 | } | 108 | } |
106 | 109 | ||
107 | /* ----------------------------------------------------------------------------- | 110 | /* ----------------------------------------------------------------------------- |
108 | * V4L2 Subdevice Core Operations | ||
109 | */ | ||
110 | |||
111 | static int uds_s_stream(struct v4l2_subdev *subdev, int enable) | ||
112 | { | ||
113 | struct vsp1_uds *uds = to_uds(subdev); | ||
114 | const struct v4l2_mbus_framefmt *output; | ||
115 | const struct v4l2_mbus_framefmt *input; | ||
116 | unsigned int hscale; | ||
117 | unsigned int vscale; | ||
118 | bool multitap; | ||
119 | |||
120 | if (!enable) | ||
121 | return 0; | ||
122 | |||
123 | input = &uds->entity.formats[UDS_PAD_SINK]; | ||
124 | output = &uds->entity.formats[UDS_PAD_SOURCE]; | ||
125 | |||
126 | hscale = uds_compute_ratio(input->width, output->width); | ||
127 | vscale = uds_compute_ratio(input->height, output->height); | ||
128 | |||
129 | dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); | ||
130 | |||
131 | /* Multi-tap scaling can't be enabled along with alpha scaling when | ||
132 | * scaling down with a factor lower than or equal to 1/2 in either | ||
133 | * direction. | ||
134 | */ | ||
135 | if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192)) | ||
136 | multitap = false; | ||
137 | else | ||
138 | multitap = true; | ||
139 | |||
140 | vsp1_uds_write(uds, VI6_UDS_CTRL, | ||
141 | (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) | | ||
142 | (multitap ? VI6_UDS_CTRL_BC : 0)); | ||
143 | |||
144 | vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, | ||
145 | (uds_passband_width(hscale) | ||
146 | << VI6_UDS_PASS_BWIDTH_H_SHIFT) | | ||
147 | (uds_passband_width(vscale) | ||
148 | << VI6_UDS_PASS_BWIDTH_V_SHIFT)); | ||
149 | |||
150 | /* Set the scaling ratios and the output size. */ | ||
151 | vsp1_uds_write(uds, VI6_UDS_SCALE, | ||
152 | (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | | ||
153 | (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); | ||
154 | vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE, | ||
155 | (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | | ||
156 | (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | /* ----------------------------------------------------------------------------- | ||
162 | * V4L2 Subdevice Pad Operations | 111 | * V4L2 Subdevice Pad Operations |
163 | */ | 112 | */ |
164 | 113 | ||
@@ -170,28 +119,9 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, | |||
170 | MEDIA_BUS_FMT_ARGB8888_1X32, | 119 | MEDIA_BUS_FMT_ARGB8888_1X32, |
171 | MEDIA_BUS_FMT_AYUV8_1X32, | 120 | MEDIA_BUS_FMT_AYUV8_1X32, |
172 | }; | 121 | }; |
173 | struct vsp1_uds *uds = to_uds(subdev); | ||
174 | |||
175 | if (code->pad == UDS_PAD_SINK) { | ||
176 | if (code->index >= ARRAY_SIZE(codes)) | ||
177 | return -EINVAL; | ||
178 | |||
179 | code->code = codes[code->index]; | ||
180 | } else { | ||
181 | struct v4l2_mbus_framefmt *format; | ||
182 | |||
183 | /* The UDS can't perform format conversion, the sink format is | ||
184 | * always identical to the source format. | ||
185 | */ | ||
186 | if (code->index) | ||
187 | return -EINVAL; | ||
188 | 122 | ||
189 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, | 123 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, |
190 | UDS_PAD_SINK, code->which); | 124 | ARRAY_SIZE(codes)); |
191 | code->code = format->code; | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | 125 | } |
196 | 126 | ||
197 | static int uds_enum_frame_size(struct v4l2_subdev *subdev, | 127 | static int uds_enum_frame_size(struct v4l2_subdev *subdev, |
@@ -199,10 +129,15 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, | |||
199 | struct v4l2_subdev_frame_size_enum *fse) | 129 | struct v4l2_subdev_frame_size_enum *fse) |
200 | { | 130 | { |
201 | struct vsp1_uds *uds = to_uds(subdev); | 131 | struct vsp1_uds *uds = to_uds(subdev); |
132 | struct v4l2_subdev_pad_config *config; | ||
202 | struct v4l2_mbus_framefmt *format; | 133 | struct v4l2_mbus_framefmt *format; |
203 | 134 | ||
204 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, | 135 | config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which); |
205 | UDS_PAD_SINK, fse->which); | 136 | if (!config) |
137 | return -EINVAL; | ||
138 | |||
139 | format = vsp1_entity_get_pad_format(&uds->entity, config, | ||
140 | UDS_PAD_SINK); | ||
206 | 141 | ||
207 | if (fse->index || fse->code != format->code) | 142 | if (fse->index || fse->code != format->code) |
208 | return -EINVAL; | 143 | return -EINVAL; |
@@ -222,20 +157,9 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, | |||
222 | return 0; | 157 | return 0; |
223 | } | 158 | } |
224 | 159 | ||
225 | static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 160 | static void uds_try_format(struct vsp1_uds *uds, |
226 | struct v4l2_subdev_format *fmt) | 161 | struct v4l2_subdev_pad_config *config, |
227 | { | 162 | unsigned int pad, struct v4l2_mbus_framefmt *fmt) |
228 | struct vsp1_uds *uds = to_uds(subdev); | ||
229 | |||
230 | fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, | ||
231 | fmt->which); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg, | ||
237 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | ||
238 | enum v4l2_subdev_format_whence which) | ||
239 | { | 163 | { |
240 | struct v4l2_mbus_framefmt *format; | 164 | struct v4l2_mbus_framefmt *format; |
241 | unsigned int minimum; | 165 | unsigned int minimum; |
@@ -254,8 +178,8 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config * | |||
254 | 178 | ||
255 | case UDS_PAD_SOURCE: | 179 | case UDS_PAD_SOURCE: |
256 | /* The UDS scales but can't perform format conversion. */ | 180 | /* The UDS scales but can't perform format conversion. */ |
257 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, | 181 | format = vsp1_entity_get_pad_format(&uds->entity, config, |
258 | UDS_PAD_SINK, which); | 182 | UDS_PAD_SINK); |
259 | fmt->code = format->code; | 183 | fmt->code = format->code; |
260 | 184 | ||
261 | uds_output_limits(format->width, &minimum, &maximum); | 185 | uds_output_limits(format->width, &minimum, &maximum); |
@@ -269,25 +193,30 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config * | |||
269 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 193 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
270 | } | 194 | } |
271 | 195 | ||
272 | static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, | 196 | static int uds_set_format(struct v4l2_subdev *subdev, |
197 | struct v4l2_subdev_pad_config *cfg, | ||
273 | struct v4l2_subdev_format *fmt) | 198 | struct v4l2_subdev_format *fmt) |
274 | { | 199 | { |
275 | struct vsp1_uds *uds = to_uds(subdev); | 200 | struct vsp1_uds *uds = to_uds(subdev); |
201 | struct v4l2_subdev_pad_config *config; | ||
276 | struct v4l2_mbus_framefmt *format; | 202 | struct v4l2_mbus_framefmt *format; |
277 | 203 | ||
278 | uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which); | 204 | config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which); |
205 | if (!config) | ||
206 | return -EINVAL; | ||
207 | |||
208 | uds_try_format(uds, config, fmt->pad, &fmt->format); | ||
279 | 209 | ||
280 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, | 210 | format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad); |
281 | fmt->which); | ||
282 | *format = fmt->format; | 211 | *format = fmt->format; |
283 | 212 | ||
284 | if (fmt->pad == UDS_PAD_SINK) { | 213 | if (fmt->pad == UDS_PAD_SINK) { |
285 | /* Propagate the format to the source pad. */ | 214 | /* Propagate the format to the source pad. */ |
286 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, | 215 | format = vsp1_entity_get_pad_format(&uds->entity, config, |
287 | UDS_PAD_SOURCE, fmt->which); | 216 | UDS_PAD_SOURCE); |
288 | *format = fmt->format; | 217 | *format = fmt->format; |
289 | 218 | ||
290 | uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which); | 219 | uds_try_format(uds, config, UDS_PAD_SOURCE, format); |
291 | } | 220 | } |
292 | 221 | ||
293 | return 0; | 222 | return 0; |
@@ -297,55 +226,97 @@ static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con | |||
297 | * V4L2 Subdevice Operations | 226 | * V4L2 Subdevice Operations |
298 | */ | 227 | */ |
299 | 228 | ||
300 | static struct v4l2_subdev_video_ops uds_video_ops = { | ||
301 | .s_stream = uds_s_stream, | ||
302 | }; | ||
303 | |||
304 | static struct v4l2_subdev_pad_ops uds_pad_ops = { | 229 | static struct v4l2_subdev_pad_ops uds_pad_ops = { |
230 | .init_cfg = vsp1_entity_init_cfg, | ||
305 | .enum_mbus_code = uds_enum_mbus_code, | 231 | .enum_mbus_code = uds_enum_mbus_code, |
306 | .enum_frame_size = uds_enum_frame_size, | 232 | .enum_frame_size = uds_enum_frame_size, |
307 | .get_fmt = uds_get_format, | 233 | .get_fmt = vsp1_subdev_get_pad_format, |
308 | .set_fmt = uds_set_format, | 234 | .set_fmt = uds_set_format, |
309 | }; | 235 | }; |
310 | 236 | ||
311 | static struct v4l2_subdev_ops uds_ops = { | 237 | static struct v4l2_subdev_ops uds_ops = { |
312 | .video = &uds_video_ops, | ||
313 | .pad = &uds_pad_ops, | 238 | .pad = &uds_pad_ops, |
314 | }; | 239 | }; |
315 | 240 | ||
316 | /* ----------------------------------------------------------------------------- | 241 | /* ----------------------------------------------------------------------------- |
242 | * VSP1 Entity Operations | ||
243 | */ | ||
244 | |||
245 | static void uds_configure(struct vsp1_entity *entity, | ||
246 | struct vsp1_pipeline *pipe, | ||
247 | struct vsp1_dl_list *dl) | ||
248 | { | ||
249 | struct vsp1_uds *uds = to_uds(&entity->subdev); | ||
250 | const struct v4l2_mbus_framefmt *output; | ||
251 | const struct v4l2_mbus_framefmt *input; | ||
252 | unsigned int hscale; | ||
253 | unsigned int vscale; | ||
254 | bool multitap; | ||
255 | |||
256 | input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | ||
257 | UDS_PAD_SINK); | ||
258 | output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | ||
259 | UDS_PAD_SOURCE); | ||
260 | |||
261 | hscale = uds_compute_ratio(input->width, output->width); | ||
262 | vscale = uds_compute_ratio(input->height, output->height); | ||
263 | |||
264 | dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); | ||
265 | |||
266 | /* Multi-tap scaling can't be enabled along with alpha scaling when | ||
267 | * scaling down with a factor lower than or equal to 1/2 in either | ||
268 | * direction. | ||
269 | */ | ||
270 | if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192)) | ||
271 | multitap = false; | ||
272 | else | ||
273 | multitap = true; | ||
274 | |||
275 | vsp1_uds_write(uds, dl, VI6_UDS_CTRL, | ||
276 | (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) | | ||
277 | (multitap ? VI6_UDS_CTRL_BC : 0)); | ||
278 | |||
279 | vsp1_uds_write(uds, dl, VI6_UDS_PASS_BWIDTH, | ||
280 | (uds_passband_width(hscale) | ||
281 | << VI6_UDS_PASS_BWIDTH_H_SHIFT) | | ||
282 | (uds_passband_width(vscale) | ||
283 | << VI6_UDS_PASS_BWIDTH_V_SHIFT)); | ||
284 | |||
285 | /* Set the scaling ratios and the output size. */ | ||
286 | vsp1_uds_write(uds, dl, VI6_UDS_SCALE, | ||
287 | (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | | ||
288 | (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); | ||
289 | vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE, | ||
290 | (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | | ||
291 | (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); | ||
292 | } | ||
293 | |||
294 | static const struct vsp1_entity_operations uds_entity_ops = { | ||
295 | .configure = uds_configure, | ||
296 | }; | ||
297 | |||
298 | /* ----------------------------------------------------------------------------- | ||
317 | * Initialization and Cleanup | 299 | * Initialization and Cleanup |
318 | */ | 300 | */ |
319 | 301 | ||
320 | struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) | 302 | struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) |
321 | { | 303 | { |
322 | struct v4l2_subdev *subdev; | ||
323 | struct vsp1_uds *uds; | 304 | struct vsp1_uds *uds; |
305 | char name[6]; | ||
324 | int ret; | 306 | int ret; |
325 | 307 | ||
326 | uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL); | 308 | uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL); |
327 | if (uds == NULL) | 309 | if (uds == NULL) |
328 | return ERR_PTR(-ENOMEM); | 310 | return ERR_PTR(-ENOMEM); |
329 | 311 | ||
312 | uds->entity.ops = &uds_entity_ops; | ||
330 | uds->entity.type = VSP1_ENTITY_UDS; | 313 | uds->entity.type = VSP1_ENTITY_UDS; |
331 | uds->entity.index = index; | 314 | uds->entity.index = index; |
332 | 315 | ||
333 | ret = vsp1_entity_init(vsp1, &uds->entity, 2); | 316 | sprintf(name, "uds.%u", index); |
317 | ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops); | ||
334 | if (ret < 0) | 318 | if (ret < 0) |
335 | return ERR_PTR(ret); | 319 | return ERR_PTR(ret); |
336 | 320 | ||
337 | /* Initialize the V4L2 subdev. */ | ||
338 | subdev = &uds->entity.subdev; | ||
339 | v4l2_subdev_init(subdev, &uds_ops); | ||
340 | |||
341 | subdev->entity.ops = &vsp1->media_ops; | ||
342 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
343 | snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u", | ||
344 | dev_name(vsp1->dev), index); | ||
345 | v4l2_set_subdevdata(subdev, uds); | ||
346 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
347 | |||
348 | vsp1_entity_init_formats(subdev, NULL); | ||
349 | |||
350 | return uds; | 321 | return uds; |
351 | } | 322 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h index 031ac0da1b66..5c8cbfcad4cc 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.h +++ b/drivers/media/platform/vsp1/vsp1_uds.h | |||
@@ -35,6 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev) | |||
35 | 35 | ||
36 | struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index); | 36 | struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index); |
37 | 37 | ||
38 | void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha); | 38 | void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, |
39 | unsigned int alpha); | ||
39 | 40 | ||
40 | #endif /* __VSP1_UDS_H__ */ | 41 | #endif /* __VSP1_UDS_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 72cc7d3729f8..a9aec5c0bec6 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include "vsp1.h" | 30 | #include "vsp1.h" |
31 | #include "vsp1_bru.h" | 31 | #include "vsp1_bru.h" |
32 | #include "vsp1_dl.h" | ||
32 | #include "vsp1_entity.h" | 33 | #include "vsp1_entity.h" |
33 | #include "vsp1_pipe.h" | 34 | #include "vsp1_pipe.h" |
34 | #include "vsp1_rwpf.h" | 35 | #include "vsp1_rwpf.h" |
@@ -171,53 +172,178 @@ static int __vsp1_video_try_format(struct vsp1_video *video, | |||
171 | * Pipeline Management | 172 | * Pipeline Management |
172 | */ | 173 | */ |
173 | 174 | ||
174 | static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe, | 175 | /* |
175 | struct vsp1_rwpf *input, | 176 | * vsp1_video_complete_buffer - Complete the current buffer |
176 | struct vsp1_rwpf *output) | 177 | * @video: the video node |
178 | * | ||
179 | * This function completes the current buffer by filling its sequence number, | ||
180 | * time stamp and payload size, and hands it back to the videobuf core. | ||
181 | * | ||
182 | * When operating in DU output mode (deep pipeline to the DU through the LIF), | ||
183 | * the VSP1 needs to constantly supply frames to the display. In that case, if | ||
184 | * no other buffer is queued, reuse the one that has just been processed instead | ||
185 | * of handing it back to the videobuf core. | ||
186 | * | ||
187 | * Return the next queued buffer or NULL if the queue is empty. | ||
188 | */ | ||
189 | static struct vsp1_vb2_buffer * | ||
190 | vsp1_video_complete_buffer(struct vsp1_video *video) | ||
191 | { | ||
192 | struct vsp1_pipeline *pipe = video->rwpf->pipe; | ||
193 | struct vsp1_vb2_buffer *next = NULL; | ||
194 | struct vsp1_vb2_buffer *done; | ||
195 | unsigned long flags; | ||
196 | unsigned int i; | ||
197 | |||
198 | spin_lock_irqsave(&video->irqlock, flags); | ||
199 | |||
200 | if (list_empty(&video->irqqueue)) { | ||
201 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
202 | return NULL; | ||
203 | } | ||
204 | |||
205 | done = list_first_entry(&video->irqqueue, | ||
206 | struct vsp1_vb2_buffer, queue); | ||
207 | |||
208 | /* In DU output mode reuse the buffer if the list is singular. */ | ||
209 | if (pipe->lif && list_is_singular(&video->irqqueue)) { | ||
210 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
211 | return done; | ||
212 | } | ||
213 | |||
214 | list_del(&done->queue); | ||
215 | |||
216 | if (!list_empty(&video->irqqueue)) | ||
217 | next = list_first_entry(&video->irqqueue, | ||
218 | struct vsp1_vb2_buffer, queue); | ||
219 | |||
220 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
221 | |||
222 | done->buf.sequence = video->sequence++; | ||
223 | done->buf.vb2_buf.timestamp = ktime_get_ns(); | ||
224 | for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) | ||
225 | vb2_set_plane_payload(&done->buf.vb2_buf, i, | ||
226 | vb2_plane_size(&done->buf.vb2_buf, i)); | ||
227 | vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); | ||
228 | |||
229 | return next; | ||
230 | } | ||
231 | |||
232 | static void vsp1_video_frame_end(struct vsp1_pipeline *pipe, | ||
233 | struct vsp1_rwpf *rwpf) | ||
234 | { | ||
235 | struct vsp1_video *video = rwpf->video; | ||
236 | struct vsp1_vb2_buffer *buf; | ||
237 | unsigned long flags; | ||
238 | |||
239 | buf = vsp1_video_complete_buffer(video); | ||
240 | if (buf == NULL) | ||
241 | return; | ||
242 | |||
243 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
244 | |||
245 | video->rwpf->mem = buf->mem; | ||
246 | pipe->buffers_ready |= 1 << video->pipe_index; | ||
247 | |||
248 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
249 | } | ||
250 | |||
251 | static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) | ||
252 | { | ||
253 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | ||
254 | unsigned int i; | ||
255 | |||
256 | if (!pipe->dl) | ||
257 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); | ||
258 | |||
259 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | ||
260 | struct vsp1_rwpf *rwpf = pipe->inputs[i]; | ||
261 | |||
262 | if (rwpf) | ||
263 | vsp1_rwpf_set_memory(rwpf, pipe->dl); | ||
264 | } | ||
265 | |||
266 | if (!pipe->lif) | ||
267 | vsp1_rwpf_set_memory(pipe->output, pipe->dl); | ||
268 | |||
269 | vsp1_dl_list_commit(pipe->dl); | ||
270 | pipe->dl = NULL; | ||
271 | |||
272 | vsp1_pipeline_run(pipe); | ||
273 | } | ||
274 | |||
275 | static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) | ||
276 | { | ||
277 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | ||
278 | enum vsp1_pipeline_state state; | ||
279 | unsigned long flags; | ||
280 | unsigned int i; | ||
281 | |||
282 | /* Complete buffers on all video nodes. */ | ||
283 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | ||
284 | if (!pipe->inputs[i]) | ||
285 | continue; | ||
286 | |||
287 | vsp1_video_frame_end(pipe, pipe->inputs[i]); | ||
288 | } | ||
289 | |||
290 | vsp1_video_frame_end(pipe, pipe->output); | ||
291 | |||
292 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
293 | |||
294 | state = pipe->state; | ||
295 | pipe->state = VSP1_PIPELINE_STOPPED; | ||
296 | |||
297 | /* If a stop has been requested, mark the pipeline as stopped and | ||
298 | * return. Otherwise restart the pipeline if ready. | ||
299 | */ | ||
300 | if (state == VSP1_PIPELINE_STOPPING) | ||
301 | wake_up(&pipe->wq); | ||
302 | else if (vsp1_pipeline_ready(pipe)) | ||
303 | vsp1_video_pipeline_run(pipe); | ||
304 | |||
305 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
306 | } | ||
307 | |||
308 | static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, | ||
309 | struct vsp1_rwpf *input, | ||
310 | struct vsp1_rwpf *output) | ||
177 | { | 311 | { |
178 | struct vsp1_entity *entity; | ||
179 | struct media_entity_enum ent_enum; | 312 | struct media_entity_enum ent_enum; |
313 | struct vsp1_entity *entity; | ||
180 | struct media_pad *pad; | 314 | struct media_pad *pad; |
181 | int rval; | ||
182 | bool bru_found = false; | 315 | bool bru_found = false; |
316 | int ret; | ||
183 | 317 | ||
184 | input->location.left = 0; | 318 | ret = media_entity_enum_init(&ent_enum, &input->entity.vsp1->media_dev); |
185 | input->location.top = 0; | 319 | if (ret < 0) |
186 | 320 | return ret; | |
187 | rval = media_entity_enum_init( | ||
188 | &ent_enum, input->entity.pads[RWPF_PAD_SOURCE].graph_obj.mdev); | ||
189 | if (rval) | ||
190 | return rval; | ||
191 | 321 | ||
192 | pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); | 322 | pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); |
193 | 323 | ||
194 | while (1) { | 324 | while (1) { |
195 | if (pad == NULL) { | 325 | if (pad == NULL) { |
196 | rval = -EPIPE; | 326 | ret = -EPIPE; |
197 | goto out; | 327 | goto out; |
198 | } | 328 | } |
199 | 329 | ||
200 | /* We've reached a video node, that shouldn't have happened. */ | 330 | /* We've reached a video node, that shouldn't have happened. */ |
201 | if (!is_media_entity_v4l2_subdev(pad->entity)) { | 331 | if (!is_media_entity_v4l2_subdev(pad->entity)) { |
202 | rval = -EPIPE; | 332 | ret = -EPIPE; |
203 | goto out; | 333 | goto out; |
204 | } | 334 | } |
205 | 335 | ||
206 | entity = to_vsp1_entity( | 336 | entity = to_vsp1_entity( |
207 | media_entity_to_v4l2_subdev(pad->entity)); | 337 | media_entity_to_v4l2_subdev(pad->entity)); |
208 | 338 | ||
209 | /* A BRU is present in the pipeline, store the compose rectangle | 339 | /* A BRU is present in the pipeline, store the BRU input pad |
210 | * location in the input RPF for use when configuring the RPF. | 340 | * number in the input RPF for use when configuring the RPF. |
211 | */ | 341 | */ |
212 | if (entity->type == VSP1_ENTITY_BRU) { | 342 | if (entity->type == VSP1_ENTITY_BRU) { |
213 | struct vsp1_bru *bru = to_bru(&entity->subdev); | 343 | struct vsp1_bru *bru = to_bru(&entity->subdev); |
214 | struct v4l2_rect *rect = | ||
215 | &bru->inputs[pad->index].compose; | ||
216 | 344 | ||
217 | bru->inputs[pad->index].rpf = input; | 345 | bru->inputs[pad->index].rpf = input; |
218 | 346 | input->bru_input = pad->index; | |
219 | input->location.left = rect->left; | ||
220 | input->location.top = rect->top; | ||
221 | 347 | ||
222 | bru_found = true; | 348 | bru_found = true; |
223 | } | 349 | } |
@@ -229,14 +355,14 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe, | |||
229 | /* Ensure the branch has no loop. */ | 355 | /* Ensure the branch has no loop. */ |
230 | if (media_entity_enum_test_and_set(&ent_enum, | 356 | if (media_entity_enum_test_and_set(&ent_enum, |
231 | &entity->subdev.entity)) { | 357 | &entity->subdev.entity)) { |
232 | rval = -EPIPE; | 358 | ret = -EPIPE; |
233 | goto out; | 359 | goto out; |
234 | } | 360 | } |
235 | 361 | ||
236 | /* UDS can't be chained. */ | 362 | /* UDS can't be chained. */ |
237 | if (entity->type == VSP1_ENTITY_UDS) { | 363 | if (entity->type == VSP1_ENTITY_UDS) { |
238 | if (pipe->uds) { | 364 | if (pipe->uds) { |
239 | rval = -EPIPE; | 365 | ret = -EPIPE; |
240 | goto out; | 366 | goto out; |
241 | } | 367 | } |
242 | 368 | ||
@@ -256,16 +382,16 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe, | |||
256 | 382 | ||
257 | /* The last entity must be the output WPF. */ | 383 | /* The last entity must be the output WPF. */ |
258 | if (entity != &output->entity) | 384 | if (entity != &output->entity) |
259 | rval = -EPIPE; | 385 | ret = -EPIPE; |
260 | 386 | ||
261 | out: | 387 | out: |
262 | media_entity_enum_cleanup(&ent_enum); | 388 | media_entity_enum_cleanup(&ent_enum); |
263 | 389 | ||
264 | return rval; | 390 | return ret; |
265 | } | 391 | } |
266 | 392 | ||
267 | static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe, | 393 | static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, |
268 | struct vsp1_video *video) | 394 | struct vsp1_video *video) |
269 | { | 395 | { |
270 | struct media_entity_graph graph; | 396 | struct media_entity_graph graph; |
271 | struct media_entity *entity = &video->video.entity; | 397 | struct media_entity *entity = &video->video.entity; |
@@ -273,14 +399,10 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe, | |||
273 | unsigned int i; | 399 | unsigned int i; |
274 | int ret; | 400 | int ret; |
275 | 401 | ||
276 | mutex_lock(&mdev->graph_mutex); | ||
277 | |||
278 | /* Walk the graph to locate the entities and video nodes. */ | 402 | /* Walk the graph to locate the entities and video nodes. */ |
279 | ret = media_entity_graph_walk_init(&graph, mdev); | 403 | ret = media_entity_graph_walk_init(&graph, mdev); |
280 | if (ret) { | 404 | if (ret) |
281 | mutex_unlock(&mdev->graph_mutex); | ||
282 | return ret; | 405 | return ret; |
283 | } | ||
284 | 406 | ||
285 | media_entity_graph_walk_start(&graph, entity); | 407 | media_entity_graph_walk_start(&graph, entity); |
286 | 408 | ||
@@ -300,10 +422,12 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe, | |||
300 | rwpf = to_rwpf(subdev); | 422 | rwpf = to_rwpf(subdev); |
301 | pipe->inputs[rwpf->entity.index] = rwpf; | 423 | pipe->inputs[rwpf->entity.index] = rwpf; |
302 | rwpf->video->pipe_index = ++pipe->num_inputs; | 424 | rwpf->video->pipe_index = ++pipe->num_inputs; |
425 | rwpf->pipe = pipe; | ||
303 | } else if (e->type == VSP1_ENTITY_WPF) { | 426 | } else if (e->type == VSP1_ENTITY_WPF) { |
304 | rwpf = to_rwpf(subdev); | 427 | rwpf = to_rwpf(subdev); |
305 | pipe->output = rwpf; | 428 | pipe->output = rwpf; |
306 | rwpf->video->pipe_index = 0; | 429 | rwpf->video->pipe_index = 0; |
430 | rwpf->pipe = pipe; | ||
307 | } else if (e->type == VSP1_ENTITY_LIF) { | 431 | } else if (e->type == VSP1_ENTITY_LIF) { |
308 | pipe->lif = e; | 432 | pipe->lif = e; |
309 | } else if (e->type == VSP1_ENTITY_BRU) { | 433 | } else if (e->type == VSP1_ENTITY_BRU) { |
@@ -311,15 +435,11 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe, | |||
311 | } | 435 | } |
312 | } | 436 | } |
313 | 437 | ||
314 | mutex_unlock(&mdev->graph_mutex); | ||
315 | |||
316 | media_entity_graph_walk_cleanup(&graph); | 438 | media_entity_graph_walk_cleanup(&graph); |
317 | 439 | ||
318 | /* We need one output and at least one input. */ | 440 | /* We need one output and at least one input. */ |
319 | if (pipe->num_inputs == 0 || !pipe->output) { | 441 | if (pipe->num_inputs == 0 || !pipe->output) |
320 | ret = -EPIPE; | 442 | return -EPIPE; |
321 | goto error; | ||
322 | } | ||
323 | 443 | ||
324 | /* Follow links downstream for each input and make sure the graph | 444 | /* Follow links downstream for each input and make sure the graph |
325 | * contains no loop and that all branches end at the output WPF. | 445 | * contains no loop and that all branches end at the output WPF. |
@@ -328,143 +448,69 @@ static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe, | |||
328 | if (!pipe->inputs[i]) | 448 | if (!pipe->inputs[i]) |
329 | continue; | 449 | continue; |
330 | 450 | ||
331 | ret = vsp1_video_pipeline_validate_branch(pipe, pipe->inputs[i], | 451 | ret = vsp1_video_pipeline_build_branch(pipe, pipe->inputs[i], |
332 | pipe->output); | 452 | pipe->output); |
333 | if (ret < 0) | 453 | if (ret < 0) |
334 | goto error; | 454 | return ret; |
335 | } | 455 | } |
336 | 456 | ||
337 | return 0; | 457 | return 0; |
338 | |||
339 | error: | ||
340 | vsp1_pipeline_reset(pipe); | ||
341 | return ret; | ||
342 | } | 458 | } |
343 | 459 | ||
344 | static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe, | 460 | static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe, |
345 | struct vsp1_video *video) | 461 | struct vsp1_video *video) |
346 | { | 462 | { |
347 | int ret; | 463 | vsp1_pipeline_init(pipe); |
348 | 464 | ||
349 | mutex_lock(&pipe->lock); | 465 | pipe->frame_end = vsp1_video_pipeline_frame_end; |
350 | |||
351 | /* If we're the first user validate and initialize the pipeline. */ | ||
352 | if (pipe->use_count == 0) { | ||
353 | ret = vsp1_video_pipeline_validate(pipe, video); | ||
354 | if (ret < 0) | ||
355 | goto done; | ||
356 | } | ||
357 | 466 | ||
358 | pipe->use_count++; | 467 | return vsp1_video_pipeline_build(pipe, video); |
359 | ret = 0; | ||
360 | |||
361 | done: | ||
362 | mutex_unlock(&pipe->lock); | ||
363 | return ret; | ||
364 | } | 468 | } |
365 | 469 | ||
366 | static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe) | 470 | static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video) |
367 | { | ||
368 | mutex_lock(&pipe->lock); | ||
369 | |||
370 | /* If we're the last user clean up the pipeline. */ | ||
371 | if (--pipe->use_count == 0) | ||
372 | vsp1_pipeline_reset(pipe); | ||
373 | |||
374 | mutex_unlock(&pipe->lock); | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * vsp1_video_complete_buffer - Complete the current buffer | ||
379 | * @video: the video node | ||
380 | * | ||
381 | * This function completes the current buffer by filling its sequence number, | ||
382 | * time stamp and payload size, and hands it back to the videobuf core. | ||
383 | * | ||
384 | * When operating in DU output mode (deep pipeline to the DU through the LIF), | ||
385 | * the VSP1 needs to constantly supply frames to the display. In that case, if | ||
386 | * no other buffer is queued, reuse the one that has just been processed instead | ||
387 | * of handing it back to the videobuf core. | ||
388 | * | ||
389 | * Return the next queued buffer or NULL if the queue is empty. | ||
390 | */ | ||
391 | static struct vsp1_vb2_buffer * | ||
392 | vsp1_video_complete_buffer(struct vsp1_video *video) | ||
393 | { | 471 | { |
394 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); | 472 | struct vsp1_pipeline *pipe; |
395 | struct vsp1_vb2_buffer *next = NULL; | 473 | int ret; |
396 | struct vsp1_vb2_buffer *done; | ||
397 | unsigned long flags; | ||
398 | unsigned int i; | ||
399 | |||
400 | spin_lock_irqsave(&video->irqlock, flags); | ||
401 | |||
402 | if (list_empty(&video->irqqueue)) { | ||
403 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
404 | return NULL; | ||
405 | } | ||
406 | |||
407 | done = list_first_entry(&video->irqqueue, | ||
408 | struct vsp1_vb2_buffer, queue); | ||
409 | 474 | ||
410 | /* In DU output mode reuse the buffer if the list is singular. */ | 475 | /* Get a pipeline object for the video node. If a pipeline has already |
411 | if (pipe->lif && list_is_singular(&video->irqqueue)) { | 476 | * been allocated just increment its reference count and return it. |
412 | spin_unlock_irqrestore(&video->irqlock, flags); | 477 | * Otherwise allocate a new pipeline and initialize it, it will be freed |
413 | return done; | 478 | * when the last reference is released. |
479 | */ | ||
480 | if (!video->rwpf->pipe) { | ||
481 | pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); | ||
482 | if (!pipe) | ||
483 | return ERR_PTR(-ENOMEM); | ||
484 | |||
485 | ret = vsp1_video_pipeline_init(pipe, video); | ||
486 | if (ret < 0) { | ||
487 | vsp1_pipeline_reset(pipe); | ||
488 | kfree(pipe); | ||
489 | return ERR_PTR(ret); | ||
490 | } | ||
491 | } else { | ||
492 | pipe = video->rwpf->pipe; | ||
493 | kref_get(&pipe->kref); | ||
414 | } | 494 | } |
415 | 495 | ||
416 | list_del(&done->queue); | 496 | return pipe; |
417 | |||
418 | if (!list_empty(&video->irqqueue)) | ||
419 | next = list_first_entry(&video->irqqueue, | ||
420 | struct vsp1_vb2_buffer, queue); | ||
421 | |||
422 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
423 | |||
424 | done->buf.sequence = video->sequence++; | ||
425 | done->buf.vb2_buf.timestamp = ktime_get_ns(); | ||
426 | for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) | ||
427 | vb2_set_plane_payload(&done->buf.vb2_buf, i, | ||
428 | done->mem.length[i]); | ||
429 | vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); | ||
430 | |||
431 | return next; | ||
432 | } | 497 | } |
433 | 498 | ||
434 | static void vsp1_video_frame_end(struct vsp1_pipeline *pipe, | 499 | static void vsp1_video_pipeline_release(struct kref *kref) |
435 | struct vsp1_rwpf *rwpf) | ||
436 | { | 500 | { |
437 | struct vsp1_video *video = rwpf->video; | 501 | struct vsp1_pipeline *pipe = container_of(kref, typeof(*pipe), kref); |
438 | struct vsp1_vb2_buffer *buf; | ||
439 | unsigned long flags; | ||
440 | 502 | ||
441 | buf = vsp1_video_complete_buffer(video); | 503 | vsp1_pipeline_reset(pipe); |
442 | if (buf == NULL) | 504 | kfree(pipe); |
443 | return; | ||
444 | |||
445 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
446 | |||
447 | video->rwpf->ops->set_memory(video->rwpf, &buf->mem); | ||
448 | pipe->buffers_ready |= 1 << video->pipe_index; | ||
449 | |||
450 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
451 | } | 505 | } |
452 | 506 | ||
453 | static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) | 507 | static void vsp1_video_pipeline_put(struct vsp1_pipeline *pipe) |
454 | { | 508 | { |
455 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | 509 | struct media_device *mdev = &pipe->output->entity.vsp1->media_dev; |
456 | unsigned int i; | ||
457 | |||
458 | /* Complete buffers on all video nodes. */ | ||
459 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | ||
460 | if (!pipe->inputs[i]) | ||
461 | continue; | ||
462 | 510 | ||
463 | vsp1_video_frame_end(pipe, pipe->inputs[i]); | 511 | mutex_lock(&mdev->graph_mutex); |
464 | } | 512 | kref_put(&pipe->kref, vsp1_video_pipeline_release); |
465 | 513 | mutex_unlock(&mdev->graph_mutex); | |
466 | if (!pipe->lif) | ||
467 | vsp1_video_frame_end(pipe, pipe->output); | ||
468 | } | 514 | } |
469 | 515 | ||
470 | /* ----------------------------------------------------------------------------- | 516 | /* ----------------------------------------------------------------------------- |
@@ -513,16 +559,16 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb) | |||
513 | if (vb->num_planes < format->num_planes) | 559 | if (vb->num_planes < format->num_planes) |
514 | return -EINVAL; | 560 | return -EINVAL; |
515 | 561 | ||
516 | buf->mem.num_planes = vb->num_planes; | ||
517 | |||
518 | for (i = 0; i < vb->num_planes; ++i) { | 562 | for (i = 0; i < vb->num_planes; ++i) { |
519 | buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); | 563 | buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); |
520 | buf->mem.length[i] = vb2_plane_size(vb, i); | ||
521 | 564 | ||
522 | if (buf->mem.length[i] < format->plane_fmt[i].sizeimage) | 565 | if (vb2_plane_size(vb, i) < format->plane_fmt[i].sizeimage) |
523 | return -EINVAL; | 566 | return -EINVAL; |
524 | } | 567 | } |
525 | 568 | ||
569 | for ( ; i < 3; ++i) | ||
570 | buf->mem.addr[i] = 0; | ||
571 | |||
526 | return 0; | 572 | return 0; |
527 | } | 573 | } |
528 | 574 | ||
@@ -530,7 +576,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb) | |||
530 | { | 576 | { |
531 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | 577 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
532 | struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue); | 578 | struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue); |
533 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); | 579 | struct vsp1_pipeline *pipe = video->rwpf->pipe; |
534 | struct vsp1_vb2_buffer *buf = to_vsp1_vb2_buffer(vbuf); | 580 | struct vsp1_vb2_buffer *buf = to_vsp1_vb2_buffer(vbuf); |
535 | unsigned long flags; | 581 | unsigned long flags; |
536 | bool empty; | 582 | bool empty; |
@@ -545,54 +591,66 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb) | |||
545 | 591 | ||
546 | spin_lock_irqsave(&pipe->irqlock, flags); | 592 | spin_lock_irqsave(&pipe->irqlock, flags); |
547 | 593 | ||
548 | video->rwpf->ops->set_memory(video->rwpf, &buf->mem); | 594 | video->rwpf->mem = buf->mem; |
549 | pipe->buffers_ready |= 1 << video->pipe_index; | 595 | pipe->buffers_ready |= 1 << video->pipe_index; |
550 | 596 | ||
551 | if (vb2_is_streaming(&video->queue) && | 597 | if (vb2_is_streaming(&video->queue) && |
552 | vsp1_pipeline_ready(pipe)) | 598 | vsp1_pipeline_ready(pipe)) |
553 | vsp1_pipeline_run(pipe); | 599 | vsp1_video_pipeline_run(pipe); |
554 | 600 | ||
555 | spin_unlock_irqrestore(&pipe->irqlock, flags); | 601 | spin_unlock_irqrestore(&pipe->irqlock, flags); |
556 | } | 602 | } |
557 | 603 | ||
604 | static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) | ||
605 | { | ||
606 | struct vsp1_entity *entity; | ||
607 | |||
608 | /* Prepare the display list. */ | ||
609 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); | ||
610 | if (!pipe->dl) | ||
611 | return -ENOMEM; | ||
612 | |||
613 | if (pipe->uds) { | ||
614 | struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); | ||
615 | |||
616 | /* If a BRU is present in the pipeline before the UDS, the alpha | ||
617 | * component doesn't need to be scaled as the BRU output alpha | ||
618 | * value is fixed to 255. Otherwise we need to scale the alpha | ||
619 | * component only when available at the input RPF. | ||
620 | */ | ||
621 | if (pipe->uds_input->type == VSP1_ENTITY_BRU) { | ||
622 | uds->scale_alpha = false; | ||
623 | } else { | ||
624 | struct vsp1_rwpf *rpf = | ||
625 | to_rwpf(&pipe->uds_input->subdev); | ||
626 | |||
627 | uds->scale_alpha = rpf->fmtinfo->alpha; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | ||
632 | vsp1_entity_route_setup(entity, pipe->dl); | ||
633 | |||
634 | if (entity->ops->configure) | ||
635 | entity->ops->configure(entity, pipe, pipe->dl); | ||
636 | } | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
558 | static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) | 641 | static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) |
559 | { | 642 | { |
560 | struct vsp1_video *video = vb2_get_drv_priv(vq); | 643 | struct vsp1_video *video = vb2_get_drv_priv(vq); |
561 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); | 644 | struct vsp1_pipeline *pipe = video->rwpf->pipe; |
562 | struct vsp1_entity *entity; | ||
563 | unsigned long flags; | 645 | unsigned long flags; |
564 | int ret; | 646 | int ret; |
565 | 647 | ||
566 | mutex_lock(&pipe->lock); | 648 | mutex_lock(&pipe->lock); |
567 | if (pipe->stream_count == pipe->num_inputs) { | 649 | if (pipe->stream_count == pipe->num_inputs) { |
568 | if (pipe->uds) { | 650 | ret = vsp1_video_setup_pipeline(pipe); |
569 | struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); | 651 | if (ret < 0) { |
570 | 652 | mutex_unlock(&pipe->lock); | |
571 | /* If a BRU is present in the pipeline before the UDS, | 653 | return ret; |
572 | * the alpha component doesn't need to be scaled as the | ||
573 | * BRU output alpha value is fixed to 255. Otherwise we | ||
574 | * need to scale the alpha component only when available | ||
575 | * at the input RPF. | ||
576 | */ | ||
577 | if (pipe->uds_input->type == VSP1_ENTITY_BRU) { | ||
578 | uds->scale_alpha = false; | ||
579 | } else { | ||
580 | struct vsp1_rwpf *rpf = | ||
581 | to_rwpf(&pipe->uds_input->subdev); | ||
582 | |||
583 | uds->scale_alpha = rpf->fmtinfo->alpha; | ||
584 | } | ||
585 | } | ||
586 | |||
587 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | ||
588 | vsp1_entity_route_setup(entity); | ||
589 | |||
590 | ret = v4l2_subdev_call(&entity->subdev, video, | ||
591 | s_stream, 1); | ||
592 | if (ret < 0) { | ||
593 | mutex_unlock(&pipe->lock); | ||
594 | return ret; | ||
595 | } | ||
596 | } | 654 | } |
597 | } | 655 | } |
598 | 656 | ||
@@ -601,7 +659,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
601 | 659 | ||
602 | spin_lock_irqsave(&pipe->irqlock, flags); | 660 | spin_lock_irqsave(&pipe->irqlock, flags); |
603 | if (vsp1_pipeline_ready(pipe)) | 661 | if (vsp1_pipeline_ready(pipe)) |
604 | vsp1_pipeline_run(pipe); | 662 | vsp1_video_pipeline_run(pipe); |
605 | spin_unlock_irqrestore(&pipe->irqlock, flags); | 663 | spin_unlock_irqrestore(&pipe->irqlock, flags); |
606 | 664 | ||
607 | return 0; | 665 | return 0; |
@@ -610,7 +668,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
610 | static void vsp1_video_stop_streaming(struct vb2_queue *vq) | 668 | static void vsp1_video_stop_streaming(struct vb2_queue *vq) |
611 | { | 669 | { |
612 | struct vsp1_video *video = vb2_get_drv_priv(vq); | 670 | struct vsp1_video *video = vb2_get_drv_priv(vq); |
613 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); | 671 | struct vsp1_pipeline *pipe = video->rwpf->pipe; |
614 | struct vsp1_vb2_buffer *buffer; | 672 | struct vsp1_vb2_buffer *buffer; |
615 | unsigned long flags; | 673 | unsigned long flags; |
616 | int ret; | 674 | int ret; |
@@ -621,11 +679,14 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) | |||
621 | ret = vsp1_pipeline_stop(pipe); | 679 | ret = vsp1_pipeline_stop(pipe); |
622 | if (ret == -ETIMEDOUT) | 680 | if (ret == -ETIMEDOUT) |
623 | dev_err(video->vsp1->dev, "pipeline stop timeout\n"); | 681 | dev_err(video->vsp1->dev, "pipeline stop timeout\n"); |
682 | |||
683 | vsp1_dl_list_put(pipe->dl); | ||
684 | pipe->dl = NULL; | ||
624 | } | 685 | } |
625 | mutex_unlock(&pipe->lock); | 686 | mutex_unlock(&pipe->lock); |
626 | 687 | ||
627 | vsp1_video_pipeline_cleanup(pipe); | ||
628 | media_entity_pipeline_stop(&video->video.entity); | 688 | media_entity_pipeline_stop(&video->video.entity); |
689 | vsp1_video_pipeline_put(pipe); | ||
629 | 690 | ||
630 | /* Remove all buffers from the IRQ queue. */ | 691 | /* Remove all buffers from the IRQ queue. */ |
631 | spin_lock_irqsave(&video->irqlock, flags); | 692 | spin_lock_irqsave(&video->irqlock, flags); |
@@ -737,6 +798,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
737 | { | 798 | { |
738 | struct v4l2_fh *vfh = file->private_data; | 799 | struct v4l2_fh *vfh = file->private_data; |
739 | struct vsp1_video *video = to_vsp1_video(vfh->vdev); | 800 | struct vsp1_video *video = to_vsp1_video(vfh->vdev); |
801 | struct media_device *mdev = &video->vsp1->media_dev; | ||
740 | struct vsp1_pipeline *pipe; | 802 | struct vsp1_pipeline *pipe; |
741 | int ret; | 803 | int ret; |
742 | 804 | ||
@@ -745,18 +807,25 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
745 | 807 | ||
746 | video->sequence = 0; | 808 | video->sequence = 0; |
747 | 809 | ||
748 | /* Start streaming on the pipeline. No link touching an entity in the | 810 | /* Get a pipeline for the video node and start streaming on it. No link |
749 | * pipeline can be activated or deactivated once streaming is started. | 811 | * touching an entity in the pipeline can be activated or deactivated |
750 | * | 812 | * once streaming is started. |
751 | * Use the VSP1 pipeline object embedded in the first video object that | ||
752 | * starts streaming. | ||
753 | */ | 813 | */ |
754 | pipe = video->video.entity.pipe | 814 | mutex_lock(&mdev->graph_mutex); |
755 | ? to_vsp1_pipeline(&video->video.entity) : &video->pipe; | ||
756 | 815 | ||
757 | ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe); | 816 | pipe = vsp1_video_pipeline_get(video); |
758 | if (ret < 0) | 817 | if (IS_ERR(pipe)) { |
759 | return ret; | 818 | mutex_unlock(&mdev->graph_mutex); |
819 | return PTR_ERR(pipe); | ||
820 | } | ||
821 | |||
822 | ret = __media_entity_pipeline_start(&video->video.entity, &pipe->pipe); | ||
823 | if (ret < 0) { | ||
824 | mutex_unlock(&mdev->graph_mutex); | ||
825 | goto err_pipe; | ||
826 | } | ||
827 | |||
828 | mutex_unlock(&mdev->graph_mutex); | ||
760 | 829 | ||
761 | /* Verify that the configured format matches the output of the connected | 830 | /* Verify that the configured format matches the output of the connected |
762 | * subdev. | 831 | * subdev. |
@@ -765,21 +834,17 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
765 | if (ret < 0) | 834 | if (ret < 0) |
766 | goto err_stop; | 835 | goto err_stop; |
767 | 836 | ||
768 | ret = vsp1_video_pipeline_init(pipe, video); | ||
769 | if (ret < 0) | ||
770 | goto err_stop; | ||
771 | |||
772 | /* Start the queue. */ | 837 | /* Start the queue. */ |
773 | ret = vb2_streamon(&video->queue, type); | 838 | ret = vb2_streamon(&video->queue, type); |
774 | if (ret < 0) | 839 | if (ret < 0) |
775 | goto err_cleanup; | 840 | goto err_stop; |
776 | 841 | ||
777 | return 0; | 842 | return 0; |
778 | 843 | ||
779 | err_cleanup: | ||
780 | vsp1_video_pipeline_cleanup(pipe); | ||
781 | err_stop: | 844 | err_stop: |
782 | media_entity_pipeline_stop(&video->video.entity); | 845 | media_entity_pipeline_stop(&video->video.entity); |
846 | err_pipe: | ||
847 | vsp1_video_pipeline_put(pipe); | ||
783 | return ret; | 848 | return ret; |
784 | } | 849 | } |
785 | 850 | ||
@@ -895,26 +960,16 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1, | |||
895 | spin_lock_init(&video->irqlock); | 960 | spin_lock_init(&video->irqlock); |
896 | INIT_LIST_HEAD(&video->irqqueue); | 961 | INIT_LIST_HEAD(&video->irqqueue); |
897 | 962 | ||
898 | vsp1_pipeline_init(&video->pipe); | ||
899 | video->pipe.frame_end = vsp1_video_pipeline_frame_end; | ||
900 | |||
901 | /* Initialize the media entity... */ | 963 | /* Initialize the media entity... */ |
902 | ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); | 964 | ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); |
903 | if (ret < 0) | 965 | if (ret < 0) |
904 | return ERR_PTR(ret); | 966 | return ERR_PTR(ret); |
905 | 967 | ||
906 | /* ... and the format ... */ | 968 | /* ... and the format ... */ |
907 | rwpf->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT); | 969 | rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT; |
908 | rwpf->format.pixelformat = rwpf->fmtinfo->fourcc; | ||
909 | rwpf->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
910 | rwpf->format.field = V4L2_FIELD_NONE; | ||
911 | rwpf->format.width = VSP1_VIDEO_DEF_WIDTH; | 970 | rwpf->format.width = VSP1_VIDEO_DEF_WIDTH; |
912 | rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT; | 971 | rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT; |
913 | rwpf->format.num_planes = 1; | 972 | __vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo); |
914 | rwpf->format.plane_fmt[0].bytesperline = | ||
915 | rwpf->format.width * rwpf->fmtinfo->bpp[0] / 8; | ||
916 | rwpf->format.plane_fmt[0].sizeimage = | ||
917 | rwpf->format.plane_fmt[0].bytesperline * rwpf->format.height; | ||
918 | 973 | ||
919 | /* ... and the video node... */ | 974 | /* ... and the video node... */ |
920 | video->video.v4l2_dev = &video->vsp1->v4l2_dev; | 975 | video->video.v4l2_dev = &video->vsp1->v4l2_dev; |
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 64abd39ee1e7..867b00807c46 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | #include <media/videobuf2-v4l2.h> | 19 | #include <media/videobuf2-v4l2.h> |
20 | 20 | ||
21 | #include "vsp1_pipe.h" | ||
22 | #include "vsp1_rwpf.h" | 21 | #include "vsp1_rwpf.h" |
23 | 22 | ||
24 | struct vsp1_vb2_buffer { | 23 | struct vsp1_vb2_buffer { |
@@ -44,7 +43,6 @@ struct vsp1_video { | |||
44 | 43 | ||
45 | struct mutex lock; | 44 | struct mutex lock; |
46 | 45 | ||
47 | struct vsp1_pipeline pipe; | ||
48 | unsigned int pipe_index; | 46 | unsigned int pipe_index; |
49 | 47 | ||
50 | struct vb2_queue queue; | 48 | struct vb2_queue queue; |
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index c78d4af50fcf..6c91eaa35e75 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -16,124 +16,114 @@ | |||
16 | #include <media/v4l2-subdev.h> | 16 | #include <media/v4l2-subdev.h> |
17 | 17 | ||
18 | #include "vsp1.h" | 18 | #include "vsp1.h" |
19 | #include "vsp1_dl.h" | ||
20 | #include "vsp1_pipe.h" | ||
19 | #include "vsp1_rwpf.h" | 21 | #include "vsp1_rwpf.h" |
20 | #include "vsp1_video.h" | 22 | #include "vsp1_video.h" |
21 | 23 | ||
22 | #define WPF_MAX_WIDTH 2048 | 24 | #define WPF_GEN2_MAX_WIDTH 2048U |
23 | #define WPF_MAX_HEIGHT 2048 | 25 | #define WPF_GEN2_MAX_HEIGHT 2048U |
26 | #define WPF_GEN3_MAX_WIDTH 8190U | ||
27 | #define WPF_GEN3_MAX_HEIGHT 8190U | ||
24 | 28 | ||
25 | /* ----------------------------------------------------------------------------- | 29 | /* ----------------------------------------------------------------------------- |
26 | * Device Access | 30 | * Device Access |
27 | */ | 31 | */ |
28 | 32 | ||
29 | static inline u32 vsp1_wpf_read(struct vsp1_rwpf *wpf, u32 reg) | 33 | static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, |
34 | struct vsp1_dl_list *dl, u32 reg, u32 data) | ||
30 | { | 35 | { |
31 | return vsp1_read(wpf->entity.vsp1, | 36 | vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data); |
32 | reg + wpf->entity.index * VI6_WPF_OFFSET); | ||
33 | } | ||
34 | |||
35 | static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data) | ||
36 | { | ||
37 | vsp1_mod_write(&wpf->entity, | ||
38 | reg + wpf->entity.index * VI6_WPF_OFFSET, data); | ||
39 | } | 37 | } |
40 | 38 | ||
41 | /* ----------------------------------------------------------------------------- | 39 | /* ----------------------------------------------------------------------------- |
42 | * Controls | 40 | * V4L2 Subdevice Core Operations |
43 | */ | 41 | */ |
44 | 42 | ||
45 | static int wpf_s_ctrl(struct v4l2_ctrl *ctrl) | 43 | static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) |
46 | { | 44 | { |
47 | struct vsp1_rwpf *wpf = | 45 | struct vsp1_rwpf *wpf = to_rwpf(subdev); |
48 | container_of(ctrl->handler, struct vsp1_rwpf, ctrls); | 46 | struct vsp1_device *vsp1 = wpf->entity.vsp1; |
49 | u32 value; | ||
50 | 47 | ||
51 | if (!vsp1_entity_is_streaming(&wpf->entity)) | 48 | if (enable) |
52 | return 0; | 49 | return 0; |
53 | 50 | ||
54 | switch (ctrl->id) { | 51 | /* Write to registers directly when stopping the stream as there will be |
55 | case V4L2_CID_ALPHA_COMPONENT: | 52 | * no pipeline run to apply the display list. |
56 | value = vsp1_wpf_read(wpf, VI6_WPF_OUTFMT); | 53 | */ |
57 | value &= ~VI6_WPF_OUTFMT_PDV_MASK; | 54 | vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); |
58 | value |= ctrl->val << VI6_WPF_OUTFMT_PDV_SHIFT; | 55 | vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET + |
59 | vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, value); | 56 | VI6_WPF_SRCRPF, 0); |
60 | break; | ||
61 | } | ||
62 | 57 | ||
63 | return 0; | 58 | return 0; |
64 | } | 59 | } |
65 | 60 | ||
66 | static const struct v4l2_ctrl_ops wpf_ctrl_ops = { | ||
67 | .s_ctrl = wpf_s_ctrl, | ||
68 | }; | ||
69 | |||
70 | /* ----------------------------------------------------------------------------- | 61 | /* ----------------------------------------------------------------------------- |
71 | * V4L2 Subdevice Core Operations | 62 | * V4L2 Subdevice Operations |
72 | */ | 63 | */ |
73 | 64 | ||
74 | static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | 65 | static struct v4l2_subdev_video_ops wpf_video_ops = { |
75 | { | 66 | .s_stream = wpf_s_stream, |
76 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity); | 67 | }; |
77 | struct vsp1_rwpf *wpf = to_rwpf(subdev); | ||
78 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | ||
79 | const struct v4l2_rect *crop = &wpf->crop; | ||
80 | unsigned int i; | ||
81 | u32 srcrpf = 0; | ||
82 | u32 outfmt = 0; | ||
83 | int ret; | ||
84 | |||
85 | ret = vsp1_entity_set_streaming(&wpf->entity, enable); | ||
86 | if (ret < 0) | ||
87 | return ret; | ||
88 | 68 | ||
89 | if (!enable) { | 69 | static struct v4l2_subdev_ops wpf_ops = { |
90 | vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); | 70 | .video = &wpf_video_ops, |
91 | vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET + | 71 | .pad = &vsp1_rwpf_pad_ops, |
92 | VI6_WPF_SRCRPF, 0); | 72 | }; |
93 | return 0; | ||
94 | } | ||
95 | 73 | ||
96 | /* Sources. If the pipeline has a single input and BRU is not used, | 74 | /* ----------------------------------------------------------------------------- |
97 | * configure it as the master layer. Otherwise configure all | 75 | * VSP1 Entity Operations |
98 | * inputs as sub-layers and select the virtual RPF as the master | 76 | */ |
99 | * layer. | ||
100 | */ | ||
101 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | ||
102 | struct vsp1_rwpf *input = pipe->inputs[i]; | ||
103 | 77 | ||
104 | if (!input) | 78 | static void vsp1_wpf_destroy(struct vsp1_entity *entity) |
105 | continue; | 79 | { |
80 | struct vsp1_rwpf *wpf = entity_to_rwpf(entity); | ||
106 | 81 | ||
107 | srcrpf |= (!pipe->bru && pipe->num_inputs == 1) | 82 | vsp1_dlm_destroy(wpf->dlm); |
108 | ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) | 83 | } |
109 | : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); | ||
110 | } | ||
111 | 84 | ||
112 | if (pipe->bru || pipe->num_inputs > 1) | 85 | static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) |
113 | srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; | 86 | { |
87 | struct vsp1_rwpf *wpf = entity_to_rwpf(entity); | ||
114 | 88 | ||
115 | vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); | 89 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]); |
90 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]); | ||
91 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]); | ||
92 | } | ||
116 | 93 | ||
117 | /* Destination stride. */ | 94 | static void wpf_configure(struct vsp1_entity *entity, |
118 | if (!pipe->lif) { | 95 | struct vsp1_pipeline *pipe, |
119 | struct v4l2_pix_format_mplane *format = &wpf->format; | 96 | struct vsp1_dl_list *dl) |
97 | { | ||
98 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | ||
99 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | ||
100 | const struct v4l2_mbus_framefmt *source_format; | ||
101 | const struct v4l2_mbus_framefmt *sink_format; | ||
102 | const struct v4l2_rect *crop; | ||
103 | unsigned int i; | ||
104 | u32 outfmt = 0; | ||
105 | u32 srcrpf = 0; | ||
120 | 106 | ||
121 | vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y, | 107 | /* Cropping */ |
122 | format->plane_fmt[0].bytesperline); | 108 | crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); |
123 | if (format->num_planes > 1) | ||
124 | vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C, | ||
125 | format->plane_fmt[1].bytesperline); | ||
126 | } | ||
127 | 109 | ||
128 | vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | | 110 | vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | |
129 | (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | | 111 | (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | |
130 | (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); | 112 | (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); |
131 | vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | | 113 | vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | |
132 | (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | | 114 | (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | |
133 | (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); | 115 | (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); |
134 | 116 | ||
135 | /* Format */ | 117 | /* Format */ |
118 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, | ||
119 | wpf->entity.config, | ||
120 | RWPF_PAD_SINK); | ||
121 | source_format = vsp1_entity_get_pad_format(&wpf->entity, | ||
122 | wpf->entity.config, | ||
123 | RWPF_PAD_SOURCE); | ||
124 | |||
136 | if (!pipe->lif) { | 125 | if (!pipe->lif) { |
126 | const struct v4l2_pix_format_mplane *format = &wpf->format; | ||
137 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | 127 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; |
138 | 128 | ||
139 | outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; | 129 | outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; |
@@ -145,73 +135,58 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
145 | if (fmtinfo->swap_uv) | 135 | if (fmtinfo->swap_uv) |
146 | outfmt |= VI6_WPF_OUTFMT_SPUVS; | 136 | outfmt |= VI6_WPF_OUTFMT_SPUVS; |
147 | 137 | ||
148 | vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap); | 138 | /* Destination stride and byte swapping. */ |
139 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y, | ||
140 | format->plane_fmt[0].bytesperline); | ||
141 | if (format->num_planes > 1) | ||
142 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C, | ||
143 | format->plane_fmt[1].bytesperline); | ||
144 | |||
145 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); | ||
149 | } | 146 | } |
150 | 147 | ||
151 | if (wpf->entity.formats[RWPF_PAD_SINK].code != | 148 | if (sink_format->code != source_format->code) |
152 | wpf->entity.formats[RWPF_PAD_SOURCE].code) | ||
153 | outfmt |= VI6_WPF_OUTFMT_CSC; | 149 | outfmt |= VI6_WPF_OUTFMT_CSC; |
154 | 150 | ||
155 | /* Take the control handler lock to ensure that the PDV value won't be | 151 | outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT; |
156 | * changed behind our back by a set control operation. | 152 | vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); |
157 | */ | ||
158 | if (vsp1->info->uapi) | ||
159 | mutex_lock(wpf->ctrls.lock); | ||
160 | outfmt |= wpf->alpha->cur.val << VI6_WPF_OUTFMT_PDV_SHIFT; | ||
161 | vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt); | ||
162 | if (vsp1->info->uapi) | ||
163 | mutex_unlock(wpf->ctrls.lock); | ||
164 | |||
165 | vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index), | ||
166 | VI6_DPR_WPF_FPORCH_FP_WPFN); | ||
167 | 153 | ||
168 | vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0); | 154 | vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), |
155 | VI6_DPR_WPF_FPORCH_FP_WPFN); | ||
169 | 156 | ||
170 | /* Enable interrupts */ | 157 | vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0); |
171 | vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0); | ||
172 | vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), | ||
173 | VI6_WFP_IRQ_ENB_FREE); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | 158 | ||
178 | /* ----------------------------------------------------------------------------- | 159 | /* Sources. If the pipeline has a single input and BRU is not used, |
179 | * V4L2 Subdevice Operations | 160 | * configure it as the master layer. Otherwise configure all |
180 | */ | 161 | * inputs as sub-layers and select the virtual RPF as the master |
162 | * layer. | ||
163 | */ | ||
164 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | ||
165 | struct vsp1_rwpf *input = pipe->inputs[i]; | ||
181 | 166 | ||
182 | static struct v4l2_subdev_video_ops wpf_video_ops = { | 167 | if (!input) |
183 | .s_stream = wpf_s_stream, | 168 | continue; |
184 | }; | ||
185 | 169 | ||
186 | static struct v4l2_subdev_pad_ops wpf_pad_ops = { | 170 | srcrpf |= (!pipe->bru && pipe->num_inputs == 1) |
187 | .enum_mbus_code = vsp1_rwpf_enum_mbus_code, | 171 | ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) |
188 | .enum_frame_size = vsp1_rwpf_enum_frame_size, | 172 | : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); |
189 | .get_fmt = vsp1_rwpf_get_format, | 173 | } |
190 | .set_fmt = vsp1_rwpf_set_format, | ||
191 | .get_selection = vsp1_rwpf_get_selection, | ||
192 | .set_selection = vsp1_rwpf_set_selection, | ||
193 | }; | ||
194 | 174 | ||
195 | static struct v4l2_subdev_ops wpf_ops = { | 175 | if (pipe->bru || pipe->num_inputs > 1) |
196 | .video = &wpf_video_ops, | 176 | srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; |
197 | .pad = &wpf_pad_ops, | ||
198 | }; | ||
199 | 177 | ||
200 | /* ----------------------------------------------------------------------------- | 178 | vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf); |
201 | * Video Device Operations | ||
202 | */ | ||
203 | 179 | ||
204 | static void wpf_set_memory(struct vsp1_rwpf *wpf, struct vsp1_rwpf_memory *mem) | 180 | /* Enable interrupts */ |
205 | { | 181 | vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0); |
206 | vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, mem->addr[0]); | 182 | vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index), |
207 | if (mem->num_planes > 1) | 183 | VI6_WFP_IRQ_ENB_FREE); |
208 | vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, mem->addr[1]); | ||
209 | if (mem->num_planes > 2) | ||
210 | vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, mem->addr[2]); | ||
211 | } | 184 | } |
212 | 185 | ||
213 | static const struct vsp1_rwpf_operations wpf_vdev_ops = { | 186 | static const struct vsp1_entity_operations wpf_entity_ops = { |
187 | .destroy = vsp1_wpf_destroy, | ||
214 | .set_memory = wpf_set_memory, | 188 | .set_memory = wpf_set_memory, |
189 | .configure = wpf_configure, | ||
215 | }; | 190 | }; |
216 | 191 | ||
217 | /* ----------------------------------------------------------------------------- | 192 | /* ----------------------------------------------------------------------------- |
@@ -220,51 +195,43 @@ static const struct vsp1_rwpf_operations wpf_vdev_ops = { | |||
220 | 195 | ||
221 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) | 196 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) |
222 | { | 197 | { |
223 | struct v4l2_subdev *subdev; | ||
224 | struct vsp1_rwpf *wpf; | 198 | struct vsp1_rwpf *wpf; |
199 | char name[6]; | ||
225 | int ret; | 200 | int ret; |
226 | 201 | ||
227 | wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL); | 202 | wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL); |
228 | if (wpf == NULL) | 203 | if (wpf == NULL) |
229 | return ERR_PTR(-ENOMEM); | 204 | return ERR_PTR(-ENOMEM); |
230 | 205 | ||
231 | wpf->ops = &wpf_vdev_ops; | 206 | if (vsp1->info->gen == 2) { |
232 | 207 | wpf->max_width = WPF_GEN2_MAX_WIDTH; | |
233 | wpf->max_width = WPF_MAX_WIDTH; | 208 | wpf->max_height = WPF_GEN2_MAX_HEIGHT; |
234 | wpf->max_height = WPF_MAX_HEIGHT; | 209 | } else { |
210 | wpf->max_width = WPF_GEN3_MAX_WIDTH; | ||
211 | wpf->max_height = WPF_GEN3_MAX_HEIGHT; | ||
212 | } | ||
235 | 213 | ||
214 | wpf->entity.ops = &wpf_entity_ops; | ||
236 | wpf->entity.type = VSP1_ENTITY_WPF; | 215 | wpf->entity.type = VSP1_ENTITY_WPF; |
237 | wpf->entity.index = index; | 216 | wpf->entity.index = index; |
238 | 217 | ||
239 | ret = vsp1_entity_init(vsp1, &wpf->entity, 2); | 218 | sprintf(name, "wpf.%u", index); |
219 | ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops); | ||
240 | if (ret < 0) | 220 | if (ret < 0) |
241 | return ERR_PTR(ret); | 221 | return ERR_PTR(ret); |
242 | 222 | ||
243 | /* Initialize the V4L2 subdev. */ | 223 | /* Initialize the display list manager. */ |
244 | subdev = &wpf->entity.subdev; | 224 | wpf->dlm = vsp1_dlm_create(vsp1, index, 4); |
245 | v4l2_subdev_init(subdev, &wpf_ops); | 225 | if (!wpf->dlm) { |
246 | 226 | ret = -ENOMEM; | |
247 | subdev->entity.ops = &vsp1->media_ops; | 227 | goto error; |
248 | subdev->internal_ops = &vsp1_subdev_internal_ops; | 228 | } |
249 | snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u", | ||
250 | dev_name(vsp1->dev), index); | ||
251 | v4l2_set_subdevdata(subdev, wpf); | ||
252 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
253 | |||
254 | vsp1_entity_init_formats(subdev, NULL); | ||
255 | 229 | ||
256 | /* Initialize the control handler. */ | 230 | /* Initialize the control handler. */ |
257 | v4l2_ctrl_handler_init(&wpf->ctrls, 1); | 231 | ret = vsp1_rwpf_init_ctrls(wpf); |
258 | wpf->alpha = v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops, | 232 | if (ret < 0) { |
259 | V4L2_CID_ALPHA_COMPONENT, | ||
260 | 0, 255, 1, 255); | ||
261 | |||
262 | wpf->entity.subdev.ctrl_handler = &wpf->ctrls; | ||
263 | |||
264 | if (wpf->ctrls.error) { | ||
265 | dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", | 233 | dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", |
266 | index); | 234 | index); |
267 | ret = wpf->ctrls.error; | ||
268 | goto error; | 235 | goto error; |
269 | } | 236 | } |
270 | 237 | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index e795a4501e8b..feb3b2f1d874 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c | |||
@@ -351,19 +351,15 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, | |||
351 | struct xvip_graph_entity *entity; | 351 | struct xvip_graph_entity *entity; |
352 | struct device_node *remote; | 352 | struct device_node *remote; |
353 | struct device_node *ep = NULL; | 353 | struct device_node *ep = NULL; |
354 | struct device_node *next; | ||
355 | int ret = 0; | 354 | int ret = 0; |
356 | 355 | ||
357 | dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); | 356 | dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); |
358 | 357 | ||
359 | while (1) { | 358 | while (1) { |
360 | next = of_graph_get_next_endpoint(node, ep); | 359 | ep = of_graph_get_next_endpoint(node, ep); |
361 | if (next == NULL) | 360 | if (ep == NULL) |
362 | break; | 361 | break; |
363 | 362 | ||
364 | of_node_put(ep); | ||
365 | ep = next; | ||
366 | |||
367 | dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); | 363 | dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); |
368 | 364 | ||
369 | remote = of_graph_get_remote_port_parent(ep); | 365 | remote = of_graph_get_remote_port_parent(ep); |
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 3f61d77d4147..9f5b59706741 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c | |||
@@ -873,13 +873,10 @@ static int ati_remote_probe(struct usb_interface *interface, | |||
873 | strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys)); | 873 | strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys)); |
874 | strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys)); | 874 | strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys)); |
875 | 875 | ||
876 | if (udev->manufacturer) | 876 | snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), "%s%s%s", |
877 | strlcpy(ati_remote->rc_name, udev->manufacturer, | 877 | udev->manufacturer ?: "", |
878 | sizeof(ati_remote->rc_name)); | 878 | udev->manufacturer && udev->product ? " " : "", |
879 | 879 | udev->product ?: ""); | |
880 | if (udev->product) | ||
881 | snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), | ||
882 | "%s %s", ati_remote->rc_name, udev->product); | ||
883 | 880 | ||
884 | if (!strlen(ati_remote->rc_name)) | 881 | if (!strlen(ati_remote->rc_name)) |
885 | snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), | 882 | snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), |
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 35155ae500c7..5cf2e749b9eb 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c | |||
@@ -188,6 +188,7 @@ | |||
188 | #define VENDOR_TWISTEDMELON 0x2596 | 188 | #define VENDOR_TWISTEDMELON 0x2596 |
189 | #define VENDOR_HAUPPAUGE 0x2040 | 189 | #define VENDOR_HAUPPAUGE 0x2040 |
190 | #define VENDOR_PCTV 0x2013 | 190 | #define VENDOR_PCTV 0x2013 |
191 | #define VENDOR_ADAPTEC 0x03f3 | ||
191 | 192 | ||
192 | enum mceusb_model_type { | 193 | enum mceusb_model_type { |
193 | MCE_GEN2 = 0, /* Most boards */ | 194 | MCE_GEN2 = 0, /* Most boards */ |
@@ -302,6 +303,9 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
302 | /* SMK/I-O Data GV-MC7/RCKIT Receiver */ | 303 | /* SMK/I-O Data GV-MC7/RCKIT Receiver */ |
303 | { USB_DEVICE(VENDOR_SMK, 0x0353), | 304 | { USB_DEVICE(VENDOR_SMK, 0x0353), |
304 | .driver_info = MCE_GEN2_NO_TX }, | 305 | .driver_info = MCE_GEN2_NO_TX }, |
306 | /* SMK RXX6000 Infrared Receiver */ | ||
307 | { USB_DEVICE(VENDOR_SMK, 0x0357), | ||
308 | .driver_info = MCE_GEN2_NO_TX }, | ||
305 | /* Tatung eHome Infrared Transceiver */ | 309 | /* Tatung eHome Infrared Transceiver */ |
306 | { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, | 310 | { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, |
307 | /* Shuttle eHome Infrared Transceiver */ | 311 | /* Shuttle eHome Infrared Transceiver */ |
@@ -405,6 +409,8 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
405 | .driver_info = HAUPPAUGE_CX_HYBRID_TV }, | 409 | .driver_info = HAUPPAUGE_CX_HYBRID_TV }, |
406 | { USB_DEVICE(VENDOR_PCTV, 0x025e), | 410 | { USB_DEVICE(VENDOR_PCTV, 0x025e), |
407 | .driver_info = HAUPPAUGE_CX_HYBRID_TV }, | 411 | .driver_info = HAUPPAUGE_CX_HYBRID_TV }, |
412 | /* Adaptec / HP eHome Receiver */ | ||
413 | { USB_DEVICE(VENDOR_ADAPTEC, 0x0094) }, | ||
408 | 414 | ||
409 | /* Terminating entry */ | 415 | /* Terminating entry */ |
410 | { } | 416 | { } |
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 4e9bbe735ae9..7dfc7c2188f0 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c | |||
@@ -1263,6 +1263,9 @@ unlock: | |||
1263 | 1263 | ||
1264 | static void rc_dev_release(struct device *device) | 1264 | static void rc_dev_release(struct device *device) |
1265 | { | 1265 | { |
1266 | struct rc_dev *dev = to_rc_dev(device); | ||
1267 | |||
1268 | kfree(dev); | ||
1266 | } | 1269 | } |
1267 | 1270 | ||
1268 | #define ADD_HOTPLUG_VAR(fmt, val...) \ | 1271 | #define ADD_HOTPLUG_VAR(fmt, val...) \ |
@@ -1384,7 +1387,9 @@ void rc_free_device(struct rc_dev *dev) | |||
1384 | 1387 | ||
1385 | put_device(&dev->dev); | 1388 | put_device(&dev->dev); |
1386 | 1389 | ||
1387 | kfree(dev); | 1390 | /* kfree(dev) will be called by the callback function |
1391 | rc_dev_release() */ | ||
1392 | |||
1388 | module_put(THIS_MODULE); | 1393 | module_put(THIS_MODULE); |
1389 | } | 1394 | } |
1390 | EXPORT_SYMBOL_GPL(rc_free_device); | 1395 | EXPORT_SYMBOL_GPL(rc_free_device); |
@@ -1492,9 +1497,7 @@ int rc_register_device(struct rc_dev *dev) | |||
1492 | } | 1497 | } |
1493 | 1498 | ||
1494 | /* Allow the RC sysfs nodes to be accessible */ | 1499 | /* Allow the RC sysfs nodes to be accessible */ |
1495 | mutex_lock(&dev->lock); | ||
1496 | atomic_set(&dev->initialized, 1); | 1500 | atomic_set(&dev->initialized, 1); |
1497 | mutex_unlock(&dev->lock); | ||
1498 | 1501 | ||
1499 | IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", | 1502 | IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", |
1500 | dev->minor, | 1503 | dev->minor, |
diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c index 18bc745ed108..9af2a155cfca 100644 --- a/drivers/media/tuners/qm1d1c0042.c +++ b/drivers/media/tuners/qm1d1c0042.c | |||
@@ -32,14 +32,24 @@ | |||
32 | #include "qm1d1c0042.h" | 32 | #include "qm1d1c0042.h" |
33 | 33 | ||
34 | #define QM1D1C0042_NUM_REGS 0x20 | 34 | #define QM1D1C0042_NUM_REGS 0x20 |
35 | 35 | #define QM1D1C0042_NUM_REG_ROWS 2 | |
36 | static const u8 reg_initval[QM1D1C0042_NUM_REGS] = { | 36 | |
37 | 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, | 37 | static const u8 |
38 | 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 38 | reg_initval[QM1D1C0042_NUM_REG_ROWS][QM1D1C0042_NUM_REGS] = { { |
39 | 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86, | 39 | 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, |
40 | 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00 | 40 | 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, |
41 | 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86, | ||
42 | 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00 | ||
43 | }, { | ||
44 | 0x68, 0x1c, 0xc0, 0x10, 0xbc, 0xc1, 0x11, 0x33, | ||
45 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
46 | 0x00, 0xff, 0xf3, 0x00, 0x3f, 0x25, 0x5c, 0xd6, | ||
47 | 0x55, 0xcf, 0x95, 0xf6, 0x36, 0xf2, 0x09, 0x00 | ||
48 | } | ||
41 | }; | 49 | }; |
42 | 50 | ||
51 | static int reg_index; | ||
52 | |||
43 | static const struct qm1d1c0042_config default_cfg = { | 53 | static const struct qm1d1c0042_config default_cfg = { |
44 | .xtal_freq = 16000, | 54 | .xtal_freq = 16000, |
45 | .lpf = 1, | 55 | .lpf = 1, |
@@ -320,7 +330,6 @@ static int qm1d1c0042_init(struct dvb_frontend *fe) | |||
320 | int i, ret; | 330 | int i, ret; |
321 | 331 | ||
322 | state = fe->tuner_priv; | 332 | state = fe->tuner_priv; |
323 | memcpy(state->regs, reg_initval, sizeof(reg_initval)); | ||
324 | 333 | ||
325 | reg_write(state, 0x01, 0x0c); | 334 | reg_write(state, 0x01, 0x0c); |
326 | reg_write(state, 0x01, 0x0c); | 335 | reg_write(state, 0x01, 0x0c); |
@@ -330,15 +339,22 @@ static int qm1d1c0042_init(struct dvb_frontend *fe) | |||
330 | goto failed; | 339 | goto failed; |
331 | usleep_range(2000, 3000); | 340 | usleep_range(2000, 3000); |
332 | 341 | ||
333 | val = state->regs[0x01] | 0x10; | 342 | ret = reg_write(state, 0x01, 0x1c); /* soft reset off */ |
334 | ret = reg_write(state, 0x01, val); /* soft reset off */ | ||
335 | if (ret < 0) | 343 | if (ret < 0) |
336 | goto failed; | 344 | goto failed; |
337 | 345 | ||
338 | /* check ID */ | 346 | /* check ID and choose initial registers corresponding ID */ |
339 | ret = reg_read(state, 0x00, &val); | 347 | ret = reg_read(state, 0x00, &val); |
340 | if (ret < 0 || val != 0x48) | 348 | if (ret < 0) |
349 | goto failed; | ||
350 | for (reg_index = 0; reg_index < QM1D1C0042_NUM_REG_ROWS; | ||
351 | reg_index++) { | ||
352 | if (val == reg_initval[reg_index][0x00]) | ||
353 | break; | ||
354 | } | ||
355 | if (reg_index >= QM1D1C0042_NUM_REG_ROWS) | ||
341 | goto failed; | 356 | goto failed; |
357 | memcpy(state->regs, reg_initval[reg_index], QM1D1C0042_NUM_REGS); | ||
342 | usleep_range(2000, 3000); | 358 | usleep_range(2000, 3000); |
343 | 359 | ||
344 | state->regs[0x0c] |= 0x40; | 360 | state->regs[0x0c] |= 0x40; |
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 243ac3816028..b07a681f3fbc 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c | |||
@@ -84,11 +84,22 @@ static int si2157_init(struct dvb_frontend *fe) | |||
84 | struct si2157_cmd cmd; | 84 | struct si2157_cmd cmd; |
85 | const struct firmware *fw; | 85 | const struct firmware *fw; |
86 | const char *fw_name; | 86 | const char *fw_name; |
87 | unsigned int chip_id; | 87 | unsigned int uitmp, chip_id; |
88 | 88 | ||
89 | dev_dbg(&client->dev, "\n"); | 89 | dev_dbg(&client->dev, "\n"); |
90 | 90 | ||
91 | if (dev->fw_loaded) | 91 | /* Returned IF frequency is garbage when firmware is not running */ |
92 | memcpy(cmd.args, "\x15\x00\x06\x07", 4); | ||
93 | cmd.wlen = 4; | ||
94 | cmd.rlen = 4; | ||
95 | ret = si2157_cmd_execute(client, &cmd); | ||
96 | if (ret) | ||
97 | goto err; | ||
98 | |||
99 | uitmp = cmd.args[2] << 0 | cmd.args[3] << 8; | ||
100 | dev_dbg(&client->dev, "if_frequency kHz=%u\n", uitmp); | ||
101 | |||
102 | if (uitmp == dev->if_frequency / 1000) | ||
92 | goto warm; | 103 | goto warm; |
93 | 104 | ||
94 | /* power up */ | 105 | /* power up */ |
@@ -203,9 +214,6 @@ skip_fw_download: | |||
203 | 214 | ||
204 | dev_info(&client->dev, "firmware version: %c.%c.%d\n", | 215 | dev_info(&client->dev, "firmware version: %c.%c.%d\n", |
205 | cmd.args[6], cmd.args[7], cmd.args[8]); | 216 | cmd.args[6], cmd.args[7], cmd.args[8]); |
206 | |||
207 | dev->fw_loaded = true; | ||
208 | |||
209 | warm: | 217 | warm: |
210 | /* init statistics in order signal app which are supported */ | 218 | /* init statistics in order signal app which are supported */ |
211 | c->strength.len = 1; | 219 | c->strength.len = 1; |
@@ -422,7 +430,6 @@ static int si2157_probe(struct i2c_client *client, | |||
422 | dev->fe = cfg->fe; | 430 | dev->fe = cfg->fe; |
423 | dev->inversion = cfg->inversion; | 431 | dev->inversion = cfg->inversion; |
424 | dev->if_port = cfg->if_port; | 432 | dev->if_port = cfg->if_port; |
425 | dev->fw_loaded = false; | ||
426 | dev->chiptype = (u8)id->driver_data; | 433 | dev->chiptype = (u8)id->driver_data; |
427 | dev->if_frequency = 5000000; /* default value of property 0x0706 */ | 434 | dev->if_frequency = 5000000; /* default value of property 0x0706 */ |
428 | mutex_init(&dev->i2c_mutex); | 435 | mutex_init(&dev->i2c_mutex); |
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 589d558d381c..d6b2c7b44053 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h | |||
@@ -26,7 +26,6 @@ struct si2157_dev { | |||
26 | struct mutex i2c_mutex; | 26 | struct mutex i2c_mutex; |
27 | struct dvb_frontend *fe; | 27 | struct dvb_frontend *fe; |
28 | bool active; | 28 | bool active; |
29 | bool fw_loaded; | ||
30 | bool inversion; | 29 | bool inversion; |
31 | u8 chiptype; | 30 | u8 chiptype; |
32 | u8 if_port; | 31 | u8 if_port; |
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index cc22b32776ad..321ea5cf1329 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c | |||
@@ -131,22 +131,36 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, | |||
131 | return status; | 131 | return status; |
132 | } | 132 | } |
133 | 133 | ||
134 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
135 | static void au0828_media_graph_notify(struct media_entity *new, | ||
136 | void *notify_data); | ||
137 | #endif | ||
138 | |||
134 | static void au0828_unregister_media_device(struct au0828_dev *dev) | 139 | static void au0828_unregister_media_device(struct au0828_dev *dev) |
135 | { | 140 | { |
136 | |||
137 | #ifdef CONFIG_MEDIA_CONTROLLER | 141 | #ifdef CONFIG_MEDIA_CONTROLLER |
138 | if (dev->media_dev && | 142 | struct media_device *mdev = dev->media_dev; |
139 | media_devnode_is_registered(&dev->media_dev->devnode)) { | 143 | struct media_entity_notify *notify, *nextp; |
140 | /* clear enable_source, disable_source */ | 144 | |
141 | dev->media_dev->source_priv = NULL; | 145 | if (!mdev || !media_devnode_is_registered(&mdev->devnode)) |
142 | dev->media_dev->enable_source = NULL; | 146 | return; |
143 | dev->media_dev->disable_source = NULL; | 147 | |
144 | 148 | /* Remove au0828 entity_notify callbacks */ | |
145 | media_device_unregister(dev->media_dev); | 149 | list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) { |
146 | media_device_cleanup(dev->media_dev); | 150 | if (notify->notify != au0828_media_graph_notify) |
147 | kfree(dev->media_dev); | 151 | continue; |
148 | dev->media_dev = NULL; | 152 | media_device_unregister_entity_notify(mdev, notify); |
149 | } | 153 | } |
154 | |||
155 | /* clear enable_source, disable_source */ | ||
156 | dev->media_dev->source_priv = NULL; | ||
157 | dev->media_dev->enable_source = NULL; | ||
158 | dev->media_dev->disable_source = NULL; | ||
159 | |||
160 | media_device_unregister(dev->media_dev); | ||
161 | media_device_cleanup(dev->media_dev); | ||
162 | kfree(dev->media_dev); | ||
163 | dev->media_dev = NULL; | ||
150 | #endif | 164 | #endif |
151 | } | 165 | } |
152 | 166 | ||
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 32d7db96479c..7d0ec4cb248c 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c | |||
@@ -679,8 +679,6 @@ int au0828_v4l2_device_register(struct usb_interface *interface, | |||
679 | if (retval) { | 679 | if (retval) { |
680 | pr_err("%s() v4l2_device_register failed\n", | 680 | pr_err("%s() v4l2_device_register failed\n", |
681 | __func__); | 681 | __func__); |
682 | mutex_unlock(&dev->lock); | ||
683 | kfree(dev); | ||
684 | return retval; | 682 | return retval; |
685 | } | 683 | } |
686 | 684 | ||
@@ -691,8 +689,6 @@ int au0828_v4l2_device_register(struct usb_interface *interface, | |||
691 | if (retval) { | 689 | if (retval) { |
692 | pr_err("%s() v4l2_ctrl_handler_init failed\n", | 690 | pr_err("%s() v4l2_ctrl_handler_init failed\n", |
693 | __func__); | 691 | __func__); |
694 | mutex_unlock(&dev->lock); | ||
695 | kfree(dev); | ||
696 | return retval; | 692 | return retval; |
697 | } | 693 | } |
698 | dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl; | 694 | dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl; |
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 87f32846f1c0..dd7b378fe070 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h | |||
@@ -55,7 +55,6 @@ | |||
55 | #define NTSC_STD_H 480 | 55 | #define NTSC_STD_H 480 |
56 | 56 | ||
57 | #define AU0828_INTERLACED_DEFAULT 1 | 57 | #define AU0828_INTERLACED_DEFAULT 1 |
58 | #define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0) | ||
59 | 58 | ||
60 | /* Defination for AU0828 USB transfer */ | 59 | /* Defination for AU0828 USB transfer */ |
61 | #define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */ | 60 | #define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */ |
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index c9320d6c6131..00da024b47a6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c | |||
@@ -360,7 +360,7 @@ static int wait_for_mci_complete(struct cx231xx *dev) | |||
360 | 360 | ||
361 | if (count++ > 100) { | 361 | if (count++ > 100) { |
362 | dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio); | 362 | dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio); |
363 | return -1; | 363 | return -EIO; |
364 | } | 364 | } |
365 | } | 365 | } |
366 | return 0; | 366 | return 0; |
@@ -856,7 +856,7 @@ static int cx231xx_find_mailbox(struct cx231xx *dev) | |||
856 | } | 856 | } |
857 | } | 857 | } |
858 | dprintk(3, "Mailbox signature values not found!\n"); | 858 | dprintk(3, "Mailbox signature values not found!\n"); |
859 | return -1; | 859 | return -EIO; |
860 | } | 860 | } |
861 | 861 | ||
862 | static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value, | 862 | static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value, |
@@ -960,13 +960,14 @@ static int cx231xx_load_firmware(struct cx231xx *dev) | |||
960 | p_fw = p_current_fw; | 960 | p_fw = p_current_fw; |
961 | if (p_current_fw == NULL) { | 961 | if (p_current_fw == NULL) { |
962 | dprintk(2, "FAIL!!!\n"); | 962 | dprintk(2, "FAIL!!!\n"); |
963 | return -1; | 963 | return -ENOMEM; |
964 | } | 964 | } |
965 | 965 | ||
966 | p_buffer = vmalloc(4096); | 966 | p_buffer = vmalloc(4096); |
967 | if (p_buffer == NULL) { | 967 | if (p_buffer == NULL) { |
968 | dprintk(2, "FAIL!!!\n"); | 968 | dprintk(2, "FAIL!!!\n"); |
969 | return -1; | 969 | vfree(p_current_fw); |
970 | return -ENOMEM; | ||
970 | } | 971 | } |
971 | 972 | ||
972 | dprintk(2, "%s()\n", __func__); | 973 | dprintk(2, "%s()\n", __func__); |
@@ -989,7 +990,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev) | |||
989 | if (retval != 0) { | 990 | if (retval != 0) { |
990 | dev_err(dev->dev, | 991 | dev_err(dev->dev, |
991 | "%s: Error with mc417_register_write\n", __func__); | 992 | "%s: Error with mc417_register_write\n", __func__); |
992 | return -1; | 993 | vfree(p_current_fw); |
994 | vfree(p_buffer); | ||
995 | return retval; | ||
993 | } | 996 | } |
994 | 997 | ||
995 | retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME, | 998 | retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME, |
@@ -1001,7 +1004,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev) | |||
1001 | CX231xx_FIRM_IMAGE_NAME); | 1004 | CX231xx_FIRM_IMAGE_NAME); |
1002 | dev_err(dev->dev, | 1005 | dev_err(dev->dev, |
1003 | "Please fix your hotplug setup, the board will not work without firmware loaded!\n"); | 1006 | "Please fix your hotplug setup, the board will not work without firmware loaded!\n"); |
1004 | return -1; | 1007 | vfree(p_current_fw); |
1008 | vfree(p_buffer); | ||
1009 | return retval; | ||
1005 | } | 1010 | } |
1006 | 1011 | ||
1007 | if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) { | 1012 | if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) { |
@@ -1009,14 +1014,18 @@ static int cx231xx_load_firmware(struct cx231xx *dev) | |||
1009 | "ERROR: Firmware size mismatch (have %zd, expected %d)\n", | 1014 | "ERROR: Firmware size mismatch (have %zd, expected %d)\n", |
1010 | firmware->size, CX231xx_FIRM_IMAGE_SIZE); | 1015 | firmware->size, CX231xx_FIRM_IMAGE_SIZE); |
1011 | release_firmware(firmware); | 1016 | release_firmware(firmware); |
1012 | return -1; | 1017 | vfree(p_current_fw); |
1018 | vfree(p_buffer); | ||
1019 | return -EINVAL; | ||
1013 | } | 1020 | } |
1014 | 1021 | ||
1015 | if (0 != memcmp(firmware->data, magic, 8)) { | 1022 | if (0 != memcmp(firmware->data, magic, 8)) { |
1016 | dev_err(dev->dev, | 1023 | dev_err(dev->dev, |
1017 | "ERROR: Firmware magic mismatch, wrong file?\n"); | 1024 | "ERROR: Firmware magic mismatch, wrong file?\n"); |
1018 | release_firmware(firmware); | 1025 | release_firmware(firmware); |
1019 | return -1; | 1026 | vfree(p_current_fw); |
1027 | vfree(p_buffer); | ||
1028 | return -EINVAL; | ||
1020 | } | 1029 | } |
1021 | 1030 | ||
1022 | initGPIO(dev); | 1031 | initGPIO(dev); |
@@ -1131,21 +1140,21 @@ static int cx231xx_initialize_codec(struct cx231xx *dev) | |||
1131 | if (retval < 0) { | 1140 | if (retval < 0) { |
1132 | dev_err(dev->dev, "%s: mailbox < 0, error\n", | 1141 | dev_err(dev->dev, "%s: mailbox < 0, error\n", |
1133 | __func__); | 1142 | __func__); |
1134 | return -1; | 1143 | return retval; |
1135 | } | 1144 | } |
1136 | dev->cx23417_mailbox = retval; | 1145 | dev->cx23417_mailbox = retval; |
1137 | retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); | 1146 | retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); |
1138 | if (retval < 0) { | 1147 | if (retval < 0) { |
1139 | dev_err(dev->dev, | 1148 | dev_err(dev->dev, |
1140 | "ERROR: cx23417 firmware ping failed!\n"); | 1149 | "ERROR: cx23417 firmware ping failed!\n"); |
1141 | return -1; | 1150 | return retval; |
1142 | } | 1151 | } |
1143 | retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, | 1152 | retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, |
1144 | &version); | 1153 | &version); |
1145 | if (retval < 0) { | 1154 | if (retval < 0) { |
1146 | dev_err(dev->dev, | 1155 | dev_err(dev->dev, |
1147 | "ERROR: cx23417 firmware get encoder: version failed!\n"); | 1156 | "ERROR: cx23417 firmware get encoder: version failed!\n"); |
1148 | return -1; | 1157 | return retval; |
1149 | } | 1158 | } |
1150 | dprintk(1, "cx23417 firmware version is 0x%08x\n", version); | 1159 | dprintk(1, "cx23417 firmware version is 0x%08x\n", version); |
1151 | msleep(200); | 1160 | msleep(200); |
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index f497888d94bf..6741fd02b50f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c | |||
@@ -752,7 +752,8 @@ EXPORT_SYMBOL_GPL(cx231xx_set_mode); | |||
752 | int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) | 752 | int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) |
753 | { | 753 | { |
754 | int errCode = 0; | 754 | int errCode = 0; |
755 | int actlen, ret = -ENOMEM; | 755 | int actlen = -1; |
756 | int ret = -ENOMEM; | ||
756 | u32 *buffer; | 757 | u32 *buffer; |
757 | 758 | ||
758 | buffer = kzalloc(4096, GFP_KERNEL); | 759 | buffer = kzalloc(4096, GFP_KERNEL); |
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index df22001f9e41..89e629a24aec 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h | |||
@@ -118,20 +118,20 @@ static const u32 clock_lut_it9135[] = { | |||
118 | * Values 0, 3 and 5 are seen to this day. 0 for single TS and 3/5 for dual TS. | 118 | * Values 0, 3 and 5 are seen to this day. 0 for single TS and 3/5 for dual TS. |
119 | */ | 119 | */ |
120 | 120 | ||
121 | #define EEPROM_BASE_AF9035 0x42fd | 121 | #define EEPROM_BASE_AF9035 0x42f5 |
122 | #define EEPROM_BASE_IT9135 0x499c | 122 | #define EEPROM_BASE_IT9135 0x4994 |
123 | #define EEPROM_SHIFT 0x10 | 123 | #define EEPROM_SHIFT 0x10 |
124 | 124 | ||
125 | #define EEPROM_IR_MODE 0x10 | 125 | #define EEPROM_IR_MODE 0x18 |
126 | #define EEPROM_TS_MODE 0x29 | 126 | #define EEPROM_TS_MODE 0x31 |
127 | #define EEPROM_2ND_DEMOD_ADDR 0x2a | 127 | #define EEPROM_2ND_DEMOD_ADDR 0x32 |
128 | #define EEPROM_IR_TYPE 0x2c | 128 | #define EEPROM_IR_TYPE 0x34 |
129 | #define EEPROM_1_IF_L 0x30 | 129 | #define EEPROM_1_IF_L 0x38 |
130 | #define EEPROM_1_IF_H 0x31 | 130 | #define EEPROM_1_IF_H 0x39 |
131 | #define EEPROM_1_TUNER_ID 0x34 | 131 | #define EEPROM_1_TUNER_ID 0x3c |
132 | #define EEPROM_2_IF_L 0x40 | 132 | #define EEPROM_2_IF_L 0x48 |
133 | #define EEPROM_2_IF_H 0x41 | 133 | #define EEPROM_2_IF_H 0x49 |
134 | #define EEPROM_2_TUNER_ID 0x44 | 134 | #define EEPROM_2_TUNER_ID 0x4c |
135 | 135 | ||
136 | /* USB commands */ | 136 | /* USB commands */ |
137 | #define CMD_MEM_RD 0x00 | 137 | #define CMD_MEM_RD 0x00 |
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 92e47d6c3ee3..2e711362847e 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c | |||
@@ -1090,6 +1090,7 @@ static struct usb_device_id az6027_usb_table[] = { | |||
1090 | { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, | 1090 | { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, |
1091 | { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, | 1091 | { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, |
1092 | { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) }, | 1092 | { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) }, |
1093 | { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V3) }, | ||
1093 | { }, | 1094 | { }, |
1094 | }; | 1095 | }; |
1095 | 1096 | ||
@@ -1138,7 +1139,7 @@ static struct dvb_usb_device_properties az6027_properties = { | |||
1138 | 1139 | ||
1139 | .i2c_algo = &az6027_i2c_algo, | 1140 | .i2c_algo = &az6027_i2c_algo, |
1140 | 1141 | ||
1141 | .num_device_descs = 7, | 1142 | .num_device_descs = 8, |
1142 | .devices = { | 1143 | .devices = { |
1143 | { | 1144 | { |
1144 | .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", | 1145 | .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", |
@@ -1168,6 +1169,10 @@ static struct dvb_usb_device_properties az6027_properties = { | |||
1168 | .name = "Elgato EyeTV Sat", | 1169 | .name = "Elgato EyeTV Sat", |
1169 | .cold_ids = { &az6027_usb_table[6], NULL }, | 1170 | .cold_ids = { &az6027_usb_table[6], NULL }, |
1170 | .warm_ids = { NULL }, | 1171 | .warm_ids = { NULL }, |
1172 | }, { | ||
1173 | .name = "Elgato EyeTV Sat", | ||
1174 | .cold_ids = { &az6027_usb_table[7], NULL }, | ||
1175 | .warm_ids = { NULL }, | ||
1171 | }, | 1176 | }, |
1172 | { NULL }, | 1177 | { NULL }, |
1173 | } | 1178 | } |
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index ea0391e32d23..0857b56e652c 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c | |||
@@ -3814,6 +3814,7 @@ struct usb_device_id dib0700_usb_id_table[] = { | |||
3814 | { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E) }, | 3814 | { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E) }, |
3815 | { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) }, | 3815 | { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) }, |
3816 | { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) }, | 3816 | { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) }, |
3817 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096PVR) }, | ||
3817 | { 0 } /* Terminating entry */ | 3818 | { 0 } /* Terminating entry */ |
3818 | }; | 3819 | }; |
3819 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); | 3820 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); |
@@ -5017,7 +5018,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
5017 | .num_device_descs = 1, | 5018 | .num_device_descs = 1, |
5018 | .devices = { | 5019 | .devices = { |
5019 | { "DiBcom STK8096-PVR reference design", | 5020 | { "DiBcom STK8096-PVR reference design", |
5020 | { &dib0700_usb_id_table[83], NULL }, | 5021 | { &dib0700_usb_id_table[83], |
5022 | &dib0700_usb_id_table[84], NULL}, | ||
5021 | { NULL }, | 5023 | { NULL }, |
5022 | }, | 5024 | }, |
5023 | }, | 5025 | }, |
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index 35de6095926d..6eea4e68891d 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c | |||
@@ -184,6 +184,8 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) | |||
184 | } | 184 | } |
185 | EXPORT_SYMBOL(dibusb_read_eeprom_byte); | 185 | EXPORT_SYMBOL(dibusb_read_eeprom_byte); |
186 | 186 | ||
187 | #if IS_ENABLED(CONFIG_DVB_DIB3000MC) | ||
188 | |||
187 | /* 3000MC/P stuff */ | 189 | /* 3000MC/P stuff */ |
188 | // Config Adjacent channels Perf -cal22 | 190 | // Config Adjacent channels Perf -cal22 |
189 | static struct dibx000_agc_config dib3000p_mt2060_agc_config = { | 191 | static struct dibx000_agc_config dib3000p_mt2060_agc_config = { |
@@ -242,8 +244,6 @@ static struct dibx000_agc_config dib3000p_panasonic_agc_config = { | |||
242 | .agc2_slope2 = 0x1e, | 244 | .agc2_slope2 = 0x1e, |
243 | }; | 245 | }; |
244 | 246 | ||
245 | #if IS_ENABLED(CONFIG_DVB_DIB3000MC) | ||
246 | |||
247 | static struct dib3000mc_config mod3000p_dib3000p_config = { | 247 | static struct dib3000mc_config mod3000p_dib3000p_config = { |
248 | &dib3000p_panasonic_agc_config, | 248 | &dib3000p_panasonic_agc_config, |
249 | 249 | ||
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 6d0dd859d684..49b55d7069b1 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * | 13 | * |
14 | * see Documentation/dvb/README.dvb-usb for more information | 14 | * see Documentation/dvb/README.dvb-usb for more information |
15 | */ | 15 | */ |
16 | #include "dvb-usb-ids.h" | ||
16 | #include "dw2102.h" | 17 | #include "dw2102.h" |
17 | #include "si21xx.h" | 18 | #include "si21xx.h" |
18 | #include "stv0299.h" | 19 | #include "stv0299.h" |
@@ -38,61 +39,6 @@ | |||
38 | /* Max transfer size done by I2C transfer functions */ | 39 | /* Max transfer size done by I2C transfer functions */ |
39 | #define MAX_XFER_SIZE 64 | 40 | #define MAX_XFER_SIZE 64 |
40 | 41 | ||
41 | #ifndef USB_PID_DW2102 | ||
42 | #define USB_PID_DW2102 0x2102 | ||
43 | #endif | ||
44 | |||
45 | #ifndef USB_PID_DW2104 | ||
46 | #define USB_PID_DW2104 0x2104 | ||
47 | #endif | ||
48 | |||
49 | #ifndef USB_PID_DW3101 | ||
50 | #define USB_PID_DW3101 0x3101 | ||
51 | #endif | ||
52 | |||
53 | #ifndef USB_PID_CINERGY_S | ||
54 | #define USB_PID_CINERGY_S 0x0064 | ||
55 | #endif | ||
56 | |||
57 | #ifndef USB_PID_TEVII_S630 | ||
58 | #define USB_PID_TEVII_S630 0xd630 | ||
59 | #endif | ||
60 | |||
61 | #ifndef USB_PID_TEVII_S650 | ||
62 | #define USB_PID_TEVII_S650 0xd650 | ||
63 | #endif | ||
64 | |||
65 | #ifndef USB_PID_TEVII_S660 | ||
66 | #define USB_PID_TEVII_S660 0xd660 | ||
67 | #endif | ||
68 | |||
69 | #ifndef USB_PID_TEVII_S662 | ||
70 | #define USB_PID_TEVII_S662 0xd662 | ||
71 | #endif | ||
72 | |||
73 | #ifndef USB_PID_TEVII_S480_1 | ||
74 | #define USB_PID_TEVII_S480_1 0xd481 | ||
75 | #endif | ||
76 | |||
77 | #ifndef USB_PID_TEVII_S480_2 | ||
78 | #define USB_PID_TEVII_S480_2 0xd482 | ||
79 | #endif | ||
80 | |||
81 | #ifndef USB_PID_PROF_1100 | ||
82 | #define USB_PID_PROF_1100 0xb012 | ||
83 | #endif | ||
84 | |||
85 | #ifndef USB_PID_TEVII_S421 | ||
86 | #define USB_PID_TEVII_S421 0xd421 | ||
87 | #endif | ||
88 | |||
89 | #ifndef USB_PID_TEVII_S632 | ||
90 | #define USB_PID_TEVII_S632 0xd632 | ||
91 | #endif | ||
92 | |||
93 | #ifndef USB_PID_GOTVIEW_SAT_HD | ||
94 | #define USB_PID_GOTVIEW_SAT_HD 0x5456 | ||
95 | #endif | ||
96 | 42 | ||
97 | #define DW210X_READ_MSG 0 | 43 | #define DW210X_READ_MSG 0 |
98 | #define DW210X_WRITE_MSG 1 | 44 | #define DW210X_WRITE_MSG 1 |
@@ -1709,7 +1655,7 @@ static struct usb_device_id dw2102_table[] = { | |||
1709 | [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, | 1655 | [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, |
1710 | [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, | 1656 | [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, |
1711 | [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, | 1657 | [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, |
1712 | [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, | 1658 | [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S)}, |
1713 | [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, | 1659 | [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, |
1714 | [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, | 1660 | [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, |
1715 | [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, | 1661 | [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, |
@@ -1801,7 +1747,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
1801 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, | 1747 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, |
1802 | DW210X_WRITE_MSG); | 1748 | DW210X_WRITE_MSG); |
1803 | break; | 1749 | break; |
1804 | case USB_PID_CINERGY_S: | 1750 | case USB_PID_TERRATEC_CINERGY_S: |
1805 | case USB_PID_DW2102: | 1751 | case USB_PID_DW2102: |
1806 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, | 1752 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, |
1807 | DW210X_WRITE_MSG); | 1753 | DW210X_WRITE_MSG); |
@@ -1843,6 +1789,9 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
1843 | msleep(100); | 1789 | msleep(100); |
1844 | kfree(p); | 1790 | kfree(p); |
1845 | } | 1791 | } |
1792 | |||
1793 | if (le16_to_cpu(dev->descriptor.idProduct) == 0x2101) | ||
1794 | release_firmware(fw); | ||
1846 | return ret; | 1795 | return ret; |
1847 | } | 1796 | } |
1848 | 1797 | ||
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index ec397c4b7cc8..c05de1b088a4 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c | |||
@@ -995,11 +995,11 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { | |||
995 | /* parameter for the MPEG2-data transfer */ | 995 | /* parameter for the MPEG2-data transfer */ |
996 | .stream = { | 996 | .stream = { |
997 | .type = USB_ISOC, | 997 | .type = USB_ISOC, |
998 | .count = 7, | 998 | .count = 4, |
999 | .endpoint = 0x02, | 999 | .endpoint = 0x02, |
1000 | .u = { | 1000 | .u = { |
1001 | .isoc = { | 1001 | .isoc = { |
1002 | .framesperurb = 4, | 1002 | .framesperurb = 64, |
1003 | .framesize = 940, | 1003 | .framesize = 940, |
1004 | .interval = 1 | 1004 | .interval = 1 |
1005 | } | 1005 | } |
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index e382210c4ada..d917b0a2beb1 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig | |||
@@ -59,6 +59,8 @@ config VIDEO_EM28XX_DVB | |||
59 | select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT | 59 | select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT |
60 | select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT | 60 | select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT |
61 | select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT | 61 | select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT |
62 | select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT | ||
63 | select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT | ||
62 | ---help--- | 64 | ---help--- |
63 | This adds support for DVB cards based on the | 65 | This adds support for DVB cards based on the |
64 | Empiatech em28xx chips. | 66 | Empiatech em28xx chips. |
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 930e3e3fc948..e397f544f108 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c | |||
@@ -492,6 +492,44 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = { | |||
492 | {-1, -1, -1, -1}, | 492 | {-1, -1, -1, -1}, |
493 | }; | 493 | }; |
494 | 494 | ||
495 | static struct em28xx_reg_seq plex_px_bcud[] = { | ||
496 | {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, | ||
497 | {0x0d, 0xff, 0xff, 0}, | ||
498 | {EM2874_R50_IR_CONFIG, 0x01, 0xff, 0}, | ||
499 | {EM28XX_R06_I2C_CLK, 0x40, 0xff, 0}, | ||
500 | {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 100}, | ||
501 | {EM28XX_R12_VINENABLE, 0x20, 0x20, 0}, | ||
502 | {0x0d, 0x42, 0xff, 1000}, | ||
503 | {EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 10}, | ||
504 | {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 10}, | ||
505 | {0x73, 0xfd, 0xff, 100}, | ||
506 | {-1, -1, -1, -1}, | ||
507 | }; | ||
508 | |||
509 | /* | ||
510 | * 2040:0265 Hauppauge WinTV-dualHD DVB | ||
511 | * reg 0x80/0x84: | ||
512 | * GPIO_0: Yellow LED tuner 1, 0=on, 1=off | ||
513 | * GPIO_1: Green LED tuner 1, 0=on, 1=off | ||
514 | * GPIO_2: Yellow LED tuner 2, 0=on, 1=off | ||
515 | * GPIO_3: Green LED tuner 2, 0=on, 1=off | ||
516 | * GPIO_5: Reset #2, 0=active | ||
517 | * GPIO_6: Reset #1, 0=active | ||
518 | */ | ||
519 | static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { | ||
520 | {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, | ||
521 | {0x0d, 0xff, 0xff, 200}, | ||
522 | {0x50, 0x04, 0xff, 300}, | ||
523 | {EM2874_R80_GPIO_P0_CTRL, 0xbf, 0xff, 100}, /* demod 1 reset */ | ||
524 | {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, | ||
525 | {EM2874_R80_GPIO_P0_CTRL, 0xdf, 0xff, 100}, /* demod 2 reset */ | ||
526 | {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, | ||
527 | {EM2874_R5F_TS_ENABLE, 0x44, 0xff, 50}, | ||
528 | {EM2874_R5D_TS1_PKT_SIZE, 0x05, 0xff, 50}, | ||
529 | {EM2874_R5E_TS2_PKT_SIZE, 0x05, 0xff, 50}, | ||
530 | {-1, -1, -1, -1}, | ||
531 | }; | ||
532 | |||
495 | /* | 533 | /* |
496 | * Button definitions | 534 | * Button definitions |
497 | */ | 535 | */ |
@@ -571,6 +609,22 @@ static struct em28xx_led terratec_grabby_leds[] = { | |||
571 | {-1, 0, 0, 0}, | 609 | {-1, 0, 0, 0}, |
572 | }; | 610 | }; |
573 | 611 | ||
612 | static struct em28xx_led hauppauge_dualhd_leds[] = { | ||
613 | { | ||
614 | .role = EM28XX_LED_DIGITAL_CAPTURING, | ||
615 | .gpio_reg = EM2874_R80_GPIO_P0_CTRL, | ||
616 | .gpio_mask = EM_GPIO_1, | ||
617 | .inverted = 1, | ||
618 | }, | ||
619 | { | ||
620 | .role = EM28XX_LED_DIGITAL_CAPTURING_TS2, | ||
621 | .gpio_reg = EM2874_R80_GPIO_P0_CTRL, | ||
622 | .gpio_mask = EM_GPIO_3, | ||
623 | .inverted = 1, | ||
624 | }, | ||
625 | {-1, 0, 0, 0}, | ||
626 | }; | ||
627 | |||
574 | /* | 628 | /* |
575 | * Board definitions | 629 | * Board definitions |
576 | */ | 630 | */ |
@@ -2306,6 +2360,35 @@ struct em28xx_board em28xx_boards[] = { | |||
2306 | .has_dvb = 1, | 2360 | .has_dvb = 1, |
2307 | .ir_codes = RC_MAP_TERRATEC_SLIM_2, | 2361 | .ir_codes = RC_MAP_TERRATEC_SLIM_2, |
2308 | }, | 2362 | }, |
2363 | |||
2364 | /* | ||
2365 | * 3275:0085 PLEX PX-BCUD. | ||
2366 | * Empia EM28178, TOSHIBA TC90532XBG, Sharp QM1D1C0042 | ||
2367 | */ | ||
2368 | [EM28178_BOARD_PLEX_PX_BCUD] = { | ||
2369 | .name = "PLEX PX-BCUD", | ||
2370 | .xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ, | ||
2371 | .def_i2c_bus = 1, | ||
2372 | .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, | ||
2373 | .tuner_type = TUNER_ABSENT, | ||
2374 | .tuner_gpio = plex_px_bcud, | ||
2375 | .has_dvb = 1, | ||
2376 | }, | ||
2377 | /* | ||
2378 | * 2040:0265 Hauppauge WinTV-dualHD (DVB version). | ||
2379 | * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 | ||
2380 | */ | ||
2381 | [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = { | ||
2382 | .name = "Hauppauge WinTV-dualHD DVB", | ||
2383 | .def_i2c_bus = 1, | ||
2384 | .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | | ||
2385 | EM28XX_I2C_FREQ_400_KHZ, | ||
2386 | .tuner_type = TUNER_ABSENT, | ||
2387 | .tuner_gpio = hauppauge_dualhd_dvb, | ||
2388 | .has_dvb = 1, | ||
2389 | .ir_codes = RC_MAP_HAUPPAUGE, | ||
2390 | .leds = hauppauge_dualhd_leds, | ||
2391 | }, | ||
2309 | }; | 2392 | }; |
2310 | EXPORT_SYMBOL_GPL(em28xx_boards); | 2393 | EXPORT_SYMBOL_GPL(em28xx_boards); |
2311 | 2394 | ||
@@ -2429,6 +2512,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
2429 | .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, | 2512 | .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, |
2430 | { USB_DEVICE(0x2040, 0x651f), | 2513 | { USB_DEVICE(0x2040, 0x651f), |
2431 | .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, | 2514 | .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, |
2515 | { USB_DEVICE(0x2040, 0x0265), | ||
2516 | .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, | ||
2432 | { USB_DEVICE(0x0438, 0xb002), | 2517 | { USB_DEVICE(0x0438, 0xb002), |
2433 | .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, | 2518 | .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, |
2434 | { USB_DEVICE(0x2001, 0xf112), | 2519 | { USB_DEVICE(0x2001, 0xf112), |
@@ -2495,6 +2580,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
2495 | .driver_info = EM2861_BOARD_LEADTEK_VC100 }, | 2580 | .driver_info = EM2861_BOARD_LEADTEK_VC100 }, |
2496 | { USB_DEVICE(0xeb1a, 0x8179), | 2581 | { USB_DEVICE(0xeb1a, 0x8179), |
2497 | .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD }, | 2582 | .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD }, |
2583 | { USB_DEVICE(0x3275, 0x0085), | ||
2584 | .driver_info = EM28178_BOARD_PLEX_PX_BCUD }, | ||
2498 | { }, | 2585 | { }, |
2499 | }; | 2586 | }; |
2500 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); | 2587 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); |
@@ -2861,6 +2948,7 @@ static void em28xx_card_setup(struct em28xx *dev) | |||
2861 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: | 2948 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: |
2862 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | 2949 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: |
2863 | case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: | 2950 | case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: |
2951 | case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: | ||
2864 | { | 2952 | { |
2865 | struct tveeprom tv; | 2953 | struct tveeprom tv; |
2866 | 2954 | ||
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 5d209c7c54d5..1a5c01202f73 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c | |||
@@ -58,6 +58,8 @@ | |||
58 | #include "ts2020.h" | 58 | #include "ts2020.h" |
59 | #include "si2168.h" | 59 | #include "si2168.h" |
60 | #include "si2157.h" | 60 | #include "si2157.h" |
61 | #include "tc90522.h" | ||
62 | #include "qm1d1c0042.h" | ||
61 | 63 | ||
62 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | 64 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); |
63 | MODULE_LICENSE("GPL"); | 65 | MODULE_LICENSE("GPL"); |
@@ -787,6 +789,68 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) | |||
787 | return 0; | 789 | return 0; |
788 | } | 790 | } |
789 | 791 | ||
792 | static void px_bcud_init(struct em28xx *dev) | ||
793 | { | ||
794 | int i; | ||
795 | struct { | ||
796 | unsigned char r[4]; | ||
797 | int len; | ||
798 | } regs1[] = { | ||
799 | {{ 0x0e, 0x77 }, 2}, | ||
800 | {{ 0x0f, 0x77 }, 2}, | ||
801 | {{ 0x03, 0x90 }, 2}, | ||
802 | }, regs2[] = { | ||
803 | {{ 0x07, 0x01 }, 2}, | ||
804 | {{ 0x08, 0x10 }, 2}, | ||
805 | {{ 0x13, 0x00 }, 2}, | ||
806 | {{ 0x17, 0x00 }, 2}, | ||
807 | {{ 0x03, 0x01 }, 2}, | ||
808 | {{ 0x10, 0xb1 }, 2}, | ||
809 | {{ 0x11, 0x40 }, 2}, | ||
810 | {{ 0x85, 0x7a }, 2}, | ||
811 | {{ 0x87, 0x04 }, 2}, | ||
812 | }; | ||
813 | static struct em28xx_reg_seq gpio[] = { | ||
814 | {EM28XX_R06_I2C_CLK, 0x40, 0xff, 300}, | ||
815 | {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 60}, | ||
816 | {EM28XX_R15_RGAIN, 0x20, 0xff, 0}, | ||
817 | {EM28XX_R16_GGAIN, 0x20, 0xff, 0}, | ||
818 | {EM28XX_R17_BGAIN, 0x20, 0xff, 0}, | ||
819 | {EM28XX_R18_ROFFSET, 0x00, 0xff, 0}, | ||
820 | {EM28XX_R19_GOFFSET, 0x00, 0xff, 0}, | ||
821 | {EM28XX_R1A_BOFFSET, 0x00, 0xff, 0}, | ||
822 | {EM28XX_R23_UOFFSET, 0x00, 0xff, 0}, | ||
823 | {EM28XX_R24_VOFFSET, 0x00, 0xff, 0}, | ||
824 | {EM28XX_R26_COMPR, 0x00, 0xff, 0}, | ||
825 | {0x13, 0x08, 0xff, 0}, | ||
826 | {EM28XX_R12_VINENABLE, 0x27, 0xff, 0}, | ||
827 | {EM28XX_R0C_USBSUSP, 0x10, 0xff, 0}, | ||
828 | {EM28XX_R27_OUTFMT, 0x00, 0xff, 0}, | ||
829 | {EM28XX_R10_VINMODE, 0x00, 0xff, 0}, | ||
830 | {EM28XX_R11_VINCTRL, 0x11, 0xff, 0}, | ||
831 | {EM2874_R50_IR_CONFIG, 0x01, 0xff, 0}, | ||
832 | {EM2874_R5F_TS_ENABLE, 0x80, 0xff, 0}, | ||
833 | {EM28XX_R06_I2C_CLK, 0x46, 0xff, 0}, | ||
834 | }; | ||
835 | em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x46); | ||
836 | /* sleeping ISDB-T */ | ||
837 | dev->dvb->i2c_client_demod->addr = 0x14; | ||
838 | for (i = 0; i < ARRAY_SIZE(regs1); i++) | ||
839 | i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r, | ||
840 | regs1[i].len); | ||
841 | /* sleeping ISDB-S */ | ||
842 | dev->dvb->i2c_client_demod->addr = 0x15; | ||
843 | for (i = 0; i < ARRAY_SIZE(regs2); i++) | ||
844 | i2c_master_send(dev->dvb->i2c_client_demod, regs2[i].r, | ||
845 | regs2[i].len); | ||
846 | for (i = 0; i < ARRAY_SIZE(gpio); i++) { | ||
847 | em28xx_write_reg_bits(dev, gpio[i].reg, gpio[i].val, | ||
848 | gpio[i].mask); | ||
849 | if (gpio[i].sleep > 0) | ||
850 | msleep(gpio[i].sleep); | ||
851 | } | ||
852 | }; | ||
853 | |||
790 | static struct mt352_config terratec_xs_mt352_cfg = { | 854 | static struct mt352_config terratec_xs_mt352_cfg = { |
791 | .demod_address = (0x1e >> 1), | 855 | .demod_address = (0x1e >> 1), |
792 | .no_tuner = 1, | 856 | .no_tuner = 1, |
@@ -1762,6 +1826,127 @@ static int em28xx_dvb_init(struct em28xx *dev) | |||
1762 | dvb->i2c_client_tuner = client; | 1826 | dvb->i2c_client_tuner = client; |
1763 | } | 1827 | } |
1764 | break; | 1828 | break; |
1829 | |||
1830 | case EM28178_BOARD_PLEX_PX_BCUD: | ||
1831 | { | ||
1832 | struct i2c_client *client; | ||
1833 | struct i2c_board_info info; | ||
1834 | struct tc90522_config tc90522_config; | ||
1835 | struct qm1d1c0042_config qm1d1c0042_config; | ||
1836 | |||
1837 | /* attach demod */ | ||
1838 | memset(&tc90522_config, 0, sizeof(tc90522_config)); | ||
1839 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1840 | strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); | ||
1841 | info.addr = 0x15; | ||
1842 | info.platform_data = &tc90522_config; | ||
1843 | request_module("tc90522"); | ||
1844 | client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); | ||
1845 | if (client == NULL || client->dev.driver == NULL) { | ||
1846 | result = -ENODEV; | ||
1847 | goto out_free; | ||
1848 | } | ||
1849 | dvb->i2c_client_demod = client; | ||
1850 | if (!try_module_get(client->dev.driver->owner)) { | ||
1851 | i2c_unregister_device(client); | ||
1852 | result = -ENODEV; | ||
1853 | goto out_free; | ||
1854 | } | ||
1855 | |||
1856 | /* attach tuner */ | ||
1857 | memset(&qm1d1c0042_config, 0, | ||
1858 | sizeof(qm1d1c0042_config)); | ||
1859 | qm1d1c0042_config.fe = tc90522_config.fe; | ||
1860 | qm1d1c0042_config.lpf = 1; | ||
1861 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1862 | strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE); | ||
1863 | info.addr = 0x61; | ||
1864 | info.platform_data = &qm1d1c0042_config; | ||
1865 | request_module(info.type); | ||
1866 | client = i2c_new_device(tc90522_config.tuner_i2c, | ||
1867 | &info); | ||
1868 | if (client == NULL || client->dev.driver == NULL) { | ||
1869 | module_put(dvb->i2c_client_demod->dev.driver->owner); | ||
1870 | i2c_unregister_device(dvb->i2c_client_demod); | ||
1871 | result = -ENODEV; | ||
1872 | goto out_free; | ||
1873 | } | ||
1874 | dvb->i2c_client_tuner = client; | ||
1875 | if (!try_module_get(client->dev.driver->owner)) { | ||
1876 | i2c_unregister_device(client); | ||
1877 | module_put(dvb->i2c_client_demod->dev.driver->owner); | ||
1878 | i2c_unregister_device(dvb->i2c_client_demod); | ||
1879 | result = -ENODEV; | ||
1880 | goto out_free; | ||
1881 | } | ||
1882 | dvb->fe[0] = tc90522_config.fe; | ||
1883 | px_bcud_init(dev); | ||
1884 | } | ||
1885 | break; | ||
1886 | case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: | ||
1887 | { | ||
1888 | struct i2c_adapter *adapter; | ||
1889 | struct i2c_client *client; | ||
1890 | struct i2c_board_info info; | ||
1891 | struct si2168_config si2168_config; | ||
1892 | struct si2157_config si2157_config; | ||
1893 | |||
1894 | /* attach demod */ | ||
1895 | memset(&si2168_config, 0, sizeof(si2168_config)); | ||
1896 | si2168_config.i2c_adapter = &adapter; | ||
1897 | si2168_config.fe = &dvb->fe[0]; | ||
1898 | si2168_config.ts_mode = SI2168_TS_SERIAL; | ||
1899 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1900 | strlcpy(info.type, "si2168", I2C_NAME_SIZE); | ||
1901 | info.addr = 0x64; | ||
1902 | info.platform_data = &si2168_config; | ||
1903 | request_module(info.type); | ||
1904 | client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); | ||
1905 | if (client == NULL || client->dev.driver == NULL) { | ||
1906 | result = -ENODEV; | ||
1907 | goto out_free; | ||
1908 | } | ||
1909 | |||
1910 | if (!try_module_get(client->dev.driver->owner)) { | ||
1911 | i2c_unregister_device(client); | ||
1912 | result = -ENODEV; | ||
1913 | goto out_free; | ||
1914 | } | ||
1915 | |||
1916 | dvb->i2c_client_demod = client; | ||
1917 | |||
1918 | /* attach tuner */ | ||
1919 | memset(&si2157_config, 0, sizeof(si2157_config)); | ||
1920 | si2157_config.fe = dvb->fe[0]; | ||
1921 | si2157_config.if_port = 1; | ||
1922 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB | ||
1923 | si2157_config.mdev = dev->media_dev; | ||
1924 | #endif | ||
1925 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1926 | strlcpy(info.type, "si2157", I2C_NAME_SIZE); | ||
1927 | info.addr = 0x60; | ||
1928 | info.platform_data = &si2157_config; | ||
1929 | request_module(info.type); | ||
1930 | client = i2c_new_device(adapter, &info); | ||
1931 | if (client == NULL || client->dev.driver == NULL) { | ||
1932 | module_put(dvb->i2c_client_demod->dev.driver->owner); | ||
1933 | i2c_unregister_device(dvb->i2c_client_demod); | ||
1934 | result = -ENODEV; | ||
1935 | goto out_free; | ||
1936 | } | ||
1937 | |||
1938 | if (!try_module_get(client->dev.driver->owner)) { | ||
1939 | i2c_unregister_device(client); | ||
1940 | module_put(dvb->i2c_client_demod->dev.driver->owner); | ||
1941 | i2c_unregister_device(dvb->i2c_client_demod); | ||
1942 | result = -ENODEV; | ||
1943 | goto out_free; | ||
1944 | } | ||
1945 | |||
1946 | dvb->i2c_client_tuner = client; | ||
1947 | |||
1948 | } | ||
1949 | break; | ||
1765 | default: | 1950 | default: |
1766 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" | 1951 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" |
1767 | " isn't supported yet\n"); | 1952 | " isn't supported yet\n"); |
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 13cbb7f3ea10..afe7a66d7dc8 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h | |||
@@ -193,6 +193,19 @@ | |||
193 | /* em2874 registers */ | 193 | /* em2874 registers */ |
194 | #define EM2874_R50_IR_CONFIG 0x50 | 194 | #define EM2874_R50_IR_CONFIG 0x50 |
195 | #define EM2874_R51_IR 0x51 | 195 | #define EM2874_R51_IR 0x51 |
196 | #define EM2874_R5D_TS1_PKT_SIZE 0x5d | ||
197 | #define EM2874_R5E_TS2_PKT_SIZE 0x5e | ||
198 | /* | ||
199 | * For both TS1 and TS2, In isochronous mode: | ||
200 | * 0x01 188 bytes | ||
201 | * 0x02 376 bytes | ||
202 | * 0x03 564 bytes | ||
203 | * 0x04 752 bytes | ||
204 | * 0x05 940 bytes | ||
205 | * In bulk mode: | ||
206 | * 0x01..0xff total packet count in 188-byte | ||
207 | */ | ||
208 | |||
196 | #define EM2874_R5F_TS_ENABLE 0x5f | 209 | #define EM2874_R5F_TS_ENABLE 0x5f |
197 | 210 | ||
198 | /* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */ | 211 | /* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */ |
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 267444961775..d148463b22c1 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h | |||
@@ -145,6 +145,8 @@ | |||
145 | #define EM2861_BOARD_LEADTEK_VC100 95 | 145 | #define EM2861_BOARD_LEADTEK_VC100 95 |
146 | #define EM28178_BOARD_TERRATEC_T2_STICK_HD 96 | 146 | #define EM28178_BOARD_TERRATEC_T2_STICK_HD 96 |
147 | #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 97 | 147 | #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 97 |
148 | #define EM28178_BOARD_PLEX_PX_BCUD 98 | ||
149 | #define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB 99 | ||
148 | 150 | ||
149 | /* Limits minimum and default number of buffers */ | 151 | /* Limits minimum and default number of buffers */ |
150 | #define EM28XX_MIN_BUF 4 | 152 | #define EM28XX_MIN_BUF 4 |
@@ -406,6 +408,7 @@ enum em28xx_adecoder { | |||
406 | enum em28xx_led_role { | 408 | enum em28xx_led_role { |
407 | EM28XX_LED_ANALOG_CAPTURING = 0, | 409 | EM28XX_LED_ANALOG_CAPTURING = 0, |
408 | EM28XX_LED_DIGITAL_CAPTURING, | 410 | EM28XX_LED_DIGITAL_CAPTURING, |
411 | EM28XX_LED_DIGITAL_CAPTURING_TS2, | ||
409 | EM28XX_LED_ILLUMINATION, | 412 | EM28XX_LED_ILLUMINATION, |
410 | EM28XX_NUM_LED_ROLES, /* must be the last */ | 413 | EM28XX_NUM_LED_ROLES, /* must be the last */ |
411 | }; | 414 | }; |
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 358c1c186d03..ea01ee5df60a 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c | |||
@@ -1125,7 +1125,7 @@ int go7007_v4l2_init(struct go7007 *go) | |||
1125 | vdev->queue = &go->vidq; | 1125 | vdev->queue = &go->vidq; |
1126 | video_set_drvdata(vdev, go); | 1126 | video_set_drvdata(vdev, go); |
1127 | vdev->v4l2_dev = &go->v4l2_dev; | 1127 | vdev->v4l2_dev = &go->v4l2_dev; |
1128 | if (!v4l2_device_has_op(&go->v4l2_dev, video, querystd)) | 1128 | if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd)) |
1129 | v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD); | 1129 | v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD); |
1130 | if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { | 1130 | if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { |
1131 | v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY); | 1131 | v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY); |
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 1a093e5953fd..83e9a3eb3859 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c | |||
@@ -3672,11 +3672,10 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, | |||
3672 | 3672 | ||
3673 | 3673 | ||
3674 | hdw->cmd_debug_state = 1; | 3674 | hdw->cmd_debug_state = 1; |
3675 | if (write_len) { | 3675 | if (write_len && write_data) |
3676 | hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; | 3676 | hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; |
3677 | } else { | 3677 | else |
3678 | hdw->cmd_debug_code = 0; | 3678 | hdw->cmd_debug_code = 0; |
3679 | } | ||
3680 | hdw->cmd_debug_write_len = write_len; | 3679 | hdw->cmd_debug_write_len = write_len; |
3681 | hdw->cmd_debug_read_len = read_len; | 3680 | hdw->cmd_debug_read_len = read_len; |
3682 | 3681 | ||
@@ -3688,7 +3687,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, | |||
3688 | setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw); | 3687 | setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw); |
3689 | timer.expires = jiffies + timeout; | 3688 | timer.expires = jiffies + timeout; |
3690 | 3689 | ||
3691 | if (write_len) { | 3690 | if (write_len && write_data) { |
3692 | hdw->cmd_debug_state = 2; | 3691 | hdw->cmd_debug_state = 2; |
3693 | /* Transfer write data to internal buffer */ | 3692 | /* Transfer write data to internal buffer */ |
3694 | for (idx = 0; idx < write_len; idx++) { | 3693 | for (idx = 0; idx < write_len; idx++) { |
@@ -3795,7 +3794,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, | |||
3795 | goto done; | 3794 | goto done; |
3796 | } | 3795 | } |
3797 | } | 3796 | } |
3798 | if (read_len) { | 3797 | if (read_len && read_data) { |
3799 | /* Validate results of read request */ | 3798 | /* Validate results of read request */ |
3800 | if ((hdw->ctl_read_urb->status != 0) && | 3799 | if ((hdw->ctl_read_urb->status != 0) && |
3801 | (hdw->ctl_read_urb->status != -ENOENT) && | 3800 | (hdw->ctl_read_urb->status != -ENOENT) && |
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 019644ff627d..bacecbd68a6d 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c | |||
@@ -280,7 +280,8 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
280 | static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) | 280 | static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) |
281 | { | 281 | { |
282 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || | 282 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || |
283 | copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format))) | 283 | copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || |
284 | copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) | ||
284 | return -EFAULT; | 285 | return -EFAULT; |
285 | return __put_v4l2_format32(&kp->format, &up->format); | 286 | return __put_v4l2_format32(&kp->format, &up->format); |
286 | } | 287 | } |
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index d8e5994cccf1..70b559d7ca80 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c | |||
@@ -735,6 +735,7 @@ static int video_register_media_controller(struct video_device *vdev, int type) | |||
735 | if (!vdev->v4l2_dev->mdev) | 735 | if (!vdev->v4l2_dev->mdev) |
736 | return 0; | 736 | return 0; |
737 | 737 | ||
738 | vdev->entity.obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE; | ||
738 | vdev->entity.function = MEDIA_ENT_F_UNKNOWN; | 739 | vdev->entity.function = MEDIA_ENT_F_UNKNOWN; |
739 | 740 | ||
740 | switch (type) { | 741 | switch (type) { |
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 170dd68d27f4..28e5be2c2eef 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c | |||
@@ -1020,9 +1020,12 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, | |||
1020 | struct file *file, void *fh, void *arg) | 1020 | struct file *file, void *fh, void *arg) |
1021 | { | 1021 | { |
1022 | struct v4l2_capability *cap = (struct v4l2_capability *)arg; | 1022 | struct v4l2_capability *cap = (struct v4l2_capability *)arg; |
1023 | struct video_device *vfd = video_devdata(file); | ||
1023 | int ret; | 1024 | int ret; |
1024 | 1025 | ||
1025 | cap->version = LINUX_VERSION_CODE; | 1026 | cap->version = LINUX_VERSION_CODE; |
1027 | cap->device_caps = vfd->device_caps; | ||
1028 | cap->capabilities = vfd->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
1026 | 1029 | ||
1027 | ret = ops->vidioc_querycap(file, fh, cap); | 1030 | ret = ops->vidioc_querycap(file, fh, cap); |
1028 | 1031 | ||
@@ -2157,40 +2160,56 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, | |||
2157 | struct file *file, void *fh, void *arg) | 2160 | struct file *file, void *fh, void *arg) |
2158 | { | 2161 | { |
2159 | struct v4l2_cropcap *p = arg; | 2162 | struct v4l2_cropcap *p = arg; |
2163 | struct v4l2_selection s = { .type = p->type }; | ||
2164 | int ret = 0; | ||
2160 | 2165 | ||
2161 | if (ops->vidioc_g_selection) { | 2166 | /* setting trivial pixelaspect */ |
2162 | struct v4l2_selection s = { .type = p->type }; | 2167 | p->pixelaspect.numerator = 1; |
2163 | int ret; | 2168 | p->pixelaspect.denominator = 1; |
2164 | 2169 | ||
2165 | /* obtaining bounds */ | 2170 | /* |
2166 | if (V4L2_TYPE_IS_OUTPUT(p->type)) | 2171 | * The determine_valid_ioctls() call already should ensure |
2167 | s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; | 2172 | * that this can never happen, but just in case... |
2168 | else | 2173 | */ |
2169 | s.target = V4L2_SEL_TGT_CROP_BOUNDS; | 2174 | if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_cropcap)) |
2175 | return -ENOTTY; | ||
2170 | 2176 | ||
2171 | ret = ops->vidioc_g_selection(file, fh, &s); | 2177 | if (ops->vidioc_cropcap) |
2172 | if (ret) | 2178 | ret = ops->vidioc_cropcap(file, fh, p); |
2173 | return ret; | ||
2174 | p->bounds = s.r; | ||
2175 | 2179 | ||
2176 | /* obtaining defrect */ | 2180 | if (!ops->vidioc_g_selection) |
2177 | if (V4L2_TYPE_IS_OUTPUT(p->type)) | 2181 | return ret; |
2178 | s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; | ||
2179 | else | ||
2180 | s.target = V4L2_SEL_TGT_CROP_DEFAULT; | ||
2181 | 2182 | ||
2182 | ret = ops->vidioc_g_selection(file, fh, &s); | 2183 | /* |
2183 | if (ret) | 2184 | * Ignore ENOTTY or ENOIOCTLCMD error returns, just use the |
2184 | return ret; | 2185 | * square pixel aspect ratio in that case. |
2185 | p->defrect = s.r; | 2186 | */ |
2186 | } | 2187 | if (ret && ret != -ENOTTY && ret != -ENOIOCTLCMD) |
2188 | return ret; | ||
2187 | 2189 | ||
2188 | /* setting trivial pixelaspect */ | 2190 | /* Use g_selection() to fill in the bounds and defrect rectangles */ |
2189 | p->pixelaspect.numerator = 1; | ||
2190 | p->pixelaspect.denominator = 1; | ||
2191 | 2191 | ||
2192 | if (ops->vidioc_cropcap) | 2192 | /* obtaining bounds */ |
2193 | return ops->vidioc_cropcap(file, fh, p); | 2193 | if (V4L2_TYPE_IS_OUTPUT(p->type)) |
2194 | s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; | ||
2195 | else | ||
2196 | s.target = V4L2_SEL_TGT_CROP_BOUNDS; | ||
2197 | |||
2198 | ret = ops->vidioc_g_selection(file, fh, &s); | ||
2199 | if (ret) | ||
2200 | return ret; | ||
2201 | p->bounds = s.r; | ||
2202 | |||
2203 | /* obtaining defrect */ | ||
2204 | if (V4L2_TYPE_IS_OUTPUT(p->type)) | ||
2205 | s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; | ||
2206 | else | ||
2207 | s.target = V4L2_SEL_TGT_CROP_DEFAULT; | ||
2208 | |||
2209 | ret = ops->vidioc_g_selection(file, fh, &s); | ||
2210 | if (ret) | ||
2211 | return ret; | ||
2212 | p->defrect = s.r; | ||
2194 | 2213 | ||
2195 | return 0; | 2214 | return 0; |
2196 | } | 2215 | } |
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index 2228cd3a846e..ca94bded3386 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c | |||
@@ -263,7 +263,7 @@ static int pipeline_pm_use_count(struct media_entity *entity, | |||
263 | media_entity_graph_walk_start(graph, entity); | 263 | media_entity_graph_walk_start(graph, entity); |
264 | 264 | ||
265 | while ((entity = media_entity_graph_walk_next(graph))) { | 265 | while ((entity = media_entity_graph_walk_next(graph))) { |
266 | if (is_media_entity_v4l2_io(entity)) | 266 | if (is_media_entity_v4l2_video_device(entity)) |
267 | use += entity->use_count; | 267 | use += entity->use_count; |
268 | } | 268 | } |
269 | 269 | ||
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index d63083803144..953eab08e420 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c | |||
@@ -35,9 +35,11 @@ | |||
35 | static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) | 35 | static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) |
36 | { | 36 | { |
37 | #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) | 37 | #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) |
38 | fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL); | 38 | if (sd->entity.num_pads) { |
39 | if (fh->pad == NULL) | 39 | fh->pad = v4l2_subdev_alloc_pad_config(sd); |
40 | return -ENOMEM; | 40 | if (fh->pad == NULL) |
41 | return -ENOMEM; | ||
42 | } | ||
41 | #endif | 43 | #endif |
42 | return 0; | 44 | return 0; |
43 | } | 45 | } |
@@ -45,7 +47,7 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) | |||
45 | static void subdev_fh_free(struct v4l2_subdev_fh *fh) | 47 | static void subdev_fh_free(struct v4l2_subdev_fh *fh) |
46 | { | 48 | { |
47 | #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) | 49 | #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) |
48 | kfree(fh->pad); | 50 | v4l2_subdev_free_pad_config(fh->pad); |
49 | fh->pad = NULL; | 51 | fh->pad = NULL; |
50 | #endif | 52 | #endif |
51 | } | 53 | } |
@@ -508,7 +510,7 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, | |||
508 | if (source_fmt->format.width != sink_fmt->format.width | 510 | if (source_fmt->format.width != sink_fmt->format.width |
509 | || source_fmt->format.height != sink_fmt->format.height | 511 | || source_fmt->format.height != sink_fmt->format.height |
510 | || source_fmt->format.code != sink_fmt->format.code) | 512 | || source_fmt->format.code != sink_fmt->format.code) |
511 | return -EINVAL; | 513 | return -EPIPE; |
512 | 514 | ||
513 | /* The field order must match, or the sink field order must be NONE | 515 | /* The field order must match, or the sink field order must be NONE |
514 | * to support interlaced hardware connected to bridges that support | 516 | * to support interlaced hardware connected to bridges that support |
@@ -516,7 +518,7 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, | |||
516 | */ | 518 | */ |
517 | if (source_fmt->format.field != sink_fmt->format.field && | 519 | if (source_fmt->format.field != sink_fmt->format.field && |
518 | sink_fmt->format.field != V4L2_FIELD_NONE) | 520 | sink_fmt->format.field != V4L2_FIELD_NONE) |
519 | return -EINVAL; | 521 | return -EPIPE; |
520 | 522 | ||
521 | return 0; | 523 | return 0; |
522 | } | 524 | } |
@@ -569,6 +571,35 @@ int v4l2_subdev_link_validate(struct media_link *link) | |||
569 | sink, link, &source_fmt, &sink_fmt); | 571 | sink, link, &source_fmt, &sink_fmt); |
570 | } | 572 | } |
571 | EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); | 573 | EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); |
574 | |||
575 | struct v4l2_subdev_pad_config * | ||
576 | v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd) | ||
577 | { | ||
578 | struct v4l2_subdev_pad_config *cfg; | ||
579 | int ret; | ||
580 | |||
581 | if (!sd->entity.num_pads) | ||
582 | return NULL; | ||
583 | |||
584 | cfg = kcalloc(sd->entity.num_pads, sizeof(*cfg), GFP_KERNEL); | ||
585 | if (!cfg) | ||
586 | return NULL; | ||
587 | |||
588 | ret = v4l2_subdev_call(sd, pad, init_cfg, cfg); | ||
589 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
590 | kfree(cfg); | ||
591 | return NULL; | ||
592 | } | ||
593 | |||
594 | return cfg; | ||
595 | } | ||
596 | EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config); | ||
597 | |||
598 | void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg) | ||
599 | { | ||
600 | kfree(cfg); | ||
601 | } | ||
602 | EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config); | ||
572 | #endif /* CONFIG_MEDIA_CONTROLLER */ | 603 | #endif /* CONFIG_MEDIA_CONTROLLER */ |
573 | 604 | ||
574 | void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) | 605 | void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) |
@@ -584,6 +615,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) | |||
584 | sd->host_priv = NULL; | 615 | sd->host_priv = NULL; |
585 | #if defined(CONFIG_MEDIA_CONTROLLER) | 616 | #if defined(CONFIG_MEDIA_CONTROLLER) |
586 | sd->entity.name = sd->name; | 617 | sd->entity.name = sd->name; |
618 | sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; | ||
587 | sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; | 619 | sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; |
588 | #endif | 620 | #endif |
589 | } | 621 | } |
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 0078b6a92f0b..de7e9f52e7eb 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig | |||
@@ -37,6 +37,8 @@ source "drivers/staging/media/omap4iss/Kconfig" | |||
37 | 37 | ||
38 | source "drivers/staging/media/timb/Kconfig" | 38 | source "drivers/staging/media/timb/Kconfig" |
39 | 39 | ||
40 | source "drivers/staging/media/tw686x-kh/Kconfig" | ||
41 | |||
40 | # Keep LIRC at the end, as it has sub-menus | 42 | # Keep LIRC at the end, as it has sub-menus |
41 | source "drivers/staging/media/lirc/Kconfig" | 43 | source "drivers/staging/media/lirc/Kconfig" |
42 | 44 | ||
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 91495882a36c..60a35b3a47e7 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_VIDEO_OMAP1) += omap1/ | |||
8 | obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ | 8 | obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ |
9 | obj-$(CONFIG_DVB_MN88472) += mn88472/ | 9 | obj-$(CONFIG_DVB_MN88472) += mn88472/ |
10 | obj-$(CONFIG_VIDEO_TIMBERDALE) += timb/ | 10 | obj-$(CONFIG_VIDEO_TIMBERDALE) += timb/ |
11 | obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh/ | ||
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index abf330f92c0b..8dade197f053 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c | |||
@@ -308,7 +308,7 @@ module_param(radio_nr, int, 0); | |||
308 | MODULE_PARM_DESC(radio_nr, | 308 | MODULE_PARM_DESC(radio_nr, |
309 | "Minor number for radio device (-1 ==> auto assign)"); | 309 | "Minor number for radio device (-1 ==> auto assign)"); |
310 | 310 | ||
311 | static struct region_info region_configs[] = { | 311 | static const struct region_info region_configs[] = { |
312 | /* USA */ | 312 | /* USA */ |
313 | { | 313 | { |
314 | .channel_spacing = 20, | 314 | .channel_spacing = 20, |
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index be72a8e5f221..ea3ddec75806 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c | |||
@@ -154,7 +154,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video) | |||
154 | while ((entity = media_entity_graph_walk_next(&graph))) { | 154 | while ((entity = media_entity_graph_walk_next(&graph))) { |
155 | if (entity == &video->video_dev.entity) | 155 | if (entity == &video->video_dev.entity) |
156 | continue; | 156 | continue; |
157 | if (!is_media_entity_v4l2_io(entity)) | 157 | if (!is_media_entity_v4l2_video_device(entity)) |
158 | continue; | 158 | continue; |
159 | far_end = to_vpfe_video(media_entity_to_video_device(entity)); | 159 | far_end = to_vpfe_video(media_entity_to_video_device(entity)); |
160 | if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | 160 | if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index f54349bce4de..cf8da23558bb 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c | |||
@@ -223,7 +223,7 @@ iss_video_far_end(struct iss_video *video) | |||
223 | if (entity == &video->video.entity) | 223 | if (entity == &video->video.entity) |
224 | continue; | 224 | continue; |
225 | 225 | ||
226 | if (!is_media_entity_v4l2_io(entity)) | 226 | if (!is_media_entity_v4l2_video_device(entity)) |
227 | continue; | 227 | continue; |
228 | 228 | ||
229 | far_end = to_iss_video(media_entity_to_video_device(entity)); | 229 | far_end = to_iss_video(media_entity_to_video_device(entity)); |
diff --git a/drivers/staging/media/tw686x-kh/Kconfig b/drivers/staging/media/tw686x-kh/Kconfig new file mode 100644 index 000000000000..6264d30edf5a --- /dev/null +++ b/drivers/staging/media/tw686x-kh/Kconfig | |||
@@ -0,0 +1,17 @@ | |||
1 | config VIDEO_TW686X_KH | ||
2 | tristate "Intersil/Techwell TW686x Video For Linux" | ||
3 | depends on VIDEO_DEV && PCI && VIDEO_V4L2 | ||
4 | depends on !(VIDEO_TW686X=y || VIDEO_TW686X=m) || COMPILE_TEST | ||
5 | select VIDEOBUF2_DMA_SG | ||
6 | help | ||
7 | Support for Intersil/Techwell TW686x-based frame grabber cards. | ||
8 | |||
9 | Currently supported chips: | ||
10 | - TW6864 (4 video channels), | ||
11 | - TW6865 (4 video channels, not tested, second generation chip), | ||
12 | - TW6868 (8 video channels but only 4 first channels using | ||
13 | built-in video decoder are supported, not tested), | ||
14 | - TW6869 (8 video channels, second generation chip). | ||
15 | |||
16 | To compile this driver as a module, choose M here: the module | ||
17 | will be named tw686x-kh. | ||
diff --git a/drivers/staging/media/tw686x-kh/Makefile b/drivers/staging/media/tw686x-kh/Makefile new file mode 100644 index 000000000000..2a36a38cf30e --- /dev/null +++ b/drivers/staging/media/tw686x-kh/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | tw686x-kh-objs := tw686x-kh-core.o tw686x-kh-video.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh.o | ||
diff --git a/drivers/staging/media/tw686x-kh/TODO b/drivers/staging/media/tw686x-kh/TODO new file mode 100644 index 000000000000..480a495b11fb --- /dev/null +++ b/drivers/staging/media/tw686x-kh/TODO | |||
@@ -0,0 +1,6 @@ | |||
1 | TODO: | ||
2 | |||
3 | - implement V4L2_FIELD_INTERLACED* mode(s). | ||
4 | - add audio support | ||
5 | |||
6 | Please Cc: patches to Krzysztof Halasa <khalasa@piap.pl>. | ||
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-core.c b/drivers/staging/media/tw686x-kh/tw686x-kh-core.c new file mode 100644 index 000000000000..03b3b62c59c4 --- /dev/null +++ b/drivers/staging/media/tw686x-kh/tw686x-kh-core.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Industrial Research Institute for Automation | ||
3 | * and Measurements PIAP | ||
4 | * | ||
5 | * Written by Krzysztof Ha?asa. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of version 2 of the GNU General Public License | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include "tw686x-kh.h" | ||
18 | #include "tw686x-kh-regs.h" | ||
19 | |||
20 | static irqreturn_t tw686x_irq(int irq, void *dev_id) | ||
21 | { | ||
22 | struct tw686x_dev *dev = (struct tw686x_dev *)dev_id; | ||
23 | u32 int_status = reg_read(dev, INT_STATUS); /* cleared on read */ | ||
24 | unsigned long flags; | ||
25 | unsigned int handled = 0; | ||
26 | |||
27 | if (int_status) { | ||
28 | spin_lock_irqsave(&dev->irq_lock, flags); | ||
29 | dev->dma_requests |= int_status; | ||
30 | spin_unlock_irqrestore(&dev->irq_lock, flags); | ||
31 | |||
32 | if (int_status & 0xFF0000FF) | ||
33 | handled = tw686x_kh_video_irq(dev); | ||
34 | } | ||
35 | |||
36 | return IRQ_RETVAL(handled); | ||
37 | } | ||
38 | |||
39 | static int tw686x_probe(struct pci_dev *pci_dev, | ||
40 | const struct pci_device_id *pci_id) | ||
41 | { | ||
42 | struct tw686x_dev *dev; | ||
43 | int err; | ||
44 | |||
45 | dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev) + | ||
46 | (pci_id->driver_data & TYPE_MAX_CHANNELS) * | ||
47 | sizeof(dev->video_channels[0]), GFP_KERNEL); | ||
48 | if (!dev) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | sprintf(dev->name, "TW%04X", pci_dev->device); | ||
52 | dev->type = pci_id->driver_data; | ||
53 | |||
54 | pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name, | ||
55 | pci_name(pci_dev), pci_dev->irq, | ||
56 | (unsigned long)pci_resource_start(pci_dev, 0)); | ||
57 | |||
58 | dev->pci_dev = pci_dev; | ||
59 | if (pcim_enable_device(pci_dev)) | ||
60 | return -EIO; | ||
61 | |||
62 | pci_set_master(pci_dev); | ||
63 | |||
64 | if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { | ||
65 | pr_err("%s: 32-bit PCI DMA not supported\n", dev->name); | ||
66 | return -EIO; | ||
67 | } | ||
68 | |||
69 | err = pci_request_regions(pci_dev, dev->name); | ||
70 | if (err < 0) { | ||
71 | pr_err("%s: Unable to get MMIO region\n", dev->name); | ||
72 | return err; | ||
73 | } | ||
74 | |||
75 | dev->mmio = pci_ioremap_bar(pci_dev, 0); | ||
76 | if (!dev->mmio) { | ||
77 | pr_err("%s: Unable to remap MMIO region\n", dev->name); | ||
78 | return -EIO; | ||
79 | } | ||
80 | |||
81 | reg_write(dev, SYS_SOFT_RST, 0x0F); /* Reset all subsystems */ | ||
82 | mdelay(1); | ||
83 | |||
84 | reg_write(dev, SRST[0], 0x3F); | ||
85 | if (max_channels(dev) > 4) | ||
86 | reg_write(dev, SRST[1], 0x3F); | ||
87 | reg_write(dev, DMA_CMD, 0); | ||
88 | reg_write(dev, DMA_CHANNEL_ENABLE, 0); | ||
89 | reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x3EFF0FF0); | ||
90 | reg_write(dev, DMA_TIMER_INTERVAL, 0x38000); | ||
91 | reg_write(dev, DMA_CONFIG, 0xFFFFFF04); | ||
92 | |||
93 | spin_lock_init(&dev->irq_lock); | ||
94 | |||
95 | err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw686x_irq, | ||
96 | IRQF_SHARED, dev->name, dev); | ||
97 | if (err < 0) { | ||
98 | pr_err("%s: Unable to get IRQ\n", dev->name); | ||
99 | return err; | ||
100 | } | ||
101 | |||
102 | err = tw686x_kh_video_init(dev); | ||
103 | if (err) | ||
104 | return err; | ||
105 | |||
106 | pci_set_drvdata(pci_dev, dev); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static void tw686x_remove(struct pci_dev *pci_dev) | ||
111 | { | ||
112 | struct tw686x_dev *dev = pci_get_drvdata(pci_dev); | ||
113 | |||
114 | tw686x_kh_video_free(dev); | ||
115 | } | ||
116 | |||
117 | /* driver_data is number of A/V channels */ | ||
118 | static const struct pci_device_id tw686x_pci_tbl[] = { | ||
119 | {PCI_DEVICE(0x1797, 0x6864), .driver_data = 4}, | ||
120 | /* not tested */ | ||
121 | {PCI_DEVICE(0x1797, 0x6865), .driver_data = 4 | TYPE_SECOND_GEN}, | ||
122 | /* TW6868 supports 8 A/V channels with an external TW2865 chip - | ||
123 | not supported by the driver */ | ||
124 | {PCI_DEVICE(0x1797, 0x6868), .driver_data = 4}, /* not tested */ | ||
125 | {PCI_DEVICE(0x1797, 0x6869), .driver_data = 8 | TYPE_SECOND_GEN}, | ||
126 | {} | ||
127 | }; | ||
128 | |||
129 | static struct pci_driver tw686x_pci_driver = { | ||
130 | .name = "tw686x-kh", | ||
131 | .id_table = tw686x_pci_tbl, | ||
132 | .probe = tw686x_probe, | ||
133 | .remove = tw686x_remove, | ||
134 | }; | ||
135 | |||
136 | MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]"); | ||
137 | MODULE_AUTHOR("Krzysztof Halasa"); | ||
138 | MODULE_LICENSE("GPL v2"); | ||
139 | MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl); | ||
140 | module_pci_driver(tw686x_pci_driver); | ||
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h b/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h new file mode 100644 index 000000000000..53e1889babd0 --- /dev/null +++ b/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* DMA controller registers */ | ||
2 | #define REG8_1(a0) ((const u16[8]) {a0, a0 + 1, a0 + 2, a0 + 3, \ | ||
3 | a0 + 4, a0 + 5, a0 + 6, a0 + 7}) | ||
4 | #define REG8_2(a0) ((const u16[8]) {a0, a0 + 2, a0 + 4, a0 + 6, \ | ||
5 | a0 + 8, a0 + 0xA, a0 + 0xC, a0 + 0xE}) | ||
6 | #define REG8_8(a0) ((const u16[8]) {a0, a0 + 8, a0 + 0x10, a0 + 0x18, \ | ||
7 | a0 + 0x20, a0 + 0x28, a0 + 0x30, a0 + 0x38}) | ||
8 | #define INT_STATUS 0x00 | ||
9 | #define PB_STATUS 0x01 | ||
10 | #define DMA_CMD 0x02 | ||
11 | #define VIDEO_FIFO_STATUS 0x03 | ||
12 | #define VIDEO_CHANNEL_ID 0x04 | ||
13 | #define VIDEO_PARSER_STATUS 0x05 | ||
14 | #define SYS_SOFT_RST 0x06 | ||
15 | #define DMA_PAGE_TABLE0_ADDR ((const u16[8]) {0x08, 0xD0, 0xD2, 0xD4, \ | ||
16 | 0xD6, 0xD8, 0xDA, 0xDC}) | ||
17 | #define DMA_PAGE_TABLE1_ADDR ((const u16[8]) {0x09, 0xD1, 0xD3, 0xD5, \ | ||
18 | 0xD7, 0xD9, 0xDB, 0xDD}) | ||
19 | #define DMA_CHANNEL_ENABLE 0x0A | ||
20 | #define DMA_CONFIG 0x0B | ||
21 | #define DMA_TIMER_INTERVAL 0x0C | ||
22 | #define DMA_CHANNEL_TIMEOUT 0x0D | ||
23 | #define VDMA_CHANNEL_CONFIG REG8_1(0x10) | ||
24 | #define ADMA_P_ADDR REG8_2(0x18) | ||
25 | #define ADMA_B_ADDR REG8_2(0x19) | ||
26 | #define DMA10_P_ADDR 0x28 /* ??? */ | ||
27 | #define DMA10_B_ADDR 0x29 | ||
28 | #define VIDEO_CONTROL1 0x2A | ||
29 | #define VIDEO_CONTROL2 0x2B | ||
30 | #define AUDIO_CONTROL1 0x2C | ||
31 | #define AUDIO_CONTROL2 0x2D | ||
32 | #define PHASE_REF 0x2E | ||
33 | #define GPIO_REG 0x2F | ||
34 | #define INTL_HBAR_CTRL REG8_1(0x30) | ||
35 | #define AUDIO_CONTROL3 0x38 | ||
36 | #define VIDEO_FIELD_CTRL REG8_1(0x39) | ||
37 | #define HSCALER_CTRL REG8_1(0x42) | ||
38 | #define VIDEO_SIZE REG8_1(0x4A) | ||
39 | #define VIDEO_SIZE_F2 REG8_1(0x52) | ||
40 | #define MD_CONF REG8_1(0x60) | ||
41 | #define MD_INIT REG8_1(0x68) | ||
42 | #define MD_MAP0 REG8_1(0x70) | ||
43 | #define VDMA_P_ADDR REG8_8(0x80) /* not used in DMA SG mode */ | ||
44 | #define VDMA_WHP REG8_8(0x81) | ||
45 | #define VDMA_B_ADDR REG8_8(0x82) | ||
46 | #define VDMA_F2_P_ADDR REG8_8(0x84) | ||
47 | #define VDMA_F2_WHP REG8_8(0x85) | ||
48 | #define VDMA_F2_B_ADDR REG8_8(0x86) | ||
49 | #define EP_REG_ADDR 0xFE | ||
50 | #define EP_REG_DATA 0xFF | ||
51 | |||
52 | /* Video decoder registers */ | ||
53 | #define VDREG8(a0) ((const u16[8]) { \ | ||
54 | a0 + 0x000, a0 + 0x010, a0 + 0x020, a0 + 0x030, \ | ||
55 | a0 + 0x100, a0 + 0x110, a0 + 0x120, a0 + 0x130}) | ||
56 | #define VIDSTAT VDREG8(0x100) | ||
57 | #define BRIGHT VDREG8(0x101) | ||
58 | #define CONTRAST VDREG8(0x102) | ||
59 | #define SHARPNESS VDREG8(0x103) | ||
60 | #define SAT_U VDREG8(0x104) | ||
61 | #define SAT_V VDREG8(0x105) | ||
62 | #define HUE VDREG8(0x106) | ||
63 | #define CROP_HI VDREG8(0x107) | ||
64 | #define VDELAY_LO VDREG8(0x108) | ||
65 | #define VACTIVE_LO VDREG8(0x109) | ||
66 | #define HDELAY_LO VDREG8(0x10A) | ||
67 | #define HACTIVE_LO VDREG8(0x10B) | ||
68 | #define MVSN VDREG8(0x10C) | ||
69 | #define STATUS2 VDREG8(0x10C) | ||
70 | #define SDT VDREG8(0x10E) | ||
71 | #define SDT_EN VDREG8(0x10F) | ||
72 | |||
73 | #define VSCALE_LO VDREG8(0x144) | ||
74 | #define SCALE_HI VDREG8(0x145) | ||
75 | #define HSCALE_LO VDREG8(0x146) | ||
76 | #define F2CROP_HI VDREG8(0x147) | ||
77 | #define F2VDELAY_LO VDREG8(0x148) | ||
78 | #define F2VACTIVE_LO VDREG8(0x149) | ||
79 | #define F2HDELAY_LO VDREG8(0x14A) | ||
80 | #define F2HACTIVE_LO VDREG8(0x14B) | ||
81 | #define F2VSCALE_LO VDREG8(0x14C) | ||
82 | #define F2SCALE_HI VDREG8(0x14D) | ||
83 | #define F2HSCALE_LO VDREG8(0x14E) | ||
84 | #define F2CNT VDREG8(0x14F) | ||
85 | |||
86 | #define VDREG2(a0) ((const u16[2]) {a0, a0 + 0x100}) | ||
87 | #define SRST VDREG2(0x180) | ||
88 | #define ACNTL VDREG2(0x181) | ||
89 | #define ACNTL2 VDREG2(0x182) | ||
90 | #define CNTRL1 VDREG2(0x183) | ||
91 | #define CKHY VDREG2(0x184) | ||
92 | #define SHCOR VDREG2(0x185) | ||
93 | #define CORING VDREG2(0x186) | ||
94 | #define CLMPG VDREG2(0x187) | ||
95 | #define IAGC VDREG2(0x188) | ||
96 | #define VCTRL1 VDREG2(0x18F) | ||
97 | #define MISC1 VDREG2(0x194) | ||
98 | #define LOOP VDREG2(0x195) | ||
99 | #define MISC2 VDREG2(0x196) | ||
100 | |||
101 | #define CLMD VDREG2(0x197) | ||
102 | #define AIGAIN ((const u16[8]) {0x1D0, 0x1D1, 0x1D2, 0x1D3, \ | ||
103 | 0x2D0, 0x2D1, 0x2D2, 0x2D3}) | ||
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c new file mode 100644 index 000000000000..6ecb504a79f9 --- /dev/null +++ b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c | |||
@@ -0,0 +1,821 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Industrial Research Institute for Automation | ||
3 | * and Measurements PIAP | ||
4 | * | ||
5 | * Written by Krzysztof Ha?asa. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of version 2 of the GNU General Public License | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <media/v4l2-common.h> | ||
18 | #include <media/v4l2-event.h> | ||
19 | #include "tw686x-kh.h" | ||
20 | #include "tw686x-kh-regs.h" | ||
21 | |||
22 | #define MAX_SG_ENTRY_SIZE (/* 8192 - 128 */ 4096) | ||
23 | #define MAX_SG_DESC_COUNT 256 /* PAL 704x576 needs up to 198 4-KB pages */ | ||
24 | |||
25 | static const struct tw686x_format formats[] = { | ||
26 | { | ||
27 | .name = "4:2:2 packed, UYVY", /* aka Y422 */ | ||
28 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
29 | .mode = 0, | ||
30 | .depth = 16, | ||
31 | }, { | ||
32 | #if 0 | ||
33 | .name = "4:2:0 packed, YUV", | ||
34 | .mode = 1, /* non-standard */ | ||
35 | .depth = 12, | ||
36 | }, { | ||
37 | .name = "4:1:1 packed, YUV", | ||
38 | .mode = 2, /* non-standard */ | ||
39 | .depth = 12, | ||
40 | }, { | ||
41 | #endif | ||
42 | .name = "4:1:1 packed, YUV", | ||
43 | .fourcc = V4L2_PIX_FMT_Y41P, | ||
44 | .mode = 3, | ||
45 | .depth = 12, | ||
46 | }, { | ||
47 | .name = "15 bpp RGB", | ||
48 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
49 | .mode = 4, | ||
50 | .depth = 16, | ||
51 | }, { | ||
52 | .name = "16 bpp RGB", | ||
53 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
54 | .mode = 5, | ||
55 | .depth = 16, | ||
56 | }, { | ||
57 | .name = "4:2:2 packed, YUYV", | ||
58 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
59 | .mode = 6, | ||
60 | .depth = 16, | ||
61 | } | ||
62 | /* mode 7 is "reserved" */ | ||
63 | }; | ||
64 | |||
65 | static const v4l2_std_id video_standards[7] = { | ||
66 | V4L2_STD_NTSC, | ||
67 | V4L2_STD_PAL, | ||
68 | V4L2_STD_SECAM, | ||
69 | V4L2_STD_NTSC_443, | ||
70 | V4L2_STD_PAL_M, | ||
71 | V4L2_STD_PAL_N, | ||
72 | V4L2_STD_PAL_60, | ||
73 | }; | ||
74 | |||
75 | static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) | ||
76 | { | ||
77 | unsigned int cnt; | ||
78 | |||
79 | for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++) | ||
80 | if (formats[cnt].fourcc == fourcc) | ||
81 | return &formats[cnt]; | ||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | static void tw686x_get_format(struct tw686x_video_channel *vc, | ||
86 | struct v4l2_format *f) | ||
87 | { | ||
88 | const struct tw686x_format *format; | ||
89 | unsigned int width, height, height_div = 1; | ||
90 | |||
91 | format = format_by_fourcc(f->fmt.pix.pixelformat); | ||
92 | if (!format) { | ||
93 | format = &formats[0]; | ||
94 | f->fmt.pix.pixelformat = format->fourcc; | ||
95 | } | ||
96 | |||
97 | width = 704; | ||
98 | if (f->fmt.pix.width < width * 3 / 4 /* halfway */) | ||
99 | width /= 2; | ||
100 | |||
101 | height = (vc->video_standard & V4L2_STD_625_50) ? 576 : 480; | ||
102 | if (f->fmt.pix.height < height * 3 / 4 /* halfway */) | ||
103 | height_div = 2; | ||
104 | |||
105 | switch (f->fmt.pix.field) { | ||
106 | case V4L2_FIELD_TOP: | ||
107 | case V4L2_FIELD_BOTTOM: | ||
108 | height_div = 2; | ||
109 | break; | ||
110 | case V4L2_FIELD_SEQ_BT: | ||
111 | if (height_div > 1) | ||
112 | f->fmt.pix.field = V4L2_FIELD_BOTTOM; | ||
113 | break; | ||
114 | default: | ||
115 | if (height_div > 1) | ||
116 | f->fmt.pix.field = V4L2_FIELD_TOP; | ||
117 | else | ||
118 | f->fmt.pix.field = V4L2_FIELD_SEQ_TB; | ||
119 | } | ||
120 | height /= height_div; | ||
121 | |||
122 | f->fmt.pix.width = width; | ||
123 | f->fmt.pix.height = height; | ||
124 | f->fmt.pix.bytesperline = f->fmt.pix.width * format->depth / 8; | ||
125 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
126 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
127 | } | ||
128 | |||
129 | /* video queue operations */ | ||
130 | |||
131 | static int tw686x_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | ||
132 | unsigned int *nplanes, unsigned int sizes[], | ||
133 | void *alloc_ctxs[]) | ||
134 | { | ||
135 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | ||
136 | unsigned int size = vc->width * vc->height * vc->format->depth / 8; | ||
137 | |||
138 | alloc_ctxs[0] = vc->alloc_ctx; | ||
139 | if (*nbuffers < 2) | ||
140 | *nbuffers = 2; | ||
141 | |||
142 | if (*nplanes) | ||
143 | return sizes[0] < size ? -EINVAL : 0; | ||
144 | |||
145 | sizes[0] = size; | ||
146 | *nplanes = 1; /* packed formats only */ | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static void tw686x_buf_queue(struct vb2_buffer *vb) | ||
151 | { | ||
152 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue); | ||
153 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
154 | struct tw686x_vb2_buf *buf; | ||
155 | |||
156 | buf = container_of(vbuf, struct tw686x_vb2_buf, vb); | ||
157 | |||
158 | spin_lock(&vc->qlock); | ||
159 | list_add_tail(&buf->list, &vc->vidq_queued); | ||
160 | spin_unlock(&vc->qlock); | ||
161 | } | ||
162 | |||
163 | static void setup_descs(struct tw686x_video_channel *vc, unsigned int n) | ||
164 | { | ||
165 | loop: | ||
166 | while (!list_empty(&vc->vidq_queued)) { | ||
167 | struct vdma_desc *descs = vc->sg_descs[n]; | ||
168 | struct tw686x_vb2_buf *buf; | ||
169 | struct sg_table *vbuf; | ||
170 | struct scatterlist *sg; | ||
171 | unsigned int buf_len, count = 0; | ||
172 | int i; | ||
173 | |||
174 | buf = list_first_entry(&vc->vidq_queued, struct tw686x_vb2_buf, | ||
175 | list); | ||
176 | list_del(&buf->list); | ||
177 | |||
178 | buf_len = vc->width * vc->height * vc->format->depth / 8; | ||
179 | if (vb2_plane_size(&buf->vb.vb2_buf, 0) < buf_len) { | ||
180 | pr_err("Video buffer size too small\n"); | ||
181 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
182 | goto loop; /* try another */ | ||
183 | } | ||
184 | |||
185 | vbuf = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); | ||
186 | for_each_sg(vbuf->sgl, sg, vbuf->nents, i) { | ||
187 | dma_addr_t phys = sg_dma_address(sg); | ||
188 | unsigned int len = sg_dma_len(sg); | ||
189 | |||
190 | while (len && buf_len) { | ||
191 | unsigned int entry_len = min_t(unsigned int, len, | ||
192 | MAX_SG_ENTRY_SIZE); | ||
193 | entry_len = min(entry_len, buf_len); | ||
194 | if (count == MAX_SG_DESC_COUNT) { | ||
195 | pr_err("Video buffer size too fragmented\n"); | ||
196 | vb2_buffer_done(&buf->vb.vb2_buf, | ||
197 | VB2_BUF_STATE_ERROR); | ||
198 | goto loop; | ||
199 | } | ||
200 | descs[count].phys = cpu_to_le32(phys); | ||
201 | descs[count++].flags_length = | ||
202 | cpu_to_le32(0x40000000 /* available */ | | ||
203 | entry_len); | ||
204 | phys += entry_len; | ||
205 | len -= entry_len; | ||
206 | buf_len -= entry_len; | ||
207 | } | ||
208 | if (!buf_len) | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | /* clear the remaining entries */ | ||
213 | while (count < MAX_SG_DESC_COUNT) { | ||
214 | descs[count].phys = 0; | ||
215 | descs[count++].flags_length = 0; /* unavailable */ | ||
216 | } | ||
217 | |||
218 | buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; | ||
219 | vc->curr_bufs[n] = buf; | ||
220 | return; | ||
221 | } | ||
222 | vc->curr_bufs[n] = NULL; | ||
223 | } | ||
224 | |||
225 | /* On TW6864 and TW6868, all channels share the pair of video DMA SG tables, | ||
226 | with 10-bit start_idx and end_idx determining start and end of frame buffer | ||
227 | for particular channel. | ||
228 | TW6868 with all its 8 channels would be problematic (only 127 SG entries per | ||
229 | channel) but we support only 4 channels on this chip anyway (the first | ||
230 | 4 channels are driven with internal video decoder, the other 4 would require | ||
231 | an external TW286x part). | ||
232 | |||
233 | On TW6865 and TW6869, each channel has its own DMA SG table, with indexes | ||
234 | starting with 0. Both chips have complete sets of internal video decoders | ||
235 | (respectively 4 or 8-channel). | ||
236 | |||
237 | All chips have separate SG tables for two video frames. */ | ||
238 | |||
239 | static void setup_dma_cfg(struct tw686x_video_channel *vc) | ||
240 | { | ||
241 | unsigned int field_width = 704; | ||
242 | unsigned int field_height = (vc->video_standard & V4L2_STD_625_50) ? | ||
243 | 288 : 240; | ||
244 | unsigned int start_idx = is_second_gen(vc->dev) ? 0 : | ||
245 | vc->ch * MAX_SG_DESC_COUNT; | ||
246 | unsigned int end_idx = start_idx + MAX_SG_DESC_COUNT - 1; | ||
247 | u32 dma_cfg = (0 << 30) /* input selection */ | | ||
248 | (1 << 29) /* field2 dropped (if any) */ | | ||
249 | ((vc->height < 300) << 28) /* field dropping */ | | ||
250 | (1 << 27) /* master */ | | ||
251 | (0 << 25) /* master channel (for slave only) */ | | ||
252 | (0 << 24) /* (no) vertical (line) decimation */ | | ||
253 | ((vc->width < 400) << 23) /* horizontal decimation */ | | ||
254 | (vc->format->mode << 20) /* output video format */ | | ||
255 | (end_idx << 10) /* DMA end index */ | | ||
256 | start_idx /* DMA start index */; | ||
257 | u32 reg; | ||
258 | |||
259 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], dma_cfg); | ||
260 | reg_write(vc->dev, VIDEO_SIZE[vc->ch], (1 << 31) | (field_height << 16) | ||
261 | | field_width); | ||
262 | reg = reg_read(vc->dev, VIDEO_CONTROL1); | ||
263 | if (vc->video_standard & V4L2_STD_625_50) | ||
264 | reg |= 1 << (vc->ch + 13); | ||
265 | else | ||
266 | reg &= ~(1 << (vc->ch + 13)); | ||
267 | reg_write(vc->dev, VIDEO_CONTROL1, reg); | ||
268 | } | ||
269 | |||
270 | static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
271 | { | ||
272 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | ||
273 | struct tw686x_dev *dev = vc->dev; | ||
274 | u32 dma_ch_mask; | ||
275 | unsigned int n; | ||
276 | |||
277 | setup_dma_cfg(vc); | ||
278 | |||
279 | /* queue video buffers if available */ | ||
280 | spin_lock(&vc->qlock); | ||
281 | for (n = 0; n < 2; n++) | ||
282 | setup_descs(vc, n); | ||
283 | spin_unlock(&vc->qlock); | ||
284 | |||
285 | dev->video_active |= 1 << vc->ch; | ||
286 | vc->seq = 0; | ||
287 | dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE) | (1 << vc->ch); | ||
288 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask); | ||
289 | reg_write(dev, DMA_CMD, (1 << 31) | dma_ch_mask); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static void tw686x_stop_streaming(struct vb2_queue *vq) | ||
294 | { | ||
295 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | ||
296 | struct tw686x_dev *dev = vc->dev; | ||
297 | u32 dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE); | ||
298 | u32 dma_cmd = reg_read(dev, DMA_CMD); | ||
299 | unsigned int n; | ||
300 | |||
301 | dma_ch_mask &= ~(1 << vc->ch); | ||
302 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask); | ||
303 | |||
304 | dev->video_active &= ~(1 << vc->ch); | ||
305 | |||
306 | dma_cmd &= ~(1 << vc->ch); | ||
307 | reg_write(dev, DMA_CMD, dma_cmd); | ||
308 | |||
309 | if (!dev->video_active) { | ||
310 | reg_write(dev, DMA_CMD, 0); | ||
311 | reg_write(dev, DMA_CHANNEL_ENABLE, 0); | ||
312 | } | ||
313 | |||
314 | spin_lock(&vc->qlock); | ||
315 | while (!list_empty(&vc->vidq_queued)) { | ||
316 | struct tw686x_vb2_buf *buf; | ||
317 | |||
318 | buf = list_entry(vc->vidq_queued.next, struct tw686x_vb2_buf, | ||
319 | list); | ||
320 | list_del(&buf->list); | ||
321 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
322 | } | ||
323 | |||
324 | for (n = 0; n < 2; n++) | ||
325 | if (vc->curr_bufs[n]) | ||
326 | vb2_buffer_done(&vc->curr_bufs[n]->vb.vb2_buf, | ||
327 | VB2_BUF_STATE_ERROR); | ||
328 | |||
329 | spin_unlock(&vc->qlock); | ||
330 | } | ||
331 | |||
332 | static struct vb2_ops tw686x_video_qops = { | ||
333 | .queue_setup = tw686x_queue_setup, | ||
334 | .buf_queue = tw686x_buf_queue, | ||
335 | .start_streaming = tw686x_start_streaming, | ||
336 | .stop_streaming = tw686x_stop_streaming, | ||
337 | .wait_prepare = vb2_ops_wait_prepare, | ||
338 | .wait_finish = vb2_ops_wait_finish, | ||
339 | }; | ||
340 | |||
341 | static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl) | ||
342 | { | ||
343 | struct tw686x_video_channel *vc; | ||
344 | struct tw686x_dev *dev; | ||
345 | unsigned int ch; | ||
346 | |||
347 | vc = container_of(ctrl->handler, struct tw686x_video_channel, | ||
348 | ctrl_handler); | ||
349 | dev = vc->dev; | ||
350 | ch = vc->ch; | ||
351 | |||
352 | switch (ctrl->id) { | ||
353 | case V4L2_CID_BRIGHTNESS: | ||
354 | reg_write(dev, BRIGHT[ch], ctrl->val & 0xFF); | ||
355 | return 0; | ||
356 | |||
357 | case V4L2_CID_CONTRAST: | ||
358 | reg_write(dev, CONTRAST[ch], ctrl->val); | ||
359 | return 0; | ||
360 | |||
361 | case V4L2_CID_SATURATION: | ||
362 | reg_write(dev, SAT_U[ch], ctrl->val); | ||
363 | reg_write(dev, SAT_V[ch], ctrl->val); | ||
364 | return 0; | ||
365 | |||
366 | case V4L2_CID_HUE: | ||
367 | reg_write(dev, HUE[ch], ctrl->val & 0xFF); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | return -EINVAL; | ||
372 | } | ||
373 | |||
374 | static const struct v4l2_ctrl_ops ctrl_ops = { | ||
375 | .s_ctrl = tw686x_s_ctrl, | ||
376 | }; | ||
377 | |||
378 | static int tw686x_g_fmt_vid_cap(struct file *file, void *priv, | ||
379 | struct v4l2_format *f) | ||
380 | { | ||
381 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
382 | |||
383 | f->fmt.pix.width = vc->width; | ||
384 | f->fmt.pix.height = vc->height; | ||
385 | f->fmt.pix.field = vc->field; | ||
386 | f->fmt.pix.pixelformat = vc->format->fourcc; | ||
387 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
388 | f->fmt.pix.bytesperline = f->fmt.pix.width * vc->format->depth / 8; | ||
389 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, | ||
394 | struct v4l2_format *f) | ||
395 | { | ||
396 | tw686x_get_format(video_drvdata(file), f); | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, | ||
401 | struct v4l2_format *f) | ||
402 | { | ||
403 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
404 | |||
405 | tw686x_get_format(vc, f); | ||
406 | vc->format = format_by_fourcc(f->fmt.pix.pixelformat); | ||
407 | vc->field = f->fmt.pix.field; | ||
408 | vc->width = f->fmt.pix.width; | ||
409 | vc->height = f->fmt.pix.height; | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int tw686x_querycap(struct file *file, void *priv, | ||
414 | struct v4l2_capability *cap) | ||
415 | { | ||
416 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
417 | struct tw686x_dev *dev = vc->dev; | ||
418 | |||
419 | strcpy(cap->driver, "tw686x-kh"); | ||
420 | strcpy(cap->card, dev->name); | ||
421 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci_dev)); | ||
422 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
423 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) | ||
428 | { | ||
429 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
430 | unsigned int cnt; | ||
431 | u32 sdt = 0; /* default */ | ||
432 | |||
433 | for (cnt = 0; cnt < ARRAY_SIZE(video_standards); cnt++) | ||
434 | if (id & video_standards[cnt]) { | ||
435 | sdt = cnt; | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | reg_write(vc->dev, SDT[vc->ch], sdt); | ||
440 | vc->video_standard = video_standards[sdt]; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id) | ||
445 | { | ||
446 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
447 | |||
448 | *id = vc->video_standard; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, | ||
453 | struct v4l2_fmtdesc *f) | ||
454 | { | ||
455 | if (f->index >= ARRAY_SIZE(formats)) | ||
456 | return -EINVAL; | ||
457 | |||
458 | strlcpy(f->description, formats[f->index].name, sizeof(f->description)); | ||
459 | f->pixelformat = formats[f->index].fourcc; | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int tw686x_g_parm(struct file *file, void *priv, | ||
464 | struct v4l2_streamparm *sp) | ||
465 | { | ||
466 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
467 | |||
468 | if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
469 | return -EINVAL; | ||
470 | memset(&sp->parm.capture, 0, sizeof(sp->parm.capture)); | ||
471 | sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | ||
472 | v4l2_video_std_frame_period(vc->video_standard, | ||
473 | &sp->parm.capture.timeperframe); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int tw686x_enum_input(struct file *file, void *priv, | ||
479 | struct v4l2_input *inp) | ||
480 | { | ||
481 | /* the chip has internal multiplexer, support can be added | ||
482 | if the actual hw uses it */ | ||
483 | if (inp->index) | ||
484 | return -EINVAL; | ||
485 | |||
486 | snprintf(inp->name, sizeof(inp->name), "Composite"); | ||
487 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
488 | inp->std = V4L2_STD_ALL; | ||
489 | inp->capabilities = V4L2_IN_CAP_STD; | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static int tw686x_g_input(struct file *file, void *priv, unsigned int *v) | ||
494 | { | ||
495 | *v = 0; | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static int tw686x_s_input(struct file *file, void *priv, unsigned int v) | ||
500 | { | ||
501 | if (v) | ||
502 | return -EINVAL; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static const struct v4l2_file_operations tw686x_video_fops = { | ||
507 | .owner = THIS_MODULE, | ||
508 | .open = v4l2_fh_open, | ||
509 | .unlocked_ioctl = video_ioctl2, | ||
510 | .release = vb2_fop_release, | ||
511 | .poll = vb2_fop_poll, | ||
512 | .read = vb2_fop_read, | ||
513 | .mmap = vb2_fop_mmap, | ||
514 | }; | ||
515 | |||
516 | static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { | ||
517 | .vidioc_querycap = tw686x_querycap, | ||
518 | .vidioc_enum_fmt_vid_cap = tw686x_enum_fmt_vid_cap, | ||
519 | .vidioc_g_fmt_vid_cap = tw686x_g_fmt_vid_cap, | ||
520 | .vidioc_s_fmt_vid_cap = tw686x_s_fmt_vid_cap, | ||
521 | .vidioc_try_fmt_vid_cap = tw686x_try_fmt_vid_cap, | ||
522 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
523 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
524 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
525 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
526 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
527 | .vidioc_streamon = vb2_ioctl_streamon, | ||
528 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
529 | .vidioc_g_std = tw686x_g_std, | ||
530 | .vidioc_s_std = tw686x_s_std, | ||
531 | .vidioc_g_parm = tw686x_g_parm, | ||
532 | .vidioc_enum_input = tw686x_enum_input, | ||
533 | .vidioc_g_input = tw686x_g_input, | ||
534 | .vidioc_s_input = tw686x_s_input, | ||
535 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
536 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
537 | }; | ||
538 | |||
539 | static int video_thread(void *arg) | ||
540 | { | ||
541 | struct tw686x_dev *dev = arg; | ||
542 | DECLARE_WAITQUEUE(wait, current); | ||
543 | |||
544 | set_freezable(); | ||
545 | add_wait_queue(&dev->video_thread_wait, &wait); | ||
546 | |||
547 | while (1) { | ||
548 | long timeout = schedule_timeout_interruptible(HZ); | ||
549 | unsigned int ch; | ||
550 | |||
551 | if (timeout == -ERESTARTSYS || kthread_should_stop()) | ||
552 | break; | ||
553 | |||
554 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
555 | struct tw686x_video_channel *vc; | ||
556 | unsigned long flags; | ||
557 | u32 request, n, stat = VB2_BUF_STATE_DONE; | ||
558 | |||
559 | vc = &dev->video_channels[ch]; | ||
560 | if (!(dev->video_active & (1 << ch))) | ||
561 | continue; | ||
562 | |||
563 | spin_lock_irq(&dev->irq_lock); | ||
564 | request = dev->dma_requests & (0x01000001 << ch); | ||
565 | if (request) | ||
566 | dev->dma_requests &= ~request; | ||
567 | spin_unlock_irq(&dev->irq_lock); | ||
568 | |||
569 | if (!request) | ||
570 | continue; | ||
571 | |||
572 | request >>= ch; | ||
573 | |||
574 | /* handle channel events */ | ||
575 | if ((request & 0x01000000) | | ||
576 | (reg_read(dev, VIDEO_FIFO_STATUS) & (0x01010001 << ch)) | | ||
577 | (reg_read(dev, VIDEO_PARSER_STATUS) & (0x00000101 << ch))) { | ||
578 | /* DMA Errors - reset channel */ | ||
579 | u32 reg; | ||
580 | |||
581 | spin_lock_irqsave(&dev->irq_lock, flags); | ||
582 | reg = reg_read(dev, DMA_CMD); | ||
583 | /* Reset DMA channel */ | ||
584 | reg_write(dev, DMA_CMD, reg & ~(1 << ch)); | ||
585 | reg_write(dev, DMA_CMD, reg); | ||
586 | spin_unlock_irqrestore(&dev->irq_lock, flags); | ||
587 | stat = VB2_BUF_STATE_ERROR; | ||
588 | } | ||
589 | |||
590 | /* handle video stream */ | ||
591 | mutex_lock(&vc->vb_mutex); | ||
592 | spin_lock(&vc->qlock); | ||
593 | n = !!(reg_read(dev, PB_STATUS) & (1 << ch)); | ||
594 | if (vc->curr_bufs[n]) { | ||
595 | struct vb2_v4l2_buffer *vb; | ||
596 | |||
597 | vb = &vc->curr_bufs[n]->vb; | ||
598 | vb->vb2_buf.timestamp = ktime_get_ns(); | ||
599 | vb->field = vc->field; | ||
600 | if (V4L2_FIELD_HAS_BOTH(vc->field)) | ||
601 | vb->sequence = vc->seq++; | ||
602 | else | ||
603 | vb->sequence = (vc->seq++) / 2; | ||
604 | vb2_set_plane_payload(&vb->vb2_buf, 0, | ||
605 | vc->width * vc->height * vc->format->depth / 8); | ||
606 | vb2_buffer_done(&vb->vb2_buf, stat); | ||
607 | } | ||
608 | setup_descs(vc, n); | ||
609 | spin_unlock(&vc->qlock); | ||
610 | mutex_unlock(&vc->vb_mutex); | ||
611 | } | ||
612 | try_to_freeze(); | ||
613 | } | ||
614 | |||
615 | remove_wait_queue(&dev->video_thread_wait, &wait); | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | int tw686x_kh_video_irq(struct tw686x_dev *dev) | ||
620 | { | ||
621 | unsigned long flags, handled = 0; | ||
622 | u32 requests; | ||
623 | |||
624 | spin_lock_irqsave(&dev->irq_lock, flags); | ||
625 | requests = dev->dma_requests; | ||
626 | spin_unlock_irqrestore(&dev->irq_lock, flags); | ||
627 | |||
628 | if (requests & dev->video_active) { | ||
629 | wake_up_interruptible_all(&dev->video_thread_wait); | ||
630 | handled = 1; | ||
631 | } | ||
632 | return handled; | ||
633 | } | ||
634 | |||
635 | void tw686x_kh_video_free(struct tw686x_dev *dev) | ||
636 | { | ||
637 | unsigned int ch, n; | ||
638 | |||
639 | if (dev->video_thread) | ||
640 | kthread_stop(dev->video_thread); | ||
641 | |||
642 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
643 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; | ||
644 | |||
645 | v4l2_ctrl_handler_free(&vc->ctrl_handler); | ||
646 | if (vc->device) | ||
647 | video_unregister_device(vc->device); | ||
648 | vb2_dma_sg_cleanup_ctx(vc->alloc_ctx); | ||
649 | for (n = 0; n < 2; n++) { | ||
650 | struct dma_desc *descs = &vc->sg_tables[n]; | ||
651 | |||
652 | if (descs->virt) | ||
653 | pci_free_consistent(dev->pci_dev, descs->size, | ||
654 | descs->virt, descs->phys); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | v4l2_device_unregister(&dev->v4l2_dev); | ||
659 | } | ||
660 | |||
661 | #define SG_TABLE_SIZE (MAX_SG_DESC_COUNT * sizeof(struct vdma_desc)) | ||
662 | |||
663 | int tw686x_kh_video_init(struct tw686x_dev *dev) | ||
664 | { | ||
665 | unsigned int ch, n; | ||
666 | int err; | ||
667 | |||
668 | init_waitqueue_head(&dev->video_thread_wait); | ||
669 | |||
670 | err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev); | ||
671 | if (err) | ||
672 | return err; | ||
673 | |||
674 | reg_write(dev, VIDEO_CONTROL1, 0); /* NTSC, disable scaler */ | ||
675 | reg_write(dev, PHASE_REF, 0x00001518); /* Scatter-gather DMA mode */ | ||
676 | |||
677 | /* setup required SG table sizes */ | ||
678 | for (n = 0; n < 2; n++) | ||
679 | if (is_second_gen(dev)) { | ||
680 | /* TW 6865, TW6869 - each channel needs a pair of | ||
681 | descriptor tables */ | ||
682 | for (ch = 0; ch < max_channels(dev); ch++) | ||
683 | dev->video_channels[ch].sg_tables[n].size = | ||
684 | SG_TABLE_SIZE; | ||
685 | |||
686 | } else | ||
687 | /* TW 6864, TW6868 - we need to allocate a pair of | ||
688 | descriptor tables, common for all channels. | ||
689 | Each table will be bigger than 4 KB. */ | ||
690 | dev->video_channels[0].sg_tables[n].size = | ||
691 | max_channels(dev) * SG_TABLE_SIZE; | ||
692 | |||
693 | /* allocate SG tables and initialize video channels */ | ||
694 | for (ch = 0; ch < max_channels(dev); ch++) { | ||
695 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; | ||
696 | struct video_device *vdev; | ||
697 | |||
698 | mutex_init(&vc->vb_mutex); | ||
699 | spin_lock_init(&vc->qlock); | ||
700 | INIT_LIST_HEAD(&vc->vidq_queued); | ||
701 | |||
702 | vc->dev = dev; | ||
703 | vc->ch = ch; | ||
704 | |||
705 | /* default settings: NTSC */ | ||
706 | vc->format = &formats[0]; | ||
707 | vc->video_standard = V4L2_STD_NTSC; | ||
708 | reg_write(vc->dev, SDT[vc->ch], 0); | ||
709 | vc->field = V4L2_FIELD_SEQ_BT; | ||
710 | vc->width = 704; | ||
711 | vc->height = 480; | ||
712 | |||
713 | for (n = 0; n < 2; n++) { | ||
714 | void *cpu; | ||
715 | |||
716 | if (vc->sg_tables[n].size) { | ||
717 | unsigned int reg = n ? DMA_PAGE_TABLE1_ADDR[ch] : | ||
718 | DMA_PAGE_TABLE0_ADDR[ch]; | ||
719 | |||
720 | cpu = pci_alloc_consistent(dev->pci_dev, | ||
721 | vc->sg_tables[n].size, | ||
722 | &vc->sg_tables[n].phys); | ||
723 | if (!cpu) { | ||
724 | pr_err("Error allocating video DMA scatter-gather tables\n"); | ||
725 | err = -ENOMEM; | ||
726 | goto error; | ||
727 | } | ||
728 | vc->sg_tables[n].virt = cpu; | ||
729 | reg_write(dev, reg, vc->sg_tables[n].phys); | ||
730 | } else | ||
731 | cpu = dev->video_channels[0].sg_tables[n].virt + | ||
732 | ch * SG_TABLE_SIZE; | ||
733 | |||
734 | vc->sg_descs[n] = cpu; | ||
735 | } | ||
736 | |||
737 | reg_write(dev, VCTRL1[0], 0x24); | ||
738 | reg_write(dev, LOOP[0], 0xA5); | ||
739 | if (max_channels(dev) > 4) { | ||
740 | reg_write(dev, VCTRL1[1], 0x24); | ||
741 | reg_write(dev, LOOP[1], 0xA5); | ||
742 | } | ||
743 | reg_write(dev, VIDEO_FIELD_CTRL[ch], 0); | ||
744 | reg_write(dev, VDELAY_LO[ch], 0x14); | ||
745 | |||
746 | vdev = video_device_alloc(); | ||
747 | if (!vdev) { | ||
748 | pr_warn("Unable to allocate video device\n"); | ||
749 | err = -ENOMEM; | ||
750 | goto error; | ||
751 | } | ||
752 | |||
753 | vc->alloc_ctx = vb2_dma_sg_init_ctx(&dev->pci_dev->dev); | ||
754 | if (IS_ERR(vc->alloc_ctx)) { | ||
755 | pr_warn("Unable to initialize DMA scatter-gather context\n"); | ||
756 | err = PTR_ERR(vc->alloc_ctx); | ||
757 | goto error; | ||
758 | } | ||
759 | |||
760 | vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
761 | vc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; | ||
762 | vc->vidq.drv_priv = vc; | ||
763 | vc->vidq.buf_struct_size = sizeof(struct tw686x_vb2_buf); | ||
764 | vc->vidq.ops = &tw686x_video_qops; | ||
765 | vc->vidq.mem_ops = &vb2_dma_sg_memops; | ||
766 | vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
767 | vc->vidq.min_buffers_needed = 2; | ||
768 | vc->vidq.lock = &vc->vb_mutex; | ||
769 | vc->vidq.gfp_flags = GFP_DMA32; | ||
770 | |||
771 | err = vb2_queue_init(&vc->vidq); | ||
772 | if (err) | ||
773 | goto error; | ||
774 | |||
775 | strcpy(vdev->name, "TW686x-video"); | ||
776 | snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name); | ||
777 | vdev->fops = &tw686x_video_fops; | ||
778 | vdev->ioctl_ops = &tw686x_video_ioctl_ops; | ||
779 | vdev->release = video_device_release; | ||
780 | vdev->v4l2_dev = &dev->v4l2_dev; | ||
781 | vdev->queue = &vc->vidq; | ||
782 | vdev->tvnorms = V4L2_STD_ALL; | ||
783 | vdev->minor = -1; | ||
784 | vdev->lock = &vc->vb_mutex; | ||
785 | |||
786 | dev->video_channels[ch].device = vdev; | ||
787 | video_set_drvdata(vdev, vc); | ||
788 | err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | ||
789 | if (err < 0) | ||
790 | goto error; | ||
791 | |||
792 | v4l2_ctrl_handler_init(&vc->ctrl_handler, | ||
793 | 4 /* number of controls */); | ||
794 | vdev->ctrl_handler = &vc->ctrl_handler; | ||
795 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
796 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); | ||
797 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
798 | V4L2_CID_CONTRAST, 0, 255, 1, 64); | ||
799 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, | ||
800 | V4L2_CID_SATURATION, 0, 255, 1, 128); | ||
801 | v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, V4L2_CID_HUE, | ||
802 | -124, 127, 1, 0); | ||
803 | err = vc->ctrl_handler.error; | ||
804 | if (err) | ||
805 | goto error; | ||
806 | |||
807 | v4l2_ctrl_handler_setup(&vc->ctrl_handler); | ||
808 | } | ||
809 | |||
810 | dev->video_thread = kthread_run(video_thread, dev, "tw686x_video"); | ||
811 | if (IS_ERR(dev->video_thread)) { | ||
812 | err = PTR_ERR(dev->video_thread); | ||
813 | goto error; | ||
814 | } | ||
815 | |||
816 | return 0; | ||
817 | |||
818 | error: | ||
819 | tw686x_kh_video_free(dev); | ||
820 | return err; | ||
821 | } | ||
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh.h b/drivers/staging/media/tw686x-kh/tw686x-kh.h new file mode 100644 index 000000000000..dc257967dbc7 --- /dev/null +++ b/drivers/staging/media/tw686x-kh/tw686x-kh.h | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Industrial Research Institute for Automation | ||
3 | * and Measurements PIAP | ||
4 | * | ||
5 | * Written by Krzysztof Ha?asa. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of version 2 of the GNU General Public License | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/freezer.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/kthread.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <media/videobuf2-dma-sg.h> | ||
19 | #include <linux/videodev2.h> | ||
20 | #include <media/v4l2-common.h> | ||
21 | #include <media/v4l2-ctrls.h> | ||
22 | #include <media/v4l2-device.h> | ||
23 | #include <media/v4l2-ioctl.h> | ||
24 | |||
25 | #define TYPE_MAX_CHANNELS 0x0F | ||
26 | #define TYPE_SECOND_GEN 0x10 | ||
27 | |||
28 | struct tw686x_format { | ||
29 | char *name; | ||
30 | unsigned int fourcc; | ||
31 | unsigned int depth; | ||
32 | unsigned int mode; | ||
33 | }; | ||
34 | |||
35 | struct dma_desc { | ||
36 | dma_addr_t phys; | ||
37 | void *virt; | ||
38 | unsigned int size; | ||
39 | }; | ||
40 | |||
41 | struct vdma_desc { | ||
42 | __le32 flags_length; /* 3 MSBits for flags, 13 LSBits for length */ | ||
43 | __le32 phys; | ||
44 | }; | ||
45 | |||
46 | struct tw686x_vb2_buf { | ||
47 | struct vb2_v4l2_buffer vb; | ||
48 | struct list_head list; | ||
49 | }; | ||
50 | |||
51 | struct tw686x_video_channel { | ||
52 | struct tw686x_dev *dev; | ||
53 | |||
54 | struct vb2_queue vidq; | ||
55 | struct list_head vidq_queued; | ||
56 | struct video_device *device; | ||
57 | struct dma_desc sg_tables[2]; | ||
58 | struct tw686x_vb2_buf *curr_bufs[2]; | ||
59 | void *alloc_ctx; | ||
60 | struct vdma_desc *sg_descs[2]; | ||
61 | |||
62 | struct v4l2_ctrl_handler ctrl_handler; | ||
63 | const struct tw686x_format *format; | ||
64 | struct mutex vb_mutex; | ||
65 | spinlock_t qlock; | ||
66 | v4l2_std_id video_standard; | ||
67 | unsigned int width, height; | ||
68 | enum v4l2_field field; /* supported TOP, BOTTOM, SEQ_TB and SEQ_BT */ | ||
69 | unsigned int seq; /* video field or frame counter */ | ||
70 | unsigned int ch; | ||
71 | }; | ||
72 | |||
73 | /* global device status */ | ||
74 | struct tw686x_dev { | ||
75 | spinlock_t irq_lock; | ||
76 | |||
77 | struct v4l2_device v4l2_dev; | ||
78 | struct snd_card *card; /* sound card */ | ||
79 | |||
80 | unsigned int video_active; /* active video channel mask */ | ||
81 | |||
82 | char name[32]; | ||
83 | unsigned int type; | ||
84 | struct pci_dev *pci_dev; | ||
85 | __u32 __iomem *mmio; | ||
86 | |||
87 | struct task_struct *video_thread; | ||
88 | wait_queue_head_t video_thread_wait; | ||
89 | u32 dma_requests; | ||
90 | |||
91 | struct tw686x_video_channel video_channels[0]; | ||
92 | }; | ||
93 | |||
94 | static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg) | ||
95 | { | ||
96 | return readl(dev->mmio + reg); | ||
97 | } | ||
98 | |||
99 | static inline void reg_write(struct tw686x_dev *dev, unsigned int reg, | ||
100 | uint32_t value) | ||
101 | { | ||
102 | writel(value, dev->mmio + reg); | ||
103 | } | ||
104 | |||
105 | static inline unsigned int max_channels(struct tw686x_dev *dev) | ||
106 | { | ||
107 | return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */ | ||
108 | } | ||
109 | |||
110 | static inline unsigned int is_second_gen(struct tw686x_dev *dev) | ||
111 | { | ||
112 | /* each channel has its own DMA SG table */ | ||
113 | return dev->type & TYPE_SECOND_GEN; | ||
114 | } | ||
115 | |||
116 | int tw686x_kh_video_irq(struct tw686x_dev *dev); | ||
117 | int tw686x_kh_video_init(struct tw686x_dev *dev); | ||
118 | void tw686x_kh_video_free(struct tw686x_dev *dev); | ||
diff --git a/include/media/media-device.h b/include/media/media-device.h index df74cfa7da4a..a9b33c47310d 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/spinlock.h> | ||
29 | 28 | ||
30 | #include <media/media-devnode.h> | 29 | #include <media/media-devnode.h> |
31 | #include <media/media-entity.h> | 30 | #include <media/media-entity.h> |
@@ -304,8 +303,7 @@ struct media_entity_notify { | |||
304 | * @pads: List of registered pads | 303 | * @pads: List of registered pads |
305 | * @links: List of registered links | 304 | * @links: List of registered links |
306 | * @entity_notify: List of registered entity_notify callbacks | 305 | * @entity_notify: List of registered entity_notify callbacks |
307 | * @lock: Entities list lock | 306 | * @graph_mutex: Protects access to struct media_device data |
308 | * @graph_mutex: Entities graph operation lock | ||
309 | * @pm_count_walk: Graph walk for power state walk. Access serialised using | 307 | * @pm_count_walk: Graph walk for power state walk. Access serialised using |
310 | * graph_mutex. | 308 | * graph_mutex. |
311 | * | 309 | * |
@@ -313,7 +311,8 @@ struct media_entity_notify { | |||
313 | * @enable_source: Enable Source Handler function pointer | 311 | * @enable_source: Enable Source Handler function pointer |
314 | * @disable_source: Disable Source Handler function pointer | 312 | * @disable_source: Disable Source Handler function pointer |
315 | * | 313 | * |
316 | * @link_notify: Link state change notification callback | 314 | * @link_notify: Link state change notification callback. This callback is |
315 | * called with the graph_mutex held. | ||
317 | * | 316 | * |
318 | * This structure represents an abstract high-level media device. It allows easy | 317 | * This structure represents an abstract high-level media device. It allows easy |
319 | * access to entities and provides basic media device-level support. The | 318 | * access to entities and provides basic media device-level support. The |
@@ -357,7 +356,7 @@ struct media_device { | |||
357 | u32 hw_revision; | 356 | u32 hw_revision; |
358 | u32 driver_version; | 357 | u32 driver_version; |
359 | 358 | ||
360 | u32 topology_version; | 359 | u64 topology_version; |
361 | 360 | ||
362 | u32 id; | 361 | u32 id; |
363 | struct ida entity_internal_idx; | 362 | struct ida entity_internal_idx; |
@@ -371,8 +370,6 @@ struct media_device { | |||
371 | /* notify callback list invoked when a new entity is registered */ | 370 | /* notify callback list invoked when a new entity is registered */ |
372 | struct list_head entity_notify; | 371 | struct list_head entity_notify; |
373 | 372 | ||
374 | /* Protects the graph objects creation/removal */ | ||
375 | spinlock_t lock; | ||
376 | /* Serializes graph operations. */ | 373 | /* Serializes graph operations. */ |
377 | struct mutex graph_mutex; | 374 | struct mutex graph_mutex; |
378 | struct media_entity_graph pm_count_walk; | 375 | struct media_entity_graph pm_count_walk; |
@@ -494,7 +491,7 @@ int __must_check __media_device_register(struct media_device *mdev, | |||
494 | #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE) | 491 | #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE) |
495 | 492 | ||
496 | /** | 493 | /** |
497 | * __media_device_unregister() - Unegisters a media device element | 494 | * media_device_unregister() - Unregisters a media device element |
498 | * | 495 | * |
499 | * @mdev: pointer to struct &media_device | 496 | * @mdev: pointer to struct &media_device |
500 | * | 497 | * |
diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 6dc9e4e8cbd4..cbb266f7f2b5 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h | |||
@@ -179,6 +179,9 @@ struct media_pad { | |||
179 | * @link_validate: Return whether a link is valid from the entity point of | 179 | * @link_validate: Return whether a link is valid from the entity point of |
180 | * view. The media_entity_pipeline_start() function | 180 | * view. The media_entity_pipeline_start() function |
181 | * validates all links by calling this operation. Optional. | 181 | * validates all links by calling this operation. Optional. |
182 | * | ||
183 | * Note: Those these callbacks are called with struct media_device.@graph_mutex | ||
184 | * mutex held. | ||
182 | */ | 185 | */ |
183 | struct media_entity_operations { | 186 | struct media_entity_operations { |
184 | int (*link_setup)(struct media_entity *entity, | 187 | int (*link_setup)(struct media_entity *entity, |
@@ -188,10 +191,38 @@ struct media_entity_operations { | |||
188 | }; | 191 | }; |
189 | 192 | ||
190 | /** | 193 | /** |
194 | * enum media_entity_type - Media entity type | ||
195 | * | ||
196 | * @MEDIA_ENTITY_TYPE_BASE: | ||
197 | * The entity isn't embedded in another subsystem structure. | ||
198 | * @MEDIA_ENTITY_TYPE_VIDEO_DEVICE: | ||
199 | * The entity is embedded in a struct video_device instance. | ||
200 | * @MEDIA_ENTITY_TYPE_V4L2_SUBDEV: | ||
201 | * The entity is embedded in a struct v4l2_subdev instance. | ||
202 | * | ||
203 | * Media entity objects are often not instantiated directly, but the media | ||
204 | * entity structure is inherited by (through embedding) other subsystem-specific | ||
205 | * structures. The media entity type identifies the type of the subclass | ||
206 | * structure that implements a media entity instance. | ||
207 | * | ||
208 | * This allows runtime type identification of media entities and safe casting to | ||
209 | * the correct object type. For instance, a media entity structure instance | ||
210 | * embedded in a v4l2_subdev structure instance will have the type | ||
211 | * MEDIA_ENTITY_TYPE_V4L2_SUBDEV and can safely be cast to a v4l2_subdev | ||
212 | * structure using the container_of() macro. | ||
213 | */ | ||
214 | enum media_entity_type { | ||
215 | MEDIA_ENTITY_TYPE_BASE, | ||
216 | MEDIA_ENTITY_TYPE_VIDEO_DEVICE, | ||
217 | MEDIA_ENTITY_TYPE_V4L2_SUBDEV, | ||
218 | }; | ||
219 | |||
220 | /** | ||
191 | * struct media_entity - A media entity graph object. | 221 | * struct media_entity - A media entity graph object. |
192 | * | 222 | * |
193 | * @graph_obj: Embedded structure containing the media object common data. | 223 | * @graph_obj: Embedded structure containing the media object common data. |
194 | * @name: Entity name. | 224 | * @name: Entity name. |
225 | * @obj_type: Type of the object that implements the media_entity. | ||
195 | * @function: Entity main function, as defined in uapi/media.h | 226 | * @function: Entity main function, as defined in uapi/media.h |
196 | * (MEDIA_ENT_F_*) | 227 | * (MEDIA_ENT_F_*) |
197 | * @flags: Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*) | 228 | * @flags: Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*) |
@@ -220,6 +251,7 @@ struct media_entity_operations { | |||
220 | struct media_entity { | 251 | struct media_entity { |
221 | struct media_gobj graph_obj; /* must be first field in struct */ | 252 | struct media_gobj graph_obj; /* must be first field in struct */ |
222 | const char *name; | 253 | const char *name; |
254 | enum media_entity_type obj_type; | ||
223 | u32 function; | 255 | u32 function; |
224 | unsigned long flags; | 256 | unsigned long flags; |
225 | 257 | ||
@@ -329,56 +361,29 @@ static inline u32 media_gobj_gen_id(enum media_gobj_type type, u64 local_id) | |||
329 | } | 361 | } |
330 | 362 | ||
331 | /** | 363 | /** |
332 | * is_media_entity_v4l2_io() - identify if the entity main function | 364 | * is_media_entity_v4l2_video_device() - Check if the entity is a video_device |
333 | * is a V4L2 I/O | ||
334 | * | ||
335 | * @entity: pointer to entity | 365 | * @entity: pointer to entity |
336 | * | 366 | * |
337 | * Return: true if the entity main function is one of the V4L2 I/O types | 367 | * Return: true if the entity is an instance of a video_device object and can |
338 | * (video, VBI or SDR radio); false otherwise. | 368 | * safely be cast to a struct video_device using the container_of() macro, or |
369 | * false otherwise. | ||
339 | */ | 370 | */ |
340 | static inline bool is_media_entity_v4l2_io(struct media_entity *entity) | 371 | static inline bool is_media_entity_v4l2_video_device(struct media_entity *entity) |
341 | { | 372 | { |
342 | if (!entity) | 373 | return entity && entity->obj_type == MEDIA_ENTITY_TYPE_VIDEO_DEVICE; |
343 | return false; | ||
344 | |||
345 | switch (entity->function) { | ||
346 | case MEDIA_ENT_F_IO_V4L: | ||
347 | case MEDIA_ENT_F_IO_VBI: | ||
348 | case MEDIA_ENT_F_IO_SWRADIO: | ||
349 | return true; | ||
350 | default: | ||
351 | return false; | ||
352 | } | ||
353 | } | 374 | } |
354 | 375 | ||
355 | /** | 376 | /** |
356 | * is_media_entity_v4l2_subdev - return true if the entity main function is | 377 | * is_media_entity_v4l2_subdev() - Check if the entity is a v4l2_subdev |
357 | * associated with the V4L2 API subdev usage | ||
358 | * | ||
359 | * @entity: pointer to entity | 378 | * @entity: pointer to entity |
360 | * | 379 | * |
361 | * This is an ancillary function used by subdev-based V4L2 drivers. | 380 | * Return: true if the entity is an instance of a v4l2_subdev object and can |
362 | * It checks if the entity function is one of functions used by a V4L2 subdev, | 381 | * safely be cast to a struct v4l2_subdev using the container_of() macro, or |
363 | * e. g. camera-relatef functions, analog TV decoder, TV tuner, V4L2 DSPs. | 382 | * false otherwise. |
364 | */ | 383 | */ |
365 | static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity) | 384 | static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity) |
366 | { | 385 | { |
367 | if (!entity) | 386 | return entity && entity->obj_type == MEDIA_ENTITY_TYPE_V4L2_SUBDEV; |
368 | return false; | ||
369 | |||
370 | switch (entity->function) { | ||
371 | case MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: | ||
372 | case MEDIA_ENT_F_CAM_SENSOR: | ||
373 | case MEDIA_ENT_F_FLASH: | ||
374 | case MEDIA_ENT_F_LENS: | ||
375 | case MEDIA_ENT_F_ATV_DECODER: | ||
376 | case MEDIA_ENT_F_TUNER: | ||
377 | return true; | ||
378 | |||
379 | default: | ||
380 | return false; | ||
381 | } | ||
382 | } | 387 | } |
383 | 388 | ||
384 | /** | 389 | /** |
diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 0f77b3dffb37..b6586a91129c 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h | |||
@@ -215,12 +215,9 @@ enum raw_event_type { | |||
215 | struct ir_raw_event { | 215 | struct ir_raw_event { |
216 | union { | 216 | union { |
217 | u32 duration; | 217 | u32 duration; |
218 | 218 | u32 carrier; | |
219 | struct { | ||
220 | u32 carrier; | ||
221 | u8 duty_cycle; | ||
222 | }; | ||
223 | }; | 219 | }; |
220 | u8 duty_cycle; | ||
224 | 221 | ||
225 | unsigned pulse:1; | 222 | unsigned pulse:1; |
226 | unsigned reset:1; | 223 | unsigned reset:1; |
@@ -228,13 +225,7 @@ struct ir_raw_event { | |||
228 | unsigned carrier_report:1; | 225 | unsigned carrier_report:1; |
229 | }; | 226 | }; |
230 | 227 | ||
231 | #define DEFINE_IR_RAW_EVENT(event) \ | 228 | #define DEFINE_IR_RAW_EVENT(event) struct ir_raw_event event = {} |
232 | struct ir_raw_event event = { \ | ||
233 | { .duration = 0 } , \ | ||
234 | .pulse = 0, \ | ||
235 | .reset = 0, \ | ||
236 | .timeout = 0, \ | ||
237 | .carrier_report = 0 } | ||
238 | 229 | ||
239 | static inline void init_ir_raw_event(struct ir_raw_event *ev) | 230 | static inline void init_ir_raw_event(struct ir_raw_event *ev) |
240 | { | 231 | { |
@@ -256,8 +247,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle); | |||
256 | 247 | ||
257 | static inline void ir_raw_event_reset(struct rc_dev *dev) | 248 | static inline void ir_raw_event_reset(struct rc_dev *dev) |
258 | { | 249 | { |
259 | DEFINE_IR_RAW_EVENT(ev); | 250 | struct ir_raw_event ev = { .reset = true }; |
260 | ev.reset = true; | ||
261 | 251 | ||
262 | ir_raw_event_store(dev, &ev); | 252 | ir_raw_event_store(dev, &ev); |
263 | ir_raw_event_handle(dev); | 253 | ir_raw_event_handle(dev); |
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 76056ab5c5bd..25a3190308fb 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h | |||
@@ -92,6 +92,9 @@ struct video_device | |||
92 | /* device ops */ | 92 | /* device ops */ |
93 | const struct v4l2_file_operations *fops; | 93 | const struct v4l2_file_operations *fops; |
94 | 94 | ||
95 | /* device capabilities as used in v4l2_capabilities */ | ||
96 | u32 device_caps; | ||
97 | |||
95 | /* sysfs */ | 98 | /* sysfs */ |
96 | struct device dev; /* v4l device */ | 99 | struct device dev; /* v4l device */ |
97 | struct cdev *cdev; /* character device */ | 100 | struct cdev *cdev; /* character device */ |
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 9c581578783f..d5d45a8d3998 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h | |||
@@ -196,11 +196,64 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, | |||
196 | ##args); \ | 196 | ##args); \ |
197 | }) | 197 | }) |
198 | 198 | ||
199 | #define v4l2_device_has_op(v4l2_dev, o, f) \ | 199 | /* |
200 | * Call the specified callback for all subdevs where grp_id & grpmsk != 0 | ||
201 | * (if grpmsk == `0, then match them all). Ignore any errors. Note that you | ||
202 | * cannot add or delete a subdev while walking the subdevs list. | ||
203 | */ | ||
204 | #define v4l2_device_mask_call_all(v4l2_dev, grpmsk, o, f, args...) \ | ||
205 | do { \ | ||
206 | struct v4l2_subdev *__sd; \ | ||
207 | \ | ||
208 | __v4l2_device_call_subdevs_p(v4l2_dev, __sd, \ | ||
209 | !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f , \ | ||
210 | ##args); \ | ||
211 | } while (0) | ||
212 | |||
213 | /* | ||
214 | * Call the specified callback for all subdevs where grp_id & grpmsk != 0 | ||
215 | * (if grpmsk == `0, then match them all). If the callback returns an error | ||
216 | * other than 0 or -ENOIOCTLCMD, then return with that error code. Note that | ||
217 | * you cannot add or delete a subdev while walking the subdevs list. | ||
218 | */ | ||
219 | #define v4l2_device_mask_call_until_err(v4l2_dev, grpmsk, o, f, args...) \ | ||
220 | ({ \ | ||
221 | struct v4l2_subdev *__sd; \ | ||
222 | __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, \ | ||
223 | !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f , \ | ||
224 | ##args); \ | ||
225 | }) | ||
226 | |||
227 | /* | ||
228 | * Does any subdev with matching grpid (or all if grpid == 0) has the given | ||
229 | * op? | ||
230 | */ | ||
231 | #define v4l2_device_has_op(v4l2_dev, grpid, o, f) \ | ||
232 | ({ \ | ||
233 | struct v4l2_subdev *__sd; \ | ||
234 | bool __result = false; \ | ||
235 | list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ | ||
236 | if ((grpid) && __sd->grp_id != (grpid)) \ | ||
237 | continue; \ | ||
238 | if (v4l2_subdev_has_op(__sd, o, f)) { \ | ||
239 | __result = true; \ | ||
240 | break; \ | ||
241 | } \ | ||
242 | } \ | ||
243 | __result; \ | ||
244 | }) | ||
245 | |||
246 | /* | ||
247 | * Does any subdev with matching grpmsk (or all if grpmsk == 0) has the given | ||
248 | * op? | ||
249 | */ | ||
250 | #define v4l2_device_mask_has_op(v4l2_dev, grpmsk, o, f) \ | ||
200 | ({ \ | 251 | ({ \ |
201 | struct v4l2_subdev *__sd; \ | 252 | struct v4l2_subdev *__sd; \ |
202 | bool __result = false; \ | 253 | bool __result = false; \ |
203 | list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ | 254 | list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ |
255 | if ((grpmsk) && !(__sd->grp_id & (grpmsk))) \ | ||
256 | continue; \ | ||
204 | if (v4l2_subdev_has_op(__sd, o, f)) { \ | 257 | if (v4l2_subdev_has_op(__sd, o, f)) { \ |
205 | __result = true; \ | 258 | __result = true; \ |
206 | break; \ | 259 | break; \ |
diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h new file mode 100644 index 000000000000..d2125f0cc7cd --- /dev/null +++ b/include/media/v4l2-rect.h | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * v4l2-rect.h - v4l2_rect helper functions | ||
3 | * | ||
4 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you may redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
12 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
13 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
14 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
16 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
17 | * SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #ifndef _V4L2_RECT_H_ | ||
21 | #define _V4L2_RECT_H_ | ||
22 | |||
23 | #include <linux/videodev2.h> | ||
24 | |||
25 | /** | ||
26 | * v4l2_rect_set_size_to() - copy the width/height values. | ||
27 | * @r: rect whose width and height fields will be set | ||
28 | * @size: rect containing the width and height fields you need. | ||
29 | */ | ||
30 | static inline void v4l2_rect_set_size_to(struct v4l2_rect *r, | ||
31 | const struct v4l2_rect *size) | ||
32 | { | ||
33 | r->width = size->width; | ||
34 | r->height = size->height; | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * v4l2_rect_set_min_size() - width and height of r should be >= min_size. | ||
39 | * @r: rect whose width and height will be modified | ||
40 | * @min_size: rect containing the minimal width and height | ||
41 | */ | ||
42 | static inline void v4l2_rect_set_min_size(struct v4l2_rect *r, | ||
43 | const struct v4l2_rect *min_size) | ||
44 | { | ||
45 | if (r->width < min_size->width) | ||
46 | r->width = min_size->width; | ||
47 | if (r->height < min_size->height) | ||
48 | r->height = min_size->height; | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * v4l2_rect_set_max_size() - width and height of r should be <= max_size | ||
53 | * @r: rect whose width and height will be modified | ||
54 | * @max_size: rect containing the maximum width and height | ||
55 | */ | ||
56 | static inline void v4l2_rect_set_max_size(struct v4l2_rect *r, | ||
57 | const struct v4l2_rect *max_size) | ||
58 | { | ||
59 | if (r->width > max_size->width) | ||
60 | r->width = max_size->width; | ||
61 | if (r->height > max_size->height) | ||
62 | r->height = max_size->height; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * v4l2_rect_map_inside()- r should be inside boundary. | ||
67 | * @r: rect that will be modified | ||
68 | * @boundary: rect containing the boundary for @r | ||
69 | */ | ||
70 | static inline void v4l2_rect_map_inside(struct v4l2_rect *r, | ||
71 | const struct v4l2_rect *boundary) | ||
72 | { | ||
73 | v4l2_rect_set_max_size(r, boundary); | ||
74 | if (r->left < boundary->left) | ||
75 | r->left = boundary->left; | ||
76 | if (r->top < boundary->top) | ||
77 | r->top = boundary->top; | ||
78 | if (r->left + r->width > boundary->width) | ||
79 | r->left = boundary->width - r->width; | ||
80 | if (r->top + r->height > boundary->height) | ||
81 | r->top = boundary->height - r->height; | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * v4l2_rect_same_size() - return true if r1 has the same size as r2 | ||
86 | * @r1: rectangle. | ||
87 | * @r2: rectangle. | ||
88 | * | ||
89 | * Return true if both rectangles have the same size. | ||
90 | */ | ||
91 | static inline bool v4l2_rect_same_size(const struct v4l2_rect *r1, | ||
92 | const struct v4l2_rect *r2) | ||
93 | { | ||
94 | return r1->width == r2->width && r1->height == r2->height; | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * v4l2_rect_intersect() - calculate the intersection of two rects. | ||
99 | * @r: intersection of @r1 and @r2. | ||
100 | * @r1: rectangle. | ||
101 | * @r2: rectangle. | ||
102 | */ | ||
103 | static inline void v4l2_rect_intersect(struct v4l2_rect *r, | ||
104 | const struct v4l2_rect *r1, | ||
105 | const struct v4l2_rect *r2) | ||
106 | { | ||
107 | int right, bottom; | ||
108 | |||
109 | r->top = max(r1->top, r2->top); | ||
110 | r->left = max(r1->left, r2->left); | ||
111 | bottom = min(r1->top + r1->height, r2->top + r2->height); | ||
112 | right = min(r1->left + r1->width, r2->left + r2->width); | ||
113 | r->height = max(0, bottom - r->top); | ||
114 | r->width = max(0, right - r->left); | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * v4l2_rect_scale() - scale rect r by to/from | ||
119 | * @r: rect to be scaled. | ||
120 | * @from: from rectangle. | ||
121 | * @to: to rectangle. | ||
122 | * | ||
123 | * This scales rectangle @r horizontally by @to->width / @from->width and | ||
124 | * vertically by @to->height / @from->height. | ||
125 | * | ||
126 | * Typically @r is a rectangle inside @from and you want the rectangle as | ||
127 | * it would appear after scaling @from to @to. So the resulting @r will | ||
128 | * be the scaled rectangle inside @to. | ||
129 | */ | ||
130 | static inline void v4l2_rect_scale(struct v4l2_rect *r, | ||
131 | const struct v4l2_rect *from, | ||
132 | const struct v4l2_rect *to) | ||
133 | { | ||
134 | if (from->width == 0 || from->height == 0) { | ||
135 | r->left = r->top = r->width = r->height = 0; | ||
136 | return; | ||
137 | } | ||
138 | r->left = (((r->left - from->left) * to->width) / from->width) & ~1; | ||
139 | r->width = ((r->width * to->width) / from->width) & ~1; | ||
140 | r->top = ((r->top - from->top) * to->height) / from->height; | ||
141 | r->height = (r->height * to->height) / from->height; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * v4l2_rect_overlap() - do r1 and r2 overlap? | ||
146 | * @r1: rectangle. | ||
147 | * @r2: rectangle. | ||
148 | * | ||
149 | * Returns true if @r1 and @r2 overlap. | ||
150 | */ | ||
151 | static inline bool v4l2_rect_overlap(const struct v4l2_rect *r1, | ||
152 | const struct v4l2_rect *r2) | ||
153 | { | ||
154 | /* | ||
155 | * IF the left side of r1 is to the right of the right side of r2 OR | ||
156 | * the left side of r2 is to the right of the right side of r1 THEN | ||
157 | * they do not overlap. | ||
158 | */ | ||
159 | if (r1->left >= r2->left + r2->width || | ||
160 | r2->left >= r1->left + r1->width) | ||
161 | return false; | ||
162 | /* | ||
163 | * IF the top side of r1 is below the bottom of r2 OR | ||
164 | * the top side of r2 is below the bottom of r1 THEN | ||
165 | * they do not overlap. | ||
166 | */ | ||
167 | if (r1->top >= r2->top + r2->height || | ||
168 | r2->top >= r1->top + r1->height) | ||
169 | return false; | ||
170 | return true; | ||
171 | } | ||
172 | |||
173 | #endif | ||
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 11e2dfec0198..32fc7a4beb5e 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
@@ -572,6 +572,7 @@ struct v4l2_subdev_pad_config { | |||
572 | /** | 572 | /** |
573 | * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations | 573 | * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations |
574 | * | 574 | * |
575 | * @init_cfg: initialize the pad config to default values | ||
575 | * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler | 576 | * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler |
576 | * code. | 577 | * code. |
577 | * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler | 578 | * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler |
@@ -607,6 +608,8 @@ struct v4l2_subdev_pad_config { | |||
607 | * may be adjusted by the subdev driver to device capabilities. | 608 | * may be adjusted by the subdev driver to device capabilities. |
608 | */ | 609 | */ |
609 | struct v4l2_subdev_pad_ops { | 610 | struct v4l2_subdev_pad_ops { |
611 | int (*init_cfg)(struct v4l2_subdev *sd, | ||
612 | struct v4l2_subdev_pad_config *cfg); | ||
610 | int (*enum_mbus_code)(struct v4l2_subdev *sd, | 613 | int (*enum_mbus_code)(struct v4l2_subdev *sd, |
611 | struct v4l2_subdev_pad_config *cfg, | 614 | struct v4l2_subdev_pad_config *cfg, |
612 | struct v4l2_subdev_mbus_code_enum *code); | 615 | struct v4l2_subdev_mbus_code_enum *code); |
@@ -801,7 +804,12 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, | |||
801 | struct v4l2_subdev_format *source_fmt, | 804 | struct v4l2_subdev_format *source_fmt, |
802 | struct v4l2_subdev_format *sink_fmt); | 805 | struct v4l2_subdev_format *sink_fmt); |
803 | int v4l2_subdev_link_validate(struct media_link *link); | 806 | int v4l2_subdev_link_validate(struct media_link *link); |
807 | |||
808 | struct v4l2_subdev_pad_config * | ||
809 | v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd); | ||
810 | void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg); | ||
804 | #endif /* CONFIG_MEDIA_CONTROLLER */ | 811 | #endif /* CONFIG_MEDIA_CONTROLLER */ |
812 | |||
805 | void v4l2_subdev_init(struct v4l2_subdev *sd, | 813 | void v4l2_subdev_init(struct v4l2_subdev *sd, |
806 | const struct v4l2_subdev_ops *ops); | 814 | const struct v4l2_subdev_ops *ops); |
807 | 815 | ||
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/include/media/v4l2-tpg-colors.h index 4e5a76a1e25b..2a88d1fae0cd 100644 --- a/drivers/media/platform/vivid/vivid-tpg-colors.h +++ b/include/media/v4l2-tpg-colors.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * vivid-color.h - Color definitions for the test pattern generator | 2 | * v4l2-tpg-colors.h - Color definitions for the test pattern generator |
3 | * | 3 | * |
4 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | 4 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
5 | * | 5 | * |
@@ -17,8 +17,8 @@ | |||
17 | * SOFTWARE. | 17 | * SOFTWARE. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #ifndef _VIVID_COLORS_H_ | 20 | #ifndef _V4L2_TPG_COLORS_H_ |
21 | #define _VIVID_COLORS_H_ | 21 | #define _V4L2_TPG_COLORS_H_ |
22 | 22 | ||
23 | struct color { | 23 | struct color { |
24 | unsigned char r, g, b; | 24 | unsigned char r, g, b; |
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/include/media/v4l2-tpg.h index 93fbaee69675..329bebfa930c 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/include/media/v4l2-tpg.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * vivid-tpg.h - Test Pattern Generator | 2 | * v4l2-tpg.h - Test Pattern Generator |
3 | * | 3 | * |
4 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | 4 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
5 | * | 5 | * |
@@ -17,8 +17,8 @@ | |||
17 | * SOFTWARE. | 17 | * SOFTWARE. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #ifndef _VIVID_TPG_H_ | 20 | #ifndef _V4L2_TPG_H_ |
21 | #define _VIVID_TPG_H_ | 21 | #define _V4L2_TPG_H_ |
22 | 22 | ||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
@@ -26,8 +26,7 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
29 | 29 | #include <media/v4l2-tpg-colors.h> | |
30 | #include "vivid-tpg-colors.h" | ||
31 | 30 | ||
32 | enum tpg_pattern { | 31 | enum tpg_pattern { |
33 | TPG_PAT_75_COLORBAR, | 32 | TPG_PAT_75_COLORBAR, |
diff --git a/include/media/vsp1.h b/include/media/vsp1.h index cc541753896f..3e654a0455bd 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h | |||
@@ -23,11 +23,22 @@ int vsp1_du_init(struct device *dev); | |||
23 | int vsp1_du_setup_lif(struct device *dev, unsigned int width, | 23 | int vsp1_du_setup_lif(struct device *dev, unsigned int width, |
24 | unsigned int height); | 24 | unsigned int height); |
25 | 25 | ||
26 | int vsp1_du_atomic_begin(struct device *dev); | 26 | void vsp1_du_atomic_begin(struct device *dev); |
27 | int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, u32 pixelformat, | 27 | int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf, |
28 | unsigned int pitch, dma_addr_t mem[2], | 28 | u32 pixelformat, unsigned int pitch, |
29 | const struct v4l2_rect *src, | 29 | dma_addr_t mem[2], const struct v4l2_rect *src, |
30 | const struct v4l2_rect *dst); | 30 | const struct v4l2_rect *dst, unsigned int alpha, |
31 | int vsp1_du_atomic_flush(struct device *dev); | 31 | unsigned int zpos); |
32 | void vsp1_du_atomic_flush(struct device *dev); | ||
33 | |||
34 | static inline int vsp1_du_atomic_update(struct device *dev, | ||
35 | unsigned int rpf_index, u32 pixelformat, | ||
36 | unsigned int pitch, dma_addr_t mem[2], | ||
37 | const struct v4l2_rect *src, | ||
38 | const struct v4l2_rect *dst) | ||
39 | { | ||
40 | return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch, | ||
41 | mem, src, dst, 255, 0); | ||
42 | } | ||
32 | 43 | ||
33 | #endif /* __MEDIA_VSP1_H__ */ | 44 | #endif /* __MEDIA_VSP1_H__ */ |
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index e895975c5b0e..8f951917be74 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h | |||
@@ -138,10 +138,7 @@ enum v4l2_buf_type { | |||
138 | V4L2_BUF_TYPE_VBI_OUTPUT = 5, | 138 | V4L2_BUF_TYPE_VBI_OUTPUT = 5, |
139 | V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, | 139 | V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, |
140 | V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, | 140 | V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, |
141 | #if 1 | ||
142 | /* Experimental */ | ||
143 | V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, | 141 | V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, |
144 | #endif | ||
145 | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, | 142 | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, |
146 | V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, | 143 | V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, |
147 | V4L2_BUF_TYPE_SDR_CAPTURE = 11, | 144 | V4L2_BUF_TYPE_SDR_CAPTURE = 11, |
@@ -657,8 +654,7 @@ struct v4l2_fmtdesc { | |||
657 | #define V4L2_FMT_FLAG_COMPRESSED 0x0001 | 654 | #define V4L2_FMT_FLAG_COMPRESSED 0x0001 |
658 | #define V4L2_FMT_FLAG_EMULATED 0x0002 | 655 | #define V4L2_FMT_FLAG_EMULATED 0x0002 |
659 | 656 | ||
660 | #if 1 | 657 | /* Frame Size and frame rate enumeration */ |
661 | /* Experimental Frame Size and frame rate enumeration */ | ||
662 | /* | 658 | /* |
663 | * F R A M E S I Z E E N U M E R A T I O N | 659 | * F R A M E S I Z E E N U M E R A T I O N |
664 | */ | 660 | */ |
@@ -724,7 +720,6 @@ struct v4l2_frmivalenum { | |||
724 | 720 | ||
725 | __u32 reserved[2]; /* Reserved space for future use */ | 721 | __u32 reserved[2]; /* Reserved space for future use */ |
726 | }; | 722 | }; |
727 | #endif | ||
728 | 723 | ||
729 | /* | 724 | /* |
730 | * T I M E C O D E | 725 | * T I M E C O D E |
@@ -1728,8 +1723,6 @@ struct v4l2_audioout { | |||
1728 | 1723 | ||
1729 | /* | 1724 | /* |
1730 | * M P E G S E R V I C E S | 1725 | * M P E G S E R V I C E S |
1731 | * | ||
1732 | * NOTE: EXPERIMENTAL API | ||
1733 | */ | 1726 | */ |
1734 | #if 1 | 1727 | #if 1 |
1735 | #define V4L2_ENC_IDX_FRAME_I (0) | 1728 | #define V4L2_ENC_IDX_FRAME_I (0) |
@@ -2259,46 +2252,35 @@ struct v4l2_create_buffers { | |||
2259 | #define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) | 2252 | #define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) |
2260 | #define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) | 2253 | #define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) |
2261 | 2254 | ||
2262 | /* Experimental, meant for debugging, testing and internal use. | 2255 | /* |
2263 | Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. | 2256 | * Experimental, meant for debugging, testing and internal use. |
2264 | You must be root to use these ioctls. Never use these in applications! */ | 2257 | * Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. |
2258 | * You must be root to use these ioctls. Never use these in applications! | ||
2259 | */ | ||
2265 | #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) | 2260 | #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) |
2266 | #define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) | 2261 | #define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) |
2267 | 2262 | ||
2268 | #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) | 2263 | #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) |
2269 | |||
2270 | #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) | 2264 | #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) |
2271 | #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) | 2265 | #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) |
2272 | #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) | 2266 | #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) |
2273 | #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) | 2267 | #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) |
2274 | #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) | 2268 | #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) |
2275 | |||
2276 | /* Experimental, the below two ioctls may change over the next couple of kernel | ||
2277 | versions */ | ||
2278 | #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) | 2269 | #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) |
2279 | #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) | 2270 | #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) |
2280 | |||
2281 | /* Experimental selection API */ | ||
2282 | #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) | 2271 | #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) |
2283 | #define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) | 2272 | #define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) |
2284 | |||
2285 | /* Experimental, these two ioctls may change over the next couple of kernel | ||
2286 | versions. */ | ||
2287 | #define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) | 2273 | #define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) |
2288 | #define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) | 2274 | #define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) |
2289 | |||
2290 | /* Experimental, these three ioctls may change over the next couple of kernel | ||
2291 | versions. */ | ||
2292 | #define VIDIOC_ENUM_DV_TIMINGS _IOWR('V', 98, struct v4l2_enum_dv_timings) | 2275 | #define VIDIOC_ENUM_DV_TIMINGS _IOWR('V', 98, struct v4l2_enum_dv_timings) |
2293 | #define VIDIOC_QUERY_DV_TIMINGS _IOR('V', 99, struct v4l2_dv_timings) | 2276 | #define VIDIOC_QUERY_DV_TIMINGS _IOR('V', 99, struct v4l2_dv_timings) |
2294 | #define VIDIOC_DV_TIMINGS_CAP _IOWR('V', 100, struct v4l2_dv_timings_cap) | 2277 | #define VIDIOC_DV_TIMINGS_CAP _IOWR('V', 100, struct v4l2_dv_timings_cap) |
2295 | |||
2296 | /* Experimental, this ioctl may change over the next couple of kernel | ||
2297 | versions. */ | ||
2298 | #define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band) | 2278 | #define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band) |
2299 | 2279 | ||
2300 | /* Experimental, meant for debugging, testing and internal use. | 2280 | /* |
2301 | Never use these in applications! */ | 2281 | * Experimental, meant for debugging, testing and internal use. |
2282 | * Never use this in applications! | ||
2283 | */ | ||
2302 | #define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) | 2284 | #define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) |
2303 | 2285 | ||
2304 | #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl) | 2286 | #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl) |
diff --git a/samples/Makefile b/samples/Makefile index 48001d7e23f0..ad440d670cdb 100644 --- a/samples/Makefile +++ b/samples/Makefile | |||
@@ -2,4 +2,4 @@ | |||
2 | 2 | ||
3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ | 3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ |
4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ | 4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ |
5 | configfs/ | 5 | configfs/ v4l/ |
diff --git a/Documentation/video4linux/Makefile b/samples/v4l/Makefile index 65a351d75c95..65a351d75c95 100644 --- a/Documentation/video4linux/Makefile +++ b/samples/v4l/Makefile | |||
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index 79af0c041056..a55cf94ac907 100644 --- a/Documentation/video4linux/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c | |||
@@ -308,9 +308,6 @@ static int skeleton_querycap(struct file *file, void *priv, | |||
308 | strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card)); | 308 | strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card)); |
309 | snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", | 309 | snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", |
310 | pci_name(skel->pdev)); | 310 | pci_name(skel->pdev)); |
311 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
312 | V4L2_CAP_STREAMING; | ||
313 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
314 | return 0; | 311 | return 0; |
315 | } | 312 | } |
316 | 313 | ||
@@ -872,6 +869,8 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
872 | vdev->release = video_device_release_empty; | 869 | vdev->release = video_device_release_empty; |
873 | vdev->fops = &skel_fops, | 870 | vdev->fops = &skel_fops, |
874 | vdev->ioctl_ops = &skel_ioctl_ops, | 871 | vdev->ioctl_ops = &skel_ioctl_ops, |
872 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
873 | V4L2_CAP_STREAMING; | ||
875 | /* | 874 | /* |
876 | * The main serialization lock. All ioctls are serialized by this | 875 | * The main serialization lock. All ioctls are serialized by this |
877 | * lock. Exception: if q->lock is set, then the streaming ioctls | 876 | * lock. Exception: if q->lock is set, then the streaming ioctls |