diff options
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 |
