Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:
- added support for Intersil/Techwell TW686x-based video capture cards
- v4l PCI skeleton driver moved to samples directory
- Documentation cleanups and improvements
- RC: reduced the memory footprint for IR raw events
- tpg: Export the tpg code from vivid as a module
- adv7180: Add device tree binding documentation
- lots of driver improvements and fixes

* tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (173 commits)
[media] exynos-gsc: avoid build warning without CONFIG_OF
[media] samples: v4l: from Documentation to samples directory
[media] dib0700: add USB ID for another STK8096-PVR ref design based card
[media] tvp5150: propagate I2C write error in .s_register callback
[media] tvp5150: return I2C write operation failure to callers
[media] em28xx: add support for Hauppauge WinTV-dualHD DVB tuner
[media] em28xx: add missing USB IDs
[media] update cx23885 and em28xx cardlists
[media] media: au0828 fix au0828_v4l2_device_register() to not unlock and free
[media] c8sectpfe: Rework firmware loading mechanism
[media] c8sectpfe: Demote print to dev_dbg
[media] c8sectpfe: Fix broken circular buffer wp management
[media] media-device: Simplify compat32 logic
[media] media: i2c: ths7303: remove redundant assignment on bt
[media] dvb-usb: hide unused functions
[media] xilinx-vipp: remove unnecessary of_node_put
[media] drivers/media/media-devnode: clear private_data before put_device()
[media] drivers/media/media-device: move debug log before _devnode_unregister()
[media] drivers/media/rc: postpone kfree(rc_dev)
[media] media/dvb-core: forward media_create_pad_links() return value
...

+6931 -3175
+1
Documentation/DocBook/device-drivers.tmpl
··· 233 233 !Iinclude/media/v4l2-mediabus.h 234 234 !Iinclude/media/v4l2-mem2mem.h 235 235 !Iinclude/media/v4l2-of.h 236 + !Iinclude/media/v4l2-rect.h 236 237 !Iinclude/media/v4l2-subdev.h 237 238 !Iinclude/media/videobuf2-core.h 238 239 !Iinclude/media/videobuf2-v4l2.h
+1 -1
Documentation/DocBook/media/dvb/net.xml
··· 15 15 that are present on the transport stream. This is done through 16 16 <constant>/dev/dvb/adapter?/net?</constant> device node. 17 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 19 ip tools (like ip, route, netstat, ifconfig, etc).</para> 20 20 <para> Data types and and ioctl definitions are defined via 21 21 <constant>linux/dvb/net.h</constant> header.</para>
-38
Documentation/DocBook/media/v4l/compat.xml
··· 2686 2686 2687 2687 <itemizedlist> 2688 2688 <listitem> 2689 - <para>Video Output Overlay (OSD) Interface, <xref 2690 - linkend="osd" />.</para> 2691 - </listitem> 2692 - <listitem> 2693 2689 <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER; 2694 2690 ioctls.</para> 2695 2691 </listitem> 2696 2692 <listitem> 2697 2693 <para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para> 2698 - </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 2694 </listitem> 2733 2695 </itemizedlist> 2734 2696 </section>
-31
Documentation/DocBook/media/v4l/controls.xml
··· 4272 4272 <section id="flash-controls"> 4273 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 4275 <para> 4283 4276 The V4L2 flash controls are intended to provide generic access 4284 4277 to flash controller devices. Flash controller devices are ··· 4736 4743 <section id="image-source-controls"> 4737 4744 <title>Image Source Control Reference</title> 4738 4745 4739 - <note> 4740 - <title>Experimental</title> 4741 - 4742 - <para>This is an <link 4743 - linkend="experimental">experimental</link> interface and may 4744 - change in the future.</para> 4745 - </note> 4746 - 4747 4746 <para> 4748 4747 The Image Source control class is intended for low-level 4749 4748 control of image source devices such as image sensors. The ··· 4847 4862 <section id="image-process-controls"> 4848 4863 <title>Image Process Control Reference</title> 4849 4864 4850 - <note> 4851 - <title>Experimental</title> 4852 - 4853 - <para>This is an <link 4854 - linkend="experimental">experimental</link> interface and may 4855 - change in the future.</para> 4856 - </note> 4857 - 4858 4865 <para> 4859 4866 The Image Process control class is intended for low-level control of 4860 4867 image processing functions. Unlike ··· 4931 4954 4932 4955 <section id="dv-controls"> 4933 4956 <title>Digital Video Control Reference</title> 4934 - 4935 - <note> 4936 - <title>Experimental</title> 4937 - 4938 - <para>This is an <link 4939 - linkend="experimental">experimental</link> interface and may 4940 - change in the future.</para> 4941 - </note> 4942 4957 4943 4958 <para> 4944 4959 The Digital Video control class is intended to control receivers
-6
Documentation/DocBook/media/v4l/dev-sdr.xml
··· 1 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 3 <para> 10 4 SDR is an abbreviation of Software Defined Radio, the radio device 11 5 which uses application software for modulation or demodulation. This interface
-6
Documentation/DocBook/media/v4l/dev-subdev.xml
··· 1 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 3 <para>The complex nature of V4L2 devices, where hardware is often made of 10 4 several integrated circuits that need to interact with each other in a 11 5 controlled way, leads to complex V4L2 drivers. The drivers usually reflect
-6
Documentation/DocBook/media/v4l/io.xml
··· 475 475 <section id="dmabuf"> 476 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 478 <para>The DMABUF framework provides a generic method for sharing buffers 485 479 between multiple devices. Device drivers that support DMABUF can export a DMA 486 480 buffer to userspace as a file descriptor (known as the exporter role), import a
+1 -8
Documentation/DocBook/media/v4l/selection-api.xml
··· 1 1 <section id="selection-api"> 2 2 3 - <title>Experimental 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> 3 + <title>API for cropping, composing and scaling</title> 11 4 12 5 <section> 13 6 <title>Introduction</title>
-6
Documentation/DocBook/media/v4l/subdev-formats.xml
··· 4002 4002 <section id="v4l2-mbus-vendor-spec-fmts"> 4003 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 4005 <para>This section lists complex data formats that are either vendor or 4012 4006 device specific. 4013 4007 </para>
-6
Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
··· 49 49 <refsect1> 50 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 52 <para>This ioctl is used to create buffers for <link linkend="mmap">memory 59 53 mapped</link> or <link linkend="userp">user pointer</link> or <link 60 54 linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in
+7 -11
Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
··· 49 49 <refsect1> 50 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 query the capabilities of the DV receiver/transmitter applications 59 - can call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node 52 + <para>To query the capabilities of the DV receiver/transmitter applications initialize the 53 + <structfield>pad</structfield> field to 0, zero the reserved array of &v4l2-dv-timings-cap; 54 + and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node 60 55 and the driver will fill in the structure. Note that drivers may return 61 56 different values after switching the video input or output.</para> 62 57 ··· 60 65 directly on a subdevice node. The capabilities are specific to inputs (for DV 61 66 receivers) or outputs (for DV transmitters), applications must specify the 62 67 desired pad number in the &v4l2-dv-timings-cap; <structfield>pad</structfield> 63 - field. Attempts to query capabilities on a pad that doesn't support them will 64 - return an &EINVAL;.</para> 68 + field and zero the <structfield>reserved</structfield> array. Attempts to query 69 + capabilities on a pad that doesn't support them will return an &EINVAL;.</para> 65 70 66 71 <table pgwide="1" frame="none" id="v4l2-bt-timings-cap"> 67 72 <title>struct <structname>v4l2_bt_timings_cap</structname></title> ··· 140 145 <row> 141 146 <entry>__u32</entry> 142 147 <entry><structfield>reserved</structfield>[2]</entry> 143 - <entry>Reserved for future extensions. Drivers must set the array to zero.</entry> 148 + <entry>Reserved for future extensions. Drivers and applications must 149 + set the array to zero.</entry> 144 150 </row> 145 151 <row> 146 152 <entry>union</entry>
+3 -8
Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
··· 49 49 <refsect1> 50 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 52 <para>While some DV receivers or transmitters support a wide range of timings, others 59 53 support only a limited number of timings. With this ioctl applications can enumerate a list 60 54 of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other 61 55 standards or even custom timings that are not in this list.</para> 62 56 63 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; 65 - and call the <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a 58 + <structfield>index</structfield> field, set the <structfield>pad</structfield> field to 0, 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 61 pointer to this structure. Drivers fill the rest of the structure or return an 67 62 &EINVAL; when the index is out of bounds. To enumerate all supported DV timings, 68 63 applications shall begin at index zero, incrementing by one until the
-6
Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml
··· 49 49 <refsect1> 50 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 52 <para>Enumerates the frequency bands that a tuner or modulator supports. 59 53 To do this applications initialize the <structfield>tuner</structfield>, 60 54 <structfield>type</structfield> and <structfield>index</structfield> fields,
-6
Documentation/DocBook/media/v4l/vidioc-expbuf.xml
··· 49 49 <refsect1> 50 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 52 <para>This ioctl is an extension to the <link linkend="mmap">memory 59 53 mapping</link> I/O method, therefore it is available only for 60 54 <constant>V4L2_MEMORY_MMAP</constant> buffers. It can be used to export a
+6 -4
Documentation/DocBook/media/v4l/vidioc-g-edid.xml
··· 1 1 <refentry id="vidioc-g-edid"> 2 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 4 &manvol; 5 5 </refmeta> 6 6 ··· 71 71 72 72 <para>To get the EDID data the application has to fill in the <structfield>pad</structfield>, 73 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 76 <structfield>start_block</structfield> and of size <structfield>blocks</structfield> 76 77 will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield> 77 78 pointer must point to memory at least <structfield>blocks</structfield>&nbsp;*&nbsp;128 bytes ··· 93 92 the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para> 94 93 95 94 <para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>, 96 - <structfield>blocks</structfield> and <structfield>edid</structfield> fields and set 97 - <structfield>start_block</structfield> to 0. It is not possible to set part of an EDID, 95 + <structfield>blocks</structfield> and <structfield>edid</structfield> fields, set 96 + <structfield>start_block</structfield> to 0 and zero the <structfield>reserved</structfield> array. 97 + It is not possible to set part of an EDID, 98 98 it is always all or nothing. Setting the EDID data is only valid for receivers as it makes 99 99 no sense for a transmitter.</para> 100 100
-6
Documentation/DocBook/media/v4l/vidioc-g-selection.xml
··· 50 50 <refsect1> 51 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 53 <para>The ioctls are used to query and configure selection rectangles.</para> 60 54 61 55 <para>To query the cropping (composing) rectangle set &v4l2-selection;
-6
Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
··· 48 48 <refsect1> 49 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 51 <para>Applications can optionally call the 58 52 <constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer 59 53 to the driver before actually enqueuing it, using the
-6
Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
··· 50 50 <refsect1> 51 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 53 <para>The hardware may be able to detect the current DV timings 60 54 automatically, similar to sensing the video standard. To do so, applications 61 55 call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a
+8
Documentation/DocBook/media/v4l/vidioc-streamon.xml
··· 123 123 </para> 124 124 </listitem> 125 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 134 </variablelist> 127 135 </refsect1> 128 136 </refentry>
-6
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml
··· 49 49 <refsect1> 50 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 52 <para>This ioctl lets applications enumerate available frame intervals on a 59 53 given sub-device pad. Frame intervals only makes sense for sub-devices that 60 54 can control the frame period on their own. This includes, for instance,
-6
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml
··· 49 49 <refsect1> 50 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 52 <para>This ioctl allows applications to enumerate all frame sizes 59 53 supported by a sub-device on the given pad for the given media bus format. 60 54 Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
-6
Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml
··· 49 49 <refsect1> 50 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 52 <para>To enumerate media bus formats available at a given sub-device pad 59 53 applications initialize the <structfield>pad</structfield>, <structfield>which</structfield> 60 54 and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
-6
Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
··· 50 50 <refsect1> 51 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 53 <para>These ioctls are used to negotiate the frame format at specific 60 54 subdev pads in the image pipeline.</para> 61 55
-6
Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml
··· 50 50 <refsect1> 51 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 53 <para>These ioctls are used to get and set the frame interval at specific 60 54 subdev pads in the image pipeline. The frame interval only makes sense for 61 55 sub-devices that can control the frame period on their own. This includes,
-6
Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
··· 49 49 <refsect1> 50 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 52 <para>The selections are used to configure various image 59 53 processing functionality performed by the subdevs which affect the 60 54 image size. This currently includes cropping, scaling and
+1 -2
Documentation/Makefile
··· 1 1 subdir-y := accounting auxdisplay blackfin connector \ 2 2 filesystems filesystems ia64 laptops mic misc-devices \ 3 - networking pcmcia prctl ptp timers vDSO video4linux \ 4 - watchdog 3 + networking pcmcia prctl ptp timers vDSO watchdog
+29
Documentation/devicetree/bindings/media/i2c/adv7180.txt
··· 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 +
+10 -2
Documentation/devicetree/bindings/media/rcar_vin.txt
··· 5 5 family of devices. The current blocks are always slaves and suppot one input 6 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 9 - "renesas,vin-r8a7795" for the R8A7795 device 10 10 - "renesas,vin-r8a7794" for the R8A7794 device 11 11 - "renesas,vin-r8a7793" for the R8A7793 device 12 + - "renesas,vin-r8a7792" for the R8A7792 device 12 13 - "renesas,vin-r8a7791" for the R8A7791 device 13 14 - "renesas,vin-r8a7790" for the R8A7790 device 14 15 - "renesas,vin-r8a7779" for the R8A7779 device 15 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 24 - reg: the register base and size for the device registers 17 25 - interrupts: the interrupt for the device 18 26 - clocks: Reference to the parent clock ··· 45 37 }; 46 38 47 39 vin0: vin@0xe6ef0000 { 48 - compatible = "renesas,vin-r8a7790"; 40 + compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin"; 49 41 clocks = <&mstp8_clks R8A7790_CLK_VIN0>; 50 42 reg = <0 0xe6ef0000 0 0x1000>; 51 43 interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>;
+1 -1
Documentation/devicetree/bindings/media/xilinx/video.txt
··· 20 20 - xlnx,video-format: This property represents a video format transmitted on an 21 21 AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream 22 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 25 - xlnx,video-width: This property qualifies the video format with the sample 26 26 width expressed as a number of bits per pixel component. All components must
+2
Documentation/video4linux/CARDLIST.cx23885
··· 52 52 51 -> DVBSky T982 [4254:0982] 53 53 52 -> Hauppauge WinTV-HVR5525 [0070:f038] 54 54 53 -> Hauppauge WinTV Starburst [0070:c12a] 55 + 54 -> ViewCast 260e [1576:0260] 56 + 55 -> ViewCast 460e [1576:0460]
+7 -5
Documentation/video4linux/CARDLIST.em28xx
··· 76 76 75 -> Dikom DK300 (em2882) 77 77 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] 78 78 77 -> EM2874 Leadership ISDBT (em2874) 79 - 78 -> PCTV nanoStick T2 290e (em28174) 79 + 78 -> PCTV nanoStick T2 290e (em28174) [2013:024f] 80 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 82 81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605] 83 83 82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2] 84 84 83 -> Honestech Vidbox NW03 (em2860) [eb1a:5006] ··· 90 90 89 -> Delock 61959 (em2874) [1b80:e1cc] 91 91 90 -> KWorld USB ATSC TV Stick UB435-Q V2 (em2874) [1b80:e346] 92 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 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 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 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]
Documentation/video4linux/Makefile samples/v4l/Makefile
+1 -1
Documentation/video4linux/v4l2-framework.txt
··· 35 35 common code into utility functions shared by all drivers. 36 36 37 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 39 a PCI capture card, and demonstrates how to use the V4L2 driver 40 40 framework. It can be used as a template for real PCI video capture driver. 41 41
+2 -3
Documentation/video4linux/v4l2-pci-skeleton.c samples/v4l/v4l2-pci-skeleton.c
··· 308 308 strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card)); 309 309 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", 310 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 311 return 0; 315 312 } 316 313 ··· 869 872 vdev->release = video_device_release_empty; 870 873 vdev->fops = &skel_fops, 871 874 vdev->ioctl_ops = &skel_ioctl_ops, 875 + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 876 + V4L2_CAP_STREAMING; 872 877 /* 873 878 * The main serialization lock. All ioctls are serialized by this 874 879 * lock. Exception: if q->lock is set, then the streaming ioctls
+3 -3
Documentation/video4linux/vivid.txt
··· 294 294 295 295 These inputs support all combinations of the field setting. Special care has 296 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 298 moving image so the temporal effect of using interlaced formats becomes clearly 299 299 visible. For 50 Hz standards the top field is the oldest and the bottom field 300 300 is the newest in time. For 60 Hz standards that is reversed: the bottom field ··· 313 313 The pixel aspect ratio will depend on the TV standard. The video aspect ratio 314 314 can be selected through the 'Standard Aspect Ratio' Vivid control. 315 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 317 video that will need to be scaled accordingly. 318 318 319 319 The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available ··· 862 862 RDS Stereo: 863 863 RDS Artificial Head: 864 864 RDS Compressed: 865 - RDS Dymanic PTY: 865 + RDS Dynamic PTY: 866 866 RDS Traffic Announcement: 867 867 RDS Traffic Program: 868 868 RDS Music: these are all controls that set the RDS data that is transmitted by
+8
MAINTAINERS
··· 11338 11338 S: Odd Fixes 11339 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 11349 TPM DEVICE DRIVER 11342 11350 M: Peter Huewe <peterhuewe@gmx.de> 11343 11351 M: Marcel Selhorst <tpmdd@selhorst.net>
+1
drivers/media/common/Kconfig
··· 19 19 source "drivers/media/common/b2c2/Kconfig" 20 20 source "drivers/media/common/saa7146/Kconfig" 21 21 source "drivers/media/common/siano/Kconfig" 22 + source "drivers/media/common/v4l2-tpg/Kconfig"
+1 -1
drivers/media/common/Makefile
··· 1 - obj-y += b2c2/ saa7146/ siano/ 1 + obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ 2 2 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o 3 3 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o 4 4 obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
+2
drivers/media/common/v4l2-tpg/Kconfig
··· 1 + config VIDEO_V4L2_TPG 2 + tristate
+3
drivers/media/common/v4l2-tpg/Makefile
··· 1 + v4l2-tpg-objs := v4l2-tpg-core.o v4l2-tpg-colors.o 2 + 3 + obj-$(CONFIG_VIDEO_V4L2_TPG) += v4l2-tpg.o
+14
drivers/media/dvb-core/dvb-usb-ids.h
··· 58 58 #define USB_VID_TELESTAR 0x10b9 59 59 #define USB_VID_VISIONPLUS 0x13d3 60 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 69 #define USB_VID_TWINHAN 0x1822 62 70 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 63 71 #define USB_VID_UNIWILL 0x1584 ··· 149 141 #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 150 142 #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 151 143 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 144 + #define USB_PID_GOTVIEW_SAT_HD 0x5456 152 145 #define USB_PID_INTEL_CE9500 0x9500 153 146 #define USB_PID_ITETECH_IT9135 0x9135 154 147 #define USB_PID_ITETECH_IT9135_9005 0x9005 ··· 168 159 #define USB_PID_KWORLD_UB499_2T_T09 0xe409 169 160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de 170 161 #define USB_PID_KWORLD_VSTREAM_WARM 0x17df 162 + #define USB_PID_PROF_1100 0xb012 163 + #define USB_PID_TERRATEC_CINERGY_S 0x0064 171 164 #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 172 165 #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 173 166 #define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 ··· 372 361 #define USB_PID_YUAN_STK7700D 0x1efc 373 362 #define USB_PID_YUAN_STK7700D_2 0x1e8c 374 363 #define USB_PID_DW2102 0x2102 364 + #define USB_PID_DW2104 0x2104 365 + #define USB_PID_DW3101 0x3101 375 366 #define USB_PID_XTENSIONS_XD_380 0x0381 376 367 #define USB_PID_TELESTAR_STARSTICK_2 0x8000 377 368 #define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 ··· 386 373 #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 387 374 #define USB_PID_ELGATO_EYETV_SAT 0x002a 388 375 #define USB_PID_ELGATO_EYETV_SAT_V2 0x0025 376 + #define USB_PID_ELGATO_EYETV_SAT_V3 0x0036 389 377 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 390 378 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 391 379 #define USB_PID_FRIIO_WHITE 0x0001
+2 -2
drivers/media/dvb-core/dvbdev.c
··· 676 676 demux, 0, MEDIA_LNK_FL_ENABLED, 677 677 false); 678 678 if (ret) 679 - return -ENOMEM; 679 + return ret; 680 680 } 681 681 if (demux && ca) { 682 682 ret = media_create_pad_link(demux, 1, ca, 683 683 0, MEDIA_LNK_FL_ENABLED); 684 684 if (ret) 685 - return -ENOMEM; 685 + return ret; 686 686 } 687 687 688 688 /* Create demux links for each ringbuffer/pad */
+1 -1
drivers/media/dvb-frontends/dib0090.c
··· 1121 1121 (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", 1122 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 1125 (state->current_band == BAND_CBAND && 1126 1126 (state->identity.version & 0x1f) <= P1D_E_F))) { 1127 1127 dprintk("DE-Engage mux for direct gain reg control");
+7 -7
drivers/media/dvb-frontends/ds3000.c
··· 458 458 459 459 break; 460 460 default: 461 - return 1; 461 + return -EINVAL; 462 462 } 463 463 464 464 if (state->config->set_lock_led) ··· 528 528 *ber = 0xffffffff; 529 529 break; 530 530 default: 531 - return 1; 531 + return -EINVAL; 532 532 } 533 533 534 534 return 0; ··· 623 623 snr_reading, *snr); 624 624 break; 625 625 default: 626 - return 1; 626 + return -EINVAL; 627 627 } 628 628 629 629 return 0; ··· 661 661 state->prevUCBS2 = _ucblocks; 662 662 break; 663 663 default: 664 - return 1; 664 + return -EINVAL; 665 665 } 666 666 667 667 return 0; ··· 754 754 data |= 0x80; 755 755 ds3000_writereg(state, 0xa2, data); 756 756 757 - return 1; 757 + return -ETIMEDOUT; 758 758 } 759 759 760 760 data = ds3000_readreg(state, 0xa2); ··· 808 808 data |= 0x80; 809 809 ds3000_writereg(state, 0xa2, data); 810 810 811 - return 1; 811 + return -ETIMEDOUT; 812 812 } 813 813 814 814 data = ds3000_readreg(state, 0xa2); ··· 951 951 ds3000_writereg(state, 0xfe, 0x98); 952 952 break; 953 953 default: 954 - return 1; 954 + return -EINVAL; 955 955 } 956 956 957 957 /* enable 27MHz clock output */
+1 -1
drivers/media/dvb-frontends/m88ds3103_priv.h
··· 46 46 /* auto detect chip id to do different config */ 47 47 u8 chip_id; 48 48 /* main mclk is calculated for M88RS6000 dynamically */ 49 - u32 mclk_khz; 49 + s32 mclk_khz; 50 50 u64 post_bit_error; 51 51 u64 post_bit_count; 52 52 };
+2 -4
drivers/media/dvb-frontends/zl10353.c
··· 135 135 136 136 value = (u64)10 * (1 << 23) / 7 * 125; 137 137 value = (bw * value) + adc_clock / 2; 138 - do_div(value, adc_clock); 139 - *nominal_rate = value; 138 + *nominal_rate = div_u64(value, adc_clock); 140 139 141 140 dprintk("%s: bw %d, adc_clock %d => 0x%x\n", 142 141 __func__, bw, adc_clock, *nominal_rate); ··· 162 163 if (ife > adc_clock / 2) 163 164 ife = adc_clock - ife; 164 165 } 165 - value = (u64)65536 * ife + adc_clock / 2; 166 - do_div(value, adc_clock); 166 + value = div_u64((u64)65536 * ife + adc_clock / 2, adc_clock); 167 167 *input_freq = -value; 168 168 169 169 dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
-8
drivers/media/i2c/ad9389b.c
··· 1130 1130 hdl = &state->hdl; 1131 1131 v4l2_ctrl_handler_init(hdl, 5); 1132 1132 1133 - /* private controls */ 1134 - 1135 1133 state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops, 1136 1134 V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, 1137 1135 0, V4L2_DV_TX_MODE_DVI_D); ··· 1149 1151 1150 1152 goto err_hdl; 1151 1153 } 1152 - state->hdmi_mode_ctrl->is_private = true; 1153 - state->hotplug_ctrl->is_private = true; 1154 - state->rx_sense_ctrl->is_private = true; 1155 - state->have_edid0_ctrl->is_private = true; 1156 - state->rgb_quantization_range_ctrl->is_private = true; 1157 - 1158 1154 state->pad.flags = MEDIA_PAD_FL_SINK; 1159 1155 err = media_entity_pads_init(&sd->entity, 1, &state->pad); 1160 1156 if (err)
+2 -2
drivers/media/i2c/adp1653.c
··· 466 466 of_node_put(child); 467 467 468 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 470 dev_err(&client->dev, "Error getting GPIO\n"); 471 - return -EINVAL; 471 + return PTR_ERR(pd->enable_gpio); 472 472 } 473 473 474 474 return 0;
+121 -39
drivers/media/i2c/adv7180.c
··· 26 26 #include <linux/i2c.h> 27 27 #include <linux/slab.h> 28 28 #include <linux/of.h> 29 - #include <media/v4l2-ioctl.h> 30 29 #include <linux/videodev2.h> 30 + #include <media/v4l2-ioctl.h> 31 + #include <media/v4l2-event.h> 31 32 #include <media/v4l2-device.h> 32 33 #include <media/v4l2-ctrls.h> 33 34 #include <linux/mutex.h> ··· 193 192 struct mutex mutex; /* mutual excl. when accessing chip */ 194 193 int irq; 195 194 v4l2_std_id curr_norm; 196 - bool autodetect; 197 195 bool powered; 196 + bool streaming; 198 197 u8 input; 199 198 200 199 struct i2c_client *client; ··· 339 338 if (err) 340 339 return err; 341 340 342 - /* when we are interrupt driven we know the state */ 343 - if (!state->autodetect || state->irq > 0) 344 - *std = state->curr_norm; 345 - else 346 - err = __adv7180_status(state, NULL, std); 341 + if (state->streaming) { 342 + err = -EBUSY; 343 + goto unlock; 344 + } 347 345 346 + err = adv7180_set_video_standard(state, 347 + ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 348 + if (err) 349 + goto unlock; 350 + 351 + msleep(100); 352 + __adv7180_status(state, NULL, std); 353 + 354 + err = v4l2_std_to_adv7180(state->curr_norm); 355 + if (err < 0) 356 + goto unlock; 357 + 358 + err = adv7180_set_video_standard(state, err); 359 + 360 + unlock: 348 361 mutex_unlock(&state->mutex); 349 362 return err; 350 363 } ··· 402 387 { 403 388 int ret; 404 389 405 - if (state->autodetect) { 406 - ret = adv7180_set_video_standard(state, 407 - ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 408 - if (ret < 0) 409 - return ret; 390 + ret = v4l2_std_to_adv7180(state->curr_norm); 391 + if (ret < 0) 392 + return ret; 410 393 411 - __adv7180_status(state, NULL, &state->curr_norm); 412 - } else { 413 - ret = v4l2_std_to_adv7180(state->curr_norm); 414 - if (ret < 0) 415 - return ret; 416 - 417 - ret = adv7180_set_video_standard(state, ret); 418 - if (ret < 0) 419 - return ret; 420 - } 421 - 394 + ret = adv7180_set_video_standard(state, ret); 395 + if (ret < 0) 396 + return ret; 422 397 return 0; 423 398 } 424 399 ··· 420 415 if (ret) 421 416 return ret; 422 417 423 - /* all standards -> autodetect */ 424 - if (std == V4L2_STD_ALL) { 425 - state->autodetect = true; 426 - } else { 427 - /* Make sure we can support this std */ 428 - ret = v4l2_std_to_adv7180(std); 429 - if (ret < 0) 430 - goto out; 418 + /* Make sure we can support this std */ 419 + ret = v4l2_std_to_adv7180(std); 420 + if (ret < 0) 421 + goto out; 431 422 432 - state->curr_norm = std; 433 - state->autodetect = false; 434 - } 423 + state->curr_norm = std; 435 424 436 425 ret = adv7180_program_std(state); 437 426 out: 438 427 mutex_unlock(&state->mutex); 439 428 return ret; 429 + } 430 + 431 + static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 432 + { 433 + struct adv7180_state *state = to_state(sd); 434 + 435 + *norm = state->curr_norm; 436 + 437 + return 0; 440 438 } 441 439 442 440 static int adv7180_set_power(struct adv7180_state *state, bool on) ··· 725 717 return 0; 726 718 } 727 719 720 + static int adv7180_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cropcap) 721 + { 722 + struct adv7180_state *state = to_state(sd); 723 + 724 + if (state->curr_norm & V4L2_STD_525_60) { 725 + cropcap->pixelaspect.numerator = 11; 726 + cropcap->pixelaspect.denominator = 10; 727 + } else { 728 + cropcap->pixelaspect.numerator = 54; 729 + cropcap->pixelaspect.denominator = 59; 730 + } 731 + 732 + return 0; 733 + } 734 + 735 + static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) 736 + { 737 + *norm = V4L2_STD_ALL; 738 + return 0; 739 + } 740 + 741 + static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) 742 + { 743 + struct adv7180_state *state = to_state(sd); 744 + int ret; 745 + 746 + /* It's always safe to stop streaming, no need to take the lock */ 747 + if (!enable) { 748 + state->streaming = enable; 749 + return 0; 750 + } 751 + 752 + /* Must wait until querystd released the lock */ 753 + ret = mutex_lock_interruptible(&state->mutex); 754 + if (ret) 755 + return ret; 756 + state->streaming = enable; 757 + mutex_unlock(&state->mutex); 758 + return 0; 759 + } 760 + 761 + static int adv7180_subscribe_event(struct v4l2_subdev *sd, 762 + struct v4l2_fh *fh, 763 + struct v4l2_event_subscription *sub) 764 + { 765 + switch (sub->type) { 766 + case V4L2_EVENT_SOURCE_CHANGE: 767 + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 768 + case V4L2_EVENT_CTRL: 769 + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 770 + default: 771 + return -EINVAL; 772 + } 773 + } 774 + 728 775 static const struct v4l2_subdev_video_ops adv7180_video_ops = { 729 776 .s_std = adv7180_s_std, 777 + .g_std = adv7180_g_std, 730 778 .querystd = adv7180_querystd, 731 779 .g_input_status = adv7180_g_input_status, 732 780 .s_routing = adv7180_s_routing, 733 781 .g_mbus_config = adv7180_g_mbus_config, 782 + .cropcap = adv7180_cropcap, 783 + .g_tvnorms = adv7180_g_tvnorms, 784 + .s_stream = adv7180_s_stream, 734 785 }; 735 - 736 786 737 787 static const struct v4l2_subdev_core_ops adv7180_core_ops = { 738 788 .s_power = adv7180_s_power, 789 + .subscribe_event = adv7180_subscribe_event, 790 + .unsubscribe_event = v4l2_event_subdev_unsubscribe, 739 791 }; 740 792 741 793 static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { ··· 820 752 /* clear */ 821 753 adv7180_write(state, ADV7180_REG_ICR3, isr3); 822 754 823 - if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect) 824 - __adv7180_status(state, NULL, &state->curr_norm); 755 + if (isr3 & ADV7180_IRQ3_AD_CHANGE) { 756 + static const struct v4l2_event src_ch = { 757 + .type = V4L2_EVENT_SOURCE_CHANGE, 758 + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 759 + }; 760 + 761 + v4l2_subdev_notify_event(&state->sd, &src_ch); 762 + } 825 763 mutex_unlock(&state->mutex); 826 764 827 765 return IRQ_HANDLED; ··· 1272 1198 1273 1199 state->irq = client->irq; 1274 1200 mutex_init(&state->mutex); 1275 - state->autodetect = true; 1201 + state->curr_norm = V4L2_STD_NTSC; 1276 1202 if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) 1277 1203 state->powered = true; 1278 1204 else ··· 1280 1206 state->input = 0; 1281 1207 sd = &state->sd; 1282 1208 v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 1283 - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; 1209 + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 1284 1210 1285 1211 ret = adv7180_init_controls(state); 1286 1212 if (ret) ··· 1402 1328 #ifdef CONFIG_OF 1403 1329 static const struct of_device_id adv7180_of_id[] = { 1404 1330 { .compatible = "adi,adv7180", }, 1331 + { .compatible = "adi,adv7182", }, 1332 + { .compatible = "adi,adv7280", }, 1333 + { .compatible = "adi,adv7280-m", }, 1334 + { .compatible = "adi,adv7281", }, 1335 + { .compatible = "adi,adv7281-m", }, 1336 + { .compatible = "adi,adv7281-ma", }, 1337 + { .compatible = "adi,adv7282", }, 1338 + { .compatible = "adi,adv7282-m", }, 1405 1339 { }, 1406 1340 }; 1407 1341
-6
drivers/media/i2c/adv7511.c
··· 1502 1502 err = hdl->error; 1503 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 1505 state->pad.flags = MEDIA_PAD_FL_SINK; 1512 1506 err = media_entity_pads_init(&sd->entity, 1, &state->pad); 1513 1507 if (err)
-8
drivers/media/i2c/adv7604.c
··· 3141 3141 if (ctrl) 3142 3142 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; 3143 3143 3144 - /* private controls */ 3145 3144 state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, 3146 3145 V4L2_CID_DV_RX_POWER_PRESENT, 0, 3147 3146 (1 << state->info->num_dv_ports) - 1, 0, 0); ··· 3163 3164 err = hdl->error; 3164 3165 goto err_hdl; 3165 3166 } 3166 - state->detect_tx_5v_ctrl->is_private = true; 3167 - state->rgb_quantization_range_ctrl->is_private = true; 3168 - if (adv76xx_has_afe(state)) 3169 - state->analog_sampling_phase_ctrl->is_private = true; 3170 - state->free_run_color_manual_ctrl->is_private = true; 3171 - state->free_run_color_ctrl->is_private = true; 3172 - 3173 3167 if (adv76xx_s_detect_tx_5v_ctrl(sd)) { 3174 3168 err = -ENODEV; 3175 3169 goto err_hdl;
-6
drivers/media/i2c/adv7842.c
··· 3300 3300 err = hdl->error; 3301 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 3303 if (adv7842_s_detect_tx_5v_ctrl(sd)) { 3310 3304 err = -ENODEV; 3311 3305 goto err_hdl;
+1 -1
drivers/media/i2c/m5mols/m5mols_controls.c
··· 405 405 struct v4l2_subdev *sd = to_sd(ctrl); 406 406 struct m5mols_info *info = to_m5mols(sd); 407 407 int ret = 0; 408 - u8 status; 408 + u8 status = REG_ISO_AUTO; 409 409 410 410 v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n", 411 411 __func__, ctrl->name, info->isp_ready);
+15
drivers/media/i2c/saa7115.c
··· 1798 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 1816 /* Chip was not discovered. Return its ID and don't bind */ 1802 1817 v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n", 1803 1818 16, chip_ver, client->addr << 1);
+12
drivers/media/i2c/smiapp/smiapp-core.c
··· 188 188 embedded_end = 0; 189 189 } 190 190 191 + sensor->image_start = image_start; 192 + 191 193 dev_dbg(&client->dev, "embedded data from lines %d to %d\n", 192 194 embedded_start, embedded_end); 193 195 dev_dbg(&client->dev, "image data starts at line %d\n", image_start); ··· 2282 2280 return 0; 2283 2281 } 2284 2282 2283 + static int smiapp_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) 2284 + { 2285 + struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); 2286 + 2287 + *lines = sensor->image_start; 2288 + 2289 + return 0; 2290 + } 2291 + 2285 2292 /* ----------------------------------------------------------------------------- 2286 2293 * sysfs attributes 2287 2294 */ ··· 2901 2890 2902 2891 static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { 2903 2892 .g_skip_frames = smiapp_get_skip_frames, 2893 + .g_skip_top_lines = smiapp_get_skip_top_lines, 2904 2894 }; 2905 2895 2906 2896 static const struct v4l2_subdev_ops smiapp_ops = {
+1
drivers/media/i2c/smiapp/smiapp.h
··· 217 217 218 218 u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ 219 219 u8 frame_skip; 220 + u16 image_start; /* Offset to first line after metadata lines */ 220 221 221 222 int power_count; 222 223
+4 -1
drivers/media/i2c/tc358743.c
··· 1551 1551 { 1552 1552 struct tc358743_state *state = to_state(sd); 1553 1553 1554 + memset(edid->reserved, 0, sizeof(edid->reserved)); 1555 + 1554 1556 if (edid->pad != 0) 1555 1557 return -EINVAL; 1556 1558 ··· 1586 1584 1587 1585 v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", 1588 1586 __func__, edid->pad, edid->start_block, edid->blocks); 1587 + 1588 + memset(edid->reserved, 0, sizeof(edid->reserved)); 1589 1589 1590 1590 if (edid->pad != 0) 1591 1591 return -EINVAL; ··· 1863 1859 /* control handlers */ 1864 1860 v4l2_ctrl_handler_init(&state->hdl, 3); 1865 1861 1866 - /* private controls */ 1867 1862 state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, 1868 1863 V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); 1869 1864
+1 -1
drivers/media/i2c/ths7303.c
··· 285 285 v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off"); 286 286 287 287 if (state->bt.pixelclock) { 288 - struct v4l2_bt_timings *bt = bt = &state->bt; 288 + struct v4l2_bt_timings *bt = &state->bt; 289 289 u32 frame_width, frame_height; 290 290 291 291 frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
+5 -4
drivers/media/i2c/tvp5150.c
··· 83 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 87 unsigned char value) 88 88 { 89 89 struct i2c_client *c = v4l2_get_subdevdata(sd); ··· 92 92 v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); 93 93 rc = i2c_smbus_write_byte_data(c, addr, value); 94 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 100 static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, ··· 1161 1159 1162 1160 static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1163 1161 { 1164 - tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); 1165 - return 0; 1162 + return tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); 1166 1163 } 1167 1164 #endif 1168 1165
+15 -35
drivers/media/media-device.c
··· 90 90 91 91 id &= ~MEDIA_ENT_ID_FLAG_NEXT; 92 92 93 - spin_lock(&mdev->lock); 94 - 95 93 media_device_for_each_entity(entity, mdev) { 96 94 if (((media_entity_id(entity) == id) && !next) || 97 95 ((media_entity_id(entity) > id) && next)) { 98 - spin_unlock(&mdev->lock); 99 96 return entity; 100 97 } 101 98 } 102 - 103 - spin_unlock(&mdev->lock); 104 99 105 100 return NULL; 106 101 } ··· 426 431 struct media_device *dev = to_media_device(devnode); 427 432 long ret; 428 433 434 + mutex_lock(&dev->graph_mutex); 429 435 switch (cmd) { 430 436 case MEDIA_IOC_DEVICE_INFO: 431 437 ret = media_device_get_info(dev, ··· 439 443 break; 440 444 441 445 case MEDIA_IOC_ENUM_LINKS: 442 - mutex_lock(&dev->graph_mutex); 443 446 ret = media_device_enum_links(dev, 444 447 (struct media_links_enum __user *)arg); 445 - mutex_unlock(&dev->graph_mutex); 446 448 break; 447 449 448 450 case MEDIA_IOC_SETUP_LINK: 449 - mutex_lock(&dev->graph_mutex); 450 451 ret = media_device_setup_link(dev, 451 452 (struct media_link_desc __user *)arg); 452 - mutex_unlock(&dev->graph_mutex); 453 453 break; 454 454 455 455 case MEDIA_IOC_G_TOPOLOGY: 456 - mutex_lock(&dev->graph_mutex); 457 456 ret = media_device_get_topology(dev, 458 457 (struct media_v2_topology __user *)arg); 459 - mutex_unlock(&dev->graph_mutex); 460 458 break; 461 459 462 460 default: 463 461 ret = -ENOIOCTLCMD; 464 462 } 463 + mutex_unlock(&dev->graph_mutex); 465 464 466 465 return ret; 467 466 } ··· 499 508 long ret; 500 509 501 510 switch (cmd) { 502 - case MEDIA_IOC_DEVICE_INFO: 503 - case MEDIA_IOC_ENUM_ENTITIES: 504 - case MEDIA_IOC_SETUP_LINK: 505 - case MEDIA_IOC_G_TOPOLOGY: 506 - return media_device_ioctl(filp, cmd, arg); 507 - 508 511 case MEDIA_IOC_ENUM_LINKS32: 509 512 mutex_lock(&dev->graph_mutex); 510 513 ret = media_device_enum_links32(dev, ··· 507 522 break; 508 523 509 524 default: 510 - ret = -ENOIOCTLCMD; 525 + return media_device_ioctl(filp, cmd, arg); 511 526 } 512 527 513 528 return ret; ··· 575 590 if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL)) 576 591 return -ENOMEM; 577 592 578 - spin_lock(&mdev->lock); 593 + mutex_lock(&mdev->graph_mutex); 579 594 580 595 ret = ida_get_new_above(&mdev->entity_internal_idx, 1, 581 596 &entity->internal_idx); 582 597 if (ret < 0) { 583 - spin_unlock(&mdev->lock); 598 + mutex_unlock(&mdev->graph_mutex); 584 599 return ret; 585 600 } 586 601 ··· 600 615 (notify)->notify(entity, notify->notify_data); 601 616 } 602 617 603 - spin_unlock(&mdev->lock); 604 - 605 - mutex_lock(&mdev->graph_mutex); 606 618 if (mdev->entity_internal_idx_max 607 619 >= mdev->pm_count_walk.ent_enum.idx_max) { 608 620 struct media_entity_graph new = { .top = 0 }; ··· 662 680 if (mdev == NULL) 663 681 return; 664 682 665 - spin_lock(&mdev->lock); 683 + mutex_lock(&mdev->graph_mutex); 666 684 __media_device_unregister_entity(entity); 667 - spin_unlock(&mdev->lock); 685 + mutex_unlock(&mdev->graph_mutex); 668 686 } 669 687 EXPORT_SYMBOL_GPL(media_device_unregister_entity); 670 688 ··· 685 703 INIT_LIST_HEAD(&mdev->pads); 686 704 INIT_LIST_HEAD(&mdev->links); 687 705 INIT_LIST_HEAD(&mdev->entity_notify); 688 - spin_lock_init(&mdev->lock); 689 706 mutex_init(&mdev->graph_mutex); 690 707 ida_init(&mdev->entity_internal_idx); 691 708 ··· 733 752 int __must_check media_device_register_entity_notify(struct media_device *mdev, 734 753 struct media_entity_notify *nptr) 735 754 { 736 - spin_lock(&mdev->lock); 755 + mutex_lock(&mdev->graph_mutex); 737 756 list_add_tail(&nptr->list, &mdev->entity_notify); 738 - spin_unlock(&mdev->lock); 757 + mutex_unlock(&mdev->graph_mutex); 739 758 return 0; 740 759 } 741 760 EXPORT_SYMBOL_GPL(media_device_register_entity_notify); ··· 752 771 void media_device_unregister_entity_notify(struct media_device *mdev, 753 772 struct media_entity_notify *nptr) 754 773 { 755 - spin_lock(&mdev->lock); 774 + mutex_lock(&mdev->graph_mutex); 756 775 __media_device_unregister_entity_notify(mdev, nptr); 757 - spin_unlock(&mdev->lock); 776 + mutex_unlock(&mdev->graph_mutex); 758 777 } 759 778 EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); 760 779 ··· 768 787 if (mdev == NULL) 769 788 return; 770 789 771 - spin_lock(&mdev->lock); 790 + mutex_lock(&mdev->graph_mutex); 772 791 773 792 /* Check if mdev was ever registered at all */ 774 793 if (!media_devnode_is_registered(&mdev->devnode)) { 775 - spin_unlock(&mdev->lock); 794 + mutex_unlock(&mdev->graph_mutex); 776 795 return; 777 796 } 778 797 ··· 792 811 kfree(intf); 793 812 } 794 813 795 - spin_unlock(&mdev->lock); 814 + mutex_unlock(&mdev->graph_mutex); 796 815 797 816 device_remove_file(&mdev->devnode.dev, &dev_attr_model); 817 + dev_dbg(mdev->dev, "Media device unregistering\n"); 798 818 media_devnode_unregister(&mdev->devnode); 799 - 800 - dev_dbg(mdev->dev, "Media device unregistered\n"); 801 819 } 802 820 EXPORT_SYMBOL_GPL(media_device_unregister); 803 821
+5 -1
drivers/media/media-devnode.c
··· 197 197 if (mdev->fops->release) 198 198 mdev->fops->release(filp); 199 199 200 + filp->private_data = NULL; 201 + 200 202 /* decrease the refcount unconditionally since the release() 201 203 return value is ignored. */ 202 204 put_device(&mdev->dev); 203 - filp->private_data = NULL; 204 205 return 0; 205 206 } 206 207 ··· 268 267 return 0; 269 268 270 269 error: 270 + mutex_lock(&media_devnode_lock); 271 271 cdev_del(&mdev->cdev); 272 272 clear_bit(mdev->minor, media_devnode_nums); 273 + mutex_unlock(&media_devnode_lock); 274 + 273 275 return ret; 274 276 } 275 277
+9 -9
drivers/media/media-entity.c
··· 219 219 entity->pads = pads; 220 220 221 221 if (mdev) 222 - spin_lock(&mdev->lock); 222 + mutex_lock(&mdev->graph_mutex); 223 223 224 224 for (i = 0; i < num_pads; i++) { 225 225 pads[i].entity = entity; ··· 230 230 } 231 231 232 232 if (mdev) 233 - spin_unlock(&mdev->lock); 233 + mutex_unlock(&mdev->graph_mutex); 234 234 235 235 return 0; 236 236 } ··· 445 445 bitmap_or(active, active, has_no_links, entity->num_pads); 446 446 447 447 if (!bitmap_full(active, entity->num_pads)) { 448 - ret = -EPIPE; 448 + ret = -ENOLINK; 449 449 dev_dbg(entity->graph_obj.mdev->dev, 450 450 "\"%s\":%u must be connected by an enabled link\n", 451 451 entity->name, ··· 747 747 if (mdev == NULL) 748 748 return; 749 749 750 - spin_lock(&mdev->lock); 750 + mutex_lock(&mdev->graph_mutex); 751 751 __media_entity_remove_links(entity); 752 - spin_unlock(&mdev->lock); 752 + mutex_unlock(&mdev->graph_mutex); 753 753 } 754 754 EXPORT_SYMBOL_GPL(media_entity_remove_links); 755 755 ··· 951 951 if (mdev == NULL) 952 952 return; 953 953 954 - spin_lock(&mdev->lock); 954 + mutex_lock(&mdev->graph_mutex); 955 955 __media_remove_intf_link(link); 956 - spin_unlock(&mdev->lock); 956 + mutex_unlock(&mdev->graph_mutex); 957 957 } 958 958 EXPORT_SYMBOL_GPL(media_remove_intf_link); 959 959 ··· 975 975 if (mdev == NULL) 976 976 return; 977 977 978 - spin_lock(&mdev->lock); 978 + mutex_lock(&mdev->graph_mutex); 979 979 __media_remove_intf_links(intf); 980 - spin_unlock(&mdev->lock); 980 + mutex_unlock(&mdev->graph_mutex); 981 981 } 982 982 EXPORT_SYMBOL_GPL(media_remove_intf_links);
+1
drivers/media/pci/Kconfig
··· 14 14 source "drivers/media/pci/solo6x10/Kconfig" 15 15 source "drivers/media/pci/sta2x11/Kconfig" 16 16 source "drivers/media/pci/tw68/Kconfig" 17 + source "drivers/media/pci/tw686x/Kconfig" 17 18 source "drivers/media/pci/zoran/Kconfig" 18 19 endif 19 20
+1
drivers/media/pci/Makefile
··· 25 25 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ 26 26 obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ 27 27 obj-$(CONFIG_VIDEO_TW68) += tw68/ 28 + obj-$(CONFIG_VIDEO_TW686X) += tw686x/ 28 29 obj-$(CONFIG_VIDEO_DT3155) += dt3155/ 29 30 obj-$(CONFIG_VIDEO_MEYE) += meye/ 30 31 obj-$(CONFIG_STA2X11_VIP) += sta2x11/
+1
drivers/media/pci/cobalt/Kconfig
··· 4 4 depends on PCI_MSI && MTD_COMPLEX_MAPPINGS 5 5 depends on GPIOLIB || COMPILE_TEST 6 6 depends on SND 7 + depends on MTD 7 8 select I2C_ALGOBIT 8 9 select VIDEO_ADV7604 9 10 select VIDEO_ADV7511
+2 -11
drivers/media/pci/cx18/cx18-driver.h
··· 707 707 /* Call the specified callback for all subdevs with a grp_id bit matching the 708 708 * mask in hw (if 0, then match them all). Ignore any errors. */ 709 709 #define cx18_call_hw(cx, hw, o, f, args...) \ 710 - do { \ 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) 710 + v4l2_device_mask_call_all(&(cx)->v4l2_dev, hw, o, f, ##args) 715 711 716 712 #define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) 717 713 ··· 715 719 * mask in hw (if 0, then match them all). If the callback returns an error 716 720 * other than 0 or -ENOIOCTLCMD, then return with that error code. */ 717 721 #define cx18_call_hw_err(cx, hw, o, f, args...) \ 718 - ({ \ 719 - struct v4l2_subdev *__sd; \ 720 - __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \ 721 - __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \ 722 - ##args); \ 723 - }) 722 + v4l2_device_mask_call_until_err(&(cx)->v4l2_dev, hw, o, f, ##args) 724 723 725 724 #define cx18_call_all_err(cx, o, f, args...) \ 726 725 cx18_call_hw_err(cx, 0, o, f , ##args)
+1 -1
drivers/media/pci/cx23885/cx23885-av.c
··· 24 24 { 25 25 struct cx23885_dev *dev = 26 26 container_of(work, struct cx23885_dev, cx25840_work); 27 - bool handled; 27 + bool handled = false; 28 28 29 29 v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine, 30 30 PCI_MSK_AV_CORE, &handled);
+2 -11
drivers/media/pci/ivtv/ivtv-driver.h
··· 827 827 /* Call the specified callback for all subdevs matching hw (if 0, then 828 828 match them all). Ignore any errors. */ 829 829 #define ivtv_call_hw(itv, hw, o, f, args...) \ 830 - do { \ 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) 830 + v4l2_device_mask_call_all(&(itv)->v4l2_dev, hw, o, f, ##args) 836 831 837 832 #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) 838 833 ··· 835 840 match them all). If the callback returns an error other than 0 or 836 841 -ENOIOCTLCMD, then return with that error code. */ 837 842 #define ivtv_call_hw_err(itv, hw, o, f, args...) \ 838 - ({ \ 839 - struct v4l2_subdev *__sd; \ 840 - __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd, \ 841 - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ 842 - }) 843 + v4l2_device_mask_call_until_err(&(itv)->v4l2_dev, hw, o, f, ##args) 843 844 844 845 #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args) 845 846
+1 -1
drivers/media/pci/smipcie/smipcie-ir.c
··· 203 203 rc_dev->dev.parent = &dev->pci_dev->dev; 204 204 205 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 208 ir->rc_dev = rc_dev; 209 209 ir->dev = dev;
+16 -1
drivers/media/pci/smipcie/smipcie-main.c
··· 716 716 /* init MAC.*/ 717 717 ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); 718 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 721 memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); 721 722 return ret; 722 723 } ··· 1067 1066 .ts_1 = SMI_TS_DMA_BOTH, 1068 1067 .fe_0 = DVBSKY_FE_NULL, 1069 1068 .fe_1 = DVBSKY_FE_M88DS3103, 1069 + .rc_map = RC_MAP_DVBSKY, 1070 1070 }; 1071 1071 1072 1072 static struct smi_cfg_info dvbsky_s952_cfg = { ··· 1077 1075 .ts_1 = SMI_TS_DMA_BOTH, 1078 1076 .fe_0 = DVBSKY_FE_M88RS6000, 1079 1077 .fe_1 = DVBSKY_FE_M88RS6000, 1078 + .rc_map = RC_MAP_DVBSKY, 1080 1079 }; 1081 1080 1082 1081 static struct smi_cfg_info dvbsky_t9580_cfg = { ··· 1087 1084 .ts_1 = SMI_TS_DMA_BOTH, 1088 1085 .fe_0 = DVBSKY_FE_SIT2, 1089 1086 .fe_1 = DVBSKY_FE_M88DS3103, 1087 + .rc_map = RC_MAP_DVBSKY, 1088 + }; 1089 + 1090 + static struct smi_cfg_info technotrend_s2_4200_cfg = { 1091 + .type = SMI_TECHNOTREND_S2_4200, 1092 + .name = "TechnoTrend TT-budget S2-4200 Twin", 1093 + .ts_0 = SMI_TS_DMA_BOTH, 1094 + .ts_1 = SMI_TS_DMA_BOTH, 1095 + .fe_0 = DVBSKY_FE_M88RS6000, 1096 + .fe_1 = DVBSKY_FE_M88RS6000, 1097 + .rc_map = RC_MAP_TT_1500, 1090 1098 }; 1091 1099 1092 1100 /* PCI IDs */ ··· 1110 1096 SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), 1111 1097 SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), 1112 1098 SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), 1099 + SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg), 1113 1100 {0} 1114 1101 }; 1115 1102 MODULE_DEVICE_TABLE(pci, smi_id_table);
+2
drivers/media/pci/smipcie/smipcie.h
··· 216 216 #define SMI_DVBSKY_S950 1 217 217 #define SMI_DVBSKY_T9580 2 218 218 #define SMI_DVBSKY_T982 3 219 + #define SMI_TECHNOTREND_S2_4200 4 219 220 int type; 220 221 char *name; 221 222 #define SMI_TS_NULL 0 ··· 233 232 #define DVBSKY_FE_SIT2 3 234 233 int fe_0; 235 234 int fe_1; 235 + char *rc_map; 236 236 }; 237 237 238 238 struct smi_rc {
+9 -17
drivers/media/pci/sta2x11/sta2x11_vip.c
··· 444 444 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) 445 445 { 446 446 struct sta2x11_vip *vip = video_drvdata(file); 447 - v4l2_std_id oldstd = vip->std, newstd; 448 - int status; 449 447 450 - if (V4L2_STD_ALL == std) { 451 - v4l2_subdev_call(vip->decoder, video, s_std, std); 452 - ssleep(2); 453 - v4l2_subdev_call(vip->decoder, video, querystd, &newstd); 454 - v4l2_subdev_call(vip->decoder, video, g_input_status, &status); 455 - if (status & V4L2_IN_ST_NO_SIGNAL) 448 + /* 449 + * This is here for backwards compatibility only. 450 + * The use of V4L2_STD_ALL to trigger a querystd is non-standard. 451 + */ 452 + if (std == V4L2_STD_ALL) { 453 + v4l2_subdev_call(vip->decoder, video, querystd, &std); 454 + if (std == V4L2_STD_UNKNOWN) 456 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 460 if (V4L2_STD_525_60 & std) 469 461 vip->format = formats_60[0]; 470 462 else
+18
drivers/media/pci/tw686x/Kconfig
··· 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.
+3
drivers/media/pci/tw686x/Makefile
··· 1 + tw686x-objs := tw686x-core.o tw686x-video.o tw686x-audio.o 2 + 3 + obj-$(CONFIG_VIDEO_TW686X) += tw686x.o
+386
drivers/media/pci/tw686x/tw686x-audio.c
··· 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 + }
+415
drivers/media/pci/tw686x/tw686x-core.c
··· 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");
+122
drivers/media/pci/tw686x/tw686x-regs.h
··· 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))
+937
drivers/media/pci/tw686x/tw686x-video.c
··· 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 + }
+158
drivers/media/pci/tw686x/tw686x.h
··· 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);
+3 -2
drivers/media/pci/zoran/videocodec.c
··· 116 116 goto out_module_put; 117 117 } 118 118 119 - snprintf(codec->name, sizeof(codec->name), 120 - "%s[%d]", codec->name, h->attached); 119 + res = strlen(codec->name); 120 + snprintf(codec->name + res, sizeof(codec->name) - res, 121 + "[%d]", h->attached); 121 122 codec->master_data = master; 122 123 res = codec->setup(codec); 123 124 if (res == 0) {
+2 -2
drivers/media/platform/Kconfig
··· 238 238 config VIDEO_RENESAS_JPU 239 239 tristate "Renesas JPEG Processing Unit" 240 240 depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA 241 - depends on ARCH_SHMOBILE || COMPILE_TEST 241 + depends on ARCH_RENESAS || COMPILE_TEST 242 242 select VIDEOBUF2_DMA_CONTIG 243 243 select V4L2_MEM2MEM_DEV 244 244 ---help--- ··· 250 250 config VIDEO_RENESAS_VSP1 251 251 tristate "Renesas VSP1 Video Processing Engine" 252 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 254 select VIDEOBUF2_DMA_CONTIG 255 255 ---help--- 256 256 This is a V4L2 driver for the Renesas VSP1 video processing engine.
+2 -2
drivers/media/platform/am437x/am437x-vpfe.c
··· 1047 1047 static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) 1048 1048 { 1049 1049 enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; 1050 - int ret; 1050 + int ret = 0; 1051 1051 1052 1052 vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); 1053 1053 ··· 1706 1706 sdinfo = &cfg->sub_devs[i]; 1707 1707 client = v4l2_get_subdevdata(sdinfo->sd); 1708 1708 if (client->addr == curr_client->addr && 1709 - client->adapter->nr == client->adapter->nr) { 1709 + client->adapter->nr == curr_client->adapter->nr) { 1710 1710 if (vpfe->current_input >= 1) 1711 1711 return -1; 1712 1712 *app_input_index = j + vpfe->current_input;
+9 -26
drivers/media/platform/exynos-gsc/gsc-core.c
··· 967 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 970 static const struct of_device_id exynos_gsc_match[] = { 980 971 { 981 972 .compatible = "samsung,exynos5-gsc", ··· 979 988 static void *gsc_get_drv_data(struct platform_device *pdev) 980 989 { 981 990 struct gsc_driverdata *driver_data = NULL; 991 + const struct of_device_id *match; 982 992 983 - if (pdev->dev.of_node) { 984 - const struct of_device_id *match; 985 - match = of_match_node(exynos_gsc_match, 986 - pdev->dev.of_node); 987 - if (match) 988 - driver_data = (struct gsc_driverdata *)match->data; 989 - } else { 990 - driver_data = (struct gsc_driverdata *) 991 - platform_get_device_id(pdev)->driver_data; 992 - } 993 + match = of_match_node(exynos_gsc_match, pdev->dev.of_node); 994 + if (match) 995 + driver_data = (struct gsc_driverdata *)match->data; 993 996 994 997 return driver_data; 995 998 } ··· 1063 1078 struct resource *res; 1064 1079 struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev); 1065 1080 struct device *dev = &pdev->dev; 1066 - int ret = 0; 1081 + int ret; 1067 1082 1068 1083 gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); 1069 1084 if (!gsc) 1070 1085 return -ENOMEM; 1071 1086 1072 - if (dev->of_node) 1073 - gsc->id = of_alias_get_id(pdev->dev.of_node, "gsc"); 1074 - else 1075 - gsc->id = pdev->id; 1087 + ret = of_alias_get_id(pdev->dev.of_node, "gsc"); 1088 + if (ret < 0) 1089 + return ret; 1076 1090 1091 + gsc->id = ret; 1077 1092 if (gsc->id >= drv_data->num_entities) { 1078 1093 dev_err(dev, "Invalid platform device id: %d\n", gsc->id); 1079 1094 return -EINVAL; ··· 1081 1096 1082 1097 gsc->variant = drv_data->variant[gsc->id]; 1083 1098 gsc->pdev = pdev; 1084 - gsc->pdata = dev->platform_data; 1085 1099 1086 1100 init_waitqueue_head(&gsc->irq_queue); 1087 1101 spin_lock_init(&gsc->slock); ··· 1237 1253 static struct platform_driver gsc_driver = { 1238 1254 .probe = gsc_probe, 1239 1255 .remove = gsc_remove, 1240 - .id_table = gsc_driver_ids, 1241 1256 .driver = { 1242 1257 .name = GSC_MODULE_NAME, 1243 1258 .pm = &gsc_pm_ops,
-1
drivers/media/platform/exynos-gsc/gsc-core.h
··· 340 340 void __iomem *regs; 341 341 wait_queue_head_t irq_queue; 342 342 struct gsc_m2m_device m2m; 343 - struct exynos_platform_gscaler *pdata; 344 343 unsigned long state; 345 344 struct vb2_alloc_ctx *alloc_ctx; 346 345 struct video_device vdev;
-50
drivers/media/platform/exynos4-is/fimc-core.c
··· 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 1157 static const struct fimc_variant fimc0_variant_s5pv210 = { 1178 1158 .has_inp_rot = 1, 1179 1159 .has_out_rot = 1, ··· 1184 1204 .hor_offs_align = 8, 1185 1205 .min_vsize_align = 16, 1186 1206 .pix_limit = &s5p_pix_limit[2], 1187 - }; 1188 - 1189 - /* S5PC100 */ 1190 - static const struct fimc_drvdata fimc_drvdata_s5p = { 1191 - .variant = { 1192 - [0] = &fimc0_variant_s5p, 1193 - [1] = &fimc0_variant_s5p, 1194 - [2] = &fimc2_variant_s5p, 1195 - }, 1196 - .num_entities = 3, 1197 - .lclk_frequency = 133000000UL, 1198 - .out_buf_count = 4, 1199 1207 }; 1200 1208 1201 1209 /* S5PV210, S5PC110 */ ··· 1219 1251 .out_buf_count = 32, 1220 1252 }; 1221 1253 1222 - static const struct platform_device_id fimc_driver_ids[] = { 1223 - { 1224 - .name = "s5p-fimc", 1225 - .driver_data = (unsigned long)&fimc_drvdata_s5p, 1226 - }, { 1227 - .name = "s5pv210-fimc", 1228 - .driver_data = (unsigned long)&fimc_drvdata_s5pv210, 1229 - }, { 1230 - .name = "exynos4-fimc", 1231 - .driver_data = (unsigned long)&fimc_drvdata_exynos4210, 1232 - }, { 1233 - .name = "exynos4x12-fimc", 1234 - .driver_data = (unsigned long)&fimc_drvdata_exynos4x12, 1235 - }, 1236 - { }, 1237 - }; 1238 - 1239 1254 static const struct of_device_id fimc_of_match[] = { 1240 1255 { 1241 1256 .compatible = "samsung,s5pv210-fimc", ··· 1241 1290 static struct platform_driver fimc_driver = { 1242 1291 .probe = fimc_probe, 1243 1292 .remove = fimc_remove, 1244 - .id_table = fimc_driver_ids, 1245 1293 .driver = { 1246 1294 .of_match_table = fimc_of_match, 1247 1295 .name = FIMC_DRIVER_NAME,
+5 -3
drivers/media/platform/exynos4-is/media-dev.c
··· 446 446 else 447 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 451 return -EINVAL; 452 + } 451 453 452 454 fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF; 453 455 fmd->sensor[index].asd.match.of.node = rem; ··· 1132 1130 media_entity_graph_walk_start(graph, entity); 1133 1131 1134 1132 while ((entity = media_entity_graph_walk_next(graph))) { 1135 - if (!is_media_entity_v4l2_io(entity)) 1133 + if (!is_media_entity_v4l2_video_device(entity)) 1136 1134 continue; 1137 1135 1138 1136 ret = __fimc_md_modify_pipeline(entity, enable); ··· 1147 1145 media_entity_graph_walk_start(graph, entity_err); 1148 1146 1149 1147 while ((entity_err = media_entity_graph_walk_next(graph))) { 1150 - if (!is_media_entity_v4l2_io(entity_err)) 1148 + if (!is_media_entity_v4l2_video_device(entity_err)) 1151 1149 continue; 1152 1150 1153 1151 __fimc_md_modify_pipeline(entity_err, !enable);
+4 -2
drivers/media/platform/exynos4-is/mipi-csis.c
··· 757 757 goto err; 758 758 759 759 state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; 760 - if (state->index >= CSIS_MAX_ENTITIES) 761 - return -ENXIO; 760 + if (state->index >= CSIS_MAX_ENTITIES) { 761 + ret = -ENXIO; 762 + goto err; 763 + } 762 764 763 765 /* Get MIPI CSI-2 bus configration from the endpoint node. */ 764 766 of_property_read_u32(node, "samsung,csis-hs-settle",
+1 -1
drivers/media/platform/omap3isp/ispvideo.c
··· 251 251 if (entity == &video->video.entity) 252 252 continue; 253 253 254 - if (!is_media_entity_v4l2_io(entity)) 254 + if (!is_media_entity_v4l2_video_device(entity)) 255 255 continue; 256 256 257 257 __video = to_isp_video(media_entity_to_video_device(entity));
+5 -22
drivers/media/platform/s5p-g2d/g2d.c
··· 719 719 720 720 def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; 721 721 722 - if (!pdev->dev.of_node) { 723 - dev->variant = g2d_get_drv_data(pdev); 724 - } else { 725 - of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); 726 - if (!of_id) { 727 - ret = -ENODEV; 728 - goto unreg_video_dev; 729 - } 730 - dev->variant = (struct g2d_variant *)of_id->data; 722 + of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); 723 + if (!of_id) { 724 + ret = -ENODEV; 725 + goto unreg_video_dev; 731 726 } 727 + dev->variant = (struct g2d_variant *)of_id->data; 732 728 733 729 return 0; 734 730 ··· 784 788 }; 785 789 MODULE_DEVICE_TABLE(of, exynos_g2d_match); 786 790 787 - static const struct platform_device_id g2d_driver_ids[] = { 788 - { 789 - .name = "s5p-g2d", 790 - .driver_data = (unsigned long)&g2d_drvdata_v3x, 791 - }, { 792 - .name = "s5p-g2d-v4x", 793 - .driver_data = (unsigned long)&g2d_drvdata_v4x, 794 - }, 795 - {}, 796 - }; 797 - MODULE_DEVICE_TABLE(platform, g2d_driver_ids); 798 - 799 791 static struct platform_driver g2d_pdrv = { 800 792 .probe = g2d_probe, 801 793 .remove = g2d_remove, 802 - .id_table = g2d_driver_ids, 803 794 .driver = { 804 795 .name = G2D_NAME, 805 796 .of_match_table = exynos_g2d_match,
-5
drivers/media/platform/s5p-g2d/g2d.h
··· 89 89 void g2d_set_v41_stretch(struct g2d_dev *d, 90 90 struct g2d_frame *src, struct g2d_frame *dst); 91 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 - }
+6 -1
drivers/media/platform/s5p-jpeg/jpeg-core.c
··· 1548 1548 struct v4l2_pix_format *pix = &f->fmt.pix; 1549 1549 u32 pix_fmt = f->fmt.pix.pixelformat; 1550 1550 int w = pix->width, h = pix->height, wh_align; 1551 + int padding = 0; 1551 1552 1552 1553 if (pix_fmt == V4L2_PIX_FMT_RGB32 || 1554 + pix_fmt == V4L2_PIX_FMT_RGB565 || 1553 1555 pix_fmt == V4L2_PIX_FMT_NV24 || 1554 1556 pix_fmt == V4L2_PIX_FMT_NV42 || 1555 1557 pix_fmt == V4L2_PIX_FMT_NV12 || ··· 1566 1564 &h, S5P_JPEG_MIN_HEIGHT, 1567 1565 S5P_JPEG_MAX_HEIGHT, wh_align); 1568 1566 1569 - return w * h * fmt_depth >> 3; 1567 + if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) 1568 + padding = PAGE_SIZE; 1569 + 1570 + return (w * h * fmt_depth >> 3) + padding; 1570 1571 } 1571 1572 1572 1573 static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
+5 -32
drivers/media/platform/s5p-mfc/s5p_mfc.c
··· 1489 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 1492 static const struct of_device_id exynos_mfc_match[] = { 1514 1493 { 1515 1494 .compatible = "samsung,mfc-v5", ··· 1510 1531 static void *mfc_get_drv_data(struct platform_device *pdev) 1511 1532 { 1512 1533 struct s5p_mfc_variant *driver_data = NULL; 1534 + const struct of_device_id *match; 1513 1535 1514 - if (pdev->dev.of_node) { 1515 - const struct of_device_id *match; 1516 - match = of_match_node(exynos_mfc_match, 1517 - pdev->dev.of_node); 1518 - if (match) 1519 - driver_data = (struct s5p_mfc_variant *)match->data; 1520 - } else { 1521 - driver_data = (struct s5p_mfc_variant *) 1522 - platform_get_device_id(pdev)->driver_data; 1523 - } 1536 + match = of_match_node(exynos_mfc_match, pdev->dev.of_node); 1537 + if (match) 1538 + driver_data = (struct s5p_mfc_variant *)match->data; 1539 + 1524 1540 return driver_data; 1525 1541 } 1526 1542 1527 1543 static struct platform_driver s5p_mfc_driver = { 1528 1544 .probe = s5p_mfc_probe, 1529 1545 .remove = s5p_mfc_remove, 1530 - .id_table = mfc_driver_ids, 1531 1546 .driver = { 1532 1547 .name = S5P_MFC_NAME, 1533 1548 .pm = &s5p_mfc_pm_ops,
+1 -1
drivers/media/platform/s5p-tv/mixer.h
··· 300 300 struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx); 301 301 struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx); 302 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 305 void mxr_base_layer_release(struct mxr_layer *layer); 306 306 void mxr_layer_release(struct mxr_layer *layer);
+1 -1
drivers/media/platform/s5p-tv/mixer_grp_layer.c
··· 235 235 { 236 236 struct mxr_layer *layer; 237 237 int ret; 238 - struct mxr_layer_ops ops = { 238 + const struct mxr_layer_ops ops = { 239 239 .release = mxr_graph_layer_release, 240 240 .buffer_set = mxr_graph_buffer_set, 241 241 .stream_set = mxr_graph_stream_set,
+1 -1
drivers/media/platform/s5p-tv/mixer_video.c
··· 1070 1070 } 1071 1071 1072 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 1075 struct mxr_layer *layer; 1076 1076
+1 -1
drivers/media/platform/s5p-tv/mixer_vp_layer.c
··· 207 207 { 208 208 struct mxr_layer *layer; 209 209 int ret; 210 - struct mxr_layer_ops ops = { 210 + const struct mxr_layer_ops ops = { 211 211 .release = mxr_vp_layer_release, 212 212 .buffer_set = mxr_vp_buffer_set, 213 213 .stream_set = mxr_vp_stream_set,
+2 -2
drivers/media/platform/soc_camera/Kconfig
··· 28 28 config VIDEO_RCAR_VIN 29 29 tristate "R-Car Video Input (VIN) support" 30 30 depends on VIDEO_DEV && SOC_CAMERA 31 - depends on ARCH_SHMOBILE || COMPILE_TEST 31 + depends on ARCH_RENESAS || COMPILE_TEST 32 32 depends on HAS_DMA 33 33 select VIDEOBUF2_DMA_CONTIG 34 34 select SOC_CAMERA_SCALE_CROP ··· 45 45 config VIDEO_SH_MOBILE_CEU 46 46 tristate "SuperH Mobile CEU Interface driver" 47 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 49 depends on HAS_DMA 50 50 select VIDEOBUF2_DMA_CONTIG 51 51 select SOC_CAMERA_SCALE_CROP
+2
drivers/media/platform/soc_camera/rcar_vin.c
··· 1845 1845 { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, 1846 1846 { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, 1847 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 1852 MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
+24 -45
drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
··· 49 49 #define PID_TABLE_SIZE 1024 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 54 #define TS_PKT_SIZE 188 55 55 #define HEADER_SIZE (4) ··· 130 130 writel(channel->back_buffer_busaddr, channel->irec + 131 131 DMA_PRDS_BUSRP_TP(0)); 132 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 136 static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) ··· 141 141 struct channel_info *channel; 142 142 u32 tmp; 143 143 unsigned long *bitmap; 144 + int ret; 144 145 145 146 switch (dvbdmxfeed->type) { 146 147 case DMX_TYPE_TS: ··· 170 169 } 171 170 172 171 if (!atomic_read(&fei->fw_loaded)) { 173 - dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__); 174 - return -EINVAL; 172 + ret = load_c8sectpfe_fw(fei); 173 + if (ret) 174 + return ret; 175 175 } 176 176 177 177 mutex_lock(&fei->lock); ··· 267 265 unsigned long *bitmap; 268 266 269 267 if (!atomic_read(&fei->fw_loaded)) { 270 - dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__); 271 - return -EINVAL; 268 + ret = load_c8sectpfe_fw(fei); 269 + if (ret) 270 + return ret; 272 271 } 273 272 274 273 mutex_lock(&fei->lock); ··· 588 585 writel(tsin->pid_buffer_busaddr, 589 586 fei->io + PIDF_BASE(tsin->tsin_id)); 590 587 591 - dev_info(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n", 588 + dev_dbg(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n", 592 589 tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)), 593 590 &tsin->pid_buffer_busaddr); 594 591 ··· 883 880 goto err_clk_disable; 884 881 } 885 882 886 - /* ensure all other init has been done before requesting firmware */ 887 - ret = load_c8sectpfe_fw_step1(fei); 888 - if (ret) { 889 - dev_err(dev, "Couldn't load slim core firmware\n"); 890 - goto err_clk_disable; 891 - } 892 - 893 883 c8sectpfe_debugfs_init(fei); 894 884 895 885 return 0; ··· 1087 1091 phdr->p_memsz - phdr->p_filesz); 1088 1092 } 1089 1093 1090 - static int load_slim_core_fw(const struct firmware *fw, void *context) 1094 + static int load_slim_core_fw(const struct firmware *fw, struct c8sectpfei *fei) 1091 1095 { 1092 - struct c8sectpfei *fei = context; 1093 1096 Elf32_Ehdr *ehdr; 1094 1097 Elf32_Phdr *phdr; 1095 1098 u8 __iomem *dst; 1096 1099 int err = 0, i; 1097 1100 1098 - if (!fw || !context) 1101 + if (!fw || !fei) 1099 1102 return -EINVAL; 1100 1103 1101 1104 ehdr = (Elf32_Ehdr *)fw->data; ··· 1146 1151 return err; 1147 1152 } 1148 1153 1149 - static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context) 1154 + static int load_c8sectpfe_fw(struct c8sectpfei *fei) 1150 1155 { 1151 - struct c8sectpfei *fei = context; 1156 + const struct firmware *fw; 1152 1157 int err; 1158 + 1159 + dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA); 1160 + 1161 + err = request_firmware(&fw, FIRMWARE_MEMDMA, fei->dev); 1162 + if (err) 1163 + return err; 1153 1164 1154 1165 err = c8sectpfe_elf_sanity_check(fei, fw); 1155 1166 if (err) { 1156 1167 dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n" 1157 1168 , err); 1158 - goto err; 1169 + return err; 1159 1170 } 1160 1171 1161 - err = load_slim_core_fw(fw, context); 1172 + err = load_slim_core_fw(fw, fei); 1162 1173 if (err) { 1163 1174 dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err); 1164 - goto err; 1175 + return err; 1165 1176 } 1166 1177 1167 1178 /* now the firmware is loaded configure the input blocks */ 1168 1179 err = configure_channels(fei); 1169 1180 if (err) { 1170 1181 dev_err(fei->dev, "configure_channels failed err=(%d)\n", err); 1171 - goto err; 1182 + return err; 1172 1183 } 1173 1184 1174 1185 /* ··· 1187 1186 writel(0x1, fei->io + DMA_CPU_RUN); 1188 1187 1189 1188 atomic_set(&fei->fw_loaded, 1); 1190 - err: 1191 - complete_all(&fei->fw_ack); 1192 - } 1193 - 1194 - static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei) 1195 - { 1196 - int err; 1197 - 1198 - dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA); 1199 - 1200 - init_completion(&fei->fw_ack); 1201 - atomic_set(&fei->fw_loaded, 0); 1202 - 1203 - err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, 1204 - FIRMWARE_MEMDMA, fei->dev, GFP_KERNEL, fei, 1205 - load_c8sectpfe_fw_cb); 1206 - 1207 - if (err) { 1208 - dev_err(fei->dev, "request_firmware_nowait err: %d.\n", err); 1209 - complete_all(&fei->fw_ack); 1210 - return err; 1211 - } 1212 1189 1213 1190 return 0; 1214 1191 }
+1
drivers/media/platform/vivid/Kconfig
··· 7 7 select FB_CFB_COPYAREA 8 8 select FB_CFB_IMAGEBLIT 9 9 select VIDEOBUF2_VMALLOC 10 + select VIDEO_V4L2_TPG 10 11 default n 11 12 ---help--- 12 13 Enables a virtual video driver. This driver emulates a webcam,
+1 -1
drivers/media/platform/vivid/Makefile
··· 2 2 vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ 3 3 vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ 4 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 6 obj-$(CONFIG_VIDEO_VIVID) += vivid.o
+7 -15
drivers/media/platform/vivid/vivid-core.c
··· 200 200 struct v4l2_capability *cap) 201 201 { 202 202 struct vivid_dev *dev = video_drvdata(file); 203 - struct video_device *vdev = video_devdata(file); 204 203 205 204 strcpy(cap->driver, "vivid"); 206 205 strcpy(cap->card, "vivid"); 207 206 snprintf(cap->bus_info, sizeof(cap->bus_info), 208 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 209 cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | 225 210 dev->vbi_cap_caps | dev->vbi_out_caps | 226 211 dev->radio_rx_caps | dev->radio_tx_caps | ··· 1120 1135 strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name)); 1121 1136 vfd->fops = &vivid_fops; 1122 1137 vfd->ioctl_ops = &vivid_ioctl_ops; 1138 + vfd->device_caps = dev->vid_cap_caps; 1123 1139 vfd->release = video_device_release_empty; 1124 1140 vfd->v4l2_dev = &dev->v4l2_dev; 1125 1141 vfd->queue = &dev->vb_vid_cap_q; ··· 1146 1160 vfd->vfl_dir = VFL_DIR_TX; 1147 1161 vfd->fops = &vivid_fops; 1148 1162 vfd->ioctl_ops = &vivid_ioctl_ops; 1163 + vfd->device_caps = dev->vid_out_caps; 1149 1164 vfd->release = video_device_release_empty; 1150 1165 vfd->v4l2_dev = &dev->v4l2_dev; 1151 1166 vfd->queue = &dev->vb_vid_out_q; ··· 1171 1184 strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name)); 1172 1185 vfd->fops = &vivid_fops; 1173 1186 vfd->ioctl_ops = &vivid_ioctl_ops; 1187 + vfd->device_caps = dev->vbi_cap_caps; 1174 1188 vfd->release = video_device_release_empty; 1175 1189 vfd->v4l2_dev = &dev->v4l2_dev; 1176 1190 vfd->queue = &dev->vb_vbi_cap_q; ··· 1195 1207 vfd->vfl_dir = VFL_DIR_TX; 1196 1208 vfd->fops = &vivid_fops; 1197 1209 vfd->ioctl_ops = &vivid_ioctl_ops; 1210 + vfd->device_caps = dev->vbi_out_caps; 1198 1211 vfd->release = video_device_release_empty; 1199 1212 vfd->v4l2_dev = &dev->v4l2_dev; 1200 1213 vfd->queue = &dev->vb_vbi_out_q; ··· 1218 1229 strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name)); 1219 1230 vfd->fops = &vivid_fops; 1220 1231 vfd->ioctl_ops = &vivid_ioctl_ops; 1232 + vfd->device_caps = dev->sdr_cap_caps; 1221 1233 vfd->release = video_device_release_empty; 1222 1234 vfd->v4l2_dev = &dev->v4l2_dev; 1223 1235 vfd->queue = &dev->vb_sdr_cap_q; ··· 1237 1247 strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name)); 1238 1248 vfd->fops = &vivid_radio_fops; 1239 1249 vfd->ioctl_ops = &vivid_ioctl_ops; 1250 + vfd->device_caps = dev->radio_rx_caps; 1240 1251 vfd->release = video_device_release_empty; 1241 1252 vfd->v4l2_dev = &dev->v4l2_dev; 1242 1253 vfd->lock = &dev->mutex; ··· 1256 1265 vfd->vfl_dir = VFL_DIR_TX; 1257 1266 vfd->fops = &vivid_radio_fops; 1258 1267 vfd->ioctl_ops = &vivid_ioctl_ops; 1268 + vfd->device_caps = dev->radio_tx_caps; 1259 1269 vfd->release = video_device_release_empty; 1260 1270 vfd->v4l2_dev = &dev->v4l2_dev; 1261 1271 vfd->lock = &dev->mutex;
+1 -1
drivers/media/platform/vivid/vivid-core.h
··· 25 25 #include <media/v4l2-device.h> 26 26 #include <media/v4l2-dev.h> 27 27 #include <media/v4l2-ctrls.h> 28 - #include "vivid-tpg.h" 28 + #include <media/v4l2-tpg.h> 29 29 #include "vivid-rds-gen.h" 30 30 #include "vivid-vbi-gen.h" 31 31
+7 -6
drivers/media/platform/vivid/vivid-kthread-cap.c
··· 36 36 #include <media/v4l2-ioctl.h> 37 37 #include <media/v4l2-fh.h> 38 38 #include <media/v4l2-event.h> 39 + #include <media/v4l2-rect.h> 39 40 40 41 #include "vivid-core.h" 41 42 #include "vivid-vid-common.h" ··· 185 184 dev->compose_out.width, dev->compose_out.height 186 185 }; 187 186 188 - dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out); 187 + v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out); 189 188 190 189 dev->loop_vid_out = dev->loop_vid_copy; 191 - rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); 190 + v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); 192 191 dev->loop_vid_out.left += dev->crop_out.left; 193 192 dev->loop_vid_out.top += dev->crop_out.top; 194 193 195 194 dev->loop_vid_cap = dev->loop_vid_copy; 196 - rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); 195 + v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); 197 196 198 197 dprintk(dev, 1, 199 198 "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", ··· 204 203 dev->loop_vid_cap.width, dev->loop_vid_cap.height, 205 204 dev->loop_vid_cap.left, dev->loop_vid_cap.top); 206 205 207 - r_overlay = rect_intersect(&r_fb, &r_overlay); 206 + v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay); 208 207 209 208 /* shift r_overlay to the same origin as compose_out */ 210 209 r_overlay.left += dev->compose_out.left - dev->overlay_out_left; 211 210 r_overlay.top += dev->compose_out.top - dev->overlay_out_top; 212 211 213 - dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy); 212 + v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy); 214 213 dev->loop_fb_copy = dev->loop_vid_overlay; 215 214 216 215 /* shift dev->loop_fb_copy back again to the fb origin */ ··· 218 217 dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; 219 218 220 219 dev->loop_vid_overlay_cap = dev->loop_vid_overlay; 221 - rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); 220 + v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); 222 221 223 222 dprintk(dev, 1, 224 223 "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n",
+11 -8
drivers/media/platform/vivid/vivid-rds-gen.c
··· 55 55 { 56 56 struct v4l2_rds_data *data = rds->data; 57 57 unsigned grp; 58 + unsigned idx; 58 59 struct tm tm; 59 60 unsigned date; 60 61 unsigned time; ··· 74 73 case 0 ... 3: 75 74 case 22 ... 25: 76 75 case 44 ... 47: /* Group 0B */ 76 + idx = (grp % 22) % 4; 77 77 data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); 78 - data[1].lsb |= vivid_get_di(rds, grp % 22); 78 + data[1].lsb |= vivid_get_di(rds, idx); 79 79 data[1].msb |= 1 << 3; 80 80 data[2].lsb = rds->picode & 0xff; 81 81 data[2].msb = rds->picode >> 8; 82 82 data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); 83 - data[3].lsb = rds->psname[2 * (grp % 22) + 1]; 84 - data[3].msb = rds->psname[2 * (grp % 22)]; 83 + data[3].lsb = rds->psname[2 * idx + 1]; 84 + data[3].msb = rds->psname[2 * idx]; 85 85 break; 86 86 case 4 ... 19: 87 87 case 26 ... 41: /* Group 2A */ 88 - data[1].lsb |= (grp - 4) % 22; 88 + idx = ((grp - 4) % 22) % 16; 89 + data[1].lsb |= idx; 89 90 data[1].msb |= 4 << 3; 90 - data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)]; 91 - data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1]; 91 + data[2].msb = rds->radiotext[4 * idx]; 92 + data[2].lsb = rds->radiotext[4 * idx + 1]; 92 93 data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); 93 - data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2]; 94 - data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3]; 94 + data[3].msb = rds->radiotext[4 * idx + 2]; 95 + data[3].lsb = rds->radiotext[4 * idx + 3]; 95 96 break; 96 97 case 56: 97 98 /*
+3 -4
drivers/media/platform/vivid/vivid-tpg-colors.c drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
··· 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 4 * The test pattern generator uses the tpg_colors for its test patterns. 5 5 * For testing colorspaces the first 8 colors of that table need to be ··· 12 12 * This source also contains the code used to generate the tpg_csc_colors 13 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 17 * and run the utility. 18 18 * ··· 36 36 */ 37 37 38 38 #include <linux/videodev2.h> 39 - 40 - #include "vivid-tpg-colors.h" 39 + #include <media/v4l2-tpg-colors.h> 41 40 42 41 /* sRGB colors with range [0-255] */ 43 42 const struct color tpg_colors[TPG_COLOR_MAX] = {
+3 -3
drivers/media/platform/vivid/vivid-tpg-colors.h include/media/v4l2-tpg-colors.h
··· 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 4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 5 5 * ··· 17 17 * SOFTWARE. 18 18 */ 19 19 20 - #ifndef _VIVID_COLORS_H_ 21 - #define _VIVID_COLORS_H_ 20 + #ifndef _V4L2_TPG_COLORS_H_ 21 + #define _V4L2_TPG_COLORS_H_ 22 22 23 23 struct color { 24 24 unsigned char r, g, b;
+23 -2
drivers/media/platform/vivid/vivid-tpg.c drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
··· 1 1 /* 2 - * vivid-tpg.c - Test Pattern Generator 2 + * v4l2-tpg-core.c - Test Pattern Generator 3 3 * 4 4 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the 5 5 * vivi.c source for the copyright information of those functions. ··· 20 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 26 /* Must remain in sync with enum tpg_pattern */ 26 27 const char * const tpg_pattern_strings[] = { ··· 49 48 "Noise", 50 49 NULL 51 50 }; 51 + EXPORT_SYMBOL_GPL(tpg_pattern_strings); 52 52 53 53 /* Must remain in sync with enum tpg_aspect */ 54 54 const char * const tpg_aspect_strings[] = { ··· 60 58 "16x9 Anamorphic", 61 59 NULL 62 60 }; 61 + EXPORT_SYMBOL_GPL(tpg_aspect_strings); 63 62 64 63 /* 65 64 * Sine table: sin[0] = 127 * sin(-180 degrees) ··· 96 93 { 97 94 font8x16 = f; 98 95 } 96 + EXPORT_SYMBOL_GPL(tpg_set_font); 99 97 100 98 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h) 101 99 { ··· 118 114 tpg->colorspace = V4L2_COLORSPACE_SRGB; 119 115 tpg->perc_fill = 100; 120 116 } 117 + EXPORT_SYMBOL_GPL(tpg_init); 121 118 122 119 int tpg_alloc(struct tpg_data *tpg, unsigned max_w) 123 120 { ··· 155 150 } 156 151 return 0; 157 152 } 153 + EXPORT_SYMBOL_GPL(tpg_alloc); 158 154 159 155 void tpg_free(struct tpg_data *tpg) 160 156 { ··· 180 174 tpg->random_line[plane] = NULL; 181 175 } 182 176 } 177 + EXPORT_SYMBOL_GPL(tpg_free); 183 178 184 179 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) 185 180 { ··· 410 403 } 411 404 return true; 412 405 } 406 + EXPORT_SYMBOL_GPL(tpg_s_fourcc); 413 407 414 408 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, 415 409 const struct v4l2_rect *compose) ··· 426 418 tpg->scaled_width = 2; 427 419 tpg->recalc_lines = true; 428 420 } 421 + EXPORT_SYMBOL_GPL(tpg_s_crop_compose); 429 422 430 423 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, 431 424 u32 field) ··· 451 442 (2 * tpg->hdownsampling[p]); 452 443 tpg->recalc_square_border = true; 453 444 } 445 + EXPORT_SYMBOL_GPL(tpg_reset_source); 454 446 455 447 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg) 456 448 { ··· 1260 1250 return 0; 1261 1251 } 1262 1252 } 1253 + EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane); 1263 1254 1264 1255 /* Return how many pattern lines are used by the current pattern. */ 1265 1256 static unsigned tpg_get_pat_lines(const struct tpg_data *tpg) ··· 1736 1725 } 1737 1726 } 1738 1727 } 1728 + EXPORT_SYMBOL_GPL(tpg_gen_text); 1739 1729 1740 1730 void tpg_update_mv_step(struct tpg_data *tpg) 1741 1731 { ··· 1785 1773 if (factor < 0) 1786 1774 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step; 1787 1775 } 1776 + EXPORT_SYMBOL_GPL(tpg_update_mv_step); 1788 1777 1789 1778 /* Map the line number relative to the crop rectangle to a frame line number */ 1790 1779 static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y, ··· 1875 1862 if (p == 0 && tpg->interleaved) 1876 1863 tpg_calc_text_basep(tpg, basep, 1, vbuf); 1877 1864 } 1865 + EXPORT_SYMBOL_GPL(tpg_calc_text_basep); 1878 1866 1879 1867 static int tpg_pattern_avg(const struct tpg_data *tpg, 1880 1868 unsigned pat1, unsigned pat2) ··· 1905 1891 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization); 1906 1892 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); 1907 1893 } 1894 + EXPORT_SYMBOL_GPL(tpg_log_status); 1908 1895 1909 1896 /* 1910 1897 * This struct contains common parameters used by both the drawing of the ··· 2311 2296 vbuf + buf_line * params.stride); 2312 2297 } 2313 2298 } 2299 + EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer); 2314 2300 2315 2301 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) 2316 2302 { ··· 2328 2312 offset += tpg_calc_plane_size(tpg, i); 2329 2313 } 2330 2314 } 2315 + EXPORT_SYMBOL_GPL(tpg_fillbuffer); 2316 + 2317 + MODULE_DESCRIPTION("V4L2 Test Pattern Generator"); 2318 + MODULE_AUTHOR("Hans Verkuil"); 2319 + MODULE_LICENSE("GPL");
+4 -5
drivers/media/platform/vivid/vivid-tpg.h include/media/v4l2-tpg.h
··· 1 1 /* 2 - * vivid-tpg.h - Test Pattern Generator 2 + * v4l2-tpg.h - Test Pattern Generator 3 3 * 4 4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 5 5 * ··· 17 17 * SOFTWARE. 18 18 */ 19 19 20 - #ifndef _VIVID_TPG_H_ 21 - #define _VIVID_TPG_H_ 20 + #ifndef _V4L2_TPG_H_ 21 + #define _V4L2_TPG_H_ 22 22 23 23 #include <linux/types.h> 24 24 #include <linux/errno.h> ··· 26 26 #include <linux/slab.h> 27 27 #include <linux/vmalloc.h> 28 28 #include <linux/videodev2.h> 29 - 30 - #include "vivid-tpg-colors.h" 29 + #include <media/v4l2-tpg-colors.h> 31 30 32 31 enum tpg_pattern { 33 32 TPG_PAT_75_COLORBAR,
+51 -50
drivers/media/platform/vivid/vivid-vid-cap.c
··· 26 26 #include <media/v4l2-common.h> 27 27 #include <media/v4l2-event.h> 28 28 #include <media/v4l2-dv-timings.h> 29 + #include <media/v4l2-rect.h> 29 30 30 31 #include "vivid-core.h" 31 32 #include "vivid-vid-common.h" ··· 591 590 } else { 592 591 struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; 593 592 594 - rect_set_min_size(&r, &vivid_min_rect); 595 - rect_set_max_size(&r, &vivid_max_rect); 593 + v4l2_rect_set_min_size(&r, &vivid_min_rect); 594 + v4l2_rect_set_max_size(&r, &vivid_max_rect); 596 595 if (dev->has_scaler_cap && !dev->has_compose_cap) { 597 596 struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; 598 597 599 - rect_set_max_size(&r, &max_r); 598 + v4l2_rect_set_max_size(&r, &max_r); 600 599 } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { 601 - rect_set_max_size(&r, &dev->src_rect); 600 + v4l2_rect_set_max_size(&r, &dev->src_rect); 602 601 } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { 603 - rect_set_min_size(&r, &dev->src_rect); 602 + v4l2_rect_set_min_size(&r, &dev->src_rect); 604 603 } 605 604 mp->width = r.width; 606 605 mp->height = r.height / factor; ··· 669 668 670 669 if (dev->has_scaler_cap) { 671 670 if (dev->has_compose_cap) 672 - rect_map_inside(compose, &r); 671 + v4l2_rect_map_inside(compose, &r); 673 672 else 674 673 *compose = r; 675 674 if (dev->has_crop_cap && !dev->has_compose_cap) { ··· 684 683 factor * r.height * MAX_ZOOM 685 684 }; 686 685 687 - rect_set_min_size(crop, &min_r); 688 - rect_set_max_size(crop, &max_r); 689 - rect_map_inside(crop, &dev->crop_bounds_cap); 686 + v4l2_rect_set_min_size(crop, &min_r); 687 + v4l2_rect_set_max_size(crop, &max_r); 688 + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); 690 689 } else if (dev->has_crop_cap) { 691 690 struct v4l2_rect min_r = { 692 691 0, 0, ··· 699 698 factor * compose->height * MAX_ZOOM 700 699 }; 701 700 702 - rect_set_min_size(crop, &min_r); 703 - rect_set_max_size(crop, &max_r); 704 - rect_map_inside(crop, &dev->crop_bounds_cap); 701 + v4l2_rect_set_min_size(crop, &min_r); 702 + v4l2_rect_set_max_size(crop, &max_r); 703 + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); 705 704 } 706 705 } else if (dev->has_crop_cap && !dev->has_compose_cap) { 707 706 r.height *= factor; 708 - rect_set_size_to(crop, &r); 709 - rect_map_inside(crop, &dev->crop_bounds_cap); 707 + v4l2_rect_set_size_to(crop, &r); 708 + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); 710 709 r = *crop; 711 710 r.height /= factor; 712 - rect_set_size_to(compose, &r); 711 + v4l2_rect_set_size_to(compose, &r); 713 712 } else if (!dev->has_crop_cap) { 714 - rect_map_inside(compose, &r); 713 + v4l2_rect_map_inside(compose, &r); 715 714 } else { 716 715 r.height *= factor; 717 - rect_set_max_size(crop, &r); 718 - rect_map_inside(crop, &dev->crop_bounds_cap); 716 + v4l2_rect_set_max_size(crop, &r); 717 + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); 719 718 compose->top *= factor; 720 719 compose->height *= factor; 721 - rect_set_size_to(compose, crop); 722 - rect_map_inside(compose, &r); 720 + v4l2_rect_set_size_to(compose, crop); 721 + v4l2_rect_map_inside(compose, &r); 723 722 compose->top /= factor; 724 723 compose->height /= factor; 725 724 } ··· 736 735 } else { 737 736 struct v4l2_rect r = { 0, 0, mp->width, mp->height }; 738 737 739 - rect_set_size_to(compose, &r); 738 + v4l2_rect_set_size_to(compose, &r); 740 739 r.height *= factor; 741 - rect_set_size_to(crop, &r); 740 + v4l2_rect_set_size_to(crop, &r); 742 741 } 743 742 744 743 dev->fmt_cap_rect.width = mp->width; ··· 887 886 ret = vivid_vid_adjust_sel(s->flags, &s->r); 888 887 if (ret) 889 888 return ret; 890 - rect_set_min_size(&s->r, &vivid_min_rect); 891 - rect_set_max_size(&s->r, &dev->src_rect); 892 - rect_map_inside(&s->r, &dev->crop_bounds_cap); 889 + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); 890 + v4l2_rect_set_max_size(&s->r, &dev->src_rect); 891 + v4l2_rect_map_inside(&s->r, &dev->crop_bounds_cap); 893 892 s->r.top /= factor; 894 893 s->r.height /= factor; 895 894 if (dev->has_scaler_cap) { ··· 905 904 s->r.height / MAX_ZOOM 906 905 }; 907 906 908 - rect_set_min_size(&fmt, &min_rect); 907 + v4l2_rect_set_min_size(&fmt, &min_rect); 909 908 if (!dev->has_compose_cap) 910 - rect_set_max_size(&fmt, &max_rect); 911 - if (!rect_same_size(&dev->fmt_cap_rect, &fmt) && 909 + v4l2_rect_set_max_size(&fmt, &max_rect); 910 + if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && 912 911 vb2_is_busy(&dev->vb_vid_cap_q)) 913 912 return -EBUSY; 914 913 if (dev->has_compose_cap) { 915 - rect_set_min_size(compose, &min_rect); 916 - rect_set_max_size(compose, &max_rect); 914 + v4l2_rect_set_min_size(compose, &min_rect); 915 + v4l2_rect_set_max_size(compose, &max_rect); 917 916 } 918 917 dev->fmt_cap_rect = fmt; 919 918 tpg_s_buf_height(&dev->tpg, fmt.height); 920 919 } else if (dev->has_compose_cap) { 921 920 struct v4l2_rect fmt = dev->fmt_cap_rect; 922 921 923 - rect_set_min_size(&fmt, &s->r); 924 - if (!rect_same_size(&dev->fmt_cap_rect, &fmt) && 922 + v4l2_rect_set_min_size(&fmt, &s->r); 923 + if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && 925 924 vb2_is_busy(&dev->vb_vid_cap_q)) 926 925 return -EBUSY; 927 926 dev->fmt_cap_rect = fmt; 928 927 tpg_s_buf_height(&dev->tpg, fmt.height); 929 - rect_set_size_to(compose, &s->r); 930 - rect_map_inside(compose, &dev->fmt_cap_rect); 928 + v4l2_rect_set_size_to(compose, &s->r); 929 + v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); 931 930 } else { 932 - if (!rect_same_size(&s->r, &dev->fmt_cap_rect) && 931 + if (!v4l2_rect_same_size(&s->r, &dev->fmt_cap_rect) && 933 932 vb2_is_busy(&dev->vb_vid_cap_q)) 934 933 return -EBUSY; 935 - rect_set_size_to(&dev->fmt_cap_rect, &s->r); 936 - rect_set_size_to(compose, &s->r); 937 - rect_map_inside(compose, &dev->fmt_cap_rect); 934 + v4l2_rect_set_size_to(&dev->fmt_cap_rect, &s->r); 935 + v4l2_rect_set_size_to(compose, &s->r); 936 + v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); 938 937 tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height); 939 938 } 940 939 s->r.top *= factor; ··· 947 946 ret = vivid_vid_adjust_sel(s->flags, &s->r); 948 947 if (ret) 949 948 return ret; 950 - rect_set_min_size(&s->r, &vivid_min_rect); 951 - rect_set_max_size(&s->r, &dev->fmt_cap_rect); 949 + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); 950 + v4l2_rect_set_max_size(&s->r, &dev->fmt_cap_rect); 952 951 if (dev->has_scaler_cap) { 953 952 struct v4l2_rect max_rect = { 954 953 0, 0, ··· 956 955 (dev->src_rect.height / factor) * MAX_ZOOM 957 956 }; 958 957 959 - rect_set_max_size(&s->r, &max_rect); 958 + v4l2_rect_set_max_size(&s->r, &max_rect); 960 959 if (dev->has_crop_cap) { 961 960 struct v4l2_rect min_rect = { 962 961 0, 0, ··· 969 968 (s->r.height * factor) * MAX_ZOOM 970 969 }; 971 970 972 - rect_set_min_size(crop, &min_rect); 973 - rect_set_max_size(crop, &max_rect); 974 - rect_map_inside(crop, &dev->crop_bounds_cap); 971 + v4l2_rect_set_min_size(crop, &min_rect); 972 + v4l2_rect_set_max_size(crop, &max_rect); 973 + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); 975 974 } 976 975 } else if (dev->has_crop_cap) { 977 976 s->r.top *= factor; 978 977 s->r.height *= factor; 979 - rect_set_max_size(&s->r, &dev->src_rect); 980 - rect_set_size_to(crop, &s->r); 981 - rect_map_inside(crop, &dev->crop_bounds_cap); 978 + v4l2_rect_set_max_size(&s->r, &dev->src_rect); 979 + v4l2_rect_set_size_to(crop, &s->r); 980 + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); 982 981 s->r.top /= factor; 983 982 s->r.height /= factor; 984 983 } else { 985 - rect_set_size_to(&s->r, &dev->src_rect); 984 + v4l2_rect_set_size_to(&s->r, &dev->src_rect); 986 985 s->r.height /= factor; 987 986 } 988 - rect_map_inside(&s->r, &dev->fmt_cap_rect); 987 + v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); 989 988 if (dev->bitmap_cap && (compose->width != s->r.width || 990 989 compose->height != s->r.height)) { 991 990 kfree(dev->bitmap_cap); ··· 1125 1124 for (j = i + 1; j < win->clipcount; j++) { 1126 1125 struct v4l2_rect *r2 = &dev->try_clips_cap[j].c; 1127 1126 1128 - if (rect_overlap(r1, r2)) 1127 + if (v4l2_rect_overlap(r1, r2)) 1129 1128 return -EINVAL; 1130 1129 } 1131 1130 }
-97
drivers/media/platform/vivid/vivid-vid-common.c
··· 653 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 656 int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) 754 657 { 755 658 unsigned w = r->width;
-9
drivers/media/platform/vivid/vivid-vid-common.h
··· 37 37 bool vivid_vid_can_loop(struct vivid_dev *dev); 38 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 40 int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); 50 41 51 42 int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f);
+52 -51
drivers/media/platform/vivid/vivid-vid-out.c
··· 25 25 #include <media/v4l2-common.h> 26 26 #include <media/v4l2-event.h> 27 27 #include <media/v4l2-dv-timings.h> 28 + #include <media/v4l2-rect.h> 28 29 29 30 #include "vivid-core.h" 30 31 #include "vivid-vid-common.h" ··· 377 376 } else { 378 377 struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; 379 378 380 - rect_set_min_size(&r, &vivid_min_rect); 381 - rect_set_max_size(&r, &vivid_max_rect); 379 + v4l2_rect_set_min_size(&r, &vivid_min_rect); 380 + v4l2_rect_set_max_size(&r, &vivid_max_rect); 382 381 if (dev->has_scaler_out && !dev->has_crop_out) { 383 382 struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; 384 383 385 - rect_set_max_size(&r, &max_r); 384 + v4l2_rect_set_max_size(&r, &max_r); 386 385 } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { 387 - rect_set_max_size(&r, &dev->sink_rect); 386 + v4l2_rect_set_max_size(&r, &dev->sink_rect); 388 387 } else if (!dev->has_scaler_out && !dev->has_compose_out) { 389 - rect_set_min_size(&r, &dev->sink_rect); 388 + v4l2_rect_set_min_size(&r, &dev->sink_rect); 390 389 } 391 390 mp->width = r.width; 392 391 mp->height = r.height / factor; ··· 474 473 475 474 if (dev->has_scaler_out) { 476 475 if (dev->has_crop_out) 477 - rect_map_inside(crop, &r); 476 + v4l2_rect_map_inside(crop, &r); 478 477 else 479 478 *crop = r; 480 479 if (dev->has_compose_out && !dev->has_crop_out) { ··· 489 488 factor * r.height * MAX_ZOOM 490 489 }; 491 490 492 - rect_set_min_size(compose, &min_r); 493 - rect_set_max_size(compose, &max_r); 494 - rect_map_inside(compose, &dev->compose_bounds_out); 491 + v4l2_rect_set_min_size(compose, &min_r); 492 + v4l2_rect_set_max_size(compose, &max_r); 493 + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); 495 494 } else if (dev->has_compose_out) { 496 495 struct v4l2_rect min_r = { 497 496 0, 0, ··· 504 503 factor * crop->height * MAX_ZOOM 505 504 }; 506 505 507 - rect_set_min_size(compose, &min_r); 508 - rect_set_max_size(compose, &max_r); 509 - rect_map_inside(compose, &dev->compose_bounds_out); 506 + v4l2_rect_set_min_size(compose, &min_r); 507 + v4l2_rect_set_max_size(compose, &max_r); 508 + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); 510 509 } 511 510 } else if (dev->has_compose_out && !dev->has_crop_out) { 512 - rect_set_size_to(crop, &r); 511 + v4l2_rect_set_size_to(crop, &r); 513 512 r.height *= factor; 514 - rect_set_size_to(compose, &r); 515 - rect_map_inside(compose, &dev->compose_bounds_out); 513 + v4l2_rect_set_size_to(compose, &r); 514 + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); 516 515 } else if (!dev->has_compose_out) { 517 - rect_map_inside(crop, &r); 516 + v4l2_rect_map_inside(crop, &r); 518 517 r.height /= factor; 519 - rect_set_size_to(compose, &r); 518 + v4l2_rect_set_size_to(compose, &r); 520 519 } else { 521 520 r.height *= factor; 522 - rect_set_max_size(compose, &r); 523 - rect_map_inside(compose, &dev->compose_bounds_out); 521 + v4l2_rect_set_max_size(compose, &r); 522 + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); 524 523 crop->top *= factor; 525 524 crop->height *= factor; 526 - rect_set_size_to(crop, compose); 527 - rect_map_inside(crop, &r); 525 + v4l2_rect_set_size_to(crop, compose); 526 + v4l2_rect_map_inside(crop, &r); 528 527 crop->top /= factor; 529 528 crop->height /= factor; 530 529 } 531 530 } else { 532 531 struct v4l2_rect r = { 0, 0, mp->width, mp->height }; 533 532 534 - rect_set_size_to(crop, &r); 533 + v4l2_rect_set_size_to(crop, &r); 535 534 r.height /= factor; 536 - rect_set_size_to(compose, &r); 535 + v4l2_rect_set_size_to(compose, &r); 537 536 } 538 537 539 538 dev->fmt_out_rect.width = mp->width; ··· 684 683 ret = vivid_vid_adjust_sel(s->flags, &s->r); 685 684 if (ret) 686 685 return ret; 687 - rect_set_min_size(&s->r, &vivid_min_rect); 688 - rect_set_max_size(&s->r, &dev->fmt_out_rect); 686 + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); 687 + v4l2_rect_set_max_size(&s->r, &dev->fmt_out_rect); 689 688 if (dev->has_scaler_out) { 690 689 struct v4l2_rect max_rect = { 691 690 0, 0, ··· 693 692 (dev->sink_rect.height / factor) * MAX_ZOOM 694 693 }; 695 694 696 - rect_set_max_size(&s->r, &max_rect); 695 + v4l2_rect_set_max_size(&s->r, &max_rect); 697 696 if (dev->has_compose_out) { 698 697 struct v4l2_rect min_rect = { 699 698 0, 0, ··· 706 705 (s->r.height * factor) * MAX_ZOOM 707 706 }; 708 707 709 - rect_set_min_size(compose, &min_rect); 710 - rect_set_max_size(compose, &max_rect); 711 - rect_map_inside(compose, &dev->compose_bounds_out); 708 + v4l2_rect_set_min_size(compose, &min_rect); 709 + v4l2_rect_set_max_size(compose, &max_rect); 710 + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); 712 711 } 713 712 } else if (dev->has_compose_out) { 714 713 s->r.top *= factor; 715 714 s->r.height *= factor; 716 - rect_set_max_size(&s->r, &dev->sink_rect); 717 - rect_set_size_to(compose, &s->r); 718 - rect_map_inside(compose, &dev->compose_bounds_out); 715 + v4l2_rect_set_max_size(&s->r, &dev->sink_rect); 716 + v4l2_rect_set_size_to(compose, &s->r); 717 + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); 719 718 s->r.top /= factor; 720 719 s->r.height /= factor; 721 720 } else { 722 - rect_set_size_to(&s->r, &dev->sink_rect); 721 + v4l2_rect_set_size_to(&s->r, &dev->sink_rect); 723 722 s->r.height /= factor; 724 723 } 725 - rect_map_inside(&s->r, &dev->fmt_out_rect); 724 + v4l2_rect_map_inside(&s->r, &dev->fmt_out_rect); 726 725 *crop = s->r; 727 726 break; 728 727 case V4L2_SEL_TGT_COMPOSE: ··· 731 730 ret = vivid_vid_adjust_sel(s->flags, &s->r); 732 731 if (ret) 733 732 return ret; 734 - rect_set_min_size(&s->r, &vivid_min_rect); 735 - rect_set_max_size(&s->r, &dev->sink_rect); 736 - rect_map_inside(&s->r, &dev->compose_bounds_out); 733 + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); 734 + v4l2_rect_set_max_size(&s->r, &dev->sink_rect); 735 + v4l2_rect_map_inside(&s->r, &dev->compose_bounds_out); 737 736 s->r.top /= factor; 738 737 s->r.height /= factor; 739 738 if (dev->has_scaler_out) { ··· 749 748 s->r.height / MAX_ZOOM 750 749 }; 751 750 752 - rect_set_min_size(&fmt, &min_rect); 751 + v4l2_rect_set_min_size(&fmt, &min_rect); 753 752 if (!dev->has_crop_out) 754 - rect_set_max_size(&fmt, &max_rect); 755 - if (!rect_same_size(&dev->fmt_out_rect, &fmt) && 753 + v4l2_rect_set_max_size(&fmt, &max_rect); 754 + if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && 756 755 vb2_is_busy(&dev->vb_vid_out_q)) 757 756 return -EBUSY; 758 757 if (dev->has_crop_out) { 759 - rect_set_min_size(crop, &min_rect); 760 - rect_set_max_size(crop, &max_rect); 758 + v4l2_rect_set_min_size(crop, &min_rect); 759 + v4l2_rect_set_max_size(crop, &max_rect); 761 760 } 762 761 dev->fmt_out_rect = fmt; 763 762 } else if (dev->has_crop_out) { 764 763 struct v4l2_rect fmt = dev->fmt_out_rect; 765 764 766 - rect_set_min_size(&fmt, &s->r); 767 - if (!rect_same_size(&dev->fmt_out_rect, &fmt) && 765 + v4l2_rect_set_min_size(&fmt, &s->r); 766 + if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && 768 767 vb2_is_busy(&dev->vb_vid_out_q)) 769 768 return -EBUSY; 770 769 dev->fmt_out_rect = fmt; 771 - rect_set_size_to(crop, &s->r); 772 - rect_map_inside(crop, &dev->fmt_out_rect); 770 + v4l2_rect_set_size_to(crop, &s->r); 771 + v4l2_rect_map_inside(crop, &dev->fmt_out_rect); 773 772 } else { 774 - if (!rect_same_size(&s->r, &dev->fmt_out_rect) && 773 + if (!v4l2_rect_same_size(&s->r, &dev->fmt_out_rect) && 775 774 vb2_is_busy(&dev->vb_vid_out_q)) 776 775 return -EBUSY; 777 - rect_set_size_to(&dev->fmt_out_rect, &s->r); 778 - rect_set_size_to(crop, &s->r); 776 + v4l2_rect_set_size_to(&dev->fmt_out_rect, &s->r); 777 + v4l2_rect_set_size_to(crop, &s->r); 779 778 crop->height /= factor; 780 - rect_map_inside(crop, &dev->fmt_out_rect); 779 + v4l2_rect_map_inside(crop, &dev->fmt_out_rect); 781 780 } 782 781 s->r.top *= factor; 783 782 s->r.height *= factor; ··· 902 901 for (j = i + 1; j < win->clipcount; j++) { 903 902 struct v4l2_rect *r2 = &dev->try_clips_out[j].c; 904 903 905 - if (rect_overlap(r1, r2)) 904 + if (v4l2_rect_overlap(r1, r2)) 906 905 return -EINVAL; 907 906 } 908 907 }
+1 -13
drivers/media/platform/vsp1/vsp1.h
··· 26 26 struct clk; 27 27 struct device; 28 28 29 - struct vsp1_dl; 30 29 struct vsp1_drm; 31 30 struct vsp1_entity; 32 31 struct vsp1_platform_data; ··· 48 49 49 50 struct vsp1_device_info { 50 51 u32 version; 52 + unsigned int gen; 51 53 unsigned int features; 52 54 unsigned int rpf_count; 53 55 unsigned int uds_count; ··· 85 85 struct media_entity_operations media_ops; 86 86 87 87 struct vsp1_drm *drm; 88 - 89 - bool use_dl; 90 88 }; 91 89 92 90 int vsp1_device_get(struct vsp1_device *vsp1); ··· 100 102 static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data) 101 103 { 102 104 iowrite32(data, vsp1->mmio + reg); 103 - } 104 - 105 - #include "vsp1_dl.h" 106 - 107 - static inline void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data) 108 - { 109 - if (e->vsp1->use_dl) 110 - vsp1_dl_add(e, reg, data); 111 - else 112 - vsp1_write(e->vsp1, reg, data); 113 105 } 114 106 115 107 #endif /* __VSP1_H__ */
+236 -273
drivers/media/platform/vsp1/vsp1_bru.c
··· 18 18 19 19 #include "vsp1.h" 20 20 #include "vsp1_bru.h" 21 + #include "vsp1_dl.h" 22 + #include "vsp1_pipe.h" 21 23 #include "vsp1_rwpf.h" 22 24 #include "vsp1_video.h" 23 25 ··· 30 28 * Device Access 31 29 */ 32 30 33 - static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data) 31 + static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl, 32 + u32 reg, u32 data) 34 33 { 35 - vsp1_mod_write(&bru->entity, reg, data); 34 + vsp1_dl_list_write(dl, reg, data); 36 35 } 37 36 38 37 /* ----------------------------------------------------------------------------- ··· 45 42 struct vsp1_bru *bru = 46 43 container_of(ctrl->handler, struct vsp1_bru, ctrls); 47 44 48 - if (!vsp1_entity_is_streaming(&bru->entity)) 49 - return 0; 50 - 51 45 switch (ctrl->id) { 52 46 case V4L2_CID_BG_COLOR: 53 - vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, ctrl->val | 54 - (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT)); 47 + bru->bgcolor = ctrl->val; 55 48 break; 56 49 } 57 50 ··· 59 60 }; 60 61 61 62 /* ----------------------------------------------------------------------------- 62 - * V4L2 Subdevice Core Operations 63 + * V4L2 Subdevice Operations 63 64 */ 64 65 65 - static int bru_s_stream(struct v4l2_subdev *subdev, int enable) 66 + /* 67 + * The BRU can't perform format conversion, all sink and source formats must be 68 + * identical. We pick the format on the first sink pad (pad 0) and propagate it 69 + * to all other pads. 70 + */ 71 + 72 + static int bru_enum_mbus_code(struct v4l2_subdev *subdev, 73 + struct v4l2_subdev_pad_config *cfg, 74 + struct v4l2_subdev_mbus_code_enum *code) 66 75 { 67 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity); 76 + static const unsigned int codes[] = { 77 + MEDIA_BUS_FMT_ARGB8888_1X32, 78 + MEDIA_BUS_FMT_AYUV8_1X32, 79 + }; 80 + 81 + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, 82 + ARRAY_SIZE(codes)); 83 + } 84 + 85 + static int bru_enum_frame_size(struct v4l2_subdev *subdev, 86 + struct v4l2_subdev_pad_config *cfg, 87 + struct v4l2_subdev_frame_size_enum *fse) 88 + { 89 + if (fse->index) 90 + return -EINVAL; 91 + 92 + if (fse->code != MEDIA_BUS_FMT_ARGB8888_1X32 && 93 + fse->code != MEDIA_BUS_FMT_AYUV8_1X32) 94 + return -EINVAL; 95 + 96 + fse->min_width = BRU_MIN_SIZE; 97 + fse->max_width = BRU_MAX_SIZE; 98 + fse->min_height = BRU_MIN_SIZE; 99 + fse->max_height = BRU_MAX_SIZE; 100 + 101 + return 0; 102 + } 103 + 104 + static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, 105 + struct v4l2_subdev_pad_config *cfg, 106 + unsigned int pad) 107 + { 108 + return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg, pad); 109 + } 110 + 111 + static void bru_try_format(struct vsp1_bru *bru, 112 + struct v4l2_subdev_pad_config *config, 113 + unsigned int pad, struct v4l2_mbus_framefmt *fmt) 114 + { 115 + struct v4l2_mbus_framefmt *format; 116 + 117 + switch (pad) { 118 + case BRU_PAD_SINK(0): 119 + /* Default to YUV if the requested format is not supported. */ 120 + if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 && 121 + fmt->code != MEDIA_BUS_FMT_AYUV8_1X32) 122 + fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; 123 + break; 124 + 125 + default: 126 + /* The BRU can't perform format conversion. */ 127 + format = vsp1_entity_get_pad_format(&bru->entity, config, 128 + BRU_PAD_SINK(0)); 129 + fmt->code = format->code; 130 + break; 131 + } 132 + 133 + fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE); 134 + fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE); 135 + fmt->field = V4L2_FIELD_NONE; 136 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 137 + } 138 + 139 + static int bru_set_format(struct v4l2_subdev *subdev, 140 + struct v4l2_subdev_pad_config *cfg, 141 + struct v4l2_subdev_format *fmt) 142 + { 68 143 struct vsp1_bru *bru = to_bru(subdev); 144 + struct v4l2_subdev_pad_config *config; 145 + struct v4l2_mbus_framefmt *format; 146 + 147 + config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which); 148 + if (!config) 149 + return -EINVAL; 150 + 151 + bru_try_format(bru, config, fmt->pad, &fmt->format); 152 + 153 + format = vsp1_entity_get_pad_format(&bru->entity, config, fmt->pad); 154 + *format = fmt->format; 155 + 156 + /* Reset the compose rectangle */ 157 + if (fmt->pad != bru->entity.source_pad) { 158 + struct v4l2_rect *compose; 159 + 160 + compose = bru_get_compose(bru, config, fmt->pad); 161 + compose->left = 0; 162 + compose->top = 0; 163 + compose->width = format->width; 164 + compose->height = format->height; 165 + } 166 + 167 + /* Propagate the format code to all pads */ 168 + if (fmt->pad == BRU_PAD_SINK(0)) { 169 + unsigned int i; 170 + 171 + for (i = 0; i <= bru->entity.source_pad; ++i) { 172 + format = vsp1_entity_get_pad_format(&bru->entity, 173 + config, i); 174 + format->code = fmt->format.code; 175 + } 176 + } 177 + 178 + return 0; 179 + } 180 + 181 + static int bru_get_selection(struct v4l2_subdev *subdev, 182 + struct v4l2_subdev_pad_config *cfg, 183 + struct v4l2_subdev_selection *sel) 184 + { 185 + struct vsp1_bru *bru = to_bru(subdev); 186 + struct v4l2_subdev_pad_config *config; 187 + 188 + if (sel->pad == bru->entity.source_pad) 189 + return -EINVAL; 190 + 191 + switch (sel->target) { 192 + case V4L2_SEL_TGT_COMPOSE_BOUNDS: 193 + sel->r.left = 0; 194 + sel->r.top = 0; 195 + sel->r.width = BRU_MAX_SIZE; 196 + sel->r.height = BRU_MAX_SIZE; 197 + return 0; 198 + 199 + case V4L2_SEL_TGT_COMPOSE: 200 + config = vsp1_entity_get_pad_config(&bru->entity, cfg, 201 + sel->which); 202 + if (!config) 203 + return -EINVAL; 204 + 205 + sel->r = *bru_get_compose(bru, config, sel->pad); 206 + return 0; 207 + 208 + default: 209 + return -EINVAL; 210 + } 211 + } 212 + 213 + static int bru_set_selection(struct v4l2_subdev *subdev, 214 + struct v4l2_subdev_pad_config *cfg, 215 + struct v4l2_subdev_selection *sel) 216 + { 217 + struct vsp1_bru *bru = to_bru(subdev); 218 + struct v4l2_subdev_pad_config *config; 219 + struct v4l2_mbus_framefmt *format; 220 + struct v4l2_rect *compose; 221 + 222 + if (sel->pad == bru->entity.source_pad) 223 + return -EINVAL; 224 + 225 + if (sel->target != V4L2_SEL_TGT_COMPOSE) 226 + return -EINVAL; 227 + 228 + config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which); 229 + if (!config) 230 + return -EINVAL; 231 + 232 + /* The compose rectangle top left corner must be inside the output 233 + * frame. 234 + */ 235 + format = vsp1_entity_get_pad_format(&bru->entity, config, 236 + bru->entity.source_pad); 237 + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); 238 + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); 239 + 240 + /* Scaling isn't supported, the compose rectangle size must be identical 241 + * to the sink format size. 242 + */ 243 + format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad); 244 + sel->r.width = format->width; 245 + sel->r.height = format->height; 246 + 247 + compose = bru_get_compose(bru, config, sel->pad); 248 + *compose = sel->r; 249 + 250 + return 0; 251 + } 252 + 253 + static struct v4l2_subdev_pad_ops bru_pad_ops = { 254 + .init_cfg = vsp1_entity_init_cfg, 255 + .enum_mbus_code = bru_enum_mbus_code, 256 + .enum_frame_size = bru_enum_frame_size, 257 + .get_fmt = vsp1_subdev_get_pad_format, 258 + .set_fmt = bru_set_format, 259 + .get_selection = bru_get_selection, 260 + .set_selection = bru_set_selection, 261 + }; 262 + 263 + static struct v4l2_subdev_ops bru_ops = { 264 + .pad = &bru_pad_ops, 265 + }; 266 + 267 + /* ----------------------------------------------------------------------------- 268 + * VSP1 Entity Operations 269 + */ 270 + 271 + static void bru_configure(struct vsp1_entity *entity, 272 + struct vsp1_pipeline *pipe, 273 + struct vsp1_dl_list *dl) 274 + { 275 + struct vsp1_bru *bru = to_bru(&entity->subdev); 69 276 struct v4l2_mbus_framefmt *format; 70 277 unsigned int flags; 71 278 unsigned int i; 72 - int ret; 73 279 74 - ret = vsp1_entity_set_streaming(&bru->entity, enable); 75 - if (ret < 0) 76 - return ret; 77 - 78 - if (!enable) 79 - return 0; 80 - 81 - format = &bru->entity.formats[bru->entity.source_pad]; 280 + format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, 281 + bru->entity.source_pad); 82 282 83 283 /* The hardware is extremely flexible but we have no userspace API to 84 284 * expose all the parameters, nor is it clear whether we would have use ··· 289 91 * format at the pipeline output is premultiplied. 290 92 */ 291 93 flags = pipe->output ? pipe->output->format.flags : 0; 292 - vsp1_bru_write(bru, VI6_BRU_INCTRL, 94 + vsp1_bru_write(bru, dl, VI6_BRU_INCTRL, 293 95 flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ? 294 96 0 : VI6_BRU_INCTRL_NRM); 295 97 296 - /* Set the background position to cover the whole output image. */ 297 - vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE, 98 + /* Set the background position to cover the whole output image and 99 + * configure its color. 100 + */ 101 + vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE, 298 102 (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | 299 103 (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); 300 - vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0); 104 + vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0); 105 + 106 + vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor | 107 + (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT)); 301 108 302 109 /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP 303 110 * unit with a NOP operation to make BRU input 1 available as the 304 111 * Blend/ROP unit B SRC input. 305 112 */ 306 - vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | 113 + vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | 307 114 VI6_BRU_ROP_CROP(VI6_ROP_NOP) | 308 115 VI6_BRU_ROP_AROP(VI6_ROP_NOP)); 309 116 ··· 345 142 if (i != 1) 346 143 ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); 347 144 348 - vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl); 145 + vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl); 349 146 350 147 /* Harcode the blending formula to 351 148 * ··· 359 156 * 360 157 * otherwise. 361 158 */ 362 - vsp1_bru_write(bru, VI6_BRU_BLD(i), 159 + vsp1_bru_write(bru, dl, VI6_BRU_BLD(i), 363 160 VI6_BRU_BLD_CCMDX_255_SRC_A | 364 161 (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY : 365 162 VI6_BRU_BLD_CCMDY_SRC_A) | ··· 367 164 VI6_BRU_BLD_ACMDY_COEFY | 368 165 (0xff << VI6_BRU_BLD_COEFY_SHIFT)); 369 166 } 370 - 371 - return 0; 372 167 } 373 168 374 - /* ----------------------------------------------------------------------------- 375 - * V4L2 Subdevice Pad Operations 376 - */ 377 - 378 - /* 379 - * The BRU can't perform format conversion, all sink and source formats must be 380 - * identical. We pick the format on the first sink pad (pad 0) and propagate it 381 - * to all other pads. 382 - */ 383 - 384 - static int bru_enum_mbus_code(struct v4l2_subdev *subdev, 385 - struct v4l2_subdev_pad_config *cfg, 386 - struct v4l2_subdev_mbus_code_enum *code) 387 - { 388 - static const unsigned int codes[] = { 389 - MEDIA_BUS_FMT_ARGB8888_1X32, 390 - MEDIA_BUS_FMT_AYUV8_1X32, 391 - }; 392 - struct vsp1_bru *bru = to_bru(subdev); 393 - struct v4l2_mbus_framefmt *format; 394 - 395 - if (code->pad == BRU_PAD_SINK(0)) { 396 - if (code->index >= ARRAY_SIZE(codes)) 397 - return -EINVAL; 398 - 399 - code->code = codes[code->index]; 400 - } else { 401 - if (code->index) 402 - return -EINVAL; 403 - 404 - format = vsp1_entity_get_pad_format(&bru->entity, cfg, 405 - BRU_PAD_SINK(0), code->which); 406 - code->code = format->code; 407 - } 408 - 409 - return 0; 410 - } 411 - 412 - static int bru_enum_frame_size(struct v4l2_subdev *subdev, 413 - struct v4l2_subdev_pad_config *cfg, 414 - struct v4l2_subdev_frame_size_enum *fse) 415 - { 416 - if (fse->index) 417 - return -EINVAL; 418 - 419 - if (fse->code != MEDIA_BUS_FMT_ARGB8888_1X32 && 420 - fse->code != MEDIA_BUS_FMT_AYUV8_1X32) 421 - return -EINVAL; 422 - 423 - fse->min_width = BRU_MIN_SIZE; 424 - fse->max_width = BRU_MAX_SIZE; 425 - fse->min_height = BRU_MIN_SIZE; 426 - fse->max_height = BRU_MAX_SIZE; 427 - 428 - return 0; 429 - } 430 - 431 - static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, 432 - struct v4l2_subdev_pad_config *cfg, 433 - unsigned int pad, u32 which) 434 - { 435 - switch (which) { 436 - case V4L2_SUBDEV_FORMAT_TRY: 437 - return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad); 438 - case V4L2_SUBDEV_FORMAT_ACTIVE: 439 - return &bru->inputs[pad].compose; 440 - default: 441 - return NULL; 442 - } 443 - } 444 - 445 - static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 446 - struct v4l2_subdev_format *fmt) 447 - { 448 - struct vsp1_bru *bru = to_bru(subdev); 449 - 450 - fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, 451 - fmt->which); 452 - 453 - return 0; 454 - } 455 - 456 - static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg, 457 - unsigned int pad, struct v4l2_mbus_framefmt *fmt, 458 - enum v4l2_subdev_format_whence which) 459 - { 460 - struct v4l2_mbus_framefmt *format; 461 - 462 - switch (pad) { 463 - case BRU_PAD_SINK(0): 464 - /* Default to YUV if the requested format is not supported. */ 465 - if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 && 466 - fmt->code != MEDIA_BUS_FMT_AYUV8_1X32) 467 - fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; 468 - break; 469 - 470 - default: 471 - /* The BRU can't perform format conversion. */ 472 - format = vsp1_entity_get_pad_format(&bru->entity, cfg, 473 - BRU_PAD_SINK(0), which); 474 - fmt->code = format->code; 475 - break; 476 - } 477 - 478 - fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE); 479 - fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE); 480 - fmt->field = V4L2_FIELD_NONE; 481 - fmt->colorspace = V4L2_COLORSPACE_SRGB; 482 - } 483 - 484 - static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 485 - struct v4l2_subdev_format *fmt) 486 - { 487 - struct vsp1_bru *bru = to_bru(subdev); 488 - struct v4l2_mbus_framefmt *format; 489 - 490 - bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which); 491 - 492 - format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, 493 - fmt->which); 494 - *format = fmt->format; 495 - 496 - /* Reset the compose rectangle */ 497 - if (fmt->pad != bru->entity.source_pad) { 498 - struct v4l2_rect *compose; 499 - 500 - compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which); 501 - compose->left = 0; 502 - compose->top = 0; 503 - compose->width = format->width; 504 - compose->height = format->height; 505 - } 506 - 507 - /* Propagate the format code to all pads */ 508 - if (fmt->pad == BRU_PAD_SINK(0)) { 509 - unsigned int i; 510 - 511 - for (i = 0; i <= bru->entity.source_pad; ++i) { 512 - format = vsp1_entity_get_pad_format(&bru->entity, cfg, 513 - i, fmt->which); 514 - format->code = fmt->format.code; 515 - } 516 - } 517 - 518 - return 0; 519 - } 520 - 521 - static int bru_get_selection(struct v4l2_subdev *subdev, 522 - struct v4l2_subdev_pad_config *cfg, 523 - struct v4l2_subdev_selection *sel) 524 - { 525 - struct vsp1_bru *bru = to_bru(subdev); 526 - 527 - if (sel->pad == bru->entity.source_pad) 528 - return -EINVAL; 529 - 530 - switch (sel->target) { 531 - case V4L2_SEL_TGT_COMPOSE_BOUNDS: 532 - sel->r.left = 0; 533 - sel->r.top = 0; 534 - sel->r.width = BRU_MAX_SIZE; 535 - sel->r.height = BRU_MAX_SIZE; 536 - return 0; 537 - 538 - case V4L2_SEL_TGT_COMPOSE: 539 - sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which); 540 - return 0; 541 - 542 - default: 543 - return -EINVAL; 544 - } 545 - } 546 - 547 - static int bru_set_selection(struct v4l2_subdev *subdev, 548 - struct v4l2_subdev_pad_config *cfg, 549 - struct v4l2_subdev_selection *sel) 550 - { 551 - struct vsp1_bru *bru = to_bru(subdev); 552 - struct v4l2_mbus_framefmt *format; 553 - struct v4l2_rect *compose; 554 - 555 - if (sel->pad == bru->entity.source_pad) 556 - return -EINVAL; 557 - 558 - if (sel->target != V4L2_SEL_TGT_COMPOSE) 559 - return -EINVAL; 560 - 561 - /* The compose rectangle top left corner must be inside the output 562 - * frame. 563 - */ 564 - format = vsp1_entity_get_pad_format(&bru->entity, cfg, 565 - bru->entity.source_pad, sel->which); 566 - sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); 567 - sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); 568 - 569 - /* Scaling isn't supported, the compose rectangle size must be identical 570 - * to the sink format size. 571 - */ 572 - format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad, 573 - sel->which); 574 - sel->r.width = format->width; 575 - sel->r.height = format->height; 576 - 577 - compose = bru_get_compose(bru, cfg, sel->pad, sel->which); 578 - *compose = sel->r; 579 - 580 - return 0; 581 - } 582 - 583 - /* ----------------------------------------------------------------------------- 584 - * V4L2 Subdevice Operations 585 - */ 586 - 587 - static struct v4l2_subdev_video_ops bru_video_ops = { 588 - .s_stream = bru_s_stream, 589 - }; 590 - 591 - static struct v4l2_subdev_pad_ops bru_pad_ops = { 592 - .enum_mbus_code = bru_enum_mbus_code, 593 - .enum_frame_size = bru_enum_frame_size, 594 - .get_fmt = bru_get_format, 595 - .set_fmt = bru_set_format, 596 - .get_selection = bru_get_selection, 597 - .set_selection = bru_set_selection, 598 - }; 599 - 600 - static struct v4l2_subdev_ops bru_ops = { 601 - .video = &bru_video_ops, 602 - .pad = &bru_pad_ops, 169 + static const struct vsp1_entity_operations bru_entity_ops = { 170 + .configure = bru_configure, 603 171 }; 604 172 605 173 /* ----------------------------------------------------------------------------- ··· 379 405 380 406 struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) 381 407 { 382 - struct v4l2_subdev *subdev; 383 408 struct vsp1_bru *bru; 384 409 int ret; 385 410 ··· 386 413 if (bru == NULL) 387 414 return ERR_PTR(-ENOMEM); 388 415 416 + bru->entity.ops = &bru_entity_ops; 389 417 bru->entity.type = VSP1_ENTITY_BRU; 390 418 391 - ret = vsp1_entity_init(vsp1, &bru->entity, 392 - vsp1->info->num_bru_inputs + 1); 419 + ret = vsp1_entity_init(vsp1, &bru->entity, "bru", 420 + vsp1->info->num_bru_inputs + 1, &bru_ops); 393 421 if (ret < 0) 394 422 return ERR_PTR(ret); 395 - 396 - /* Initialize the V4L2 subdev. */ 397 - subdev = &bru->entity.subdev; 398 - v4l2_subdev_init(subdev, &bru_ops); 399 - 400 - subdev->entity.ops = &vsp1->media_ops; 401 - subdev->internal_ops = &vsp1_subdev_internal_ops; 402 - snprintf(subdev->name, sizeof(subdev->name), "%s bru", 403 - dev_name(vsp1->dev)); 404 - v4l2_set_subdevdata(subdev, bru); 405 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 406 - 407 - vsp1_entity_init_formats(subdev, NULL); 408 423 409 424 /* Initialize the control handler. */ 410 425 v4l2_ctrl_handler_init(&bru->ctrls, 1); 411 426 v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR, 412 427 0, 0xffffff, 1, 0); 428 + 429 + bru->bgcolor = 0; 413 430 414 431 bru->entity.subdev.ctrl_handler = &bru->ctrls; 415 432
+2 -1
drivers/media/platform/vsp1/vsp1_bru.h
··· 31 31 32 32 struct { 33 33 struct vsp1_rwpf *rpf; 34 - struct v4l2_rect compose; 35 34 } inputs[VSP1_MAX_RPF]; 35 + 36 + u32 bgcolor; 36 37 }; 37 38 38 39 static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
+450 -159
drivers/media/platform/vsp1/vsp1_dl.c
··· 18 18 19 19 #include "vsp1.h" 20 20 #include "vsp1_dl.h" 21 - #include "vsp1_pipe.h" 22 21 23 - /* 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) 22 + #define VSP1_DL_NUM_ENTRIES 256 33 23 #define VSP1_DL_NUM_LISTS 3 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__)); 34 39 35 40 struct vsp1_dl_entry { 36 41 u32 addr; 37 42 u32 data; 38 43 } __attribute__((__packed__)); 39 44 40 - struct vsp1_dl_list { 41 - size_t size; 42 - int reg_count; 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; 43 57 44 - bool in_use; 45 - 46 - struct vsp1_dl_entry *body; 58 + struct vsp1_dl_entry *entries; 47 59 dma_addr_t dma; 60 + size_t size; 61 + 62 + unsigned int num_entries; 48 63 }; 49 64 50 65 /** 51 - * struct vsp1_dl - Display List manager 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; 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, 88 + }; 89 + 90 + /** 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 94 * @vsp1: the VSP1 device 53 95 * @lock: protects the active, queued and pending lists 54 - * @lists.all: array of all allocate display lists 55 - * @lists.active: list currently being processed (loaded) by hardware 56 - * @lists.queued: list queued to the hardware (written to the DL registers) 57 - * @lists.pending: list waiting to be queued to the hardware 58 - * @lists.write: list being written to by software 96 + * @free: array of all free display lists 97 + * @active: list currently being processed (loaded) by hardware 98 + * @queued: list queued to the hardware (written to the DL registers) 99 + * @pending: list waiting to be queued to the hardware 59 100 */ 60 - struct vsp1_dl { 101 + struct vsp1_dl_manager { 102 + unsigned int index; 103 + enum vsp1_dl_mode mode; 61 104 struct vsp1_device *vsp1; 62 105 63 106 spinlock_t lock; 64 - 65 - size_t size; 66 - dma_addr_t dma; 67 - void *mem; 68 - 69 - struct { 70 - struct vsp1_dl_list all[VSP1_DL_NUM_LISTS]; 71 - 72 - struct vsp1_dl_list *active; 73 - struct vsp1_dl_list *queued; 74 - struct vsp1_dl_list *pending; 75 - struct vsp1_dl_list *write; 76 - } lists; 107 + struct list_head free; 108 + struct vsp1_dl_list *active; 109 + struct vsp1_dl_list *queued; 110 + struct vsp1_dl_list *pending; 77 111 }; 112 + 113 + /* ----------------------------------------------------------------------------- 114 + * Display List Body Management 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; 127 + 128 + dlb->vsp1 = vsp1; 129 + dlb->size = size; 130 + 131 + dlb->entries = dma_alloc_wc(vsp1->dev, dlb->size, &dlb->dma, 132 + GFP_KERNEL); 133 + if (!dlb->entries) 134 + return -ENOMEM; 135 + 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 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; 224 + size_t header_size; 225 + int ret; 226 + 227 + dl = kzalloc(sizeof(*dl), GFP_KERNEL); 228 + if (!dl) 229 + return NULL; 230 + 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; 263 + } 264 + 265 + static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl) 266 + { 267 + struct vsp1_dl_body *dlb, *next; 268 + 269 + list_for_each_entry_safe(dlb, next, &dl->fragments, list) { 270 + list_del(&dlb->list); 271 + vsp1_dl_body_cleanup(dlb); 272 + kfree(dlb); 273 + } 274 + } 275 + 276 + static void vsp1_dl_list_free(struct vsp1_dl_list *dl) 277 + { 278 + vsp1_dl_body_cleanup(&dl->body0); 279 + vsp1_dl_list_free_fragments(dl); 280 + kfree(dl); 281 + } 282 + 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) 292 + { 293 + struct vsp1_dl_list *dl = NULL; 294 + unsigned long flags; 295 + 296 + spin_lock_irqsave(&dlm->lock, flags); 297 + 298 + if (!list_empty(&dlm->free)) { 299 + dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list); 300 + list_del(&dl->list); 301 + } 302 + 303 + spin_unlock_irqrestore(&dlm->lock, flags); 304 + 305 + return dl; 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) 86 312 return; 87 313 88 - list->in_use = false; 314 + vsp1_dl_list_free_fragments(dl); 315 + dl->body0.num_entries = 0; 316 + 317 + list_add_tail(&dl->list, &dl->dlm->free); 89 318 } 90 319 91 - void vsp1_dl_reset(struct vsp1_dl *dl) 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) 92 330 { 93 - unsigned int i; 94 - 95 - dl->lists.active = NULL; 96 - dl->lists.queued = NULL; 97 - dl->lists.pending = NULL; 98 - dl->lists.write = NULL; 99 - 100 - for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) 101 - dl->lists.all[i].in_use = false; 102 - } 103 - 104 - void vsp1_dl_begin(struct vsp1_dl *dl) 105 - { 106 - struct vsp1_dl_list *list = NULL; 107 331 unsigned long flags; 108 - unsigned int i; 109 332 110 - spin_lock_irqsave(&dl->lock, flags); 333 + if (!dl) 334 + return; 111 335 112 - for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) { 113 - if (!dl->lists.all[i].in_use) { 114 - list = &dl->lists.all[i]; 115 - break; 116 - } 117 - } 118 - 119 - if (!list) { 120 - list = dl->lists.pending; 121 - dl->lists.pending = NULL; 122 - } 123 - 124 - spin_unlock_irqrestore(&dl->lock, flags); 125 - 126 - dl->lists.write = list; 127 - 128 - list->in_use = true; 129 - list->reg_count = 0; 336 + spin_lock_irqsave(&dl->dlm->lock, flags); 337 + __vsp1_dl_list_put(dl); 338 + spin_unlock_irqrestore(&dl->dlm->lock, flags); 130 339 } 131 340 132 - void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data) 341 + /** 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) 133 351 { 134 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity); 135 - struct vsp1_dl *dl = pipe->dl; 136 - struct vsp1_dl_list *list = dl->lists.write; 137 - 138 - list->body[list->reg_count].addr = reg; 139 - list->body[list->reg_count].data = data; 140 - list->reg_count++; 352 + vsp1_dl_fragment_write(&dl->body0, reg, data); 141 353 } 142 354 143 - void vsp1_dl_commit(struct vsp1_dl *dl) 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) 144 373 { 145 - struct vsp1_device *vsp1 = dl->vsp1; 146 - struct vsp1_dl_list *list; 374 + /* Multi-body lists are only available in header mode. */ 375 + if (dl->dlm->mode != VSP1_DL_MODE_HEADER) 376 + return -EINVAL; 377 + 378 + list_add_tail(&dlb->list, &dl->fragments); 379 + return 0; 380 + } 381 + 382 + void vsp1_dl_list_commit(struct vsp1_dl_list *dl) 383 + { 384 + struct vsp1_dl_manager *dlm = dl->dlm; 385 + struct vsp1_device *vsp1 = dlm->vsp1; 147 386 unsigned long flags; 148 387 bool update; 149 388 150 - list = dl->lists.write; 151 - dl->lists.write = NULL; 389 + spin_lock_irqsave(&dlm->lock, flags); 152 390 153 - spin_lock_irqsave(&dl->lock, flags); 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); 417 + 418 + dlm->active = dl; 419 + goto done; 420 + } 154 421 155 422 /* Once the UPD bit has been set the hardware can start processing the 156 423 * display list at any time and we can't touch the address and size ··· 426 159 */ 427 160 update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); 428 161 if (update) { 429 - vsp1_dl_free_list(dl->lists.pending); 430 - dl->lists.pending = list; 162 + __vsp1_dl_list_put(dlm->pending); 163 + dlm->pending = dl; 431 164 goto done; 432 165 } 433 166 ··· 435 168 * The UPD bit will be cleared by the device when the display list is 436 169 * processed. 437 170 */ 438 - vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma); 171 + vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); 439 172 vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | 440 - (list->reg_count * 8)); 173 + (dl->body0.num_entries * sizeof(*dl->header->lists))); 441 174 442 - vsp1_dl_free_list(dl->lists.queued); 443 - dl->lists.queued = list; 175 + __vsp1_dl_list_put(dlm->queued); 176 + dlm->queued = dl; 444 177 445 178 done: 446 - spin_unlock_irqrestore(&dl->lock, flags); 179 + spin_unlock_irqrestore(&dlm->lock, flags); 447 180 } 448 181 449 182 /* ----------------------------------------------------------------------------- 450 - * Interrupt Handling 183 + * Display List Manager 451 184 */ 452 185 453 - void vsp1_dl_irq_display_start(struct vsp1_dl *dl) 186 + /* Interrupt Handling */ 187 + void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm) 454 188 { 455 - spin_lock(&dl->lock); 189 + spin_lock(&dlm->lock); 456 190 457 191 /* The display start interrupt signals the end of the display list 458 192 * processing by the device. The active display list, if any, won't be 459 193 * accessed anymore and can be reused. 460 194 */ 461 - if (dl->lists.active) { 462 - vsp1_dl_free_list(dl->lists.active); 463 - dl->lists.active = NULL; 464 - } 195 + __vsp1_dl_list_put(dlm->active); 196 + dlm->active = NULL; 465 197 466 - spin_unlock(&dl->lock); 198 + spin_unlock(&dlm->lock); 467 199 } 468 200 469 - void vsp1_dl_irq_frame_end(struct vsp1_dl *dl) 201 + void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) 470 202 { 471 - struct vsp1_device *vsp1 = dl->vsp1; 203 + struct vsp1_device *vsp1 = dlm->vsp1; 472 204 473 - spin_lock(&dl->lock); 205 + spin_lock(&dlm->lock); 206 + 207 + __vsp1_dl_list_put(dlm->active); 208 + dlm->active = NULL; 209 + 210 + /* Header mode is used for mem-to-mem pipelines only. We don't need to 211 + * perform any operation as there can't be any new display list queued 212 + * in that case. 213 + */ 214 + if (dlm->mode == VSP1_DL_MODE_HEADER) 215 + goto done; 474 216 475 217 /* The UPD bit set indicates that the commit operation raced with the 476 218 * interrupt and occurred after the frame end event and UPD clear but ··· 492 216 /* The device starts processing the queued display list right after the 493 217 * frame end interrupt. The display list thus becomes active. 494 218 */ 495 - if (dl->lists.queued) { 496 - WARN_ON(dl->lists.active); 497 - dl->lists.active = dl->lists.queued; 498 - dl->lists.queued = NULL; 219 + if (dlm->queued) { 220 + dlm->active = dlm->queued; 221 + dlm->queued = NULL; 499 222 } 500 223 501 224 /* Now that the UPD bit has been cleared we can queue the next display 502 225 * list to the hardware if one has been prepared. 503 226 */ 504 - if (dl->lists.pending) { 505 - struct vsp1_dl_list *list = dl->lists.pending; 227 + if (dlm->pending) { 228 + struct vsp1_dl_list *dl = dlm->pending; 506 229 507 - vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma); 230 + vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); 508 231 vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | 509 - (list->reg_count * 8)); 232 + (dl->body0.num_entries * 233 + sizeof(*dl->header->lists))); 510 234 511 - dl->lists.queued = list; 512 - dl->lists.pending = NULL; 235 + dlm->queued = dl; 236 + dlm->pending = NULL; 513 237 } 514 238 515 239 done: 516 - spin_unlock(&dl->lock); 240 + spin_unlock(&dlm->lock); 517 241 } 518 242 519 - /* ----------------------------------------------------------------------------- 520 - * Hardware Setup 521 - */ 522 - 523 - void vsp1_dl_setup(struct vsp1_device *vsp1) 243 + /* Hardware Setup */ 244 + void vsp1_dlm_setup(struct vsp1_device *vsp1) 524 245 { 525 246 u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT) 526 247 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 527 248 | VI6_DL_CTRL_DLE; 528 249 529 - /* The DRM pipeline operates with header-less display lists in 530 - * Continuous Frame Mode. 250 + /* The DRM pipeline operates with display lists in Continuous Frame 251 + * Mode, all other pipelines use manual start. 531 252 */ 532 253 if (vsp1->drm) 533 254 ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0; ··· 533 260 vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS); 534 261 } 535 262 536 - /* ----------------------------------------------------------------------------- 537 - * Initialization and Cleanup 538 - */ 539 - 540 - struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1) 263 + void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) 541 264 { 542 - struct vsp1_dl *dl; 543 - unsigned int i; 265 + unsigned long flags; 544 266 545 - dl = kzalloc(sizeof(*dl), GFP_KERNEL); 546 - if (!dl) 547 - return NULL; 267 + spin_lock_irqsave(&dlm->lock, flags); 548 268 549 - spin_lock_init(&dl->lock); 269 + __vsp1_dl_list_put(dlm->active); 270 + __vsp1_dl_list_put(dlm->queued); 271 + __vsp1_dl_list_put(dlm->pending); 550 272 551 - dl->vsp1 = vsp1; 552 - dl->size = VSP1_DL_BODY_SIZE * ARRAY_SIZE(dl->lists.all); 273 + spin_unlock_irqrestore(&dlm->lock, flags); 553 274 554 - dl->mem = dma_alloc_wc(vsp1->dev, dl->size, &dl->dma, 555 - GFP_KERNEL); 556 - if (!dl->mem) { 557 - kfree(dl); 558 - return NULL; 559 - } 560 - 561 - for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) { 562 - struct vsp1_dl_list *list = &dl->lists.all[i]; 563 - 564 - list->size = VSP1_DL_BODY_SIZE; 565 - list->reg_count = 0; 566 - list->in_use = false; 567 - list->dma = dl->dma + VSP1_DL_BODY_SIZE * i; 568 - list->body = dl->mem + VSP1_DL_BODY_SIZE * i; 569 - } 570 - 571 - return dl; 275 + dlm->active = NULL; 276 + dlm->queued = NULL; 277 + dlm->pending = NULL; 572 278 } 573 279 574 - void vsp1_dl_destroy(struct vsp1_dl *dl) 280 + struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, 281 + unsigned int index, 282 + unsigned int prealloc) 575 283 { 576 - dma_free_wc(dl->vsp1->dev, dl->size, dl->mem, dl->dma); 577 - kfree(dl); 284 + struct vsp1_dl_manager *dlm; 285 + unsigned int i; 286 + 287 + dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL); 288 + if (!dlm) 289 + return NULL; 290 + 291 + dlm->index = index; 292 + dlm->mode = index == 0 && !vsp1->info->uapi 293 + ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER; 294 + dlm->vsp1 = vsp1; 295 + 296 + spin_lock_init(&dlm->lock); 297 + INIT_LIST_HEAD(&dlm->free); 298 + 299 + for (i = 0; i < prealloc; ++i) { 300 + struct vsp1_dl_list *dl; 301 + 302 + dl = vsp1_dl_list_alloc(dlm); 303 + if (!dl) 304 + return NULL; 305 + 306 + list_add_tail(&dl->list, &dlm->free); 307 + } 308 + 309 + return dlm; 310 + } 311 + 312 + void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm) 313 + { 314 + struct vsp1_dl_list *dl, *next; 315 + 316 + if (!dlm) 317 + return; 318 + 319 + list_for_each_entry_safe(dl, next, &dlm->free, list) { 320 + list_del(&dl->list); 321 + vsp1_dl_list_free(dl); 322 + } 578 323 }
+22 -19
drivers/media/platform/vsp1/vsp1_dl.h
··· 13 13 #ifndef __VSP1_DL_H__ 14 14 #define __VSP1_DL_H__ 15 15 16 - #include "vsp1_entity.h" 16 + #include <linux/types.h> 17 17 18 18 struct vsp1_device; 19 - struct vsp1_dl; 19 + struct vsp1_dl_fragment; 20 + struct vsp1_dl_list; 21 + struct vsp1_dl_manager; 20 22 21 - struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1); 22 - void vsp1_dl_destroy(struct vsp1_dl *dl); 23 + void vsp1_dlm_setup(struct vsp1_device *vsp1); 23 24 24 - void vsp1_dl_setup(struct vsp1_device *vsp1); 25 + struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, 26 + unsigned int index, 27 + unsigned int prealloc); 28 + void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm); 29 + void vsp1_dlm_reset(struct vsp1_dl_manager *dlm); 30 + void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm); 31 + void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm); 25 32 26 - void vsp1_dl_reset(struct vsp1_dl *dl); 27 - void vsp1_dl_begin(struct vsp1_dl *dl); 28 - void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data); 29 - void vsp1_dl_commit(struct vsp1_dl *dl); 33 + struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm); 34 + void vsp1_dl_list_put(struct vsp1_dl_list *dl); 35 + void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data); 36 + void vsp1_dl_list_commit(struct vsp1_dl_list *dl); 30 37 31 - void vsp1_dl_irq_display_start(struct vsp1_dl *dl); 32 - void vsp1_dl_irq_frame_end(struct vsp1_dl *dl); 33 - 34 - static inline void vsp1_dl_mod_write(struct vsp1_entity *e, u32 reg, u32 data) 35 - { 36 - if (e->vsp1->use_dl) 37 - vsp1_dl_add(e, reg, data); 38 - else 39 - vsp1_write(e->vsp1, reg, data); 40 - } 38 + struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1, 39 + unsigned int num_entries); 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 45 #endif /* __VSP1_DL_H__ */
+125 -109
drivers/media/platform/vsp1/vsp1_drm.c
··· 13 13 14 14 #include <linux/device.h> 15 15 #include <linux/slab.h> 16 - #include <linux/vsp1.h> 17 16 18 17 #include <media/media-entity.h> 19 18 #include <media/v4l2-subdev.h> 19 + #include <media/vsp1.h> 20 20 21 21 #include "vsp1.h" 22 22 #include "vsp1_bru.h" ··· 26 26 #include "vsp1_pipe.h" 27 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 - 37 - spin_lock_irqsave(&pipe->irqlock, flags); 38 - if (pipe->num_inputs) 39 - vsp1_pipeline_run(pipe); 40 - spin_unlock_irqrestore(&pipe->irqlock, flags); 36 + vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm); 41 37 } 42 38 43 39 /* ----------------------------------------------------------------------------- ··· 93 97 media_entity_pipeline_stop(&pipe->output->entity.subdev.entity); 94 98 95 99 for (i = 0; i < bru->entity.source_pad; ++i) { 100 + vsp1->drm->inputs[i].enabled = false; 96 101 bru->inputs[i].rpf = NULL; 97 102 pipe->inputs[i] = NULL; 98 103 } 99 104 100 105 pipe->num_inputs = 0; 101 106 107 + vsp1_dlm_reset(pipe->output->dlm); 102 108 vsp1_device_put(vsp1); 103 109 104 110 dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__); 105 111 106 112 return 0; 107 113 } 108 - 109 - vsp1_dl_reset(vsp1->drm->dl); 110 114 111 115 /* Configure the format at the BRU sinks and propagate it through the 112 116 * pipeline. ··· 218 222 { 219 223 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 220 224 struct vsp1_pipeline *pipe = &vsp1->drm->pipe; 221 - unsigned long flags; 222 - 223 - spin_lock_irqsave(&pipe->irqlock, flags); 224 225 225 226 vsp1->drm->num_inputs = pipe->num_inputs; 226 227 227 - spin_unlock_irqrestore(&pipe->irqlock, flags); 228 - 229 228 /* Prepare the display list. */ 230 - vsp1_dl_begin(vsp1->drm->dl); 229 + pipe->dl = vsp1_dl_list_get(pipe->output->dlm); 231 230 } 232 231 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); 233 232 ··· 235 244 * @mem: DMA addresses of the memory buffers (one per plane) 236 245 * @src: the source crop rectangle for the RPF 237 246 * @dst: the destination compose rectangle for the BRU input 247 + * @alpha: global alpha value for the input 248 + * @zpos: the Z-order position of the input 238 249 * 239 250 * Configure the VSP to perform composition of the image referenced by @mem 240 251 * through RPF @rpf_index, using the @src crop rectangle and the @dst 241 - * composition rectangle. The Z-order is fixed with RPF 0 at the bottom. 252 + * composition rectangle. The Z-order is configurable with higher @zpos values 253 + * displayed on top. 242 254 * 243 255 * Image format as stored in memory is expressed as a V4L2 @pixelformat value. 244 256 * As a special case, setting the pixel format to 0 will disable the RPF. The ··· 259 265 * 260 266 * This function isn't reentrant, the caller needs to serialize calls. 261 267 * 262 - * TODO: Implement Z-order control by decoupling the RPF index from the BRU 263 - * input index. 264 - * 265 268 * Return 0 on success or a negative error code on failure. 266 269 */ 267 - int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, 268 - u32 pixelformat, unsigned int pitch, 269 - dma_addr_t mem[2], const struct v4l2_rect *src, 270 - const struct v4l2_rect *dst) 270 + int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, 271 + u32 pixelformat, unsigned int pitch, 272 + dma_addr_t mem[2], const struct v4l2_rect *src, 273 + const struct v4l2_rect *dst, unsigned int alpha, 274 + unsigned int zpos) 271 275 { 272 276 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 273 - struct vsp1_pipeline *pipe = &vsp1->drm->pipe; 274 277 const struct vsp1_format_info *fmtinfo; 275 - struct v4l2_subdev_selection sel; 276 - struct v4l2_subdev_format format; 277 - struct vsp1_rwpf_memory memory; 278 278 struct vsp1_rwpf *rpf; 279 - unsigned long flags; 280 - int ret; 281 279 282 280 if (rpf_index >= vsp1->info->rpf_count) 283 281 return -EINVAL; ··· 280 294 dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, 281 295 rpf_index); 282 296 283 - spin_lock_irqsave(&pipe->irqlock, flags); 284 - 285 - if (pipe->inputs[rpf_index]) { 286 - /* Remove the RPF from the pipeline if it was previously 287 - * enabled. 288 - */ 289 - vsp1->bru->inputs[rpf_index].rpf = NULL; 290 - pipe->inputs[rpf_index] = NULL; 291 - 292 - pipe->num_inputs--; 293 - } 294 - 295 - spin_unlock_irqrestore(&pipe->irqlock, flags); 296 - 297 + vsp1->drm->inputs[rpf_index].enabled = false; 297 298 return 0; 298 299 } 299 300 300 301 dev_dbg(vsp1->dev, 301 - "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad }\n", 302 + "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", 302 303 __func__, rpf_index, 303 304 src->left, src->top, src->width, src->height, 304 305 dst->left, dst->top, dst->width, dst->height, 305 - pixelformat, pitch, &mem[0], &mem[1]); 306 + pixelformat, pitch, &mem[0], &mem[1], zpos); 306 307 307 - /* Set the stride at the RPF input. */ 308 + /* Store the format, stride, memory buffer address, crop and compose 309 + * rectangles and Z-order position and for the input. 310 + */ 308 311 fmtinfo = vsp1_get_format_info(pixelformat); 309 312 if (!fmtinfo) { 310 313 dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", ··· 305 330 rpf->format.num_planes = fmtinfo->planes; 306 331 rpf->format.plane_fmt[0].bytesperline = pitch; 307 332 rpf->format.plane_fmt[1].bytesperline = pitch; 333 + rpf->alpha = alpha; 334 + 335 + rpf->mem.addr[0] = mem[0]; 336 + rpf->mem.addr[1] = mem[1]; 337 + rpf->mem.addr[2] = 0; 338 + 339 + vsp1->drm->inputs[rpf_index].crop = *src; 340 + vsp1->drm->inputs[rpf_index].compose = *dst; 341 + vsp1->drm->inputs[rpf_index].zpos = zpos; 342 + vsp1->drm->inputs[rpf_index].enabled = true; 343 + 344 + return 0; 345 + } 346 + EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext); 347 + 348 + static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, 349 + struct vsp1_rwpf *rpf, unsigned int bru_input) 350 + { 351 + struct v4l2_subdev_selection sel; 352 + struct v4l2_subdev_format format; 353 + const struct v4l2_rect *crop; 354 + int ret; 308 355 309 356 /* Configure the format on the RPF sink pad and propagate it up to the 310 357 * BRU sink pad. 311 358 */ 359 + crop = &vsp1->drm->inputs[rpf->entity.index].crop; 360 + 312 361 memset(&format, 0, sizeof(format)); 313 362 format.which = V4L2_SUBDEV_FORMAT_ACTIVE; 314 363 format.pad = RWPF_PAD_SINK; 315 - format.format.width = src->width + src->left; 316 - format.format.height = src->height + src->top; 317 - format.format.code = fmtinfo->mbus; 364 + format.format.width = crop->width + crop->left; 365 + format.format.height = crop->height + crop->top; 366 + format.format.code = rpf->fmtinfo->mbus; 318 367 format.format.field = V4L2_FIELD_NONE; 319 368 320 369 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL, ··· 355 356 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; 356 357 sel.pad = RWPF_PAD_SINK; 357 358 sel.target = V4L2_SEL_TGT_CROP; 358 - sel.r = *src; 359 + sel.r = *crop; 359 360 360 361 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL, 361 362 &sel); ··· 390 391 return ret; 391 392 392 393 /* BRU sink, propagate the format from the RPF source. */ 393 - format.pad = rpf->entity.index; 394 + format.pad = bru_input; 394 395 395 396 ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL, 396 397 &format); ··· 401 402 __func__, format.format.width, format.format.height, 402 403 format.format.code, format.pad); 403 404 404 - sel.pad = rpf->entity.index; 405 + sel.pad = bru_input; 405 406 sel.target = V4L2_SEL_TGT_COMPOSE; 406 - sel.r = *dst; 407 + sel.r = vsp1->drm->inputs[rpf->entity.index].compose; 407 408 408 409 ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection, 409 410 NULL, &sel); ··· 415 416 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, 416 417 sel.pad); 417 418 418 - /* Store the compose rectangle coordinates in the RPF. */ 419 - rpf->location.left = dst->left; 420 - rpf->location.top = dst->top; 421 - 422 - /* Set the memory buffer address. */ 423 - memory.num_planes = fmtinfo->planes; 424 - memory.addr[0] = mem[0]; 425 - memory.addr[1] = mem[1]; 426 - 427 - rpf->ops->set_memory(rpf, &memory); 428 - 429 - spin_lock_irqsave(&pipe->irqlock, flags); 430 - 431 - /* If the RPF was previously stopped set the BRU input to the RPF and 432 - * store the RPF in the pipeline inputs array. 433 - */ 434 - if (!pipe->inputs[rpf->entity.index]) { 435 - vsp1->bru->inputs[rpf_index].rpf = rpf; 436 - pipe->inputs[rpf->entity.index] = rpf; 437 - pipe->num_inputs++; 438 - } 439 - 440 - spin_unlock_irqrestore(&pipe->irqlock, flags); 441 - 442 419 return 0; 443 420 } 444 - EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); 421 + 422 + static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf) 423 + { 424 + return vsp1->drm->inputs[rpf->entity.index].zpos; 425 + } 445 426 446 427 /** 447 428 * vsp1_du_atomic_flush - Commit an atomic update ··· 431 452 { 432 453 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 433 454 struct vsp1_pipeline *pipe = &vsp1->drm->pipe; 455 + struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, }; 434 456 struct vsp1_entity *entity; 435 457 unsigned long flags; 436 - bool stop = false; 458 + unsigned int i; 437 459 int ret; 438 460 461 + /* Count the number of enabled inputs and sort them by Z-order. */ 462 + pipe->num_inputs = 0; 463 + 464 + for (i = 0; i < vsp1->info->rpf_count; ++i) { 465 + struct vsp1_rwpf *rpf = vsp1->rpf[i]; 466 + unsigned int j; 467 + 468 + if (!vsp1->drm->inputs[i].enabled) { 469 + pipe->inputs[i] = NULL; 470 + continue; 471 + } 472 + 473 + pipe->inputs[i] = rpf; 474 + 475 + /* Insert the RPF in the sorted RPFs array. */ 476 + for (j = pipe->num_inputs++; j > 0; --j) { 477 + if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf)) 478 + break; 479 + inputs[j] = inputs[j-1]; 480 + } 481 + 482 + inputs[j] = rpf; 483 + } 484 + 485 + /* Setup the RPF input pipeline for every enabled input. */ 486 + for (i = 0; i < vsp1->info->num_bru_inputs; ++i) { 487 + struct vsp1_rwpf *rpf = inputs[i]; 488 + 489 + if (!rpf) { 490 + vsp1->bru->inputs[i].rpf = NULL; 491 + continue; 492 + } 493 + 494 + vsp1->bru->inputs[i].rpf = rpf; 495 + rpf->bru_input = i; 496 + rpf->entity.sink_pad = i; 497 + 498 + dev_dbg(vsp1->dev, "%s: connecting RPF.%u to BRU:%u\n", 499 + __func__, rpf->entity.index, i); 500 + 501 + ret = vsp1_du_setup_rpf_pipe(vsp1, rpf, i); 502 + if (ret < 0) 503 + dev_err(vsp1->dev, 504 + "%s: failed to setup RPF.%u\n", 505 + __func__, rpf->entity.index); 506 + } 507 + 508 + /* Configure all entities in the pipeline. */ 439 509 list_for_each_entry(entity, &pipe->entities, list_pipe) { 440 510 /* Disconnect unused RPFs from the pipeline. */ 441 511 if (entity->type == VSP1_ENTITY_RPF) { 442 512 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 443 513 444 514 if (!pipe->inputs[rpf->entity.index]) { 445 - vsp1_mod_write(entity, entity->route->reg, 446 - VI6_DPR_NODE_UNUSED); 515 + vsp1_dl_list_write(pipe->dl, entity->route->reg, 516 + VI6_DPR_NODE_UNUSED); 447 517 continue; 448 518 } 449 519 } 450 520 451 - vsp1_entity_route_setup(entity); 521 + vsp1_entity_route_setup(entity, pipe->dl); 452 522 453 - ret = v4l2_subdev_call(&entity->subdev, video, 454 - s_stream, 1); 455 - if (ret < 0) { 456 - dev_err(vsp1->dev, 457 - "DRM pipeline start failure on entity %s\n", 458 - entity->subdev.name); 459 - return; 460 - } 523 + if (entity->ops->configure) 524 + entity->ops->configure(entity, pipe, pipe->dl); 525 + 526 + /* The memory buffer address must be applied after configuring 527 + * the RPF to make sure the crop offset are computed. 528 + */ 529 + if (entity->type == VSP1_ENTITY_RPF) 530 + vsp1_rwpf_set_memory(to_rwpf(&entity->subdev), 531 + pipe->dl); 461 532 } 462 533 463 - vsp1_dl_commit(vsp1->drm->dl); 464 - 465 - spin_lock_irqsave(&pipe->irqlock, flags); 534 + vsp1_dl_list_commit(pipe->dl); 535 + pipe->dl = NULL; 466 536 467 537 /* Start or stop the pipeline if needed. */ 468 538 if (!vsp1->drm->num_inputs && pipe->num_inputs) { 469 539 vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0); 470 540 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE); 541 + spin_lock_irqsave(&pipe->irqlock, flags); 471 542 vsp1_pipeline_run(pipe); 543 + spin_unlock_irqrestore(&pipe->irqlock, flags); 472 544 } else if (vsp1->drm->num_inputs && !pipe->num_inputs) { 473 - stop = true; 474 - } 475 - 476 - spin_unlock_irqrestore(&pipe->irqlock, flags); 477 - 478 - if (stop) { 479 545 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0); 480 546 vsp1_pipeline_stop(pipe); 481 547 } ··· 586 562 if (!vsp1->drm) 587 563 return -ENOMEM; 588 564 589 - vsp1->drm->dl = vsp1_dl_create(vsp1); 590 - if (!vsp1->drm->dl) 591 - return -ENOMEM; 592 - 593 565 pipe = &vsp1->drm->pipe; 594 566 595 567 vsp1_pipeline_init(pipe); 596 - pipe->frame_end = vsp1_drm_pipeline_frame_end; 597 568 598 569 /* The DRM pipeline is static, add entities manually. */ 599 570 for (i = 0; i < vsp1->info->rpf_count; ++i) { ··· 605 586 pipe->lif = &vsp1->lif->entity; 606 587 pipe->output = vsp1->wpf[0]; 607 588 608 - pipe->dl = vsp1->drm->dl; 609 - 610 589 return 0; 611 590 } 612 591 613 592 void vsp1_drm_cleanup(struct vsp1_device *vsp1) 614 593 { 615 - vsp1_dl_destroy(vsp1->drm->dl); 616 594 }
+11 -16
drivers/media/platform/vsp1/vsp1_drm.h
··· 13 13 #ifndef __VSP1_DRM_H__ 14 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 21 * vsp1_drm - State for the API exposed to the DRM driver 22 - * @dl: display list for DRM pipeline operation 23 22 * @pipe: the VSP1 pipeline used for display 24 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 27 struct vsp1_drm { 28 - struct vsp1_dl *dl; 29 28 struct vsp1_pipeline pipe; 30 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 38 int vsp1_drm_init(struct vsp1_device *vsp1); 35 39 void vsp1_drm_cleanup(struct vsp1_device *vsp1); 36 40 int vsp1_drm_create_links(struct vsp1_device *vsp1); 37 41 38 - int vsp1_du_init(struct device *dev); 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 - 42 + void vsp1_drm_display_start(struct vsp1_device *vsp1); 48 43 49 44 #endif /* __VSP1_DRM_H__ */
+15 -19
drivers/media/platform/vsp1/vsp1_drv.c
··· 30 30 #include "vsp1_hsit.h" 31 31 #include "vsp1_lif.h" 32 32 #include "vsp1_lut.h" 33 + #include "vsp1_pipe.h" 33 34 #include "vsp1_rwpf.h" 34 35 #include "vsp1_sru.h" 35 36 #include "vsp1_uds.h" ··· 50 49 51 50 for (i = 0; i < vsp1->info->wpf_count; ++i) { 52 51 struct vsp1_rwpf *wpf = vsp1->wpf[i]; 53 - struct vsp1_pipeline *pipe; 54 52 55 53 if (wpf == NULL) 56 54 continue; 57 55 58 - pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); 59 56 status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); 60 57 vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); 61 58 62 59 if (status & VI6_WFP_IRQ_STA_FRE) { 63 - vsp1_pipeline_frame_end(pipe); 60 + vsp1_pipeline_frame_end(wpf->pipe); 64 61 ret = IRQ_HANDLED; 65 62 } 66 63 } ··· 67 68 vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST); 68 69 69 70 if (status & VI6_DISP_IRQ_STA_DST) { 70 - struct vsp1_rwpf *wpf = vsp1->wpf[0]; 71 - struct vsp1_pipeline *pipe; 72 - 73 - if (wpf) { 74 - pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); 75 - vsp1_pipeline_display_start(pipe); 76 - } 77 - 71 + vsp1_drm_display_start(vsp1); 78 72 ret = IRQ_HANDLED; 79 73 } 80 74 ··· 379 387 /* Register subdev nodes if the userspace API is enabled or initialize 380 388 * the DRM pipeline otherwise. 381 389 */ 382 - if (vsp1->info->uapi) { 383 - vsp1->use_dl = false; 390 + if (vsp1->info->uapi) 384 391 ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); 385 - } else { 386 - vsp1->use_dl = true; 392 + else 387 393 ret = vsp1_drm_init(vsp1); 388 - } 389 394 if (ret < 0) 390 395 goto done; 391 396 ··· 454 465 vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 455 466 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 456 467 457 - if (vsp1->use_dl) 458 - vsp1_dl_setup(vsp1); 468 + vsp1_dlm_setup(vsp1); 459 469 460 470 return 0; 461 471 } ··· 558 570 static const struct vsp1_device_info vsp1_device_infos[] = { 559 571 { 560 572 .version = VI6_IP_VERSION_MODEL_VSPS_H2, 573 + .gen = 2, 561 574 .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, 562 575 .rpf_count = 5, 563 576 .uds_count = 3, ··· 567 578 .uapi = true, 568 579 }, { 569 580 .version = VI6_IP_VERSION_MODEL_VSPR_H2, 581 + .gen = 2, 570 582 .features = VSP1_HAS_BRU | VSP1_HAS_SRU, 571 583 .rpf_count = 5, 572 584 .uds_count = 1, ··· 576 586 .uapi = true, 577 587 }, { 578 588 .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, 589 + .gen = 2, 579 590 .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, 580 591 .rpf_count = 4, 581 592 .uds_count = 1, ··· 585 594 .uapi = true, 586 595 }, { 587 596 .version = VI6_IP_VERSION_MODEL_VSPS_M2, 597 + .gen = 2, 588 598 .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, 589 599 .rpf_count = 5, 590 600 .uds_count = 3, ··· 594 602 .uapi = true, 595 603 }, { 596 604 .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, 605 + .gen = 3, 597 606 .features = VSP1_HAS_LUT | VSP1_HAS_SRU, 598 607 .rpf_count = 1, 599 608 .uds_count = 1, ··· 602 609 .uapi = true, 603 610 }, { 604 611 .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, 612 + .gen = 3, 605 613 .features = VSP1_HAS_BRU, 606 614 .rpf_count = 5, 607 615 .wpf_count = 1, ··· 610 616 .uapi = true, 611 617 }, { 612 618 .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, 619 + .gen = 3, 613 620 .features = VSP1_HAS_BRU | VSP1_HAS_LUT, 614 621 .rpf_count = 5, 615 622 .wpf_count = 1, ··· 618 623 .uapi = true, 619 624 }, { 620 625 .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, 621 - .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, 626 + .gen = 3, 627 + .features = VSP1_HAS_BRU | VSP1_HAS_LIF, 622 628 .rpf_count = 5, 623 629 .wpf_count = 2, 624 630 .num_bru_inputs = 5,
+214 -80
drivers/media/platform/vsp1/vsp1_entity.c
··· 19 19 #include <media/v4l2-subdev.h> 20 20 21 21 #include "vsp1.h" 22 + #include "vsp1_dl.h" 22 23 #include "vsp1_entity.h" 23 24 24 - bool vsp1_entity_is_streaming(struct vsp1_entity *entity) 25 - { 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) 25 + void vsp1_entity_route_setup(struct vsp1_entity *source, 26 + struct vsp1_dl_list *dl) 62 27 { 63 28 struct vsp1_entity *sink; 64 29 ··· 31 66 return; 32 67 33 68 sink = container_of(source->sink, struct vsp1_entity, subdev.entity); 34 - vsp1_mod_write(source, source->route->reg, 35 - sink->route->inputs[source->sink_pad]); 69 + vsp1_dl_list_write(dl, source->route->reg, 70 + sink->route->inputs[source->sink_pad]); 36 71 } 37 72 38 73 /* ----------------------------------------------------------------------------- 39 74 * V4L2 Subdevice Operations 40 75 */ 41 76 42 - struct v4l2_mbus_framefmt * 43 - vsp1_entity_get_pad_format(struct vsp1_entity *entity, 77 + /** 78 + * vsp1_entity_get_pad_config - Get the pad configuration for an entity 79 + * @entity: the entity 80 + * @cfg: the TRY pad configuration 81 + * @which: configuration selector (ACTIVE or TRY) 82 + * 83 + * Return the pad configuration requested by the which argument. The TRY 84 + * configuration is passed explicitly to the function through the cfg argument 85 + * and simply returned when requested. The ACTIVE configuration comes from the 86 + * entity structure. 87 + */ 88 + struct v4l2_subdev_pad_config * 89 + vsp1_entity_get_pad_config(struct vsp1_entity *entity, 44 90 struct v4l2_subdev_pad_config *cfg, 45 - unsigned int pad, u32 which) 91 + enum v4l2_subdev_format_whence which) 46 92 { 47 93 switch (which) { 48 - case V4L2_SUBDEV_FORMAT_TRY: 49 - return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); 50 94 case V4L2_SUBDEV_FORMAT_ACTIVE: 51 - return &entity->formats[pad]; 95 + return entity->config; 96 + case V4L2_SUBDEV_FORMAT_TRY: 52 97 default: 53 - return NULL; 98 + return cfg; 54 99 } 55 100 } 56 101 102 + /** 103 + * vsp1_entity_get_pad_format - Get a pad format from storage for an entity 104 + * @entity: the entity 105 + * @cfg: the configuration storage 106 + * @pad: the pad number 107 + * 108 + * Return the format stored in the given configuration for an entity's pad. The 109 + * configuration can be an ACTIVE or TRY configuration. 110 + */ 111 + struct v4l2_mbus_framefmt * 112 + vsp1_entity_get_pad_format(struct vsp1_entity *entity, 113 + struct v4l2_subdev_pad_config *cfg, 114 + unsigned int pad) 115 + { 116 + return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); 117 + } 118 + 119 + struct v4l2_rect * 120 + vsp1_entity_get_pad_compose(struct vsp1_entity *entity, 121 + struct v4l2_subdev_pad_config *cfg, 122 + unsigned int pad) 123 + { 124 + return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad); 125 + } 126 + 57 127 /* 58 - * vsp1_entity_init_formats - Initialize formats on all pads 128 + * vsp1_entity_init_cfg - Initialize formats on all pads 59 129 * @subdev: V4L2 subdevice 60 130 * @cfg: V4L2 subdev pad configuration 61 131 * 62 - * Initialize all pad formats with default values. If cfg is not NULL, try 63 - * formats are initialized on the file handle. Otherwise active formats are 64 - * initialized on the device. 132 + * Initialize all pad formats with default values in the given pad config. This 133 + * function can be used as a handler for the subdev pad::init_cfg operation. 65 134 */ 66 - void vsp1_entity_init_formats(struct v4l2_subdev *subdev, 67 - struct v4l2_subdev_pad_config *cfg) 135 + int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, 136 + struct v4l2_subdev_pad_config *cfg) 68 137 { 69 138 struct v4l2_subdev_format format; 70 139 unsigned int pad; ··· 112 113 113 114 v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format); 114 115 } 115 - } 116 - 117 - static int vsp1_entity_open(struct v4l2_subdev *subdev, 118 - struct v4l2_subdev_fh *fh) 119 - { 120 - vsp1_entity_init_formats(subdev, fh->pad); 121 116 122 117 return 0; 123 118 } 124 119 125 - const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = { 126 - .open = vsp1_entity_open, 127 - }; 120 + /* 121 + * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler 122 + * @subdev: V4L2 subdevice 123 + * @cfg: V4L2 subdev pad configuration 124 + * @fmt: V4L2 subdev format 125 + * 126 + * This function implements the subdev get_fmt pad operation. It can be used as 127 + * a direct drop-in for the operation handler. 128 + */ 129 + int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, 130 + struct v4l2_subdev_pad_config *cfg, 131 + struct v4l2_subdev_format *fmt) 132 + { 133 + struct vsp1_entity *entity = to_vsp1_entity(subdev); 134 + struct v4l2_subdev_pad_config *config; 135 + 136 + config = vsp1_entity_get_pad_config(entity, cfg, fmt->which); 137 + if (!config) 138 + return -EINVAL; 139 + 140 + fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad); 141 + 142 + return 0; 143 + } 144 + 145 + /* 146 + * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler 147 + * @subdev: V4L2 subdevice 148 + * @cfg: V4L2 subdev pad configuration 149 + * @code: Media bus code enumeration 150 + * @codes: Array of supported media bus codes 151 + * @ncodes: Number of supported media bus codes 152 + * 153 + * This function implements the subdev enum_mbus_code pad operation for entities 154 + * that do not support format conversion. It enumerates the given supported 155 + * media bus codes on the sink pad and reports a source pad format identical to 156 + * the sink pad. 157 + */ 158 + int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, 159 + struct v4l2_subdev_pad_config *cfg, 160 + struct v4l2_subdev_mbus_code_enum *code, 161 + const unsigned int *codes, unsigned int ncodes) 162 + { 163 + struct vsp1_entity *entity = to_vsp1_entity(subdev); 164 + 165 + if (code->pad == 0) { 166 + if (code->index >= ncodes) 167 + return -EINVAL; 168 + 169 + code->code = codes[code->index]; 170 + } else { 171 + struct v4l2_subdev_pad_config *config; 172 + struct v4l2_mbus_framefmt *format; 173 + 174 + /* The entity can't perform format conversion, the sink format 175 + * is always identical to the source format. 176 + */ 177 + if (code->index) 178 + return -EINVAL; 179 + 180 + config = vsp1_entity_get_pad_config(entity, cfg, code->which); 181 + if (!config) 182 + return -EINVAL; 183 + 184 + format = vsp1_entity_get_pad_format(entity, config, 0); 185 + code->code = format->code; 186 + } 187 + 188 + return 0; 189 + } 190 + 191 + /* 192 + * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler 193 + * @subdev: V4L2 subdevice 194 + * @cfg: V4L2 subdev pad configuration 195 + * @fse: Frame size enumeration 196 + * @min_width: Minimum image width 197 + * @min_height: Minimum image height 198 + * @max_width: Maximum image width 199 + * @max_height: Maximum image height 200 + * 201 + * This function implements the subdev enum_frame_size pad operation for 202 + * entities that do not support scaling or cropping. It reports the given 203 + * minimum and maximum frame width and height on the sink pad, and a fixed 204 + * source pad size identical to the sink pad. 205 + */ 206 + int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, 207 + struct v4l2_subdev_pad_config *cfg, 208 + struct v4l2_subdev_frame_size_enum *fse, 209 + unsigned int min_width, unsigned int min_height, 210 + unsigned int max_width, unsigned int max_height) 211 + { 212 + struct vsp1_entity *entity = to_vsp1_entity(subdev); 213 + struct v4l2_subdev_pad_config *config; 214 + struct v4l2_mbus_framefmt *format; 215 + 216 + config = vsp1_entity_get_pad_config(entity, cfg, fse->which); 217 + if (!config) 218 + return -EINVAL; 219 + 220 + format = vsp1_entity_get_pad_format(entity, config, fse->pad); 221 + 222 + if (fse->index || fse->code != format->code) 223 + return -EINVAL; 224 + 225 + if (fse->pad == 0) { 226 + fse->min_width = min_width; 227 + fse->max_width = max_width; 228 + fse->min_height = min_height; 229 + fse->max_height = max_height; 230 + } else { 231 + /* The size on the source pad are fixed and always identical to 232 + * the size on the sink pad. 233 + */ 234 + fse->min_width = format->width; 235 + fse->max_width = format->width; 236 + fse->min_height = format->height; 237 + fse->max_height = format->height; 238 + } 239 + 240 + return 0; 241 + } 128 242 129 243 /* ----------------------------------------------------------------------------- 130 244 * Media Operations ··· 283 171 { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, 284 172 { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, 285 173 { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, 286 - { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } }, 287 - { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } }, 288 - { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } }, 289 - { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } }, 290 - { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } }, 174 + { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { 0, } }, 175 + { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { 0, } }, 176 + { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { 0, } }, 177 + { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { 0, } }, 178 + { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { 0, } }, 291 179 { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, 292 180 { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, 293 181 { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, ··· 299 187 }; 300 188 301 189 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, 302 - unsigned int num_pads) 190 + const char *name, unsigned int num_pads, 191 + const struct v4l2_subdev_ops *ops) 303 192 { 193 + struct v4l2_subdev *subdev; 304 194 unsigned int i; 195 + int ret; 305 196 306 197 for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) { 307 198 if (vsp1_routes[i].type == entity->type && ··· 317 202 if (i == ARRAY_SIZE(vsp1_routes)) 318 203 return -EINVAL; 319 204 320 - spin_lock_init(&entity->lock); 321 - 322 205 entity->vsp1 = vsp1; 323 206 entity->source_pad = num_pads - 1; 324 207 325 - /* Allocate formats and pads. */ 326 - entity->formats = devm_kzalloc(vsp1->dev, 327 - num_pads * sizeof(*entity->formats), 328 - GFP_KERNEL); 329 - if (entity->formats == NULL) 330 - return -ENOMEM; 331 - 208 + /* Allocate and initialize pads. */ 332 209 entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads), 333 210 GFP_KERNEL); 334 211 if (entity->pads == NULL) 335 212 return -ENOMEM; 336 213 337 - /* Initialize pads. */ 338 214 for (i = 0; i < num_pads - 1; ++i) 339 215 entity->pads[i].flags = MEDIA_PAD_FL_SINK; 340 216 341 217 entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE; 342 218 343 219 /* Initialize the media entity. */ 344 - return media_entity_pads_init(&entity->subdev.entity, num_pads, 345 - entity->pads); 220 + ret = media_entity_pads_init(&entity->subdev.entity, num_pads, 221 + entity->pads); 222 + if (ret < 0) 223 + return ret; 224 + 225 + /* Initialize the V4L2 subdev. */ 226 + subdev = &entity->subdev; 227 + v4l2_subdev_init(subdev, ops); 228 + 229 + subdev->entity.ops = &vsp1->media_ops; 230 + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 231 + 232 + snprintf(subdev->name, sizeof(subdev->name), "%s %s", 233 + dev_name(vsp1->dev), name); 234 + 235 + vsp1_entity_init_cfg(subdev, NULL); 236 + 237 + /* Allocate the pad configuration to store formats and selection 238 + * rectangles. 239 + */ 240 + entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev); 241 + if (entity->config == NULL) { 242 + media_entity_cleanup(&entity->subdev.entity); 243 + return -ENOMEM; 244 + } 245 + 246 + return 0; 346 247 } 347 248 348 249 void vsp1_entity_destroy(struct vsp1_entity *entity) 349 250 { 251 + if (entity->ops && entity->ops->destroy) 252 + entity->ops->destroy(entity); 350 253 if (entity->subdev.ctrl_handler) 351 254 v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); 255 + v4l2_subdev_free_pad_config(entity->config); 352 256 media_entity_cleanup(&entity->subdev.entity); 353 257 }
+48 -11
drivers/media/platform/vsp1/vsp1_entity.h
··· 19 19 #include <media/v4l2-subdev.h> 20 20 21 21 struct vsp1_device; 22 + struct vsp1_dl_list; 23 + struct vsp1_pipeline; 22 24 23 25 enum vsp1_entity_type { 24 26 VSP1_ENTITY_BRU, ··· 55 53 unsigned int inputs[VSP1_ENTITY_MAX_INPUTS]; 56 54 }; 57 55 56 + /** 57 + * struct vsp1_entity_operations - Entity operations 58 + * @destroy: Destroy the entity. 59 + * @set_memory: Setup memory buffer access. This operation applies the settings 60 + * stored in the rwpf mem field to the display list. Valid for RPF 61 + * and WPF only. 62 + * @configure: Setup the hardware based on the entity state (pipeline, formats, 63 + * selection rectangles, ...) 64 + */ 65 + struct vsp1_entity_operations { 66 + void (*destroy)(struct vsp1_entity *); 67 + void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl); 68 + void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, 69 + struct vsp1_dl_list *); 70 + }; 71 + 58 72 struct vsp1_entity { 59 73 struct vsp1_device *vsp1; 74 + 75 + const struct vsp1_entity_operations *ops; 60 76 61 77 enum vsp1_entity_type type; 62 78 unsigned int index; ··· 90 70 unsigned int sink_pad; 91 71 92 72 struct v4l2_subdev subdev; 93 - struct v4l2_mbus_framefmt *formats; 94 - 95 - spinlock_t lock; /* Protects the streaming field */ 96 - bool streaming; 73 + struct v4l2_subdev_pad_config *config; 97 74 }; 98 75 99 76 static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) ··· 99 82 } 100 83 101 84 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, 102 - unsigned int num_pads); 85 + const char *name, unsigned int num_pads, 86 + const struct v4l2_subdev_ops *ops); 103 87 void vsp1_entity_destroy(struct vsp1_entity *entity); 104 88 105 89 extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops; ··· 109 91 const struct media_pad *local, 110 92 const struct media_pad *remote, u32 flags); 111 93 94 + struct v4l2_subdev_pad_config * 95 + vsp1_entity_get_pad_config(struct vsp1_entity *entity, 96 + struct v4l2_subdev_pad_config *cfg, 97 + enum v4l2_subdev_format_whence which); 112 98 struct v4l2_mbus_framefmt * 113 99 vsp1_entity_get_pad_format(struct vsp1_entity *entity, 114 100 struct v4l2_subdev_pad_config *cfg, 115 - unsigned int pad, u32 which); 116 - void vsp1_entity_init_formats(struct v4l2_subdev *subdev, 117 - struct v4l2_subdev_pad_config *cfg); 101 + unsigned int pad); 102 + struct v4l2_rect * 103 + vsp1_entity_get_pad_compose(struct vsp1_entity *entity, 104 + struct v4l2_subdev_pad_config *cfg, 105 + unsigned int pad); 106 + int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, 107 + struct v4l2_subdev_pad_config *cfg); 118 108 119 - bool vsp1_entity_is_streaming(struct vsp1_entity *entity); 120 - int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming); 109 + void vsp1_entity_route_setup(struct vsp1_entity *source, 110 + struct vsp1_dl_list *dl); 121 111 122 - void vsp1_entity_route_setup(struct vsp1_entity *source); 112 + int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, 113 + struct v4l2_subdev_pad_config *cfg, 114 + struct v4l2_subdev_format *fmt); 115 + int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, 116 + struct v4l2_subdev_pad_config *cfg, 117 + struct v4l2_subdev_mbus_code_enum *code, 118 + const unsigned int *codes, unsigned int ncodes); 119 + int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, 120 + struct v4l2_subdev_pad_config *cfg, 121 + struct v4l2_subdev_frame_size_enum *fse, 122 + unsigned int min_w, unsigned int min_h, 123 + unsigned int max_w, unsigned int max_h); 123 124 124 125 #endif /* __VSP1_ENTITY_H__ */
+42 -88
drivers/media/platform/vsp1/vsp1_hsit.c
··· 17 17 #include <media/v4l2-subdev.h> 18 18 19 19 #include "vsp1.h" 20 + #include "vsp1_dl.h" 20 21 #include "vsp1_hsit.h" 21 22 22 23 #define HSIT_MIN_SIZE 4U ··· 27 26 * Device Access 28 27 */ 29 28 30 - static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data) 29 + static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, 30 + struct vsp1_dl_list *dl, u32 reg, u32 data) 31 31 { 32 - vsp1_write(hsit->entity.vsp1, reg, data); 32 + vsp1_dl_list_write(dl, reg, data); 33 33 } 34 34 35 35 /* ----------------------------------------------------------------------------- 36 - * V4L2 Subdevice Core Operations 37 - */ 38 - 39 - static int hsit_s_stream(struct v4l2_subdev *subdev, int enable) 40 - { 41 - struct vsp1_hsit *hsit = to_hsit(subdev); 42 - 43 - if (!enable) 44 - return 0; 45 - 46 - if (hsit->inverse) 47 - vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); 48 - else 49 - vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN); 50 - 51 - return 0; 52 - } 53 - 54 - /* ----------------------------------------------------------------------------- 55 - * V4L2 Subdevice Pad Operations 36 + * V4L2 Subdevice Operations 56 37 */ 57 38 58 39 static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, ··· 59 76 struct v4l2_subdev_pad_config *cfg, 60 77 struct v4l2_subdev_frame_size_enum *fse) 61 78 { 62 - struct vsp1_hsit *hsit = to_hsit(subdev); 63 - struct v4l2_mbus_framefmt *format; 64 - 65 - format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad, 66 - fse->which); 67 - 68 - if (fse->index || fse->code != format->code) 69 - return -EINVAL; 70 - 71 - if (fse->pad == HSIT_PAD_SINK) { 72 - fse->min_width = HSIT_MIN_SIZE; 73 - fse->max_width = HSIT_MAX_SIZE; 74 - fse->min_height = HSIT_MIN_SIZE; 75 - fse->max_height = HSIT_MAX_SIZE; 76 - } else { 77 - /* The size on the source pad are fixed and always identical to 78 - * the size on the sink pad. 79 - */ 80 - fse->min_width = format->width; 81 - fse->max_width = format->width; 82 - fse->min_height = format->height; 83 - fse->max_height = format->height; 84 - } 85 - 86 - return 0; 87 - } 88 - 89 - static int hsit_get_format(struct v4l2_subdev *subdev, 90 - struct v4l2_subdev_pad_config *cfg, 91 - struct v4l2_subdev_format *fmt) 92 - { 93 - struct vsp1_hsit *hsit = to_hsit(subdev); 94 - 95 - fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, 96 - fmt->which); 97 - 98 - return 0; 79 + return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HSIT_MIN_SIZE, 80 + HSIT_MIN_SIZE, HSIT_MAX_SIZE, 81 + HSIT_MAX_SIZE); 99 82 } 100 83 101 84 static int hsit_set_format(struct v4l2_subdev *subdev, ··· 69 120 struct v4l2_subdev_format *fmt) 70 121 { 71 122 struct vsp1_hsit *hsit = to_hsit(subdev); 123 + struct v4l2_subdev_pad_config *config; 72 124 struct v4l2_mbus_framefmt *format; 73 125 74 - format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, 75 - fmt->which); 126 + config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which); 127 + if (!config) 128 + return -EINVAL; 129 + 130 + format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); 76 131 77 132 if (fmt->pad == HSIT_PAD_SOURCE) { 78 133 /* The HST and HSI output format code and resolution can't be ··· 98 145 fmt->format = *format; 99 146 100 147 /* Propagate the format to the source pad. */ 101 - format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE, 102 - fmt->which); 148 + format = vsp1_entity_get_pad_format(&hsit->entity, config, 149 + HSIT_PAD_SOURCE); 103 150 *format = fmt->format; 104 151 format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 105 152 : MEDIA_BUS_FMT_AHSV8888_1X32; ··· 107 154 return 0; 108 155 } 109 156 110 - /* ----------------------------------------------------------------------------- 111 - * V4L2 Subdevice Operations 112 - */ 113 - 114 - static struct v4l2_subdev_video_ops hsit_video_ops = { 115 - .s_stream = hsit_s_stream, 116 - }; 117 - 118 157 static struct v4l2_subdev_pad_ops hsit_pad_ops = { 158 + .init_cfg = vsp1_entity_init_cfg, 119 159 .enum_mbus_code = hsit_enum_mbus_code, 120 160 .enum_frame_size = hsit_enum_frame_size, 121 - .get_fmt = hsit_get_format, 161 + .get_fmt = vsp1_subdev_get_pad_format, 122 162 .set_fmt = hsit_set_format, 123 163 }; 124 164 125 165 static struct v4l2_subdev_ops hsit_ops = { 126 - .video = &hsit_video_ops, 127 166 .pad = &hsit_pad_ops, 167 + }; 168 + 169 + /* ----------------------------------------------------------------------------- 170 + * VSP1 Entity Operations 171 + */ 172 + 173 + static void hsit_configure(struct vsp1_entity *entity, 174 + struct vsp1_pipeline *pipe, 175 + struct vsp1_dl_list *dl) 176 + { 177 + struct vsp1_hsit *hsit = to_hsit(&entity->subdev); 178 + 179 + if (hsit->inverse) 180 + vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); 181 + else 182 + vsp1_hsit_write(hsit, dl, VI6_HST_CTRL, VI6_HST_CTRL_EN); 183 + } 184 + 185 + static const struct vsp1_entity_operations hsit_entity_ops = { 186 + .configure = hsit_configure, 128 187 }; 129 188 130 189 /* ----------------------------------------------------------------------------- ··· 145 180 146 181 struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) 147 182 { 148 - struct v4l2_subdev *subdev; 149 183 struct vsp1_hsit *hsit; 150 184 int ret; 151 185 ··· 154 190 155 191 hsit->inverse = inverse; 156 192 193 + hsit->entity.ops = &hsit_entity_ops; 194 + 157 195 if (inverse) 158 196 hsit->entity.type = VSP1_ENTITY_HSI; 159 197 else 160 198 hsit->entity.type = VSP1_ENTITY_HST; 161 199 162 - ret = vsp1_entity_init(vsp1, &hsit->entity, 2); 200 + ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2, 201 + &hsit_ops); 163 202 if (ret < 0) 164 203 return ERR_PTR(ret); 165 - 166 - /* Initialize the V4L2 subdev. */ 167 - subdev = &hsit->entity.subdev; 168 - v4l2_subdev_init(subdev, &hsit_ops); 169 - 170 - subdev->entity.ops = &vsp1->media_ops; 171 - subdev->internal_ops = &vsp1_subdev_internal_ops; 172 - snprintf(subdev->name, sizeof(subdev->name), "%s %s", 173 - dev_name(vsp1->dev), inverse ? "hsi" : "hst"); 174 - v4l2_set_subdevdata(subdev, hsit); 175 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 176 - 177 - vsp1_entity_init_formats(subdev, NULL); 178 204 179 205 return hsit; 180 206 }
+60 -123
drivers/media/platform/vsp1/vsp1_lif.c
··· 17 17 #include <media/v4l2-subdev.h> 18 18 19 19 #include "vsp1.h" 20 + #include "vsp1_dl.h" 20 21 #include "vsp1_lif.h" 21 22 22 23 #define LIF_MIN_SIZE 2U 23 - #define LIF_MAX_SIZE 2048U 24 + #define LIF_MAX_SIZE 8190U 24 25 25 26 /* ----------------------------------------------------------------------------- 26 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 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 37 + * V4L2 Subdevice Operations 69 38 */ 70 39 71 40 static int lif_enum_mbus_code(struct v4l2_subdev *subdev, ··· 45 76 MEDIA_BUS_FMT_ARGB8888_1X32, 46 77 MEDIA_BUS_FMT_AYUV8_1X32, 47 78 }; 48 - struct vsp1_lif *lif = to_lif(subdev); 49 79 50 - if (code->pad == LIF_PAD_SINK) { 51 - if (code->index >= ARRAY_SIZE(codes)) 52 - return -EINVAL; 53 - 54 - code->code = codes[code->index]; 55 - } else { 56 - struct v4l2_mbus_framefmt *format; 57 - 58 - /* The LIF can't perform format conversion, the sink format is 59 - * always identical to the source format. 60 - */ 61 - if (code->index) 62 - return -EINVAL; 63 - 64 - format = vsp1_entity_get_pad_format(&lif->entity, cfg, 65 - LIF_PAD_SINK, code->which); 66 - code->code = format->code; 67 - } 68 - 69 - return 0; 80 + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, 81 + ARRAY_SIZE(codes)); 70 82 } 71 83 72 84 static int lif_enum_frame_size(struct v4l2_subdev *subdev, 73 85 struct v4l2_subdev_pad_config *cfg, 74 86 struct v4l2_subdev_frame_size_enum *fse) 75 87 { 88 + return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE, 89 + LIF_MIN_SIZE, LIF_MAX_SIZE, 90 + LIF_MAX_SIZE); 91 + } 92 + 93 + static int lif_set_format(struct v4l2_subdev *subdev, 94 + struct v4l2_subdev_pad_config *cfg, 95 + struct v4l2_subdev_format *fmt) 96 + { 76 97 struct vsp1_lif *lif = to_lif(subdev); 98 + struct v4l2_subdev_pad_config *config; 77 99 struct v4l2_mbus_framefmt *format; 78 100 79 - format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK, 80 - fse->which); 81 - 82 - if (fse->index || fse->code != format->code) 101 + config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which); 102 + if (!config) 83 103 return -EINVAL; 84 - 85 - if (fse->pad == LIF_PAD_SINK) { 86 - fse->min_width = LIF_MIN_SIZE; 87 - fse->max_width = LIF_MAX_SIZE; 88 - fse->min_height = LIF_MIN_SIZE; 89 - fse->max_height = LIF_MAX_SIZE; 90 - } else { 91 - fse->min_width = format->width; 92 - fse->max_width = format->width; 93 - fse->min_height = format->height; 94 - fse->max_height = format->height; 95 - } 96 - 97 - return 0; 98 - } 99 - 100 - static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 101 - struct v4l2_subdev_format *fmt) 102 - { 103 - struct vsp1_lif *lif = to_lif(subdev); 104 - 105 - fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, 106 - fmt->which); 107 - 108 - return 0; 109 - } 110 - 111 - static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 112 - struct v4l2_subdev_format *fmt) 113 - { 114 - struct vsp1_lif *lif = to_lif(subdev); 115 - struct v4l2_mbus_framefmt *format; 116 104 117 105 /* Default to YUV if the requested format is not supported. */ 118 106 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && 119 107 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) 120 108 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; 121 109 122 - format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, 123 - fmt->which); 110 + format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad); 124 111 125 112 if (fmt->pad == LIF_PAD_SOURCE) { 126 113 /* The LIF source format is always identical to its sink ··· 97 172 fmt->format = *format; 98 173 99 174 /* Propagate the format to the source pad. */ 100 - format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE, 101 - fmt->which); 175 + format = vsp1_entity_get_pad_format(&lif->entity, config, 176 + LIF_PAD_SOURCE); 102 177 *format = fmt->format; 103 178 104 179 return 0; 105 180 } 106 181 107 - /* ----------------------------------------------------------------------------- 108 - * V4L2 Subdevice Operations 109 - */ 110 - 111 - static struct v4l2_subdev_video_ops lif_video_ops = { 112 - .s_stream = lif_s_stream, 113 - }; 114 - 115 182 static struct v4l2_subdev_pad_ops lif_pad_ops = { 183 + .init_cfg = vsp1_entity_init_cfg, 116 184 .enum_mbus_code = lif_enum_mbus_code, 117 185 .enum_frame_size = lif_enum_frame_size, 118 - .get_fmt = lif_get_format, 186 + .get_fmt = vsp1_subdev_get_pad_format, 119 187 .set_fmt = lif_set_format, 120 188 }; 121 189 122 190 static struct v4l2_subdev_ops lif_ops = { 123 - .video = &lif_video_ops, 124 191 .pad = &lif_pad_ops, 192 + }; 193 + 194 + /* ----------------------------------------------------------------------------- 195 + * VSP1 Entity Operations 196 + */ 197 + 198 + static void lif_configure(struct vsp1_entity *entity, 199 + struct vsp1_pipeline *pipe, 200 + struct vsp1_dl_list *dl) 201 + { 202 + const struct v4l2_mbus_framefmt *format; 203 + struct vsp1_lif *lif = to_lif(&entity->subdev); 204 + unsigned int hbth = 1300; 205 + unsigned int obth = 400; 206 + unsigned int lbth = 200; 207 + 208 + format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, 209 + LIF_PAD_SOURCE); 210 + 211 + obth = min(obth, (format->width + 1) / 2 * format->height - 4); 212 + 213 + vsp1_lif_write(lif, dl, VI6_LIF_CSBTH, 214 + (hbth << VI6_LIF_CSBTH_HBTH_SHIFT) | 215 + (lbth << VI6_LIF_CSBTH_LBTH_SHIFT)); 216 + 217 + vsp1_lif_write(lif, dl, VI6_LIF_CTRL, 218 + (obth << VI6_LIF_CTRL_OBTH_SHIFT) | 219 + (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | 220 + VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); 221 + } 222 + 223 + static const struct vsp1_entity_operations lif_entity_ops = { 224 + .configure = lif_configure, 125 225 }; 126 226 127 227 /* ----------------------------------------------------------------------------- ··· 155 205 156 206 struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) 157 207 { 158 - struct v4l2_subdev *subdev; 159 208 struct vsp1_lif *lif; 160 209 int ret; 161 210 ··· 162 213 if (lif == NULL) 163 214 return ERR_PTR(-ENOMEM); 164 215 216 + lif->entity.ops = &lif_entity_ops; 165 217 lif->entity.type = VSP1_ENTITY_LIF; 166 218 167 - ret = vsp1_entity_init(vsp1, &lif->entity, 2); 219 + ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops); 168 220 if (ret < 0) 169 221 return ERR_PTR(ret); 170 - 171 - /* Initialize the V4L2 subdev. */ 172 - subdev = &lif->entity.subdev; 173 - v4l2_subdev_init(subdev, &lif_ops); 174 - 175 - subdev->entity.ops = &vsp1->media_ops; 176 - subdev->internal_ops = &vsp1_subdev_internal_ops; 177 - snprintf(subdev->name, sizeof(subdev->name), "%s lif", 178 - dev_name(vsp1->dev)); 179 - v4l2_set_subdevdata(subdev, lif); 180 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 181 - 182 - vsp1_entity_init_formats(subdev, NULL); 183 222 184 223 return lif; 185 224 }
+69 -107
drivers/media/platform/vsp1/vsp1_lut.c
··· 18 18 #include <media/v4l2-subdev.h> 19 19 20 20 #include "vsp1.h" 21 + #include "vsp1_dl.h" 21 22 #include "vsp1_lut.h" 22 23 23 24 #define LUT_MIN_SIZE 4U ··· 28 27 * Device Access 29 28 */ 30 29 31 - static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data) 30 + static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl, 31 + u32 reg, u32 data) 32 32 { 33 - vsp1_write(lut->entity.vsp1, reg, data); 33 + vsp1_dl_list_write(dl, reg, data); 34 34 } 35 35 36 36 /* ----------------------------------------------------------------------------- 37 37 * V4L2 Subdevice Core Operations 38 38 */ 39 39 40 - static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config) 40 + static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config) 41 41 { 42 - memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut, 43 - sizeof(config->lut)); 42 + struct vsp1_dl_body *dlb; 43 + unsigned int i; 44 + 45 + dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut)); 46 + if (!dlb) 47 + return -ENOMEM; 48 + 49 + for (i = 0; i < ARRAY_SIZE(config->lut); ++i) 50 + vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, 51 + config->lut[i]); 52 + 53 + mutex_lock(&lut->lock); 54 + swap(lut->lut, dlb); 55 + mutex_unlock(&lut->lock); 56 + 57 + vsp1_dl_fragment_free(dlb); 58 + return 0; 44 59 } 45 60 46 61 static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) ··· 65 48 66 49 switch (cmd) { 67 50 case VIDIOC_VSP1_LUT_CONFIG: 68 - lut_configure(lut, arg); 69 - return 0; 51 + return lut_set_table(lut, arg); 70 52 71 53 default: 72 54 return -ENOIOCTLCMD; 73 55 } 74 - } 75 - 76 - /* ----------------------------------------------------------------------------- 77 - * V4L2 Subdevice Video Operations 78 - */ 79 - 80 - static int lut_s_stream(struct v4l2_subdev *subdev, int enable) 81 - { 82 - struct vsp1_lut *lut = to_lut(subdev); 83 - 84 - if (!enable) 85 - return 0; 86 - 87 - vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); 88 - 89 - return 0; 90 56 } 91 57 92 58 /* ----------------------------------------------------------------------------- ··· 85 85 MEDIA_BUS_FMT_AHSV8888_1X32, 86 86 MEDIA_BUS_FMT_AYUV8_1X32, 87 87 }; 88 - struct vsp1_lut *lut = to_lut(subdev); 89 - struct v4l2_mbus_framefmt *format; 90 88 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 - 108 - return 0; 89 + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, 90 + ARRAY_SIZE(codes)); 109 91 } 110 92 111 93 static int lut_enum_frame_size(struct v4l2_subdev *subdev, 112 94 struct v4l2_subdev_pad_config *cfg, 113 95 struct v4l2_subdev_frame_size_enum *fse) 114 96 { 97 + return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE, 98 + LUT_MIN_SIZE, LUT_MAX_SIZE, 99 + LUT_MAX_SIZE); 100 + } 101 + 102 + static int lut_set_format(struct v4l2_subdev *subdev, 103 + struct v4l2_subdev_pad_config *cfg, 104 + struct v4l2_subdev_format *fmt) 105 + { 115 106 struct vsp1_lut *lut = to_lut(subdev); 107 + struct v4l2_subdev_pad_config *config; 116 108 struct v4l2_mbus_framefmt *format; 117 109 118 - format = vsp1_entity_get_pad_format(&lut->entity, cfg, 119 - fse->pad, fse->which); 120 - 121 - if (fse->index || fse->code != format->code) 110 + config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which); 111 + if (!config) 122 112 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 - } 152 - 153 - static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 154 - struct v4l2_subdev_format *fmt) 155 - { 156 - struct vsp1_lut *lut = to_lut(subdev); 157 - struct v4l2_mbus_framefmt *format; 158 113 159 114 /* Default to YUV if the requested format is not supported. */ 160 115 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && ··· 117 162 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) 118 163 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; 119 164 120 - format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, 121 - fmt->which); 165 + format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad); 122 166 123 167 if (fmt->pad == LUT_PAD_SOURCE) { 124 168 /* The LUT output format can't be modified. */ ··· 125 171 return 0; 126 172 } 127 173 174 + format->code = fmt->format.code; 128 175 format->width = clamp_t(unsigned int, fmt->format.width, 129 176 LUT_MIN_SIZE, LUT_MAX_SIZE); 130 177 format->height = clamp_t(unsigned int, fmt->format.height, ··· 136 181 fmt->format = *format; 137 182 138 183 /* Propagate the format to the source pad. */ 139 - format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE, 140 - fmt->which); 184 + format = vsp1_entity_get_pad_format(&lut->entity, config, 185 + LUT_PAD_SOURCE); 141 186 *format = fmt->format; 142 187 143 188 return 0; ··· 151 196 .ioctl = lut_ioctl, 152 197 }; 153 198 154 - static struct v4l2_subdev_video_ops lut_video_ops = { 155 - .s_stream = lut_s_stream, 156 - }; 157 - 158 199 static struct v4l2_subdev_pad_ops lut_pad_ops = { 200 + .init_cfg = vsp1_entity_init_cfg, 159 201 .enum_mbus_code = lut_enum_mbus_code, 160 202 .enum_frame_size = lut_enum_frame_size, 161 - .get_fmt = lut_get_format, 203 + .get_fmt = vsp1_subdev_get_pad_format, 162 204 .set_fmt = lut_set_format, 163 205 }; 164 206 165 207 static struct v4l2_subdev_ops lut_ops = { 166 208 .core = &lut_core_ops, 167 - .video = &lut_video_ops, 168 209 .pad = &lut_pad_ops, 210 + }; 211 + 212 + /* ----------------------------------------------------------------------------- 213 + * VSP1 Entity Operations 214 + */ 215 + 216 + static void lut_configure(struct vsp1_entity *entity, 217 + struct vsp1_pipeline *pipe, 218 + struct vsp1_dl_list *dl) 219 + { 220 + struct vsp1_lut *lut = to_lut(&entity->subdev); 221 + 222 + vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); 223 + 224 + mutex_lock(&lut->lock); 225 + if (lut->lut) { 226 + vsp1_dl_list_add_fragment(dl, lut->lut); 227 + lut->lut = NULL; 228 + } 229 + mutex_unlock(&lut->lock); 230 + } 231 + 232 + static const struct vsp1_entity_operations lut_entity_ops = { 233 + .configure = lut_configure, 169 234 }; 170 235 171 236 /* ----------------------------------------------------------------------------- ··· 194 219 195 220 struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) 196 221 { 197 - struct v4l2_subdev *subdev; 198 222 struct vsp1_lut *lut; 199 223 int ret; 200 224 ··· 201 227 if (lut == NULL) 202 228 return ERR_PTR(-ENOMEM); 203 229 230 + lut->entity.ops = &lut_entity_ops; 204 231 lut->entity.type = VSP1_ENTITY_LUT; 205 232 206 - ret = vsp1_entity_init(vsp1, &lut->entity, 2); 233 + ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops); 207 234 if (ret < 0) 208 235 return ERR_PTR(ret); 209 - 210 - /* Initialize the V4L2 subdev. */ 211 - subdev = &lut->entity.subdev; 212 - v4l2_subdev_init(subdev, &lut_ops); 213 - 214 - subdev->entity.ops = &vsp1->media_ops; 215 - subdev->internal_ops = &vsp1_subdev_internal_ops; 216 - snprintf(subdev->name, sizeof(subdev->name), "%s lut", 217 - dev_name(vsp1->dev)); 218 - v4l2_set_subdevdata(subdev, lut); 219 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 220 - 221 - vsp1_entity_init_formats(subdev, NULL); 222 236 223 237 return lut; 224 238 }
+5 -1
drivers/media/platform/vsp1/vsp1_lut.h
··· 13 13 #ifndef __VSP1_LUT_H__ 14 14 #define __VSP1_LUT_H__ 15 15 16 + #include <linux/mutex.h> 17 + 16 18 #include <media/media-entity.h> 17 19 #include <media/v4l2-subdev.h> 18 20 ··· 27 25 28 26 struct vsp1_lut { 29 27 struct vsp1_entity entity; 30 - u32 lut[256]; 28 + 29 + struct mutex lock; 30 + struct vsp1_dl_body *lut; 31 31 }; 32 32 33 33 static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev)
+23 -48
drivers/media/platform/vsp1/vsp1_pipe.c
··· 43 43 { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32, 44 44 VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 45 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 47 { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, 48 48 VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 49 49 VI6_RPF_DSWAP_P_WDS, ··· 172 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 177 pipe->inputs[i] = NULL; 178 + } 179 + 180 + pipe->output->pipe = NULL; 181 + pipe->output = NULL; 177 182 178 183 INIT_LIST_HEAD(&pipe->entities); 179 184 pipe->state = VSP1_PIPELINE_STOPPED; 180 185 pipe->buffers_ready = 0; 181 186 pipe->num_inputs = 0; 182 - pipe->output = NULL; 183 187 pipe->bru = NULL; 184 188 pipe->lif = NULL; 185 189 pipe->uds = NULL; ··· 194 190 mutex_init(&pipe->lock); 195 191 spin_lock_init(&pipe->irqlock); 196 192 init_waitqueue_head(&pipe->wq); 193 + kref_init(&pipe->kref); 197 194 198 195 INIT_LIST_HEAD(&pipe->entities); 199 196 pipe->state = VSP1_PIPELINE_STOPPED; 200 197 } 201 198 199 + /* Must be called with the pipe irqlock held. */ 202 200 void vsp1_pipeline_run(struct vsp1_pipeline *pipe) 203 201 { 204 202 struct vsp1_device *vsp1 = pipe->output->entity.vsp1; ··· 232 226 unsigned long flags; 233 227 int ret; 234 228 235 - if (pipe->dl) { 229 + if (pipe->lif) { 236 230 /* When using display lists in continuous frame mode the only 237 231 * way to stop the pipeline is to reset the hardware. 238 232 */ ··· 259 253 if (entity->route && entity->route->reg) 260 254 vsp1_write(entity->vsp1, entity->route->reg, 261 255 VI6_DPR_NODE_UNUSED); 262 - 263 - v4l2_subdev_call(&entity->subdev, video, s_stream, 0); 264 256 } 257 + 258 + v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0); 265 259 266 260 return ret; 267 261 } ··· 277 271 return pipe->buffers_ready == mask; 278 272 } 279 273 280 - void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe) 281 - { 282 - if (pipe->dl) 283 - vsp1_dl_irq_display_start(pipe->dl); 284 - } 285 - 286 274 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) 287 275 { 288 - enum vsp1_pipeline_state state; 289 - unsigned long flags; 290 - 291 276 if (pipe == NULL) 292 277 return; 293 278 294 - if (pipe->dl) 295 - vsp1_dl_irq_frame_end(pipe->dl); 279 + vsp1_dlm_irq_frame_end(pipe->output->dlm); 296 280 297 - /* Signal frame end to the pipeline handler. */ 298 - pipe->frame_end(pipe); 299 - 300 - spin_lock_irqsave(&pipe->irqlock, flags); 301 - 302 - state = pipe->state; 303 - 304 - /* When using display lists in continuous frame mode the pipeline is 305 - * automatically restarted by the hardware. 306 - */ 307 - if (!pipe->dl) 308 - pipe->state = VSP1_PIPELINE_STOPPED; 309 - 310 - /* If a stop has been requested, mark the pipeline as stopped and 311 - * return. 312 - */ 313 - if (state == VSP1_PIPELINE_STOPPING) { 314 - wake_up(&pipe->wq); 315 - goto done; 316 - } 317 - 318 - /* Restart the pipeline if ready. */ 319 - if (vsp1_pipeline_ready(pipe)) 320 - vsp1_pipeline_run(pipe); 321 - 322 - done: 323 - spin_unlock_irqrestore(&pipe->irqlock, flags); 281 + if (pipe->frame_end) 282 + pipe->frame_end(pipe); 324 283 } 325 284 326 285 /* ··· 295 324 * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha 296 325 * value. The UDS then outputs a fixed alpha value which needs to be programmed 297 326 * from the input RPF alpha. 327 + * 328 + * This function can only be called from a subdev s_stream handler as it 329 + * requires a valid display list context. 298 330 */ 299 331 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, 300 332 struct vsp1_entity *input, 333 + struct vsp1_dl_list *dl, 301 334 unsigned int alpha) 302 335 { 303 336 struct vsp1_entity *entity; ··· 324 349 if (entity->type == VSP1_ENTITY_UDS) { 325 350 struct vsp1_uds *uds = to_uds(&entity->subdev); 326 351 327 - vsp1_uds_set_alpha(uds, alpha); 352 + vsp1_uds_set_alpha(uds, dl, alpha); 328 353 break; 329 354 } 330 355 ··· 350 375 if (wpf == NULL) 351 376 continue; 352 377 353 - pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); 378 + pipe = wpf->pipe; 354 379 if (pipe == NULL) 355 380 continue; 356 381 ··· 367 392 if (wpf == NULL) 368 393 continue; 369 394 370 - pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); 395 + pipe = wpf->pipe; 371 396 if (pipe == NULL) 372 397 continue; 373 398 ··· 391 416 if (wpf == NULL) 392 417 continue; 393 418 394 - pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); 419 + pipe = wpf->pipe; 395 420 if (pipe == NULL) 396 421 continue; 397 422
+6 -13
drivers/media/platform/vsp1/vsp1_pipe.h
··· 13 13 #ifndef __VSP1_PIPE_H__ 14 14 #define __VSP1_PIPE_H__ 15 15 16 + #include <linux/kref.h> 16 17 #include <linux/list.h> 17 18 #include <linux/spinlock.h> 18 19 #include <linux/wait.h> 19 20 20 21 #include <media/media-entity.h> 21 22 22 - struct vsp1_dl; 23 + struct vsp1_dl_list; 23 24 struct vsp1_rwpf; 24 25 25 26 /* ··· 64 63 * @wq: work queue to wait for state change completion 65 64 * @frame_end: frame end interrupt handler 66 65 * @lock: protects the pipeline use count and stream count 67 - * @use_count: number of video nodes using the pipeline 66 + * @kref: pipeline reference count 68 67 * @stream_count: number of streaming video nodes 69 68 * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available 70 69 * @num_inputs: number of RPFs ··· 87 86 void (*frame_end)(struct vsp1_pipeline *pipe); 88 87 89 88 struct mutex lock; 90 - unsigned int use_count; 89 + struct kref kref; 91 90 unsigned int stream_count; 92 91 unsigned int buffers_ready; 93 92 ··· 101 100 102 101 struct list_head entities; 103 102 104 - struct vsp1_dl *dl; 103 + struct vsp1_dl_list *dl; 105 104 }; 106 - 107 - static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e) 108 - { 109 - if (likely(e->pipe)) 110 - return container_of(e->pipe, struct vsp1_pipeline, pipe); 111 - else 112 - return NULL; 113 - } 114 105 115 106 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); 116 107 void vsp1_pipeline_init(struct vsp1_pipeline *pipe); ··· 112 119 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe); 113 120 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe); 114 121 115 - void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe); 116 122 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); 117 123 118 124 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, 119 125 struct vsp1_entity *input, 126 + struct vsp1_dl_list *dl, 120 127 unsigned int alpha); 121 128 122 129 void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
+10
drivers/media/platform/vsp1/vsp1_regs.h
··· 217 217 #define VI6_RPF_SRCM_ADDR_C1 0x0344 218 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 231 * WPF Control Registers 222 232 */
+128 -149
drivers/media/platform/vsp1/vsp1_rpf.c
··· 16 16 #include <media/v4l2-subdev.h> 17 17 18 18 #include "vsp1.h" 19 + #include "vsp1_dl.h" 20 + #include "vsp1_pipe.h" 19 21 #include "vsp1_rwpf.h" 20 22 #include "vsp1_video.h" 21 23 ··· 28 26 * Device Access 29 27 */ 30 28 31 - static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data) 29 + static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, 30 + struct vsp1_dl_list *dl, u32 reg, u32 data) 32 31 { 33 - vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET, 34 - data); 32 + vsp1_dl_list_write(dl, reg + rpf->entity.index * VI6_RPF_OFFSET, data); 35 33 } 36 34 37 35 /* ----------------------------------------------------------------------------- 38 - * Controls 36 + * V4L2 Subdevice Operations 39 37 */ 40 38 41 - static int rpf_s_ctrl(struct v4l2_ctrl *ctrl) 42 - { 43 - struct vsp1_rwpf *rpf = 44 - container_of(ctrl->handler, struct vsp1_rwpf, ctrls); 45 - struct vsp1_pipeline *pipe; 46 - 47 - if (!vsp1_entity_is_streaming(&rpf->entity)) 48 - return 0; 49 - 50 - switch (ctrl->id) { 51 - case V4L2_CID_ALPHA_COMPONENT: 52 - vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET, 53 - ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); 54 - 55 - pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity); 56 - vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val); 57 - break; 58 - } 59 - 60 - return 0; 61 - } 62 - 63 - static const struct v4l2_ctrl_ops rpf_ctrl_ops = { 64 - .s_ctrl = rpf_s_ctrl, 39 + static struct v4l2_subdev_ops rpf_ops = { 40 + .pad = &vsp1_rwpf_pad_ops, 65 41 }; 66 42 67 43 /* ----------------------------------------------------------------------------- 68 - * V4L2 Subdevice Core Operations 44 + * VSP1 Entity Operations 69 45 */ 70 46 71 - static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) 47 + static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) 72 48 { 73 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity); 74 - struct vsp1_rwpf *rpf = to_rwpf(subdev); 75 - struct vsp1_device *vsp1 = rpf->entity.vsp1; 49 + struct vsp1_rwpf *rpf = entity_to_rwpf(entity); 50 + 51 + vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y, 52 + rpf->mem.addr[0] + rpf->offsets[0]); 53 + vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0, 54 + rpf->mem.addr[1] + rpf->offsets[1]); 55 + vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1, 56 + rpf->mem.addr[2] + rpf->offsets[1]); 57 + } 58 + 59 + static void rpf_configure(struct vsp1_entity *entity, 60 + struct vsp1_pipeline *pipe, 61 + struct vsp1_dl_list *dl) 62 + { 63 + struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 76 64 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; 77 65 const struct v4l2_pix_format_mplane *format = &rpf->format; 78 - const struct v4l2_rect *crop = &rpf->crop; 66 + const struct v4l2_mbus_framefmt *source_format; 67 + const struct v4l2_mbus_framefmt *sink_format; 68 + const struct v4l2_rect *crop; 69 + unsigned int left = 0; 70 + unsigned int top = 0; 79 71 u32 pstride; 80 72 u32 infmt; 81 - int ret; 82 - 83 - ret = vsp1_entity_set_streaming(&rpf->entity, enable); 84 - if (ret < 0) 85 - return ret; 86 - 87 - if (!enable) 88 - return 0; 89 73 90 74 /* Source size, stride and crop offsets. 91 75 * ··· 79 91 * left corner in the plane buffer. Only two offsets are needed, as 80 92 * planes 2 and 3 always have identical strides. 81 93 */ 82 - vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE, 94 + crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config); 95 + 96 + vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, 83 97 (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | 84 98 (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); 85 - vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE, 99 + vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE, 86 100 (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | 87 101 (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); 88 102 ··· 93 103 pstride = format->plane_fmt[0].bytesperline 94 104 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; 95 105 96 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, 97 - rpf->buf_addr[0] + rpf->offsets[0]); 98 - 99 106 if (format->num_planes > 1) { 100 107 rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline 101 108 + crop->left * fmtinfo->bpp[1] / 8; 102 109 pstride |= format->plane_fmt[1].bytesperline 103 110 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; 104 - 105 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, 106 - rpf->buf_addr[1] + rpf->offsets[1]); 107 - 108 - if (format->num_planes > 2) 109 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, 110 - rpf->buf_addr[2] + rpf->offsets[1]); 111 + } else { 112 + rpf->offsets[1] = 0; 111 113 } 112 114 113 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride); 115 + vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride); 114 116 115 117 /* Format */ 118 + sink_format = vsp1_entity_get_pad_format(&rpf->entity, 119 + rpf->entity.config, 120 + RWPF_PAD_SINK); 121 + source_format = vsp1_entity_get_pad_format(&rpf->entity, 122 + rpf->entity.config, 123 + RWPF_PAD_SOURCE); 124 + 116 125 infmt = VI6_RPF_INFMT_CIPM 117 126 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); 118 127 ··· 120 131 if (fmtinfo->swap_uv) 121 132 infmt |= VI6_RPF_INFMT_SPUVS; 122 133 123 - if (rpf->entity.formats[RWPF_PAD_SINK].code != 124 - rpf->entity.formats[RWPF_PAD_SOURCE].code) 134 + if (sink_format->code != source_format->code) 125 135 infmt |= VI6_RPF_INFMT_CSC; 126 136 127 - vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); 128 - vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); 137 + vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt); 138 + vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap); 129 139 130 140 /* Output location */ 131 - vsp1_rpf_write(rpf, VI6_RPF_LOC, 132 - (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) | 133 - (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT)); 141 + if (pipe->bru) { 142 + const struct v4l2_rect *compose; 134 143 135 - /* Use the alpha channel (extended to 8 bits) when available or an 136 - * alpha value set through the V4L2_CID_ALPHA_COMPONENT control 137 - * otherwise. Disable color keying. 144 + compose = vsp1_entity_get_pad_compose(pipe->bru, 145 + pipe->bru->config, 146 + rpf->bru_input); 147 + left = compose->left; 148 + top = compose->top; 149 + } 150 + 151 + vsp1_rpf_write(rpf, dl, VI6_RPF_LOC, 152 + (left << VI6_RPF_LOC_HCOORD_SHIFT) | 153 + (top << VI6_RPF_LOC_VCOORD_SHIFT)); 154 + 155 + /* On Gen2 use the alpha channel (extended to 8 bits) when available or 156 + * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control 157 + * otherwise. 158 + * 159 + * The Gen3 RPF has extended alpha capability and can both multiply the 160 + * alpha channel by a fixed global alpha value, and multiply the pixel 161 + * components to convert the input to premultiplied alpha. 162 + * 163 + * As alpha premultiplication is available in the BRU for both Gen2 and 164 + * Gen3 we handle it there and use the Gen3 alpha multiplier for global 165 + * alpha multiplication only. This however prevents conversion to 166 + * premultiplied alpha if no BRU is present in the pipeline. If that use 167 + * case turns out to be useful we will revisit the implementation (for 168 + * Gen3 only). 169 + * 170 + * We enable alpha multiplication on Gen3 using the fixed alpha value 171 + * set through the V4L2_CID_ALPHA_COMPONENT control when the input 172 + * contains an alpha channel. On Gen2 the global alpha is ignored in 173 + * that case. 174 + * 175 + * In all cases, disable color keying. 138 176 */ 139 - vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | 177 + vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | 140 178 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED 141 179 : VI6_RPF_ALPH_SEL_ASEL_FIXED)); 142 180 143 - if (vsp1->info->uapi) 144 - mutex_lock(rpf->ctrls.lock); 145 - vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET, 146 - rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); 147 - vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val); 148 - if (vsp1->info->uapi) 149 - mutex_unlock(rpf->ctrls.lock); 181 + vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, 182 + rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); 150 183 151 - vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0); 152 - vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0); 184 + if (entity->vsp1->info->gen == 3) { 185 + u32 mult; 153 186 154 - return 0; 187 + if (fmtinfo->alpha) { 188 + /* When the input contains an alpha channel enable the 189 + * alpha multiplier. If the input is premultiplied we 190 + * need to multiply both the alpha channel and the pixel 191 + * components by the global alpha value to keep them 192 + * premultiplied. Otherwise multiply the alpha channel 193 + * only. 194 + */ 195 + bool premultiplied = format->flags 196 + & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; 197 + 198 + mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO 199 + | (premultiplied ? 200 + VI6_RPF_MULT_ALPHA_P_MMD_RATIO : 201 + VI6_RPF_MULT_ALPHA_P_MMD_NONE) 202 + | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT); 203 + } else { 204 + /* When the input doesn't contain an alpha channel the 205 + * global alpha value is applied in the unpacking unit, 206 + * the alpha multiplier isn't needed and must be 207 + * disabled. 208 + */ 209 + mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE 210 + | VI6_RPF_MULT_ALPHA_P_MMD_NONE; 211 + } 212 + 213 + vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult); 214 + } 215 + 216 + vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha); 217 + 218 + vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); 219 + vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); 220 + 155 221 } 156 222 157 - /* ----------------------------------------------------------------------------- 158 - * V4L2 Subdevice Operations 159 - */ 160 - 161 - static struct v4l2_subdev_video_ops rpf_video_ops = { 162 - .s_stream = rpf_s_stream, 163 - }; 164 - 165 - static struct v4l2_subdev_pad_ops rpf_pad_ops = { 166 - .enum_mbus_code = vsp1_rwpf_enum_mbus_code, 167 - .enum_frame_size = vsp1_rwpf_enum_frame_size, 168 - .get_fmt = vsp1_rwpf_get_format, 169 - .set_fmt = vsp1_rwpf_set_format, 170 - .get_selection = vsp1_rwpf_get_selection, 171 - .set_selection = vsp1_rwpf_set_selection, 172 - }; 173 - 174 - static struct v4l2_subdev_ops rpf_ops = { 175 - .video = &rpf_video_ops, 176 - .pad = &rpf_pad_ops, 177 - }; 178 - 179 - /* ----------------------------------------------------------------------------- 180 - * Video Device Operations 181 - */ 182 - 183 - static void rpf_set_memory(struct vsp1_rwpf *rpf, struct vsp1_rwpf_memory *mem) 184 - { 185 - unsigned int i; 186 - 187 - for (i = 0; i < 3; ++i) 188 - rpf->buf_addr[i] = mem->addr[i]; 189 - 190 - if (!vsp1_entity_is_streaming(&rpf->entity)) 191 - return; 192 - 193 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, 194 - mem->addr[0] + rpf->offsets[0]); 195 - if (mem->num_planes > 1) 196 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, 197 - mem->addr[1] + rpf->offsets[1]); 198 - if (mem->num_planes > 2) 199 - vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, 200 - mem->addr[2] + rpf->offsets[1]); 201 - } 202 - 203 - static const struct vsp1_rwpf_operations rpf_vdev_ops = { 223 + static const struct vsp1_entity_operations rpf_entity_ops = { 204 224 .set_memory = rpf_set_memory, 225 + .configure = rpf_configure, 205 226 }; 206 227 207 228 /* ----------------------------------------------------------------------------- ··· 220 221 221 222 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) 222 223 { 223 - struct v4l2_subdev *subdev; 224 224 struct vsp1_rwpf *rpf; 225 + char name[6]; 225 226 int ret; 226 227 227 228 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL); 228 229 if (rpf == NULL) 229 230 return ERR_PTR(-ENOMEM); 230 231 231 - rpf->ops = &rpf_vdev_ops; 232 - 233 232 rpf->max_width = RPF_MAX_WIDTH; 234 233 rpf->max_height = RPF_MAX_HEIGHT; 235 234 235 + rpf->entity.ops = &rpf_entity_ops; 236 236 rpf->entity.type = VSP1_ENTITY_RPF; 237 237 rpf->entity.index = index; 238 238 239 - ret = vsp1_entity_init(vsp1, &rpf->entity, 2); 239 + sprintf(name, "rpf.%u", index); 240 + ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops); 240 241 if (ret < 0) 241 242 return ERR_PTR(ret); 242 243 243 - /* Initialize the V4L2 subdev. */ 244 - subdev = &rpf->entity.subdev; 245 - v4l2_subdev_init(subdev, &rpf_ops); 246 - 247 - subdev->entity.ops = &vsp1->media_ops; 248 - subdev->internal_ops = &vsp1_subdev_internal_ops; 249 - snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u", 250 - dev_name(vsp1->dev), index); 251 - v4l2_set_subdevdata(subdev, rpf); 252 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 253 - 254 - vsp1_entity_init_formats(subdev, NULL); 255 - 256 244 /* Initialize the control handler. */ 257 - v4l2_ctrl_handler_init(&rpf->ctrls, 1); 258 - rpf->alpha = v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops, 259 - V4L2_CID_ALPHA_COMPONENT, 260 - 0, 255, 1, 255); 261 - 262 - rpf->entity.subdev.ctrl_handler = &rpf->ctrls; 263 - 264 - if (rpf->ctrls.error) { 245 + ret = vsp1_rwpf_init_ctrls(rpf); 246 + if (ret < 0) { 265 247 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", 266 248 index); 267 - ret = rpf->ctrls.error; 268 249 goto error; 269 250 } 270 251
+97 -74
drivers/media/platform/vsp1/vsp1_rwpf.c
··· 20 20 #define RWPF_MIN_WIDTH 1 21 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 31 * V4L2 Subdevice Pad Operations 25 32 */ 26 33 27 - int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, 28 - struct v4l2_subdev_pad_config *cfg, 29 - struct v4l2_subdev_mbus_code_enum *code) 34 + static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, 35 + struct v4l2_subdev_pad_config *cfg, 36 + struct v4l2_subdev_mbus_code_enum *code) 30 37 { 31 38 static const unsigned int codes[] = { 32 39 MEDIA_BUS_FMT_ARGB8888_1X32, ··· 48 41 return 0; 49 42 } 50 43 51 - int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, 52 - struct v4l2_subdev_pad_config *cfg, 53 - struct v4l2_subdev_frame_size_enum *fse) 54 - { 55 - struct vsp1_rwpf *rwpf = to_rwpf(subdev); 56 - struct v4l2_mbus_framefmt *format; 57 - 58 - format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad, 59 - fse->which); 60 - 61 - if (fse->index || fse->code != format->code) 62 - return -EINVAL; 63 - 64 - if (fse->pad == RWPF_PAD_SINK) { 65 - fse->min_width = RWPF_MIN_WIDTH; 66 - fse->max_width = rwpf->max_width; 67 - fse->min_height = RWPF_MIN_HEIGHT; 68 - fse->max_height = rwpf->max_height; 69 - } else { 70 - /* The size on the source pad are fixed and always identical to 71 - * the size on the sink pad. 72 - */ 73 - fse->min_width = format->width; 74 - fse->max_width = format->width; 75 - fse->min_height = format->height; 76 - fse->max_height = format->height; 77 - } 78 - 79 - return 0; 80 - } 81 - 82 - static struct v4l2_rect * 83 - vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which) 84 - { 85 - switch (which) { 86 - case V4L2_SUBDEV_FORMAT_TRY: 87 - return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK); 88 - case V4L2_SUBDEV_FORMAT_ACTIVE: 89 - return &rwpf->crop; 90 - default: 91 - return NULL; 92 - } 93 - } 94 - 95 - int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 96 - struct v4l2_subdev_format *fmt) 44 + static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, 45 + struct v4l2_subdev_pad_config *cfg, 46 + struct v4l2_subdev_frame_size_enum *fse) 97 47 { 98 48 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 99 49 100 - fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, 101 - fmt->which); 102 - 103 - return 0; 50 + return vsp1_subdev_enum_frame_size(subdev, cfg, fse, RWPF_MIN_WIDTH, 51 + RWPF_MIN_HEIGHT, rwpf->max_width, 52 + rwpf->max_height); 104 53 } 105 54 106 - int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 107 - struct v4l2_subdev_format *fmt) 55 + static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, 56 + struct v4l2_subdev_pad_config *cfg, 57 + struct v4l2_subdev_format *fmt) 108 58 { 109 59 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 60 + struct v4l2_subdev_pad_config *config; 110 61 struct v4l2_mbus_framefmt *format; 111 62 struct v4l2_rect *crop; 63 + 64 + config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which); 65 + if (!config) 66 + return -EINVAL; 112 67 113 68 /* Default to YUV if the requested format is not supported. */ 114 69 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && 115 70 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) 116 71 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; 117 72 118 - format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, 119 - fmt->which); 73 + format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad); 120 74 121 75 if (fmt->pad == RWPF_PAD_SOURCE) { 122 76 /* The RWPF performs format conversion but can't scale, only the ··· 99 131 fmt->format = *format; 100 132 101 133 /* Update the sink crop rectangle. */ 102 - crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); 134 + crop = vsp1_rwpf_get_crop(rwpf, config); 103 135 crop->left = 0; 104 136 crop->top = 0; 105 137 crop->width = fmt->format.width; 106 138 crop->height = fmt->format.height; 107 139 108 140 /* Propagate the format to the source pad. */ 109 - format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, 110 - fmt->which); 141 + format = vsp1_entity_get_pad_format(&rwpf->entity, config, 142 + RWPF_PAD_SOURCE); 111 143 *format = fmt->format; 112 144 113 145 return 0; 114 146 } 115 147 116 - int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, 117 - struct v4l2_subdev_pad_config *cfg, 118 - struct v4l2_subdev_selection *sel) 148 + static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, 149 + struct v4l2_subdev_pad_config *cfg, 150 + struct v4l2_subdev_selection *sel) 119 151 { 120 152 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 153 + struct v4l2_subdev_pad_config *config; 121 154 struct v4l2_mbus_framefmt *format; 122 155 123 156 /* Cropping is implemented on the sink pad. */ 124 157 if (sel->pad != RWPF_PAD_SINK) 125 158 return -EINVAL; 126 159 160 + config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); 161 + if (!config) 162 + return -EINVAL; 163 + 127 164 switch (sel->target) { 128 165 case V4L2_SEL_TGT_CROP: 129 - sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); 166 + sel->r = *vsp1_rwpf_get_crop(rwpf, config); 130 167 break; 131 168 132 169 case V4L2_SEL_TGT_CROP_BOUNDS: 133 - format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, 134 - RWPF_PAD_SINK, sel->which); 170 + format = vsp1_entity_get_pad_format(&rwpf->entity, config, 171 + RWPF_PAD_SINK); 135 172 sel->r.left = 0; 136 173 sel->r.top = 0; 137 174 sel->r.width = format->width; ··· 150 177 return 0; 151 178 } 152 179 153 - int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, 154 - struct v4l2_subdev_pad_config *cfg, 155 - struct v4l2_subdev_selection *sel) 180 + static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, 181 + struct v4l2_subdev_pad_config *cfg, 182 + struct v4l2_subdev_selection *sel) 156 183 { 157 184 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 185 + struct v4l2_subdev_pad_config *config; 158 186 struct v4l2_mbus_framefmt *format; 159 187 struct v4l2_rect *crop; 160 188 ··· 166 192 if (sel->target != V4L2_SEL_TGT_CROP) 167 193 return -EINVAL; 168 194 195 + config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); 196 + if (!config) 197 + return -EINVAL; 198 + 169 199 /* Make sure the crop rectangle is entirely contained in the image. The 170 200 * WPF top and left offsets are limited to 255. 171 201 */ 172 - format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, 173 - sel->which); 202 + format = vsp1_entity_get_pad_format(&rwpf->entity, config, 203 + RWPF_PAD_SINK); 174 204 175 205 /* Restrict the crop rectangle coordinates to multiples of 2 to avoid 176 206 * shifting the color plane. ··· 197 219 sel->r.height = min_t(unsigned int, sel->r.height, 198 220 format->height - sel->r.top); 199 221 200 - crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); 222 + crop = vsp1_rwpf_get_crop(rwpf, config); 201 223 *crop = sel->r; 202 224 203 225 /* Propagate the format to the source pad. */ 204 - format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, 205 - sel->which); 226 + format = vsp1_entity_get_pad_format(&rwpf->entity, config, 227 + RWPF_PAD_SOURCE); 206 228 format->width = crop->width; 207 229 format->height = crop->height; 208 230 209 231 return 0; 232 + } 233 + 234 + const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { 235 + .init_cfg = vsp1_entity_init_cfg, 236 + .enum_mbus_code = vsp1_rwpf_enum_mbus_code, 237 + .enum_frame_size = vsp1_rwpf_enum_frame_size, 238 + .get_fmt = vsp1_subdev_get_pad_format, 239 + .set_fmt = vsp1_rwpf_set_format, 240 + .get_selection = vsp1_rwpf_get_selection, 241 + .set_selection = vsp1_rwpf_set_selection, 242 + }; 243 + 244 + /* ----------------------------------------------------------------------------- 245 + * Controls 246 + */ 247 + 248 + static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl) 249 + { 250 + struct vsp1_rwpf *rwpf = 251 + container_of(ctrl->handler, struct vsp1_rwpf, ctrls); 252 + 253 + switch (ctrl->id) { 254 + case V4L2_CID_ALPHA_COMPONENT: 255 + rwpf->alpha = ctrl->val; 256 + break; 257 + } 258 + 259 + return 0; 260 + } 261 + 262 + static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = { 263 + .s_ctrl = vsp1_rwpf_s_ctrl, 264 + }; 265 + 266 + int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf) 267 + { 268 + rwpf->alpha = 255; 269 + 270 + v4l2_ctrl_handler_init(&rwpf->ctrls, 1); 271 + v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, 272 + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); 273 + 274 + rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls; 275 + 276 + return rwpf->ctrls.error; 210 277 }
+32 -32
drivers/media/platform/vsp1/vsp1_rwpf.h
··· 24 24 #define RWPF_PAD_SOURCE 1 25 25 26 26 struct v4l2_ctrl; 27 + struct vsp1_dl_manager; 28 + struct vsp1_pipeline; 27 29 struct vsp1_rwpf; 28 30 struct vsp1_video; 29 31 30 32 struct vsp1_rwpf_memory { 31 - unsigned int num_planes; 32 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 36 struct vsp1_rwpf { 42 37 struct vsp1_entity entity; 43 38 struct v4l2_ctrl_handler ctrls; 44 - struct v4l2_ctrl *alpha; 45 39 40 + struct vsp1_pipeline *pipe; 46 41 struct vsp1_video *video; 47 - 48 - const struct vsp1_rwpf_operations *ops; 49 42 50 43 unsigned int max_width; 51 44 unsigned int max_height; 52 45 53 46 struct v4l2_pix_format_mplane format; 54 47 const struct vsp1_format_info *fmtinfo; 55 - struct { 56 - unsigned int left; 57 - unsigned int top; 58 - } location; 59 - struct v4l2_rect crop; 48 + unsigned int bru_input; 49 + 50 + unsigned int alpha; 60 51 61 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 58 static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) ··· 60 67 return container_of(subdev, struct vsp1_rwpf, entity.subdev); 61 68 } 62 69 70 + static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity) 71 + { 72 + return container_of(entity, struct vsp1_rwpf, entity); 73 + } 74 + 63 75 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); 64 76 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); 65 77 66 - int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, 67 - struct v4l2_subdev_pad_config *cfg, 68 - struct v4l2_subdev_mbus_code_enum *code); 69 - int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, 70 - struct v4l2_subdev_pad_config *cfg, 71 - struct v4l2_subdev_frame_size_enum *fse); 72 - int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 73 - struct v4l2_subdev_format *fmt); 74 - int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 75 - struct v4l2_subdev_format *fmt); 76 - int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, 77 - struct v4l2_subdev_pad_config *cfg, 78 - struct v4l2_subdev_selection *sel); 79 - int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, 80 - struct v4l2_subdev_pad_config *cfg, 81 - struct v4l2_subdev_selection *sel); 78 + int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf); 79 + 80 + extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; 81 + 82 + struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, 83 + struct v4l2_subdev_pad_config *config); 84 + /** 85 + * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF 86 + * @rwpf: the [RW]PF instance 87 + * @dl: the display list 88 + * 89 + * This function applies the cached memory buffer address to the display list. 90 + */ 91 + static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, 92 + struct vsp1_dl_list *dl) 93 + { 94 + rwpf->entity.ops->set_memory(&rwpf->entity, dl); 95 + } 82 96 83 97 #endif /* __VSP1_RWPF_H__ */
+78 -136
drivers/media/platform/vsp1/vsp1_sru.c
··· 17 17 #include <media/v4l2-subdev.h> 18 18 19 19 #include "vsp1.h" 20 + #include "vsp1_dl.h" 20 21 #include "vsp1_sru.h" 21 22 22 23 #define SRU_MIN_SIZE 4U ··· 27 26 * Device Access 28 27 */ 29 28 30 - static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg) 29 + static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl, 30 + u32 reg, u32 data) 31 31 { 32 - return vsp1_read(sru->entity.vsp1, reg); 33 - } 34 - 35 - static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data) 36 - { 37 - vsp1_write(sru->entity.vsp1, reg, data); 32 + vsp1_dl_list_write(dl, reg, data); 38 33 } 39 34 40 35 /* ----------------------------------------------------------------------------- ··· 79 82 { 80 83 struct vsp1_sru *sru = 81 84 container_of(ctrl->handler, struct vsp1_sru, ctrls); 82 - const struct vsp1_sru_param *param; 83 - u32 value; 84 85 85 86 switch (ctrl->id) { 86 87 case V4L2_CID_VSP1_SRU_INTENSITY: 87 - param = &vsp1_sru_params[ctrl->val - 1]; 88 - 89 - value = vsp1_sru_read(sru, VI6_SRU_CTRL0); 90 - value &= ~(VI6_SRU_CTRL0_PARAM0_MASK | 91 - VI6_SRU_CTRL0_PARAM1_MASK); 92 - value |= param->ctrl0; 93 - vsp1_sru_write(sru, VI6_SRU_CTRL0, value); 94 - 95 - vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2); 88 + sru->intensity = ctrl->val; 96 89 break; 97 90 } 98 91 ··· 105 118 }; 106 119 107 120 /* ----------------------------------------------------------------------------- 108 - * V4L2 Subdevice Core Operations 109 - */ 110 - 111 - static int sru_s_stream(struct v4l2_subdev *subdev, int enable) 112 - { 113 - struct vsp1_sru *sru = to_sru(subdev); 114 - struct v4l2_mbus_framefmt *input; 115 - struct v4l2_mbus_framefmt *output; 116 - u32 ctrl0; 117 - int ret; 118 - 119 - ret = vsp1_entity_set_streaming(&sru->entity, enable); 120 - if (ret < 0) 121 - return ret; 122 - 123 - if (!enable) 124 - return 0; 125 - 126 - input = &sru->entity.formats[SRU_PAD_SINK]; 127 - output = &sru->entity.formats[SRU_PAD_SOURCE]; 128 - 129 - if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) 130 - ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 131 - | VI6_SRU_CTRL0_PARAM4; 132 - else 133 - ctrl0 = VI6_SRU_CTRL0_PARAM3; 134 - 135 - if (input->width != output->width) 136 - ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE; 137 - 138 - /* Take the control handler lock to ensure that the CTRL0 value won't be 139 - * changed behind our back by a set control operation. 140 - */ 141 - if (sru->entity.vsp1->info->uapi) 142 - mutex_lock(sru->ctrls.lock); 143 - ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0) 144 - & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK); 145 - vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0); 146 - if (sru->entity.vsp1->info->uapi) 147 - mutex_unlock(sru->ctrls.lock); 148 - 149 - vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5); 150 - 151 - return 0; 152 - } 153 - 154 - /* ----------------------------------------------------------------------------- 155 - * V4L2 Subdevice Pad Operations 121 + * V4L2 Subdevice Operations 156 122 */ 157 123 158 124 static int sru_enum_mbus_code(struct v4l2_subdev *subdev, ··· 116 176 MEDIA_BUS_FMT_ARGB8888_1X32, 117 177 MEDIA_BUS_FMT_AYUV8_1X32, 118 178 }; 119 - struct vsp1_sru *sru = to_sru(subdev); 120 - struct v4l2_mbus_framefmt *format; 121 179 122 - if (code->pad == SRU_PAD_SINK) { 123 - if (code->index >= ARRAY_SIZE(codes)) 124 - return -EINVAL; 125 - 126 - code->code = codes[code->index]; 127 - } else { 128 - /* The SRU can't perform format conversion, the sink format is 129 - * always identical to the source format. 130 - */ 131 - if (code->index) 132 - return -EINVAL; 133 - 134 - format = vsp1_entity_get_pad_format(&sru->entity, cfg, 135 - SRU_PAD_SINK, code->which); 136 - code->code = format->code; 137 - } 138 - 139 - return 0; 180 + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, 181 + ARRAY_SIZE(codes)); 140 182 } 141 183 142 184 static int sru_enum_frame_size(struct v4l2_subdev *subdev, ··· 126 204 struct v4l2_subdev_frame_size_enum *fse) 127 205 { 128 206 struct vsp1_sru *sru = to_sru(subdev); 207 + struct v4l2_subdev_pad_config *config; 129 208 struct v4l2_mbus_framefmt *format; 130 209 131 - format = vsp1_entity_get_pad_format(&sru->entity, cfg, 132 - SRU_PAD_SINK, fse->which); 210 + config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which); 211 + if (!config) 212 + return -EINVAL; 213 + 214 + format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK); 133 215 134 216 if (fse->index || fse->code != format->code) 135 217 return -EINVAL; ··· 159 233 return 0; 160 234 } 161 235 162 - static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 163 - struct v4l2_subdev_format *fmt) 164 - { 165 - struct vsp1_sru *sru = to_sru(subdev); 166 - 167 - fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, 168 - fmt->which); 169 - 170 - return 0; 171 - } 172 - 173 - static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg, 174 - unsigned int pad, struct v4l2_mbus_framefmt *fmt, 175 - enum v4l2_subdev_format_whence which) 236 + static void sru_try_format(struct vsp1_sru *sru, 237 + struct v4l2_subdev_pad_config *config, 238 + unsigned int pad, struct v4l2_mbus_framefmt *fmt) 176 239 { 177 240 struct v4l2_mbus_framefmt *format; 178 241 unsigned int input_area; ··· 180 265 181 266 case SRU_PAD_SOURCE: 182 267 /* The SRU can't perform format conversion. */ 183 - format = vsp1_entity_get_pad_format(&sru->entity, cfg, 184 - SRU_PAD_SINK, which); 268 + format = vsp1_entity_get_pad_format(&sru->entity, config, 269 + SRU_PAD_SINK); 185 270 fmt->code = format->code; 186 271 187 272 /* We can upscale by 2 in both direction, but not independently. ··· 210 295 fmt->colorspace = V4L2_COLORSPACE_SRGB; 211 296 } 212 297 213 - static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 298 + static int sru_set_format(struct v4l2_subdev *subdev, 299 + struct v4l2_subdev_pad_config *cfg, 214 300 struct v4l2_subdev_format *fmt) 215 301 { 216 302 struct vsp1_sru *sru = to_sru(subdev); 303 + struct v4l2_subdev_pad_config *config; 217 304 struct v4l2_mbus_framefmt *format; 218 305 219 - sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which); 306 + config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which); 307 + if (!config) 308 + return -EINVAL; 220 309 221 - format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, 222 - fmt->which); 310 + sru_try_format(sru, config, fmt->pad, &fmt->format); 311 + 312 + format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad); 223 313 *format = fmt->format; 224 314 225 315 if (fmt->pad == SRU_PAD_SINK) { 226 316 /* Propagate the format to the source pad. */ 227 - format = vsp1_entity_get_pad_format(&sru->entity, cfg, 228 - SRU_PAD_SOURCE, fmt->which); 317 + format = vsp1_entity_get_pad_format(&sru->entity, config, 318 + SRU_PAD_SOURCE); 229 319 *format = fmt->format; 230 320 231 - sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which); 321 + sru_try_format(sru, config, SRU_PAD_SOURCE, format); 232 322 } 233 323 234 324 return 0; 235 325 } 236 326 237 - /* ----------------------------------------------------------------------------- 238 - * V4L2 Subdevice Operations 239 - */ 240 - 241 - static struct v4l2_subdev_video_ops sru_video_ops = { 242 - .s_stream = sru_s_stream, 243 - }; 244 - 245 327 static struct v4l2_subdev_pad_ops sru_pad_ops = { 328 + .init_cfg = vsp1_entity_init_cfg, 246 329 .enum_mbus_code = sru_enum_mbus_code, 247 330 .enum_frame_size = sru_enum_frame_size, 248 - .get_fmt = sru_get_format, 331 + .get_fmt = vsp1_subdev_get_pad_format, 249 332 .set_fmt = sru_set_format, 250 333 }; 251 334 252 335 static struct v4l2_subdev_ops sru_ops = { 253 - .video = &sru_video_ops, 254 336 .pad = &sru_pad_ops, 337 + }; 338 + 339 + /* ----------------------------------------------------------------------------- 340 + * VSP1 Entity Operations 341 + */ 342 + 343 + static void sru_configure(struct vsp1_entity *entity, 344 + struct vsp1_pipeline *pipe, 345 + struct vsp1_dl_list *dl) 346 + { 347 + const struct vsp1_sru_param *param; 348 + struct vsp1_sru *sru = to_sru(&entity->subdev); 349 + struct v4l2_mbus_framefmt *input; 350 + struct v4l2_mbus_framefmt *output; 351 + u32 ctrl0; 352 + 353 + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, 354 + SRU_PAD_SINK); 355 + output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, 356 + SRU_PAD_SOURCE); 357 + 358 + if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) 359 + ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 360 + | VI6_SRU_CTRL0_PARAM4; 361 + else 362 + ctrl0 = VI6_SRU_CTRL0_PARAM3; 363 + 364 + if (input->width != output->width) 365 + ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE; 366 + 367 + param = &vsp1_sru_params[sru->intensity - 1]; 368 + 369 + ctrl0 |= param->ctrl0; 370 + 371 + vsp1_sru_write(sru, dl, VI6_SRU_CTRL0, ctrl0); 372 + vsp1_sru_write(sru, dl, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5); 373 + vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2); 374 + } 375 + 376 + static const struct vsp1_entity_operations sru_entity_ops = { 377 + .configure = sru_configure, 255 378 }; 256 379 257 380 /* ----------------------------------------------------------------------------- ··· 298 345 299 346 struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) 300 347 { 301 - struct v4l2_subdev *subdev; 302 348 struct vsp1_sru *sru; 303 349 int ret; 304 350 ··· 305 353 if (sru == NULL) 306 354 return ERR_PTR(-ENOMEM); 307 355 356 + sru->entity.ops = &sru_entity_ops; 308 357 sru->entity.type = VSP1_ENTITY_SRU; 309 358 310 - ret = vsp1_entity_init(vsp1, &sru->entity, 2); 359 + ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops); 311 360 if (ret < 0) 312 361 return ERR_PTR(ret); 313 - 314 - /* Initialize the V4L2 subdev. */ 315 - subdev = &sru->entity.subdev; 316 - v4l2_subdev_init(subdev, &sru_ops); 317 - 318 - subdev->entity.ops = &vsp1->media_ops; 319 - subdev->internal_ops = &vsp1_subdev_internal_ops; 320 - snprintf(subdev->name, sizeof(subdev->name), "%s sru", 321 - dev_name(vsp1->dev)); 322 - v4l2_set_subdevdata(subdev, sru); 323 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 324 - 325 - vsp1_entity_init_formats(subdev, NULL); 326 362 327 363 /* Initialize the control handler. */ 328 364 v4l2_ctrl_handler_init(&sru->ctrls, 1); 329 365 v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL); 366 + 367 + sru->intensity = 1; 330 368 331 369 sru->entity.subdev.ctrl_handler = &sru->ctrls; 332 370
+2
drivers/media/platform/vsp1/vsp1_sru.h
··· 28 28 struct vsp1_entity entity; 29 29 30 30 struct v4l2_ctrl_handler ctrls; 31 + 32 + unsigned int intensity; 31 33 }; 32 34 33 35 static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
+97 -126
drivers/media/platform/vsp1/vsp1_uds.c
··· 17 17 #include <media/v4l2-subdev.h> 18 18 19 19 #include "vsp1.h" 20 + #include "vsp1_dl.h" 20 21 #include "vsp1_uds.h" 21 22 22 23 #define UDS_MIN_SIZE 4U ··· 30 29 * Device Access 31 30 */ 32 31 33 - static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data) 32 + static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl, 33 + u32 reg, u32 data) 34 34 { 35 - vsp1_write(uds->entity.vsp1, 36 - reg + uds->entity.index * VI6_UDS_OFFSET, data); 35 + vsp1_dl_list_write(dl, reg + uds->entity.index * VI6_UDS_OFFSET, data); 37 36 } 38 37 39 38 /* ----------------------------------------------------------------------------- 40 39 * Scaling Computation 41 40 */ 42 41 43 - void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha) 42 + void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, 43 + unsigned int alpha) 44 44 { 45 - vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); 45 + vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, 46 + alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); 46 47 } 47 48 48 49 /* ··· 108 105 } 109 106 110 107 /* ----------------------------------------------------------------------------- 111 - * V4L2 Subdevice Core Operations 112 - */ 113 - 114 - static int uds_s_stream(struct v4l2_subdev *subdev, int enable) 115 - { 116 - struct vsp1_uds *uds = to_uds(subdev); 117 - const struct v4l2_mbus_framefmt *output; 118 - const struct v4l2_mbus_framefmt *input; 119 - unsigned int hscale; 120 - unsigned int vscale; 121 - bool multitap; 122 - 123 - if (!enable) 124 - return 0; 125 - 126 - input = &uds->entity.formats[UDS_PAD_SINK]; 127 - output = &uds->entity.formats[UDS_PAD_SOURCE]; 128 - 129 - hscale = uds_compute_ratio(input->width, output->width); 130 - vscale = uds_compute_ratio(input->height, output->height); 131 - 132 - dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); 133 - 134 - /* Multi-tap scaling can't be enabled along with alpha scaling when 135 - * scaling down with a factor lower than or equal to 1/2 in either 136 - * direction. 137 - */ 138 - if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192)) 139 - multitap = false; 140 - else 141 - multitap = true; 142 - 143 - vsp1_uds_write(uds, VI6_UDS_CTRL, 144 - (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) | 145 - (multitap ? VI6_UDS_CTRL_BC : 0)); 146 - 147 - vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, 148 - (uds_passband_width(hscale) 149 - << VI6_UDS_PASS_BWIDTH_H_SHIFT) | 150 - (uds_passband_width(vscale) 151 - << VI6_UDS_PASS_BWIDTH_V_SHIFT)); 152 - 153 - /* Set the scaling ratios and the output size. */ 154 - vsp1_uds_write(uds, VI6_UDS_SCALE, 155 - (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | 156 - (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); 157 - vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE, 158 - (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | 159 - (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); 160 - 161 - return 0; 162 - } 163 - 164 - /* ----------------------------------------------------------------------------- 165 108 * V4L2 Subdevice Pad Operations 166 109 */ 167 110 ··· 119 170 MEDIA_BUS_FMT_ARGB8888_1X32, 120 171 MEDIA_BUS_FMT_AYUV8_1X32, 121 172 }; 122 - struct vsp1_uds *uds = to_uds(subdev); 123 173 124 - if (code->pad == UDS_PAD_SINK) { 125 - if (code->index >= ARRAY_SIZE(codes)) 126 - return -EINVAL; 127 - 128 - code->code = codes[code->index]; 129 - } else { 130 - struct v4l2_mbus_framefmt *format; 131 - 132 - /* The UDS can't perform format conversion, the sink format is 133 - * always identical to the source format. 134 - */ 135 - if (code->index) 136 - return -EINVAL; 137 - 138 - format = vsp1_entity_get_pad_format(&uds->entity, cfg, 139 - UDS_PAD_SINK, code->which); 140 - code->code = format->code; 141 - } 142 - 143 - return 0; 174 + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, 175 + ARRAY_SIZE(codes)); 144 176 } 145 177 146 178 static int uds_enum_frame_size(struct v4l2_subdev *subdev, ··· 129 199 struct v4l2_subdev_frame_size_enum *fse) 130 200 { 131 201 struct vsp1_uds *uds = to_uds(subdev); 202 + struct v4l2_subdev_pad_config *config; 132 203 struct v4l2_mbus_framefmt *format; 133 204 134 - format = vsp1_entity_get_pad_format(&uds->entity, cfg, 135 - UDS_PAD_SINK, fse->which); 205 + config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which); 206 + if (!config) 207 + return -EINVAL; 208 + 209 + format = vsp1_entity_get_pad_format(&uds->entity, config, 210 + UDS_PAD_SINK); 136 211 137 212 if (fse->index || fse->code != format->code) 138 213 return -EINVAL; ··· 157 222 return 0; 158 223 } 159 224 160 - static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 161 - struct v4l2_subdev_format *fmt) 162 - { 163 - struct vsp1_uds *uds = to_uds(subdev); 164 - 165 - fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, 166 - fmt->which); 167 - 168 - return 0; 169 - } 170 - 171 - static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg, 172 - unsigned int pad, struct v4l2_mbus_framefmt *fmt, 173 - enum v4l2_subdev_format_whence which) 225 + static void uds_try_format(struct vsp1_uds *uds, 226 + struct v4l2_subdev_pad_config *config, 227 + unsigned int pad, struct v4l2_mbus_framefmt *fmt) 174 228 { 175 229 struct v4l2_mbus_framefmt *format; 176 230 unsigned int minimum; ··· 178 254 179 255 case UDS_PAD_SOURCE: 180 256 /* The UDS scales but can't perform format conversion. */ 181 - format = vsp1_entity_get_pad_format(&uds->entity, cfg, 182 - UDS_PAD_SINK, which); 257 + format = vsp1_entity_get_pad_format(&uds->entity, config, 258 + UDS_PAD_SINK); 183 259 fmt->code = format->code; 184 260 185 261 uds_output_limits(format->width, &minimum, &maximum); ··· 193 269 fmt->colorspace = V4L2_COLORSPACE_SRGB; 194 270 } 195 271 196 - static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 272 + static int uds_set_format(struct v4l2_subdev *subdev, 273 + struct v4l2_subdev_pad_config *cfg, 197 274 struct v4l2_subdev_format *fmt) 198 275 { 199 276 struct vsp1_uds *uds = to_uds(subdev); 277 + struct v4l2_subdev_pad_config *config; 200 278 struct v4l2_mbus_framefmt *format; 201 279 202 - uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which); 280 + config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which); 281 + if (!config) 282 + return -EINVAL; 203 283 204 - format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, 205 - fmt->which); 284 + uds_try_format(uds, config, fmt->pad, &fmt->format); 285 + 286 + format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad); 206 287 *format = fmt->format; 207 288 208 289 if (fmt->pad == UDS_PAD_SINK) { 209 290 /* Propagate the format to the source pad. */ 210 - format = vsp1_entity_get_pad_format(&uds->entity, cfg, 211 - UDS_PAD_SOURCE, fmt->which); 291 + format = vsp1_entity_get_pad_format(&uds->entity, config, 292 + UDS_PAD_SOURCE); 212 293 *format = fmt->format; 213 294 214 - uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which); 295 + uds_try_format(uds, config, UDS_PAD_SOURCE, format); 215 296 } 216 297 217 298 return 0; ··· 226 297 * V4L2 Subdevice Operations 227 298 */ 228 299 229 - static struct v4l2_subdev_video_ops uds_video_ops = { 230 - .s_stream = uds_s_stream, 231 - }; 232 - 233 300 static struct v4l2_subdev_pad_ops uds_pad_ops = { 301 + .init_cfg = vsp1_entity_init_cfg, 234 302 .enum_mbus_code = uds_enum_mbus_code, 235 303 .enum_frame_size = uds_enum_frame_size, 236 - .get_fmt = uds_get_format, 304 + .get_fmt = vsp1_subdev_get_pad_format, 237 305 .set_fmt = uds_set_format, 238 306 }; 239 307 240 308 static struct v4l2_subdev_ops uds_ops = { 241 - .video = &uds_video_ops, 242 309 .pad = &uds_pad_ops, 310 + }; 311 + 312 + /* ----------------------------------------------------------------------------- 313 + * VSP1 Entity Operations 314 + */ 315 + 316 + static void uds_configure(struct vsp1_entity *entity, 317 + struct vsp1_pipeline *pipe, 318 + struct vsp1_dl_list *dl) 319 + { 320 + struct vsp1_uds *uds = to_uds(&entity->subdev); 321 + const struct v4l2_mbus_framefmt *output; 322 + const struct v4l2_mbus_framefmt *input; 323 + unsigned int hscale; 324 + unsigned int vscale; 325 + bool multitap; 326 + 327 + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 328 + UDS_PAD_SINK); 329 + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 330 + UDS_PAD_SOURCE); 331 + 332 + hscale = uds_compute_ratio(input->width, output->width); 333 + vscale = uds_compute_ratio(input->height, output->height); 334 + 335 + dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); 336 + 337 + /* Multi-tap scaling can't be enabled along with alpha scaling when 338 + * scaling down with a factor lower than or equal to 1/2 in either 339 + * direction. 340 + */ 341 + if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192)) 342 + multitap = false; 343 + else 344 + multitap = true; 345 + 346 + vsp1_uds_write(uds, dl, VI6_UDS_CTRL, 347 + (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) | 348 + (multitap ? VI6_UDS_CTRL_BC : 0)); 349 + 350 + vsp1_uds_write(uds, dl, VI6_UDS_PASS_BWIDTH, 351 + (uds_passband_width(hscale) 352 + << VI6_UDS_PASS_BWIDTH_H_SHIFT) | 353 + (uds_passband_width(vscale) 354 + << VI6_UDS_PASS_BWIDTH_V_SHIFT)); 355 + 356 + /* Set the scaling ratios and the output size. */ 357 + vsp1_uds_write(uds, dl, VI6_UDS_SCALE, 358 + (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | 359 + (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); 360 + vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE, 361 + (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | 362 + (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); 363 + } 364 + 365 + static const struct vsp1_entity_operations uds_entity_ops = { 366 + .configure = uds_configure, 243 367 }; 244 368 245 369 /* ----------------------------------------------------------------------------- ··· 301 319 302 320 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) 303 321 { 304 - struct v4l2_subdev *subdev; 305 322 struct vsp1_uds *uds; 323 + char name[6]; 306 324 int ret; 307 325 308 326 uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL); 309 327 if (uds == NULL) 310 328 return ERR_PTR(-ENOMEM); 311 329 330 + uds->entity.ops = &uds_entity_ops; 312 331 uds->entity.type = VSP1_ENTITY_UDS; 313 332 uds->entity.index = index; 314 333 315 - ret = vsp1_entity_init(vsp1, &uds->entity, 2); 334 + sprintf(name, "uds.%u", index); 335 + ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops); 316 336 if (ret < 0) 317 337 return ERR_PTR(ret); 318 - 319 - /* Initialize the V4L2 subdev. */ 320 - subdev = &uds->entity.subdev; 321 - v4l2_subdev_init(subdev, &uds_ops); 322 - 323 - subdev->entity.ops = &vsp1->media_ops; 324 - subdev->internal_ops = &vsp1_subdev_internal_ops; 325 - snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u", 326 - dev_name(vsp1->dev), index); 327 - v4l2_set_subdevdata(subdev, uds); 328 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 329 - 330 - vsp1_entity_init_formats(subdev, NULL); 331 338 332 339 return uds; 333 340 }
+2 -1
drivers/media/platform/vsp1/vsp1_uds.h
··· 35 35 36 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 41 #endif /* __VSP1_UDS_H__ */
+332 -277
drivers/media/platform/vsp1/vsp1_video.c
··· 29 29 30 30 #include "vsp1.h" 31 31 #include "vsp1_bru.h" 32 + #include "vsp1_dl.h" 32 33 #include "vsp1_entity.h" 33 34 #include "vsp1_pipe.h" 34 35 #include "vsp1_rwpf.h" ··· 172 171 * Pipeline Management 173 172 */ 174 173 175 - static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe, 176 - struct vsp1_rwpf *input, 177 - struct vsp1_rwpf *output) 178 - { 179 - struct vsp1_entity *entity; 180 - struct media_entity_enum ent_enum; 181 - struct media_pad *pad; 182 - int rval; 183 - bool bru_found = false; 184 - 185 - input->location.left = 0; 186 - input->location.top = 0; 187 - 188 - rval = media_entity_enum_init( 189 - &ent_enum, input->entity.pads[RWPF_PAD_SOURCE].graph_obj.mdev); 190 - if (rval) 191 - return rval; 192 - 193 - pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); 194 - 195 - while (1) { 196 - if (pad == NULL) { 197 - rval = -EPIPE; 198 - goto out; 199 - } 200 - 201 - /* We've reached a video node, that shouldn't have happened. */ 202 - if (!is_media_entity_v4l2_subdev(pad->entity)) { 203 - rval = -EPIPE; 204 - goto out; 205 - } 206 - 207 - entity = to_vsp1_entity( 208 - media_entity_to_v4l2_subdev(pad->entity)); 209 - 210 - /* A BRU is present in the pipeline, store the compose rectangle 211 - * location in the input RPF for use when configuring the RPF. 212 - */ 213 - if (entity->type == VSP1_ENTITY_BRU) { 214 - struct vsp1_bru *bru = to_bru(&entity->subdev); 215 - struct v4l2_rect *rect = 216 - &bru->inputs[pad->index].compose; 217 - 218 - bru->inputs[pad->index].rpf = input; 219 - 220 - input->location.left = rect->left; 221 - input->location.top = rect->top; 222 - 223 - bru_found = true; 224 - } 225 - 226 - /* We've reached the WPF, we're done. */ 227 - if (entity->type == VSP1_ENTITY_WPF) 228 - break; 229 - 230 - /* Ensure the branch has no loop. */ 231 - if (media_entity_enum_test_and_set(&ent_enum, 232 - &entity->subdev.entity)) { 233 - rval = -EPIPE; 234 - goto out; 235 - } 236 - 237 - /* UDS can't be chained. */ 238 - if (entity->type == VSP1_ENTITY_UDS) { 239 - if (pipe->uds) { 240 - rval = -EPIPE; 241 - goto out; 242 - } 243 - 244 - pipe->uds = entity; 245 - pipe->uds_input = bru_found ? pipe->bru 246 - : &input->entity; 247 - } 248 - 249 - /* Follow the source link. The link setup operations ensure 250 - * that the output fan-out can't be more than one, there is thus 251 - * no need to verify here that only a single source link is 252 - * activated. 253 - */ 254 - pad = &entity->pads[entity->source_pad]; 255 - pad = media_entity_remote_pad(pad); 256 - } 257 - 258 - /* The last entity must be the output WPF. */ 259 - if (entity != &output->entity) 260 - rval = -EPIPE; 261 - 262 - out: 263 - media_entity_enum_cleanup(&ent_enum); 264 - 265 - return rval; 266 - } 267 - 268 - static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe, 269 - struct vsp1_video *video) 270 - { 271 - struct media_entity_graph graph; 272 - struct media_entity *entity = &video->video.entity; 273 - struct media_device *mdev = entity->graph_obj.mdev; 274 - unsigned int i; 275 - int ret; 276 - 277 - mutex_lock(&mdev->graph_mutex); 278 - 279 - /* Walk the graph to locate the entities and video nodes. */ 280 - ret = media_entity_graph_walk_init(&graph, mdev); 281 - if (ret) { 282 - mutex_unlock(&mdev->graph_mutex); 283 - return ret; 284 - } 285 - 286 - media_entity_graph_walk_start(&graph, entity); 287 - 288 - while ((entity = media_entity_graph_walk_next(&graph))) { 289 - struct v4l2_subdev *subdev; 290 - struct vsp1_rwpf *rwpf; 291 - struct vsp1_entity *e; 292 - 293 - if (!is_media_entity_v4l2_subdev(entity)) 294 - continue; 295 - 296 - subdev = media_entity_to_v4l2_subdev(entity); 297 - e = to_vsp1_entity(subdev); 298 - list_add_tail(&e->list_pipe, &pipe->entities); 299 - 300 - if (e->type == VSP1_ENTITY_RPF) { 301 - rwpf = to_rwpf(subdev); 302 - pipe->inputs[rwpf->entity.index] = rwpf; 303 - rwpf->video->pipe_index = ++pipe->num_inputs; 304 - } else if (e->type == VSP1_ENTITY_WPF) { 305 - rwpf = to_rwpf(subdev); 306 - pipe->output = rwpf; 307 - rwpf->video->pipe_index = 0; 308 - } else if (e->type == VSP1_ENTITY_LIF) { 309 - pipe->lif = e; 310 - } else if (e->type == VSP1_ENTITY_BRU) { 311 - pipe->bru = e; 312 - } 313 - } 314 - 315 - mutex_unlock(&mdev->graph_mutex); 316 - 317 - media_entity_graph_walk_cleanup(&graph); 318 - 319 - /* We need one output and at least one input. */ 320 - if (pipe->num_inputs == 0 || !pipe->output) { 321 - ret = -EPIPE; 322 - goto error; 323 - } 324 - 325 - /* Follow links downstream for each input and make sure the graph 326 - * contains no loop and that all branches end at the output WPF. 327 - */ 328 - for (i = 0; i < video->vsp1->info->rpf_count; ++i) { 329 - if (!pipe->inputs[i]) 330 - continue; 331 - 332 - ret = vsp1_video_pipeline_validate_branch(pipe, pipe->inputs[i], 333 - pipe->output); 334 - if (ret < 0) 335 - goto error; 336 - } 337 - 338 - return 0; 339 - 340 - error: 341 - vsp1_pipeline_reset(pipe); 342 - return ret; 343 - } 344 - 345 - static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe, 346 - struct vsp1_video *video) 347 - { 348 - int ret; 349 - 350 - mutex_lock(&pipe->lock); 351 - 352 - /* If we're the first user validate and initialize the pipeline. */ 353 - if (pipe->use_count == 0) { 354 - ret = vsp1_video_pipeline_validate(pipe, video); 355 - if (ret < 0) 356 - goto done; 357 - } 358 - 359 - pipe->use_count++; 360 - ret = 0; 361 - 362 - done: 363 - mutex_unlock(&pipe->lock); 364 - return ret; 365 - } 366 - 367 - static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe) 368 - { 369 - mutex_lock(&pipe->lock); 370 - 371 - /* If we're the last user clean up the pipeline. */ 372 - if (--pipe->use_count == 0) 373 - vsp1_pipeline_reset(pipe); 374 - 375 - mutex_unlock(&pipe->lock); 376 - } 377 - 378 174 /* 379 175 * vsp1_video_complete_buffer - Complete the current buffer 380 176 * @video: the video node ··· 189 391 static struct vsp1_vb2_buffer * 190 392 vsp1_video_complete_buffer(struct vsp1_video *video) 191 393 { 192 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); 394 + struct vsp1_pipeline *pipe = video->rwpf->pipe; 193 395 struct vsp1_vb2_buffer *next = NULL; 194 396 struct vsp1_vb2_buffer *done; 195 397 unsigned long flags; ··· 223 425 done->buf.vb2_buf.timestamp = ktime_get_ns(); 224 426 for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) 225 427 vb2_set_plane_payload(&done->buf.vb2_buf, i, 226 - done->mem.length[i]); 428 + vb2_plane_size(&done->buf.vb2_buf, i)); 227 429 vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); 228 430 229 431 return next; ··· 242 444 243 445 spin_lock_irqsave(&pipe->irqlock, flags); 244 446 245 - video->rwpf->ops->set_memory(video->rwpf, &buf->mem); 447 + video->rwpf->mem = buf->mem; 246 448 pipe->buffers_ready |= 1 << video->pipe_index; 247 449 248 450 spin_unlock_irqrestore(&pipe->irqlock, flags); 249 451 } 250 452 453 + static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) 454 + { 455 + struct vsp1_device *vsp1 = pipe->output->entity.vsp1; 456 + unsigned int i; 457 + 458 + if (!pipe->dl) 459 + pipe->dl = vsp1_dl_list_get(pipe->output->dlm); 460 + 461 + for (i = 0; i < vsp1->info->rpf_count; ++i) { 462 + struct vsp1_rwpf *rwpf = pipe->inputs[i]; 463 + 464 + if (rwpf) 465 + vsp1_rwpf_set_memory(rwpf, pipe->dl); 466 + } 467 + 468 + if (!pipe->lif) 469 + vsp1_rwpf_set_memory(pipe->output, pipe->dl); 470 + 471 + vsp1_dl_list_commit(pipe->dl); 472 + pipe->dl = NULL; 473 + 474 + vsp1_pipeline_run(pipe); 475 + } 476 + 251 477 static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) 252 478 { 253 479 struct vsp1_device *vsp1 = pipe->output->entity.vsp1; 480 + enum vsp1_pipeline_state state; 481 + unsigned long flags; 254 482 unsigned int i; 255 483 256 484 /* Complete buffers on all video nodes. */ ··· 287 463 vsp1_video_frame_end(pipe, pipe->inputs[i]); 288 464 } 289 465 290 - if (!pipe->lif) 291 - vsp1_video_frame_end(pipe, pipe->output); 466 + vsp1_video_frame_end(pipe, pipe->output); 467 + 468 + spin_lock_irqsave(&pipe->irqlock, flags); 469 + 470 + state = pipe->state; 471 + pipe->state = VSP1_PIPELINE_STOPPED; 472 + 473 + /* If a stop has been requested, mark the pipeline as stopped and 474 + * return. Otherwise restart the pipeline if ready. 475 + */ 476 + if (state == VSP1_PIPELINE_STOPPING) 477 + wake_up(&pipe->wq); 478 + else if (vsp1_pipeline_ready(pipe)) 479 + vsp1_video_pipeline_run(pipe); 480 + 481 + spin_unlock_irqrestore(&pipe->irqlock, flags); 482 + } 483 + 484 + static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, 485 + struct vsp1_rwpf *input, 486 + struct vsp1_rwpf *output) 487 + { 488 + struct media_entity_enum ent_enum; 489 + struct vsp1_entity *entity; 490 + struct media_pad *pad; 491 + bool bru_found = false; 492 + int ret; 493 + 494 + ret = media_entity_enum_init(&ent_enum, &input->entity.vsp1->media_dev); 495 + if (ret < 0) 496 + return ret; 497 + 498 + pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); 499 + 500 + while (1) { 501 + if (pad == NULL) { 502 + ret = -EPIPE; 503 + goto out; 504 + } 505 + 506 + /* We've reached a video node, that shouldn't have happened. */ 507 + if (!is_media_entity_v4l2_subdev(pad->entity)) { 508 + ret = -EPIPE; 509 + goto out; 510 + } 511 + 512 + entity = to_vsp1_entity( 513 + media_entity_to_v4l2_subdev(pad->entity)); 514 + 515 + /* A BRU is present in the pipeline, store the BRU input pad 516 + * number in the input RPF for use when configuring the RPF. 517 + */ 518 + if (entity->type == VSP1_ENTITY_BRU) { 519 + struct vsp1_bru *bru = to_bru(&entity->subdev); 520 + 521 + bru->inputs[pad->index].rpf = input; 522 + input->bru_input = pad->index; 523 + 524 + bru_found = true; 525 + } 526 + 527 + /* We've reached the WPF, we're done. */ 528 + if (entity->type == VSP1_ENTITY_WPF) 529 + break; 530 + 531 + /* Ensure the branch has no loop. */ 532 + if (media_entity_enum_test_and_set(&ent_enum, 533 + &entity->subdev.entity)) { 534 + ret = -EPIPE; 535 + goto out; 536 + } 537 + 538 + /* UDS can't be chained. */ 539 + if (entity->type == VSP1_ENTITY_UDS) { 540 + if (pipe->uds) { 541 + ret = -EPIPE; 542 + goto out; 543 + } 544 + 545 + pipe->uds = entity; 546 + pipe->uds_input = bru_found ? pipe->bru 547 + : &input->entity; 548 + } 549 + 550 + /* Follow the source link. The link setup operations ensure 551 + * that the output fan-out can't be more than one, there is thus 552 + * no need to verify here that only a single source link is 553 + * activated. 554 + */ 555 + pad = &entity->pads[entity->source_pad]; 556 + pad = media_entity_remote_pad(pad); 557 + } 558 + 559 + /* The last entity must be the output WPF. */ 560 + if (entity != &output->entity) 561 + ret = -EPIPE; 562 + 563 + out: 564 + media_entity_enum_cleanup(&ent_enum); 565 + 566 + return ret; 567 + } 568 + 569 + static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, 570 + struct vsp1_video *video) 571 + { 572 + struct media_entity_graph graph; 573 + struct media_entity *entity = &video->video.entity; 574 + struct media_device *mdev = entity->graph_obj.mdev; 575 + unsigned int i; 576 + int ret; 577 + 578 + /* Walk the graph to locate the entities and video nodes. */ 579 + ret = media_entity_graph_walk_init(&graph, mdev); 580 + if (ret) 581 + return ret; 582 + 583 + media_entity_graph_walk_start(&graph, entity); 584 + 585 + while ((entity = media_entity_graph_walk_next(&graph))) { 586 + struct v4l2_subdev *subdev; 587 + struct vsp1_rwpf *rwpf; 588 + struct vsp1_entity *e; 589 + 590 + if (!is_media_entity_v4l2_subdev(entity)) 591 + continue; 592 + 593 + subdev = media_entity_to_v4l2_subdev(entity); 594 + e = to_vsp1_entity(subdev); 595 + list_add_tail(&e->list_pipe, &pipe->entities); 596 + 597 + if (e->type == VSP1_ENTITY_RPF) { 598 + rwpf = to_rwpf(subdev); 599 + pipe->inputs[rwpf->entity.index] = rwpf; 600 + rwpf->video->pipe_index = ++pipe->num_inputs; 601 + rwpf->pipe = pipe; 602 + } else if (e->type == VSP1_ENTITY_WPF) { 603 + rwpf = to_rwpf(subdev); 604 + pipe->output = rwpf; 605 + rwpf->video->pipe_index = 0; 606 + rwpf->pipe = pipe; 607 + } else if (e->type == VSP1_ENTITY_LIF) { 608 + pipe->lif = e; 609 + } else if (e->type == VSP1_ENTITY_BRU) { 610 + pipe->bru = e; 611 + } 612 + } 613 + 614 + media_entity_graph_walk_cleanup(&graph); 615 + 616 + /* We need one output and at least one input. */ 617 + if (pipe->num_inputs == 0 || !pipe->output) 618 + return -EPIPE; 619 + 620 + /* Follow links downstream for each input and make sure the graph 621 + * contains no loop and that all branches end at the output WPF. 622 + */ 623 + for (i = 0; i < video->vsp1->info->rpf_count; ++i) { 624 + if (!pipe->inputs[i]) 625 + continue; 626 + 627 + ret = vsp1_video_pipeline_build_branch(pipe, pipe->inputs[i], 628 + pipe->output); 629 + if (ret < 0) 630 + return ret; 631 + } 632 + 633 + return 0; 634 + } 635 + 636 + static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe, 637 + struct vsp1_video *video) 638 + { 639 + vsp1_pipeline_init(pipe); 640 + 641 + pipe->frame_end = vsp1_video_pipeline_frame_end; 642 + 643 + return vsp1_video_pipeline_build(pipe, video); 644 + } 645 + 646 + static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video) 647 + { 648 + struct vsp1_pipeline *pipe; 649 + int ret; 650 + 651 + /* Get a pipeline object for the video node. If a pipeline has already 652 + * been allocated just increment its reference count and return it. 653 + * Otherwise allocate a new pipeline and initialize it, it will be freed 654 + * when the last reference is released. 655 + */ 656 + if (!video->rwpf->pipe) { 657 + pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); 658 + if (!pipe) 659 + return ERR_PTR(-ENOMEM); 660 + 661 + ret = vsp1_video_pipeline_init(pipe, video); 662 + if (ret < 0) { 663 + vsp1_pipeline_reset(pipe); 664 + kfree(pipe); 665 + return ERR_PTR(ret); 666 + } 667 + } else { 668 + pipe = video->rwpf->pipe; 669 + kref_get(&pipe->kref); 670 + } 671 + 672 + return pipe; 673 + } 674 + 675 + static void vsp1_video_pipeline_release(struct kref *kref) 676 + { 677 + struct vsp1_pipeline *pipe = container_of(kref, typeof(*pipe), kref); 678 + 679 + vsp1_pipeline_reset(pipe); 680 + kfree(pipe); 681 + } 682 + 683 + static void vsp1_video_pipeline_put(struct vsp1_pipeline *pipe) 684 + { 685 + struct media_device *mdev = &pipe->output->entity.vsp1->media_dev; 686 + 687 + mutex_lock(&mdev->graph_mutex); 688 + kref_put(&pipe->kref, vsp1_video_pipeline_release); 689 + mutex_unlock(&mdev->graph_mutex); 292 690 } 293 691 294 692 /* ----------------------------------------------------------------------------- ··· 559 513 if (vb->num_planes < format->num_planes) 560 514 return -EINVAL; 561 515 562 - buf->mem.num_planes = vb->num_planes; 563 - 564 516 for (i = 0; i < vb->num_planes; ++i) { 565 517 buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); 566 - buf->mem.length[i] = vb2_plane_size(vb, i); 567 518 568 - if (buf->mem.length[i] < format->plane_fmt[i].sizeimage) 519 + if (vb2_plane_size(vb, i) < format->plane_fmt[i].sizeimage) 569 520 return -EINVAL; 570 521 } 522 + 523 + for ( ; i < 3; ++i) 524 + buf->mem.addr[i] = 0; 571 525 572 526 return 0; 573 527 } ··· 576 530 { 577 531 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 578 532 struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue); 579 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); 533 + struct vsp1_pipeline *pipe = video->rwpf->pipe; 580 534 struct vsp1_vb2_buffer *buf = to_vsp1_vb2_buffer(vbuf); 581 535 unsigned long flags; 582 536 bool empty; ··· 591 545 592 546 spin_lock_irqsave(&pipe->irqlock, flags); 593 547 594 - video->rwpf->ops->set_memory(video->rwpf, &buf->mem); 548 + video->rwpf->mem = buf->mem; 595 549 pipe->buffers_ready |= 1 << video->pipe_index; 596 550 597 551 if (vb2_is_streaming(&video->queue) && 598 552 vsp1_pipeline_ready(pipe)) 599 - vsp1_pipeline_run(pipe); 553 + vsp1_video_pipeline_run(pipe); 600 554 601 555 spin_unlock_irqrestore(&pipe->irqlock, flags); 556 + } 557 + 558 + static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) 559 + { 560 + struct vsp1_entity *entity; 561 + 562 + /* Prepare the display list. */ 563 + pipe->dl = vsp1_dl_list_get(pipe->output->dlm); 564 + if (!pipe->dl) 565 + return -ENOMEM; 566 + 567 + if (pipe->uds) { 568 + struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); 569 + 570 + /* If a BRU is present in the pipeline before the UDS, the alpha 571 + * component doesn't need to be scaled as the BRU output alpha 572 + * value is fixed to 255. Otherwise we need to scale the alpha 573 + * component only when available at the input RPF. 574 + */ 575 + if (pipe->uds_input->type == VSP1_ENTITY_BRU) { 576 + uds->scale_alpha = false; 577 + } else { 578 + struct vsp1_rwpf *rpf = 579 + to_rwpf(&pipe->uds_input->subdev); 580 + 581 + uds->scale_alpha = rpf->fmtinfo->alpha; 582 + } 583 + } 584 + 585 + list_for_each_entry(entity, &pipe->entities, list_pipe) { 586 + vsp1_entity_route_setup(entity, pipe->dl); 587 + 588 + if (entity->ops->configure) 589 + entity->ops->configure(entity, pipe, pipe->dl); 590 + } 591 + 592 + return 0; 602 593 } 603 594 604 595 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) 605 596 { 606 597 struct vsp1_video *video = vb2_get_drv_priv(vq); 607 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); 608 - struct vsp1_entity *entity; 598 + struct vsp1_pipeline *pipe = video->rwpf->pipe; 609 599 unsigned long flags; 610 600 int ret; 611 601 612 602 mutex_lock(&pipe->lock); 613 603 if (pipe->stream_count == pipe->num_inputs) { 614 - if (pipe->uds) { 615 - struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); 616 - 617 - /* If a BRU is present in the pipeline before the UDS, 618 - * the alpha component doesn't need to be scaled as the 619 - * BRU output alpha value is fixed to 255. Otherwise we 620 - * need to scale the alpha component only when available 621 - * at the input RPF. 622 - */ 623 - if (pipe->uds_input->type == VSP1_ENTITY_BRU) { 624 - uds->scale_alpha = false; 625 - } else { 626 - struct vsp1_rwpf *rpf = 627 - to_rwpf(&pipe->uds_input->subdev); 628 - 629 - uds->scale_alpha = rpf->fmtinfo->alpha; 630 - } 631 - } 632 - 633 - list_for_each_entry(entity, &pipe->entities, list_pipe) { 634 - vsp1_entity_route_setup(entity); 635 - 636 - ret = v4l2_subdev_call(&entity->subdev, video, 637 - s_stream, 1); 638 - if (ret < 0) { 639 - mutex_unlock(&pipe->lock); 640 - return ret; 641 - } 604 + ret = vsp1_video_setup_pipeline(pipe); 605 + if (ret < 0) { 606 + mutex_unlock(&pipe->lock); 607 + return ret; 642 608 } 643 609 } 644 610 ··· 659 601 660 602 spin_lock_irqsave(&pipe->irqlock, flags); 661 603 if (vsp1_pipeline_ready(pipe)) 662 - vsp1_pipeline_run(pipe); 604 + vsp1_video_pipeline_run(pipe); 663 605 spin_unlock_irqrestore(&pipe->irqlock, flags); 664 606 665 607 return 0; ··· 668 610 static void vsp1_video_stop_streaming(struct vb2_queue *vq) 669 611 { 670 612 struct vsp1_video *video = vb2_get_drv_priv(vq); 671 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); 613 + struct vsp1_pipeline *pipe = video->rwpf->pipe; 672 614 struct vsp1_vb2_buffer *buffer; 673 615 unsigned long flags; 674 616 int ret; ··· 679 621 ret = vsp1_pipeline_stop(pipe); 680 622 if (ret == -ETIMEDOUT) 681 623 dev_err(video->vsp1->dev, "pipeline stop timeout\n"); 624 + 625 + vsp1_dl_list_put(pipe->dl); 626 + pipe->dl = NULL; 682 627 } 683 628 mutex_unlock(&pipe->lock); 684 629 685 - vsp1_video_pipeline_cleanup(pipe); 686 630 media_entity_pipeline_stop(&video->video.entity); 631 + vsp1_video_pipeline_put(pipe); 687 632 688 633 /* Remove all buffers from the IRQ queue. */ 689 634 spin_lock_irqsave(&video->irqlock, flags); ··· 798 737 { 799 738 struct v4l2_fh *vfh = file->private_data; 800 739 struct vsp1_video *video = to_vsp1_video(vfh->vdev); 740 + struct media_device *mdev = &video->vsp1->media_dev; 801 741 struct vsp1_pipeline *pipe; 802 742 int ret; 803 743 ··· 807 745 808 746 video->sequence = 0; 809 747 810 - /* Start streaming on the pipeline. No link touching an entity in the 811 - * pipeline can be activated or deactivated once streaming is started. 812 - * 813 - * Use the VSP1 pipeline object embedded in the first video object that 814 - * starts streaming. 748 + /* Get a pipeline for the video node and start streaming on it. No link 749 + * touching an entity in the pipeline can be activated or deactivated 750 + * once streaming is started. 815 751 */ 816 - pipe = video->video.entity.pipe 817 - ? to_vsp1_pipeline(&video->video.entity) : &video->pipe; 752 + mutex_lock(&mdev->graph_mutex); 818 753 819 - ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe); 820 - if (ret < 0) 821 - return ret; 754 + pipe = vsp1_video_pipeline_get(video); 755 + if (IS_ERR(pipe)) { 756 + mutex_unlock(&mdev->graph_mutex); 757 + return PTR_ERR(pipe); 758 + } 759 + 760 + ret = __media_entity_pipeline_start(&video->video.entity, &pipe->pipe); 761 + if (ret < 0) { 762 + mutex_unlock(&mdev->graph_mutex); 763 + goto err_pipe; 764 + } 765 + 766 + mutex_unlock(&mdev->graph_mutex); 822 767 823 768 /* Verify that the configured format matches the output of the connected 824 769 * subdev. ··· 834 765 if (ret < 0) 835 766 goto err_stop; 836 767 837 - ret = vsp1_video_pipeline_init(pipe, video); 838 - if (ret < 0) 839 - goto err_stop; 840 - 841 768 /* Start the queue. */ 842 769 ret = vb2_streamon(&video->queue, type); 843 770 if (ret < 0) 844 - goto err_cleanup; 771 + goto err_stop; 845 772 846 773 return 0; 847 774 848 - err_cleanup: 849 - vsp1_video_pipeline_cleanup(pipe); 850 775 err_stop: 851 776 media_entity_pipeline_stop(&video->video.entity); 777 + err_pipe: 778 + vsp1_video_pipeline_put(pipe); 852 779 return ret; 853 780 } 854 781 ··· 960 895 spin_lock_init(&video->irqlock); 961 896 INIT_LIST_HEAD(&video->irqqueue); 962 897 963 - vsp1_pipeline_init(&video->pipe); 964 - video->pipe.frame_end = vsp1_video_pipeline_frame_end; 965 - 966 898 /* Initialize the media entity... */ 967 899 ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); 968 900 if (ret < 0) 969 901 return ERR_PTR(ret); 970 902 971 903 /* ... and the format ... */ 972 - rwpf->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT); 973 - rwpf->format.pixelformat = rwpf->fmtinfo->fourcc; 974 - rwpf->format.colorspace = V4L2_COLORSPACE_SRGB; 975 - rwpf->format.field = V4L2_FIELD_NONE; 904 + rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT; 976 905 rwpf->format.width = VSP1_VIDEO_DEF_WIDTH; 977 906 rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT; 978 - rwpf->format.num_planes = 1; 979 - rwpf->format.plane_fmt[0].bytesperline = 980 - rwpf->format.width * rwpf->fmtinfo->bpp[0] / 8; 981 - rwpf->format.plane_fmt[0].sizeimage = 982 - rwpf->format.plane_fmt[0].bytesperline * rwpf->format.height; 907 + __vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo); 983 908 984 909 /* ... and the video node... */ 985 910 video->video.v4l2_dev = &video->vsp1->v4l2_dev;
-2
drivers/media/platform/vsp1/vsp1_video.h
··· 18 18 19 19 #include <media/videobuf2-v4l2.h> 20 20 21 - #include "vsp1_pipe.h" 22 21 #include "vsp1_rwpf.h" 23 22 24 23 struct vsp1_vb2_buffer { ··· 43 44 44 45 struct mutex lock; 45 46 46 - struct vsp1_pipeline pipe; 47 47 unsigned int pipe_index; 48 48 49 49 struct vb2_queue queue;
+143 -176
drivers/media/platform/vsp1/vsp1_wpf.c
··· 16 16 #include <media/v4l2-subdev.h> 17 17 18 18 #include "vsp1.h" 19 + #include "vsp1_dl.h" 20 + #include "vsp1_pipe.h" 19 21 #include "vsp1_rwpf.h" 20 22 #include "vsp1_video.h" 21 23 22 - #define WPF_MAX_WIDTH 2048 23 - #define WPF_MAX_HEIGHT 2048 24 + #define WPF_GEN2_MAX_WIDTH 2048U 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 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, 32 - reg + wpf->entity.index * VI6_WPF_OFFSET); 36 + vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data); 33 37 } 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 - } 40 - 41 - /* ----------------------------------------------------------------------------- 42 - * Controls 43 - */ 44 - 45 - static int wpf_s_ctrl(struct v4l2_ctrl *ctrl) 46 - { 47 - struct vsp1_rwpf *wpf = 48 - container_of(ctrl->handler, struct vsp1_rwpf, ctrls); 49 - u32 value; 50 - 51 - if (!vsp1_entity_is_streaming(&wpf->entity)) 52 - return 0; 53 - 54 - switch (ctrl->id) { 55 - case V4L2_CID_ALPHA_COMPONENT: 56 - value = vsp1_wpf_read(wpf, VI6_WPF_OUTFMT); 57 - value &= ~VI6_WPF_OUTFMT_PDV_MASK; 58 - value |= ctrl->val << VI6_WPF_OUTFMT_PDV_SHIFT; 59 - vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, value); 60 - break; 61 - } 62 - 63 - return 0; 64 - } 65 - 66 - static const struct v4l2_ctrl_ops wpf_ctrl_ops = { 67 - .s_ctrl = wpf_s_ctrl, 68 - }; 69 38 70 39 /* ----------------------------------------------------------------------------- 71 40 * V4L2 Subdevice Core Operations ··· 42 73 43 74 static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) 44 75 { 45 - struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity); 46 76 struct vsp1_rwpf *wpf = to_rwpf(subdev); 47 77 struct vsp1_device *vsp1 = wpf->entity.vsp1; 48 - const struct v4l2_rect *crop = &wpf->crop; 49 - unsigned int i; 50 - u32 srcrpf = 0; 51 - u32 outfmt = 0; 52 - int ret; 53 78 54 - ret = vsp1_entity_set_streaming(&wpf->entity, enable); 55 - if (ret < 0) 56 - return ret; 57 - 58 - if (!enable) { 59 - vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); 60 - vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET + 61 - VI6_WPF_SRCRPF, 0); 79 + if (enable) 62 80 return 0; 81 + 82 + /* Write to registers directly when stopping the stream as there will be 83 + * no pipeline run to apply the display list. 84 + */ 85 + vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); 86 + vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET + 87 + VI6_WPF_SRCRPF, 0); 88 + 89 + return 0; 90 + } 91 + 92 + /* ----------------------------------------------------------------------------- 93 + * V4L2 Subdevice Operations 94 + */ 95 + 96 + static struct v4l2_subdev_video_ops wpf_video_ops = { 97 + .s_stream = wpf_s_stream, 98 + }; 99 + 100 + static struct v4l2_subdev_ops wpf_ops = { 101 + .video = &wpf_video_ops, 102 + .pad = &vsp1_rwpf_pad_ops, 103 + }; 104 + 105 + /* ----------------------------------------------------------------------------- 106 + * VSP1 Entity Operations 107 + */ 108 + 109 + static void vsp1_wpf_destroy(struct vsp1_entity *entity) 110 + { 111 + struct vsp1_rwpf *wpf = entity_to_rwpf(entity); 112 + 113 + vsp1_dlm_destroy(wpf->dlm); 114 + } 115 + 116 + static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) 117 + { 118 + struct vsp1_rwpf *wpf = entity_to_rwpf(entity); 119 + 120 + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]); 121 + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]); 122 + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]); 123 + } 124 + 125 + static void wpf_configure(struct vsp1_entity *entity, 126 + struct vsp1_pipeline *pipe, 127 + struct vsp1_dl_list *dl) 128 + { 129 + struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); 130 + struct vsp1_device *vsp1 = wpf->entity.vsp1; 131 + const struct v4l2_mbus_framefmt *source_format; 132 + const struct v4l2_mbus_framefmt *sink_format; 133 + const struct v4l2_rect *crop; 134 + unsigned int i; 135 + u32 outfmt = 0; 136 + u32 srcrpf = 0; 137 + 138 + /* Cropping */ 139 + crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); 140 + 141 + vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | 142 + (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | 143 + (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); 144 + vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | 145 + (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | 146 + (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); 147 + 148 + /* Format */ 149 + sink_format = vsp1_entity_get_pad_format(&wpf->entity, 150 + wpf->entity.config, 151 + RWPF_PAD_SINK); 152 + source_format = vsp1_entity_get_pad_format(&wpf->entity, 153 + wpf->entity.config, 154 + RWPF_PAD_SOURCE); 155 + 156 + if (!pipe->lif) { 157 + const struct v4l2_pix_format_mplane *format = &wpf->format; 158 + const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; 159 + 160 + outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; 161 + 162 + if (fmtinfo->alpha) 163 + outfmt |= VI6_WPF_OUTFMT_PXA; 164 + if (fmtinfo->swap_yc) 165 + outfmt |= VI6_WPF_OUTFMT_SPYCS; 166 + if (fmtinfo->swap_uv) 167 + outfmt |= VI6_WPF_OUTFMT_SPUVS; 168 + 169 + /* Destination stride and byte swapping. */ 170 + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y, 171 + format->plane_fmt[0].bytesperline); 172 + if (format->num_planes > 1) 173 + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C, 174 + format->plane_fmt[1].bytesperline); 175 + 176 + vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); 63 177 } 178 + 179 + if (sink_format->code != source_format->code) 180 + outfmt |= VI6_WPF_OUTFMT_CSC; 181 + 182 + outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT; 183 + vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); 184 + 185 + vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), 186 + VI6_DPR_WPF_FPORCH_FP_WPFN); 187 + 188 + vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0); 64 189 65 190 /* Sources. If the pipeline has a single input and BRU is not used, 66 191 * configure it as the master layer. Otherwise configure all ··· 175 112 if (pipe->bru || pipe->num_inputs > 1) 176 113 srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; 177 114 178 - vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); 179 - 180 - /* Destination stride. */ 181 - if (!pipe->lif) { 182 - struct v4l2_pix_format_mplane *format = &wpf->format; 183 - 184 - vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y, 185 - format->plane_fmt[0].bytesperline); 186 - if (format->num_planes > 1) 187 - vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C, 188 - format->plane_fmt[1].bytesperline); 189 - } 190 - 191 - vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | 192 - (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | 193 - (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); 194 - vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | 195 - (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | 196 - (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); 197 - 198 - /* Format */ 199 - if (!pipe->lif) { 200 - const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; 201 - 202 - outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; 203 - 204 - if (fmtinfo->alpha) 205 - outfmt |= VI6_WPF_OUTFMT_PXA; 206 - if (fmtinfo->swap_yc) 207 - outfmt |= VI6_WPF_OUTFMT_SPYCS; 208 - if (fmtinfo->swap_uv) 209 - outfmt |= VI6_WPF_OUTFMT_SPUVS; 210 - 211 - vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap); 212 - } 213 - 214 - if (wpf->entity.formats[RWPF_PAD_SINK].code != 215 - wpf->entity.formats[RWPF_PAD_SOURCE].code) 216 - outfmt |= VI6_WPF_OUTFMT_CSC; 217 - 218 - /* Take the control handler lock to ensure that the PDV value won't be 219 - * changed behind our back by a set control operation. 220 - */ 221 - if (vsp1->info->uapi) 222 - mutex_lock(wpf->ctrls.lock); 223 - outfmt |= wpf->alpha->cur.val << VI6_WPF_OUTFMT_PDV_SHIFT; 224 - vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt); 225 - if (vsp1->info->uapi) 226 - mutex_unlock(wpf->ctrls.lock); 227 - 228 - vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index), 229 - VI6_DPR_WPF_FPORCH_FP_WPFN); 230 - 231 - vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0); 115 + vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf); 232 116 233 117 /* Enable interrupts */ 234 - vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0); 235 - vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 236 - VI6_WFP_IRQ_ENB_FREE); 237 - 238 - return 0; 118 + vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0); 119 + vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index), 120 + VI6_WFP_IRQ_ENB_FREE); 239 121 } 240 122 241 - /* ----------------------------------------------------------------------------- 242 - * V4L2 Subdevice Operations 243 - */ 244 - 245 - static struct v4l2_subdev_video_ops wpf_video_ops = { 246 - .s_stream = wpf_s_stream, 247 - }; 248 - 249 - static struct v4l2_subdev_pad_ops wpf_pad_ops = { 250 - .enum_mbus_code = vsp1_rwpf_enum_mbus_code, 251 - .enum_frame_size = vsp1_rwpf_enum_frame_size, 252 - .get_fmt = vsp1_rwpf_get_format, 253 - .set_fmt = vsp1_rwpf_set_format, 254 - .get_selection = vsp1_rwpf_get_selection, 255 - .set_selection = vsp1_rwpf_set_selection, 256 - }; 257 - 258 - static struct v4l2_subdev_ops wpf_ops = { 259 - .video = &wpf_video_ops, 260 - .pad = &wpf_pad_ops, 261 - }; 262 - 263 - /* ----------------------------------------------------------------------------- 264 - * Video Device Operations 265 - */ 266 - 267 - static void wpf_set_memory(struct vsp1_rwpf *wpf, struct vsp1_rwpf_memory *mem) 268 - { 269 - vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, mem->addr[0]); 270 - if (mem->num_planes > 1) 271 - vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, mem->addr[1]); 272 - if (mem->num_planes > 2) 273 - vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, mem->addr[2]); 274 - } 275 - 276 - static const struct vsp1_rwpf_operations wpf_vdev_ops = { 123 + static const struct vsp1_entity_operations wpf_entity_ops = { 124 + .destroy = vsp1_wpf_destroy, 277 125 .set_memory = wpf_set_memory, 126 + .configure = wpf_configure, 278 127 }; 279 128 280 129 /* ----------------------------------------------------------------------------- ··· 195 220 196 221 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) 197 222 { 198 - struct v4l2_subdev *subdev; 199 223 struct vsp1_rwpf *wpf; 224 + char name[6]; 200 225 int ret; 201 226 202 227 wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL); 203 228 if (wpf == NULL) 204 229 return ERR_PTR(-ENOMEM); 205 230 206 - wpf->ops = &wpf_vdev_ops; 231 + if (vsp1->info->gen == 2) { 232 + wpf->max_width = WPF_GEN2_MAX_WIDTH; 233 + wpf->max_height = WPF_GEN2_MAX_HEIGHT; 234 + } else { 235 + wpf->max_width = WPF_GEN3_MAX_WIDTH; 236 + wpf->max_height = WPF_GEN3_MAX_HEIGHT; 237 + } 207 238 208 - wpf->max_width = WPF_MAX_WIDTH; 209 - wpf->max_height = WPF_MAX_HEIGHT; 210 - 239 + wpf->entity.ops = &wpf_entity_ops; 211 240 wpf->entity.type = VSP1_ENTITY_WPF; 212 241 wpf->entity.index = index; 213 242 214 - ret = vsp1_entity_init(vsp1, &wpf->entity, 2); 243 + sprintf(name, "wpf.%u", index); 244 + ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops); 215 245 if (ret < 0) 216 246 return ERR_PTR(ret); 217 247 218 - /* Initialize the V4L2 subdev. */ 219 - subdev = &wpf->entity.subdev; 220 - v4l2_subdev_init(subdev, &wpf_ops); 221 - 222 - subdev->entity.ops = &vsp1->media_ops; 223 - subdev->internal_ops = &vsp1_subdev_internal_ops; 224 - snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u", 225 - dev_name(vsp1->dev), index); 226 - v4l2_set_subdevdata(subdev, wpf); 227 - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 228 - 229 - vsp1_entity_init_formats(subdev, NULL); 248 + /* Initialize the display list manager. */ 249 + wpf->dlm = vsp1_dlm_create(vsp1, index, 4); 250 + if (!wpf->dlm) { 251 + ret = -ENOMEM; 252 + goto error; 253 + } 230 254 231 255 /* Initialize the control handler. */ 232 - v4l2_ctrl_handler_init(&wpf->ctrls, 1); 233 - wpf->alpha = v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops, 234 - V4L2_CID_ALPHA_COMPONENT, 235 - 0, 255, 1, 255); 236 - 237 - wpf->entity.subdev.ctrl_handler = &wpf->ctrls; 238 - 239 - if (wpf->ctrls.error) { 256 + ret = vsp1_rwpf_init_ctrls(wpf); 257 + if (ret < 0) { 240 258 dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", 241 259 index); 242 - ret = wpf->ctrls.error; 243 260 goto error; 244 261 } 245 262
+2 -6
drivers/media/platform/xilinx/xilinx-vipp.c
··· 351 351 struct xvip_graph_entity *entity; 352 352 struct device_node *remote; 353 353 struct device_node *ep = NULL; 354 - struct device_node *next; 355 354 int ret = 0; 356 355 357 356 dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); 358 357 359 358 while (1) { 360 - next = of_graph_get_next_endpoint(node, ep); 361 - if (next == NULL) 359 + ep = of_graph_get_next_endpoint(node, ep); 360 + if (ep == NULL) 362 361 break; 363 - 364 - of_node_put(ep); 365 - ep = next; 366 362 367 363 dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); 368 364
+4 -7
drivers/media/rc/ati_remote.c
··· 873 873 strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys)); 874 874 strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys)); 875 875 876 - if (udev->manufacturer) 877 - strlcpy(ati_remote->rc_name, udev->manufacturer, 878 - sizeof(ati_remote->rc_name)); 879 - 880 - if (udev->product) 881 - snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), 882 - "%s %s", ati_remote->rc_name, udev->product); 876 + snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), "%s%s%s", 877 + udev->manufacturer ?: "", 878 + udev->manufacturer && udev->product ? " " : "", 879 + udev->product ?: ""); 883 880 884 881 if (!strlen(ati_remote->rc_name)) 885 882 snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
+6
drivers/media/rc/mceusb.c
··· 188 188 #define VENDOR_TWISTEDMELON 0x2596 189 189 #define VENDOR_HAUPPAUGE 0x2040 190 190 #define VENDOR_PCTV 0x2013 191 + #define VENDOR_ADAPTEC 0x03f3 191 192 192 193 enum mceusb_model_type { 193 194 MCE_GEN2 = 0, /* Most boards */ ··· 303 302 /* SMK/I-O Data GV-MC7/RCKIT Receiver */ 304 303 { USB_DEVICE(VENDOR_SMK, 0x0353), 305 304 .driver_info = MCE_GEN2_NO_TX }, 305 + /* SMK RXX6000 Infrared Receiver */ 306 + { USB_DEVICE(VENDOR_SMK, 0x0357), 307 + .driver_info = MCE_GEN2_NO_TX }, 306 308 /* Tatung eHome Infrared Transceiver */ 307 309 { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, 308 310 /* Shuttle eHome Infrared Transceiver */ ··· 409 405 .driver_info = HAUPPAUGE_CX_HYBRID_TV }, 410 406 { USB_DEVICE(VENDOR_PCTV, 0x025e), 411 407 .driver_info = HAUPPAUGE_CX_HYBRID_TV }, 408 + /* Adaptec / HP eHome Receiver */ 409 + { USB_DEVICE(VENDOR_ADAPTEC, 0x0094) }, 412 410 413 411 /* Terminating entry */ 414 412 { }
+6 -3
drivers/media/rc/rc-main.c
··· 1263 1263 1264 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 1271 #define ADD_HOTPLUG_VAR(fmt, val...) \ ··· 1387 1384 1388 1385 put_device(&dev->dev); 1389 1386 1390 - kfree(dev); 1387 + /* kfree(dev) will be called by the callback function 1388 + rc_dev_release() */ 1389 + 1391 1390 module_put(THIS_MODULE); 1392 1391 } 1393 1392 EXPORT_SYMBOL_GPL(rc_free_device); ··· 1497 1492 } 1498 1493 1499 1494 /* Allow the RC sysfs nodes to be accessible */ 1500 - mutex_lock(&dev->lock); 1501 1495 atomic_set(&dev->initialized, 1); 1502 - mutex_unlock(&dev->lock); 1503 1496 1504 1497 IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", 1505 1498 dev->minor,
+26 -10
drivers/media/tuners/qm1d1c0042.c
··· 32 32 #include "qm1d1c0042.h" 33 33 34 34 #define QM1D1C0042_NUM_REGS 0x20 35 + #define QM1D1C0042_NUM_REG_ROWS 2 35 36 36 - static const u8 reg_initval[QM1D1C0042_NUM_REGS] = { 37 - 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, 38 - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 39 - 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86, 40 - 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00 37 + static const u8 38 + reg_initval[QM1D1C0042_NUM_REG_ROWS][QM1D1C0042_NUM_REGS] = { { 39 + 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, 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 }; 50 + 51 + static int reg_index; 42 52 43 53 static const struct qm1d1c0042_config default_cfg = { 44 54 .xtal_freq = 16000, ··· 330 320 int i, ret; 331 321 332 322 state = fe->tuner_priv; 333 - memcpy(state->regs, reg_initval, sizeof(reg_initval)); 334 323 335 324 reg_write(state, 0x01, 0x0c); 336 325 reg_write(state, 0x01, 0x0c); ··· 339 330 goto failed; 340 331 usleep_range(2000, 3000); 341 332 342 - val = state->regs[0x01] | 0x10; 343 - ret = reg_write(state, 0x01, val); /* soft reset off */ 333 + ret = reg_write(state, 0x01, 0x1c); /* soft reset off */ 344 334 if (ret < 0) 345 335 goto failed; 346 336 347 - /* check ID */ 337 + /* check ID and choose initial registers corresponding ID */ 348 338 ret = reg_read(state, 0x00, &val); 349 - if (ret < 0 || val != 0x48) 339 + if (ret < 0) 350 340 goto failed; 341 + for (reg_index = 0; reg_index < QM1D1C0042_NUM_REG_ROWS; 342 + reg_index++) { 343 + if (val == reg_initval[reg_index][0x00]) 344 + break; 345 + } 346 + if (reg_index >= QM1D1C0042_NUM_REG_ROWS) 347 + goto failed; 348 + memcpy(state->regs, reg_initval[reg_index], QM1D1C0042_NUM_REGS); 351 349 usleep_range(2000, 3000); 352 350 353 351 state->regs[0x0c] |= 0x40;
+13 -6
drivers/media/tuners/si2157.c
··· 84 84 struct si2157_cmd cmd; 85 85 const struct firmware *fw; 86 86 const char *fw_name; 87 - unsigned int chip_id; 87 + unsigned int uitmp, chip_id; 88 88 89 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 103 goto warm; 93 104 94 105 /* power up */ ··· 214 203 215 204 dev_info(&client->dev, "firmware version: %c.%c.%d\n", 216 205 cmd.args[6], cmd.args[7], cmd.args[8]); 217 - 218 - dev->fw_loaded = true; 219 - 220 206 warm: 221 207 /* init statistics in order signal app which are supported */ 222 208 c->strength.len = 1; ··· 430 422 dev->fe = cfg->fe; 431 423 dev->inversion = cfg->inversion; 432 424 dev->if_port = cfg->if_port; 433 - dev->fw_loaded = false; 434 425 dev->chiptype = (u8)id->driver_data; 435 426 dev->if_frequency = 5000000; /* default value of property 0x0706 */ 436 427 mutex_init(&dev->i2c_mutex);
-1
drivers/media/tuners/si2157_priv.h
··· 26 26 struct mutex i2c_mutex; 27 27 struct dvb_frontend *fe; 28 28 bool active; 29 - bool fw_loaded; 30 29 bool inversion; 31 30 u8 chiptype; 32 31 u8 if_port;
+25 -11
drivers/media/usb/au0828/au0828-core.c
··· 131 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 139 static void au0828_unregister_media_device(struct au0828_dev *dev) 135 140 { 136 - 137 141 #ifdef CONFIG_MEDIA_CONTROLLER 138 - if (dev->media_dev && 139 - media_devnode_is_registered(&dev->media_dev->devnode)) { 140 - /* clear enable_source, disable_source */ 141 - dev->media_dev->source_priv = NULL; 142 - dev->media_dev->enable_source = NULL; 143 - dev->media_dev->disable_source = NULL; 142 + struct media_device *mdev = dev->media_dev; 143 + struct media_entity_notify *notify, *nextp; 144 144 145 - media_device_unregister(dev->media_dev); 146 - media_device_cleanup(dev->media_dev); 147 - kfree(dev->media_dev); 148 - dev->media_dev = NULL; 145 + if (!mdev || !media_devnode_is_registered(&mdev->devnode)) 146 + return; 147 + 148 + /* Remove au0828 entity_notify callbacks */ 149 + list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) { 150 + if (notify->notify != au0828_media_graph_notify) 151 + continue; 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 164 #endif 151 165 } 152 166
-4
drivers/media/usb/au0828/au0828-video.c
··· 679 679 if (retval) { 680 680 pr_err("%s() v4l2_device_register failed\n", 681 681 __func__); 682 - mutex_unlock(&dev->lock); 683 - kfree(dev); 684 682 return retval; 685 683 } 686 684 ··· 689 691 if (retval) { 690 692 pr_err("%s() v4l2_ctrl_handler_init failed\n", 691 693 __func__); 692 - mutex_unlock(&dev->lock); 693 - kfree(dev); 694 694 return retval; 695 695 } 696 696 dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
-1
drivers/media/usb/au0828/au0828.h
··· 55 55 #define NTSC_STD_H 480 56 56 57 57 #define AU0828_INTERLACED_DEFAULT 1 58 - #define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0) 59 58 60 59 /* Defination for AU0828 USB transfer */ 61 60 #define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
+20 -11
drivers/media/usb/cx231xx/cx231xx-417.c
··· 360 360 361 361 if (count++ > 100) { 362 362 dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio); 363 - return -1; 363 + return -EIO; 364 364 } 365 365 } 366 366 return 0; ··· 856 856 } 857 857 } 858 858 dprintk(3, "Mailbox signature values not found!\n"); 859 - return -1; 859 + return -EIO; 860 860 } 861 861 862 862 static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value, ··· 960 960 p_fw = p_current_fw; 961 961 if (p_current_fw == NULL) { 962 962 dprintk(2, "FAIL!!!\n"); 963 - return -1; 963 + return -ENOMEM; 964 964 } 965 965 966 966 p_buffer = vmalloc(4096); 967 967 if (p_buffer == NULL) { 968 968 dprintk(2, "FAIL!!!\n"); 969 - return -1; 969 + vfree(p_current_fw); 970 + return -ENOMEM; 970 971 } 971 972 972 973 dprintk(2, "%s()\n", __func__); ··· 990 989 if (retval != 0) { 991 990 dev_err(dev->dev, 992 991 "%s: Error with mc417_register_write\n", __func__); 993 - return -1; 992 + vfree(p_current_fw); 993 + vfree(p_buffer); 994 + return retval; 994 995 } 995 996 996 997 retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME, ··· 1004 1001 CX231xx_FIRM_IMAGE_NAME); 1005 1002 dev_err(dev->dev, 1006 1003 "Please fix your hotplug setup, the board will not work without firmware loaded!\n"); 1007 - return -1; 1004 + vfree(p_current_fw); 1005 + vfree(p_buffer); 1006 + return retval; 1008 1007 } 1009 1008 1010 1009 if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) { ··· 1014 1009 "ERROR: Firmware size mismatch (have %zd, expected %d)\n", 1015 1010 firmware->size, CX231xx_FIRM_IMAGE_SIZE); 1016 1011 release_firmware(firmware); 1017 - return -1; 1012 + vfree(p_current_fw); 1013 + vfree(p_buffer); 1014 + return -EINVAL; 1018 1015 } 1019 1016 1020 1017 if (0 != memcmp(firmware->data, magic, 8)) { 1021 1018 dev_err(dev->dev, 1022 1019 "ERROR: Firmware magic mismatch, wrong file?\n"); 1023 1020 release_firmware(firmware); 1024 - return -1; 1021 + vfree(p_current_fw); 1022 + vfree(p_buffer); 1023 + return -EINVAL; 1025 1024 } 1026 1025 1027 1026 initGPIO(dev); ··· 1140 1131 if (retval < 0) { 1141 1132 dev_err(dev->dev, "%s: mailbox < 0, error\n", 1142 1133 __func__); 1143 - return -1; 1134 + return retval; 1144 1135 } 1145 1136 dev->cx23417_mailbox = retval; 1146 1137 retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); 1147 1138 if (retval < 0) { 1148 1139 dev_err(dev->dev, 1149 1140 "ERROR: cx23417 firmware ping failed!\n"); 1150 - return -1; 1141 + return retval; 1151 1142 } 1152 1143 retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, 1153 1144 &version); 1154 1145 if (retval < 0) { 1155 1146 dev_err(dev->dev, 1156 1147 "ERROR: cx23417 firmware get encoder: version failed!\n"); 1157 - return -1; 1148 + return retval; 1158 1149 } 1159 1150 dprintk(1, "cx23417 firmware version is 0x%08x\n", version); 1160 1151 msleep(200);
+2 -1
drivers/media/usb/cx231xx/cx231xx-core.c
··· 752 752 int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) 753 753 { 754 754 int errCode = 0; 755 - int actlen, ret = -ENOMEM; 755 + int actlen = -1; 756 + int ret = -ENOMEM; 756 757 u32 *buffer; 757 758 758 759 buffer = kzalloc(4096, GFP_KERNEL);
+12 -12
drivers/media/usb/dvb-usb-v2/af9035.h
··· 118 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 122 - #define EEPROM_BASE_IT9135 0x499c 121 + #define EEPROM_BASE_AF9035 0x42f5 122 + #define EEPROM_BASE_IT9135 0x4994 123 123 #define EEPROM_SHIFT 0x10 124 124 125 - #define EEPROM_IR_MODE 0x10 126 - #define EEPROM_TS_MODE 0x29 127 - #define EEPROM_2ND_DEMOD_ADDR 0x2a 128 - #define EEPROM_IR_TYPE 0x2c 129 - #define EEPROM_1_IF_L 0x30 130 - #define EEPROM_1_IF_H 0x31 131 - #define EEPROM_1_TUNER_ID 0x34 132 - #define EEPROM_2_IF_L 0x40 133 - #define EEPROM_2_IF_H 0x41 134 - #define EEPROM_2_TUNER_ID 0x44 125 + #define EEPROM_IR_MODE 0x18 126 + #define EEPROM_TS_MODE 0x31 127 + #define EEPROM_2ND_DEMOD_ADDR 0x32 128 + #define EEPROM_IR_TYPE 0x34 129 + #define EEPROM_1_IF_L 0x38 130 + #define EEPROM_1_IF_H 0x39 131 + #define EEPROM_1_TUNER_ID 0x3c 132 + #define EEPROM_2_IF_L 0x48 133 + #define EEPROM_2_IF_H 0x49 134 + #define EEPROM_2_TUNER_ID 0x4c 135 135 136 136 /* USB commands */ 137 137 #define CMD_MEM_RD 0x00
+6 -1
drivers/media/usb/dvb-usb/az6027.c
··· 1090 1090 { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, 1091 1091 { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, 1092 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 ··· 1139 1138 1140 1139 .i2c_algo = &az6027_i2c_algo, 1141 1140 1142 - .num_device_descs = 7, 1141 + .num_device_descs = 8, 1143 1142 .devices = { 1144 1143 { 1145 1144 .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", ··· 1168 1167 }, { 1169 1168 .name = "Elgato EyeTV Sat", 1170 1169 .cold_ids = { &az6027_usb_table[6], NULL }, 1170 + .warm_ids = { NULL }, 1171 + }, { 1172 + .name = "Elgato EyeTV Sat", 1173 + .cold_ids = { &az6027_usb_table[7], NULL }, 1171 1174 .warm_ids = { NULL }, 1172 1175 }, 1173 1176 { NULL },
+3 -1
drivers/media/usb/dvb-usb/dib0700_devices.c
··· 3814 3814 { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E) }, 3815 3815 { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) }, 3816 3816 { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) }, 3817 + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096PVR) }, 3817 3818 { 0 } /* Terminating entry */ 3818 3819 }; 3819 3820 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); ··· 5018 5017 .num_device_descs = 1, 5019 5018 .devices = { 5020 5019 { "DiBcom STK8096-PVR reference design", 5021 - { &dib0700_usb_id_table[83], NULL }, 5020 + { &dib0700_usb_id_table[83], 5021 + &dib0700_usb_id_table[84], NULL}, 5022 5022 { NULL }, 5023 5023 }, 5024 5024 },
+2 -2
drivers/media/usb/dvb-usb/dibusb-common.c
··· 184 184 } 185 185 EXPORT_SYMBOL(dibusb_read_eeprom_byte); 186 186 187 + #if IS_ENABLED(CONFIG_DVB_DIB3000MC) 188 + 187 189 /* 3000MC/P stuff */ 188 190 // Config Adjacent channels Perf -cal22 189 191 static struct dibx000_agc_config dib3000p_mt2060_agc_config = { ··· 243 241 .agc2_slope1 = 0x95, 244 242 .agc2_slope2 = 0x1e, 245 243 }; 246 - 247 - #if IS_ENABLED(CONFIG_DVB_DIB3000MC) 248 244 249 245 static struct dib3000mc_config mod3000p_dib3000p_config = { 250 246 &dib3000p_panasonic_agc_config,
+6 -57
drivers/media/usb/dvb-usb/dw2102.c
··· 13 13 * 14 14 * see Documentation/dvb/README.dvb-usb for more information 15 15 */ 16 + #include "dvb-usb-ids.h" 16 17 #include "dw2102.h" 17 18 #include "si21xx.h" 18 19 #include "stv0299.h" ··· 39 38 /* Max transfer size done by I2C transfer functions */ 40 39 #define MAX_XFER_SIZE 64 41 40 42 - #ifndef USB_PID_DW2102 43 - #define USB_PID_DW2102 0x2102 44 - #endif 45 - 46 - #ifndef USB_PID_DW2104 47 - #define USB_PID_DW2104 0x2104 48 - #endif 49 - 50 - #ifndef USB_PID_DW3101 51 - #define USB_PID_DW3101 0x3101 52 - #endif 53 - 54 - #ifndef USB_PID_CINERGY_S 55 - #define USB_PID_CINERGY_S 0x0064 56 - #endif 57 - 58 - #ifndef USB_PID_TEVII_S630 59 - #define USB_PID_TEVII_S630 0xd630 60 - #endif 61 - 62 - #ifndef USB_PID_TEVII_S650 63 - #define USB_PID_TEVII_S650 0xd650 64 - #endif 65 - 66 - #ifndef USB_PID_TEVII_S660 67 - #define USB_PID_TEVII_S660 0xd660 68 - #endif 69 - 70 - #ifndef USB_PID_TEVII_S662 71 - #define USB_PID_TEVII_S662 0xd662 72 - #endif 73 - 74 - #ifndef USB_PID_TEVII_S480_1 75 - #define USB_PID_TEVII_S480_1 0xd481 76 - #endif 77 - 78 - #ifndef USB_PID_TEVII_S480_2 79 - #define USB_PID_TEVII_S480_2 0xd482 80 - #endif 81 - 82 - #ifndef USB_PID_PROF_1100 83 - #define USB_PID_PROF_1100 0xb012 84 - #endif 85 - 86 - #ifndef USB_PID_TEVII_S421 87 - #define USB_PID_TEVII_S421 0xd421 88 - #endif 89 - 90 - #ifndef USB_PID_TEVII_S632 91 - #define USB_PID_TEVII_S632 0xd632 92 - #endif 93 - 94 - #ifndef USB_PID_GOTVIEW_SAT_HD 95 - #define USB_PID_GOTVIEW_SAT_HD 0x5456 96 - #endif 97 41 98 42 #define DW210X_READ_MSG 0 99 43 #define DW210X_WRITE_MSG 1 ··· 1655 1709 [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, 1656 1710 [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, 1657 1711 [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, 1658 - [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, 1712 + [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S)}, 1659 1713 [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, 1660 1714 [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, 1661 1715 [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, ··· 1747 1801 dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, 1748 1802 DW210X_WRITE_MSG); 1749 1803 break; 1750 - case USB_PID_CINERGY_S: 1804 + case USB_PID_TERRATEC_CINERGY_S: 1751 1805 case USB_PID_DW2102: 1752 1806 dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, 1753 1807 DW210X_WRITE_MSG); ··· 1789 1843 msleep(100); 1790 1844 kfree(p); 1791 1845 } 1846 + 1847 + if (le16_to_cpu(dev->descriptor.idProduct) == 0x2101) 1848 + release_firmware(fw); 1792 1849 return ret; 1793 1850 } 1794 1851
+2 -2
drivers/media/usb/dvb-usb/pctv452e.c
··· 995 995 /* parameter for the MPEG2-data transfer */ 996 996 .stream = { 997 997 .type = USB_ISOC, 998 - .count = 7, 998 + .count = 4, 999 999 .endpoint = 0x02, 1000 1000 .u = { 1001 1001 .isoc = { 1002 - .framesperurb = 4, 1002 + .framesperurb = 64, 1003 1003 .framesize = 940, 1004 1004 .interval = 1 1005 1005 }
+2
drivers/media/usb/em28xx/Kconfig
··· 59 59 select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT 60 60 select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT 61 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 64 ---help--- 63 65 This adds support for DVB cards based on the 64 66 Empiatech em28xx chips.
+88
drivers/media/usb/em28xx/em28xx-cards.c
··· 492 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 534 * Button definitions 497 535 */ ··· 603 565 { 604 566 .role = EM28XX_LED_ANALOG_CAPTURING, 605 567 .gpio_reg = EM2820_R08_GPIO_CTRL, 568 + .gpio_mask = EM_GPIO_3, 569 + .inverted = 1, 570 + }, 571 + {-1, 0, 0, 0}, 572 + }; 573 + 574 + static struct em28xx_led hauppauge_dualhd_leds[] = { 575 + { 576 + .role = EM28XX_LED_DIGITAL_CAPTURING, 577 + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, 578 + .gpio_mask = EM_GPIO_1, 579 + .inverted = 1, 580 + }, 581 + { 582 + .role = EM28XX_LED_DIGITAL_CAPTURING_TS2, 583 + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, 606 584 .gpio_mask = EM_GPIO_3, 607 585 .inverted = 1, 608 586 }, ··· 2360 2306 .has_dvb = 1, 2361 2307 .ir_codes = RC_MAP_TERRATEC_SLIM_2, 2362 2308 }, 2309 + 2310 + /* 2311 + * 3275:0085 PLEX PX-BCUD. 2312 + * Empia EM28178, TOSHIBA TC90532XBG, Sharp QM1D1C0042 2313 + */ 2314 + [EM28178_BOARD_PLEX_PX_BCUD] = { 2315 + .name = "PLEX PX-BCUD", 2316 + .xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ, 2317 + .def_i2c_bus = 1, 2318 + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, 2319 + .tuner_type = TUNER_ABSENT, 2320 + .tuner_gpio = plex_px_bcud, 2321 + .has_dvb = 1, 2322 + }, 2323 + /* 2324 + * 2040:0265 Hauppauge WinTV-dualHD (DVB version). 2325 + * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 2326 + */ 2327 + [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = { 2328 + .name = "Hauppauge WinTV-dualHD DVB", 2329 + .def_i2c_bus = 1, 2330 + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | 2331 + EM28XX_I2C_FREQ_400_KHZ, 2332 + .tuner_type = TUNER_ABSENT, 2333 + .tuner_gpio = hauppauge_dualhd_dvb, 2334 + .has_dvb = 1, 2335 + .ir_codes = RC_MAP_HAUPPAUGE, 2336 + .leds = hauppauge_dualhd_leds, 2337 + }, 2363 2338 }; 2364 2339 EXPORT_SYMBOL_GPL(em28xx_boards); 2365 2340 ··· 2512 2429 .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, 2513 2430 { USB_DEVICE(0x2040, 0x651f), 2514 2431 .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, 2432 + { USB_DEVICE(0x2040, 0x0265), 2433 + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, 2515 2434 { USB_DEVICE(0x0438, 0xb002), 2516 2435 .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, 2517 2436 { USB_DEVICE(0x2001, 0xf112), ··· 2580 2495 .driver_info = EM2861_BOARD_LEADTEK_VC100 }, 2581 2496 { USB_DEVICE(0xeb1a, 0x8179), 2582 2497 .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD }, 2498 + { USB_DEVICE(0x3275, 0x0085), 2499 + .driver_info = EM28178_BOARD_PLEX_PX_BCUD }, 2583 2500 { }, 2584 2501 }; 2585 2502 MODULE_DEVICE_TABLE(usb, em28xx_id_table); ··· 2948 2861 case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: 2949 2862 case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: 2950 2863 case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: 2864 + case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: 2951 2865 { 2952 2866 struct tveeprom tv; 2953 2867
+185
drivers/media/usb/em28xx/em28xx-dvb.c
··· 58 58 #include "ts2020.h" 59 59 #include "si2168.h" 60 60 #include "si2157.h" 61 + #include "tc90522.h" 62 + #include "qm1d1c0042.h" 61 63 62 64 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); 63 65 MODULE_LICENSE("GPL"); ··· 788 786 mt352_write(fe, tuner_go, sizeof(tuner_go)); 789 787 return 0; 790 788 } 789 + 790 + static void px_bcud_init(struct em28xx *dev) 791 + { 792 + int i; 793 + struct { 794 + unsigned char r[4]; 795 + int len; 796 + } regs1[] = { 797 + {{ 0x0e, 0x77 }, 2}, 798 + {{ 0x0f, 0x77 }, 2}, 799 + {{ 0x03, 0x90 }, 2}, 800 + }, regs2[] = { 801 + {{ 0x07, 0x01 }, 2}, 802 + {{ 0x08, 0x10 }, 2}, 803 + {{ 0x13, 0x00 }, 2}, 804 + {{ 0x17, 0x00 }, 2}, 805 + {{ 0x03, 0x01 }, 2}, 806 + {{ 0x10, 0xb1 }, 2}, 807 + {{ 0x11, 0x40 }, 2}, 808 + {{ 0x85, 0x7a }, 2}, 809 + {{ 0x87, 0x04 }, 2}, 810 + }; 811 + static struct em28xx_reg_seq gpio[] = { 812 + {EM28XX_R06_I2C_CLK, 0x40, 0xff, 300}, 813 + {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 60}, 814 + {EM28XX_R15_RGAIN, 0x20, 0xff, 0}, 815 + {EM28XX_R16_GGAIN, 0x20, 0xff, 0}, 816 + {EM28XX_R17_BGAIN, 0x20, 0xff, 0}, 817 + {EM28XX_R18_ROFFSET, 0x00, 0xff, 0}, 818 + {EM28XX_R19_GOFFSET, 0x00, 0xff, 0}, 819 + {EM28XX_R1A_BOFFSET, 0x00, 0xff, 0}, 820 + {EM28XX_R23_UOFFSET, 0x00, 0xff, 0}, 821 + {EM28XX_R24_VOFFSET, 0x00, 0xff, 0}, 822 + {EM28XX_R26_COMPR, 0x00, 0xff, 0}, 823 + {0x13, 0x08, 0xff, 0}, 824 + {EM28XX_R12_VINENABLE, 0x27, 0xff, 0}, 825 + {EM28XX_R0C_USBSUSP, 0x10, 0xff, 0}, 826 + {EM28XX_R27_OUTFMT, 0x00, 0xff, 0}, 827 + {EM28XX_R10_VINMODE, 0x00, 0xff, 0}, 828 + {EM28XX_R11_VINCTRL, 0x11, 0xff, 0}, 829 + {EM2874_R50_IR_CONFIG, 0x01, 0xff, 0}, 830 + {EM2874_R5F_TS_ENABLE, 0x80, 0xff, 0}, 831 + {EM28XX_R06_I2C_CLK, 0x46, 0xff, 0}, 832 + }; 833 + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x46); 834 + /* sleeping ISDB-T */ 835 + dev->dvb->i2c_client_demod->addr = 0x14; 836 + for (i = 0; i < ARRAY_SIZE(regs1); i++) 837 + i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r, 838 + regs1[i].len); 839 + /* sleeping ISDB-S */ 840 + dev->dvb->i2c_client_demod->addr = 0x15; 841 + for (i = 0; i < ARRAY_SIZE(regs2); i++) 842 + i2c_master_send(dev->dvb->i2c_client_demod, regs2[i].r, 843 + regs2[i].len); 844 + for (i = 0; i < ARRAY_SIZE(gpio); i++) { 845 + em28xx_write_reg_bits(dev, gpio[i].reg, gpio[i].val, 846 + gpio[i].mask); 847 + if (gpio[i].sleep > 0) 848 + msleep(gpio[i].sleep); 849 + } 850 + }; 791 851 792 852 static struct mt352_config terratec_xs_mt352_cfg = { 793 853 .demod_address = (0x1e >> 1), ··· 1824 1760 } 1825 1761 1826 1762 dvb->i2c_client_tuner = client; 1763 + } 1764 + break; 1765 + 1766 + case EM28178_BOARD_PLEX_PX_BCUD: 1767 + { 1768 + struct i2c_client *client; 1769 + struct i2c_board_info info; 1770 + struct tc90522_config tc90522_config; 1771 + struct qm1d1c0042_config qm1d1c0042_config; 1772 + 1773 + /* attach demod */ 1774 + memset(&tc90522_config, 0, sizeof(tc90522_config)); 1775 + memset(&info, 0, sizeof(struct i2c_board_info)); 1776 + strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); 1777 + info.addr = 0x15; 1778 + info.platform_data = &tc90522_config; 1779 + request_module("tc90522"); 1780 + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); 1781 + if (client == NULL || client->dev.driver == NULL) { 1782 + result = -ENODEV; 1783 + goto out_free; 1784 + } 1785 + dvb->i2c_client_demod = client; 1786 + if (!try_module_get(client->dev.driver->owner)) { 1787 + i2c_unregister_device(client); 1788 + result = -ENODEV; 1789 + goto out_free; 1790 + } 1791 + 1792 + /* attach tuner */ 1793 + memset(&qm1d1c0042_config, 0, 1794 + sizeof(qm1d1c0042_config)); 1795 + qm1d1c0042_config.fe = tc90522_config.fe; 1796 + qm1d1c0042_config.lpf = 1; 1797 + memset(&info, 0, sizeof(struct i2c_board_info)); 1798 + strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE); 1799 + info.addr = 0x61; 1800 + info.platform_data = &qm1d1c0042_config; 1801 + request_module(info.type); 1802 + client = i2c_new_device(tc90522_config.tuner_i2c, 1803 + &info); 1804 + if (client == NULL || client->dev.driver == NULL) { 1805 + module_put(dvb->i2c_client_demod->dev.driver->owner); 1806 + i2c_unregister_device(dvb->i2c_client_demod); 1807 + result = -ENODEV; 1808 + goto out_free; 1809 + } 1810 + dvb->i2c_client_tuner = client; 1811 + if (!try_module_get(client->dev.driver->owner)) { 1812 + i2c_unregister_device(client); 1813 + module_put(dvb->i2c_client_demod->dev.driver->owner); 1814 + i2c_unregister_device(dvb->i2c_client_demod); 1815 + result = -ENODEV; 1816 + goto out_free; 1817 + } 1818 + dvb->fe[0] = tc90522_config.fe; 1819 + px_bcud_init(dev); 1820 + } 1821 + break; 1822 + case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: 1823 + { 1824 + struct i2c_adapter *adapter; 1825 + struct i2c_client *client; 1826 + struct i2c_board_info info; 1827 + struct si2168_config si2168_config; 1828 + struct si2157_config si2157_config; 1829 + 1830 + /* attach demod */ 1831 + memset(&si2168_config, 0, sizeof(si2168_config)); 1832 + si2168_config.i2c_adapter = &adapter; 1833 + si2168_config.fe = &dvb->fe[0]; 1834 + si2168_config.ts_mode = SI2168_TS_SERIAL; 1835 + memset(&info, 0, sizeof(struct i2c_board_info)); 1836 + strlcpy(info.type, "si2168", I2C_NAME_SIZE); 1837 + info.addr = 0x64; 1838 + info.platform_data = &si2168_config; 1839 + request_module(info.type); 1840 + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); 1841 + if (client == NULL || client->dev.driver == NULL) { 1842 + result = -ENODEV; 1843 + goto out_free; 1844 + } 1845 + 1846 + if (!try_module_get(client->dev.driver->owner)) { 1847 + i2c_unregister_device(client); 1848 + result = -ENODEV; 1849 + goto out_free; 1850 + } 1851 + 1852 + dvb->i2c_client_demod = client; 1853 + 1854 + /* attach tuner */ 1855 + memset(&si2157_config, 0, sizeof(si2157_config)); 1856 + si2157_config.fe = dvb->fe[0]; 1857 + si2157_config.if_port = 1; 1858 + #ifdef CONFIG_MEDIA_CONTROLLER_DVB 1859 + si2157_config.mdev = dev->media_dev; 1860 + #endif 1861 + memset(&info, 0, sizeof(struct i2c_board_info)); 1862 + strlcpy(info.type, "si2157", I2C_NAME_SIZE); 1863 + info.addr = 0x60; 1864 + info.platform_data = &si2157_config; 1865 + request_module(info.type); 1866 + client = i2c_new_device(adapter, &info); 1867 + if (client == NULL || client->dev.driver == NULL) { 1868 + module_put(dvb->i2c_client_demod->dev.driver->owner); 1869 + i2c_unregister_device(dvb->i2c_client_demod); 1870 + result = -ENODEV; 1871 + goto out_free; 1872 + } 1873 + 1874 + if (!try_module_get(client->dev.driver->owner)) { 1875 + i2c_unregister_device(client); 1876 + module_put(dvb->i2c_client_demod->dev.driver->owner); 1877 + i2c_unregister_device(dvb->i2c_client_demod); 1878 + result = -ENODEV; 1879 + goto out_free; 1880 + } 1881 + 1882 + dvb->i2c_client_tuner = client; 1883 + 1827 1884 } 1828 1885 break; 1829 1886 default:
+13
drivers/media/usb/em28xx/em28xx-reg.h
··· 193 193 /* em2874 registers */ 194 194 #define EM2874_R50_IR_CONFIG 0x50 195 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 209 #define EM2874_R5F_TS_ENABLE 0x5f 197 210 198 211 /* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */
+3
drivers/media/usb/em28xx/em28xx.h
··· 145 145 #define EM2861_BOARD_LEADTEK_VC100 95 146 146 #define EM28178_BOARD_TERRATEC_T2_STICK_HD 96 147 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 151 /* Limits minimum and default number of buffers */ 150 152 #define EM28XX_MIN_BUF 4 ··· 408 406 enum em28xx_led_role { 409 407 EM28XX_LED_ANALOG_CAPTURING = 0, 410 408 EM28XX_LED_DIGITAL_CAPTURING, 409 + EM28XX_LED_DIGITAL_CAPTURING_TS2, 411 410 EM28XX_LED_ILLUMINATION, 412 411 EM28XX_NUM_LED_ROLES, /* must be the last */ 413 412 };
+1 -1
drivers/media/usb/go7007/go7007-v4l2.c
··· 1125 1125 vdev->queue = &go->vidq; 1126 1126 video_set_drvdata(vdev, go); 1127 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 1129 v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD); 1130 1130 if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { 1131 1131 v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY);
+4 -5
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
··· 3672 3672 3673 3673 3674 3674 hdw->cmd_debug_state = 1; 3675 - if (write_len) { 3675 + if (write_len && write_data) 3676 3676 hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; 3677 - } else { 3677 + else 3678 3678 hdw->cmd_debug_code = 0; 3679 - } 3680 3679 hdw->cmd_debug_write_len = write_len; 3681 3680 hdw->cmd_debug_read_len = read_len; 3682 3681 ··· 3687 3688 setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw); 3688 3689 timer.expires = jiffies + timeout; 3689 3690 3690 - if (write_len) { 3691 + if (write_len && write_data) { 3691 3692 hdw->cmd_debug_state = 2; 3692 3693 /* Transfer write data to internal buffer */ 3693 3694 for (idx = 0; idx < write_len; idx++) { ··· 3794 3795 goto done; 3795 3796 } 3796 3797 } 3797 - if (read_len) { 3798 + if (read_len && read_data) { 3798 3799 /* Validate results of read request */ 3799 3800 if ((hdw->ctl_read_urb->status != 0) && 3800 3801 (hdw->ctl_read_urb->status != -ENOENT) &&
+2 -1
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
··· 280 280 static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) 281 281 { 282 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 285 return -EFAULT; 285 286 return __put_v4l2_format32(&kp->format, &up->format); 286 287 }
+1
drivers/media/v4l2-core/v4l2-dev.c
··· 735 735 if (!vdev->v4l2_dev->mdev) 736 736 return 0; 737 737 738 + vdev->entity.obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE; 738 739 vdev->entity.function = MEDIA_ENT_F_UNKNOWN; 739 740 740 741 switch (type) {
+47 -28
drivers/media/v4l2-core/v4l2-ioctl.c
··· 1020 1020 struct file *file, void *fh, void *arg) 1021 1021 { 1022 1022 struct v4l2_capability *cap = (struct v4l2_capability *)arg; 1023 + struct video_device *vfd = video_devdata(file); 1023 1024 int ret; 1024 1025 1025 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 1030 ret = ops->vidioc_querycap(file, fh, cap); 1028 1031 ··· 2160 2157 struct file *file, void *fh, void *arg) 2161 2158 { 2162 2159 struct v4l2_cropcap *p = arg; 2163 - 2164 - if (ops->vidioc_g_selection) { 2165 - struct v4l2_selection s = { .type = p->type }; 2166 - int ret; 2167 - 2168 - /* obtaining bounds */ 2169 - if (V4L2_TYPE_IS_OUTPUT(p->type)) 2170 - s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; 2171 - else 2172 - s.target = V4L2_SEL_TGT_CROP_BOUNDS; 2173 - 2174 - ret = ops->vidioc_g_selection(file, fh, &s); 2175 - if (ret) 2176 - return ret; 2177 - p->bounds = s.r; 2178 - 2179 - /* obtaining defrect */ 2180 - if (V4L2_TYPE_IS_OUTPUT(p->type)) 2181 - s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; 2182 - else 2183 - s.target = V4L2_SEL_TGT_CROP_DEFAULT; 2184 - 2185 - ret = ops->vidioc_g_selection(file, fh, &s); 2186 - if (ret) 2187 - return ret; 2188 - p->defrect = s.r; 2189 - } 2160 + struct v4l2_selection s = { .type = p->type }; 2161 + int ret = 0; 2190 2162 2191 2163 /* setting trivial pixelaspect */ 2192 2164 p->pixelaspect.numerator = 1; 2193 2165 p->pixelaspect.denominator = 1; 2194 2166 2167 + /* 2168 + * The determine_valid_ioctls() call already should ensure 2169 + * that this can never happen, but just in case... 2170 + */ 2171 + if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_cropcap)) 2172 + return -ENOTTY; 2173 + 2195 2174 if (ops->vidioc_cropcap) 2196 - return ops->vidioc_cropcap(file, fh, p); 2175 + ret = ops->vidioc_cropcap(file, fh, p); 2176 + 2177 + if (!ops->vidioc_g_selection) 2178 + return ret; 2179 + 2180 + /* 2181 + * Ignore ENOTTY or ENOIOCTLCMD error returns, just use the 2182 + * square pixel aspect ratio in that case. 2183 + */ 2184 + if (ret && ret != -ENOTTY && ret != -ENOIOCTLCMD) 2185 + return ret; 2186 + 2187 + /* Use g_selection() to fill in the bounds and defrect rectangles */ 2188 + 2189 + /* obtaining bounds */ 2190 + if (V4L2_TYPE_IS_OUTPUT(p->type)) 2191 + s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; 2192 + else 2193 + s.target = V4L2_SEL_TGT_CROP_BOUNDS; 2194 + 2195 + ret = ops->vidioc_g_selection(file, fh, &s); 2196 + if (ret) 2197 + return ret; 2198 + p->bounds = s.r; 2199 + 2200 + /* obtaining defrect */ 2201 + if (V4L2_TYPE_IS_OUTPUT(p->type)) 2202 + s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; 2203 + else 2204 + s.target = V4L2_SEL_TGT_CROP_DEFAULT; 2205 + 2206 + ret = ops->vidioc_g_selection(file, fh, &s); 2207 + if (ret) 2208 + return ret; 2209 + p->defrect = s.r; 2197 2210 2198 2211 return 0; 2199 2212 }
+1 -1
drivers/media/v4l2-core/v4l2-mc.c
··· 263 263 media_entity_graph_walk_start(graph, entity); 264 264 265 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 267 use += entity->use_count; 268 268 } 269 269
+38 -6
drivers/media/v4l2-core/v4l2-subdev.c
··· 35 35 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) 36 36 { 37 37 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 38 - fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL); 39 - if (fh->pad == NULL) 40 - return -ENOMEM; 38 + if (sd->entity.num_pads) { 39 + fh->pad = v4l2_subdev_alloc_pad_config(sd); 40 + if (fh->pad == NULL) 41 + return -ENOMEM; 42 + } 41 43 #endif 42 44 return 0; 43 45 } ··· 47 45 static void subdev_fh_free(struct v4l2_subdev_fh *fh) 48 46 { 49 47 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 50 - kfree(fh->pad); 48 + v4l2_subdev_free_pad_config(fh->pad); 51 49 fh->pad = NULL; 52 50 #endif 53 51 } ··· 510 508 if (source_fmt->format.width != sink_fmt->format.width 511 509 || source_fmt->format.height != sink_fmt->format.height 512 510 || source_fmt->format.code != sink_fmt->format.code) 513 - return -EINVAL; 511 + return -EPIPE; 514 512 515 513 /* The field order must match, or the sink field order must be NONE 516 514 * to support interlaced hardware connected to bridges that support ··· 518 516 */ 519 517 if (source_fmt->format.field != sink_fmt->format.field && 520 518 sink_fmt->format.field != V4L2_FIELD_NONE) 521 - return -EINVAL; 519 + return -EPIPE; 522 520 523 521 return 0; 524 522 } ··· 571 569 sink, link, &source_fmt, &sink_fmt); 572 570 } 573 571 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); 572 + 573 + struct v4l2_subdev_pad_config * 574 + v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd) 575 + { 576 + struct v4l2_subdev_pad_config *cfg; 577 + int ret; 578 + 579 + if (!sd->entity.num_pads) 580 + return NULL; 581 + 582 + cfg = kcalloc(sd->entity.num_pads, sizeof(*cfg), GFP_KERNEL); 583 + if (!cfg) 584 + return NULL; 585 + 586 + ret = v4l2_subdev_call(sd, pad, init_cfg, cfg); 587 + if (ret < 0 && ret != -ENOIOCTLCMD) { 588 + kfree(cfg); 589 + return NULL; 590 + } 591 + 592 + return cfg; 593 + } 594 + EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config); 595 + 596 + void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg) 597 + { 598 + kfree(cfg); 599 + } 600 + EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config); 574 601 #endif /* CONFIG_MEDIA_CONTROLLER */ 575 602 576 603 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) ··· 615 584 sd->host_priv = NULL; 616 585 #if defined(CONFIG_MEDIA_CONTROLLER) 617 586 sd->entity.name = sd->name; 587 + sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; 618 588 sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; 619 589 #endif 620 590 }
+2
drivers/staging/media/Kconfig
··· 37 37 38 38 source "drivers/staging/media/timb/Kconfig" 39 39 40 + source "drivers/staging/media/tw686x-kh/Kconfig" 41 + 40 42 # Keep LIRC at the end, as it has sub-menus 41 43 source "drivers/staging/media/lirc/Kconfig" 42 44
+1
drivers/staging/media/Makefile
··· 8 8 obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ 9 9 obj-$(CONFIG_DVB_MN88472) += mn88472/ 10 10 obj-$(CONFIG_VIDEO_TIMBERDALE) += timb/ 11 + obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh/
+1 -1
drivers/staging/media/bcm2048/radio-bcm2048.c
··· 308 308 MODULE_PARM_DESC(radio_nr, 309 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 312 /* USA */ 313 313 { 314 314 .channel_spacing = 20,
+1 -1
drivers/staging/media/davinci_vpfe/vpfe_video.c
··· 154 154 while ((entity = media_entity_graph_walk_next(&graph))) { 155 155 if (entity == &video->video_dev.entity) 156 156 continue; 157 - if (!is_media_entity_v4l2_io(entity)) 157 + if (!is_media_entity_v4l2_video_device(entity)) 158 158 continue; 159 159 far_end = to_vpfe_video(media_entity_to_video_device(entity)); 160 160 if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+1 -1
drivers/staging/media/omap4iss/iss_video.c
··· 223 223 if (entity == &video->video.entity) 224 224 continue; 225 225 226 - if (!is_media_entity_v4l2_io(entity)) 226 + if (!is_media_entity_v4l2_video_device(entity)) 227 227 continue; 228 228 229 229 far_end = to_iss_video(media_entity_to_video_device(entity));
+17
drivers/staging/media/tw686x-kh/Kconfig
··· 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.
+3
drivers/staging/media/tw686x-kh/Makefile
··· 1 + tw686x-kh-objs := tw686x-kh-core.o tw686x-kh-video.o 2 + 3 + obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh.o
+6
drivers/staging/media/tw686x-kh/TODO
··· 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>.
+140
drivers/staging/media/tw686x-kh/tw686x-kh-core.c
··· 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);
+103
drivers/staging/media/tw686x-kh/tw686x-kh-regs.h
··· 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})
+821
drivers/staging/media/tw686x-kh/tw686x-kh-video.c
··· 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 + }
+118
drivers/staging/media/tw686x-kh/tw686x-kh.h
··· 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);
+5 -8
include/media/media-device.h
··· 25 25 26 26 #include <linux/list.h> 27 27 #include <linux/mutex.h> 28 - #include <linux/spinlock.h> 29 28 30 29 #include <media/media-devnode.h> 31 30 #include <media/media-entity.h> ··· 303 304 * @pads: List of registered pads 304 305 * @links: List of registered links 305 306 * @entity_notify: List of registered entity_notify callbacks 306 - * @lock: Entities list lock 307 - * @graph_mutex: Entities graph operation lock 307 + * @graph_mutex: Protects access to struct media_device data 308 308 * @pm_count_walk: Graph walk for power state walk. Access serialised using 309 309 * graph_mutex. 310 310 * ··· 311 313 * @enable_source: Enable Source Handler function pointer 312 314 * @disable_source: Disable Source Handler function pointer 313 315 * 314 - * @link_notify: Link state change notification callback 316 + * @link_notify: Link state change notification callback. This callback is 317 + * called with the graph_mutex held. 315 318 * 316 319 * This structure represents an abstract high-level media device. It allows easy 317 320 * access to entities and provides basic media device-level support. The ··· 356 357 u32 hw_revision; 357 358 u32 driver_version; 358 359 359 - u32 topology_version; 360 + u64 topology_version; 360 361 361 362 u32 id; 362 363 struct ida entity_internal_idx; ··· 370 371 /* notify callback list invoked when a new entity is registered */ 371 372 struct list_head entity_notify; 372 373 373 - /* Protects the graph objects creation/removal */ 374 - spinlock_t lock; 375 374 /* Serializes graph operations. */ 376 375 struct mutex graph_mutex; 377 376 struct media_entity_graph pm_count_walk; ··· 491 494 #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE) 492 495 493 496 /** 494 - * __media_device_unregister() - Unegisters a media device element 497 + * media_device_unregister() - Unregisters a media device element 495 498 * 496 499 * @mdev: pointer to struct &media_device 497 500 *
+43 -38
include/media/media-entity.h
··· 179 179 * @link_validate: Return whether a link is valid from the entity point of 180 180 * view. The media_entity_pipeline_start() function 181 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 186 struct media_entity_operations { 184 187 int (*link_setup)(struct media_entity *entity, ··· 191 188 }; 192 189 193 190 /** 191 + * enum media_entity_type - Media entity type 192 + * 193 + * @MEDIA_ENTITY_TYPE_BASE: 194 + * The entity isn't embedded in another subsystem structure. 195 + * @MEDIA_ENTITY_TYPE_VIDEO_DEVICE: 196 + * The entity is embedded in a struct video_device instance. 197 + * @MEDIA_ENTITY_TYPE_V4L2_SUBDEV: 198 + * The entity is embedded in a struct v4l2_subdev instance. 199 + * 200 + * Media entity objects are often not instantiated directly, but the media 201 + * entity structure is inherited by (through embedding) other subsystem-specific 202 + * structures. The media entity type identifies the type of the subclass 203 + * structure that implements a media entity instance. 204 + * 205 + * This allows runtime type identification of media entities and safe casting to 206 + * the correct object type. For instance, a media entity structure instance 207 + * embedded in a v4l2_subdev structure instance will have the type 208 + * MEDIA_ENTITY_TYPE_V4L2_SUBDEV and can safely be cast to a v4l2_subdev 209 + * structure using the container_of() macro. 210 + */ 211 + enum media_entity_type { 212 + MEDIA_ENTITY_TYPE_BASE, 213 + MEDIA_ENTITY_TYPE_VIDEO_DEVICE, 214 + MEDIA_ENTITY_TYPE_V4L2_SUBDEV, 215 + }; 216 + 217 + /** 194 218 * struct media_entity - A media entity graph object. 195 219 * 196 220 * @graph_obj: Embedded structure containing the media object common data. 197 221 * @name: Entity name. 222 + * @obj_type: Type of the object that implements the media_entity. 198 223 * @function: Entity main function, as defined in uapi/media.h 199 224 * (MEDIA_ENT_F_*) 200 225 * @flags: Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*) ··· 251 220 struct media_entity { 252 221 struct media_gobj graph_obj; /* must be first field in struct */ 253 222 const char *name; 223 + enum media_entity_type obj_type; 254 224 u32 function; 255 225 unsigned long flags; 256 226 ··· 361 329 } 362 330 363 331 /** 364 - * is_media_entity_v4l2_io() - identify if the entity main function 365 - * is a V4L2 I/O 366 - * 332 + * is_media_entity_v4l2_video_device() - Check if the entity is a video_device 367 333 * @entity: pointer to entity 368 334 * 369 - * Return: true if the entity main function is one of the V4L2 I/O types 370 - * (video, VBI or SDR radio); false otherwise. 335 + * Return: true if the entity is an instance of a video_device object and can 336 + * safely be cast to a struct video_device using the container_of() macro, or 337 + * false otherwise. 371 338 */ 372 - static inline bool is_media_entity_v4l2_io(struct media_entity *entity) 339 + static inline bool is_media_entity_v4l2_video_device(struct media_entity *entity) 373 340 { 374 - if (!entity) 375 - return false; 376 - 377 - switch (entity->function) { 378 - case MEDIA_ENT_F_IO_V4L: 379 - case MEDIA_ENT_F_IO_VBI: 380 - case MEDIA_ENT_F_IO_SWRADIO: 381 - return true; 382 - default: 383 - return false; 384 - } 341 + return entity && entity->obj_type == MEDIA_ENTITY_TYPE_VIDEO_DEVICE; 385 342 } 386 343 387 344 /** 388 - * is_media_entity_v4l2_subdev - return true if the entity main function is 389 - * associated with the V4L2 API subdev usage 390 - * 345 + * is_media_entity_v4l2_subdev() - Check if the entity is a v4l2_subdev 391 346 * @entity: pointer to entity 392 347 * 393 - * This is an ancillary function used by subdev-based V4L2 drivers. 394 - * It checks if the entity function is one of functions used by a V4L2 subdev, 395 - * e. g. camera-relatef functions, analog TV decoder, TV tuner, V4L2 DSPs. 348 + * Return: true if the entity is an instance of a v4l2_subdev object and can 349 + * safely be cast to a struct v4l2_subdev using the container_of() macro, or 350 + * false otherwise. 396 351 */ 397 352 static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity) 398 353 { 399 - if (!entity) 400 - return false; 401 - 402 - switch (entity->function) { 403 - case MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: 404 - case MEDIA_ENT_F_CAM_SENSOR: 405 - case MEDIA_ENT_F_FLASH: 406 - case MEDIA_ENT_F_LENS: 407 - case MEDIA_ENT_F_ATV_DECODER: 408 - case MEDIA_ENT_F_TUNER: 409 - return true; 410 - 411 - default: 412 - return false; 413 - } 354 + return entity && entity->obj_type == MEDIA_ENTITY_TYPE_V4L2_SUBDEV; 414 355 } 415 356 416 357 /**
+4 -14
include/media/rc-core.h
··· 215 215 struct ir_raw_event { 216 216 union { 217 217 u32 duration; 218 - 219 - struct { 220 - u32 carrier; 221 - u8 duty_cycle; 222 - }; 218 + u32 carrier; 223 219 }; 220 + u8 duty_cycle; 224 221 225 222 unsigned pulse:1; 226 223 unsigned reset:1; ··· 225 228 unsigned carrier_report:1; 226 229 }; 227 230 228 - #define DEFINE_IR_RAW_EVENT(event) \ 229 - struct ir_raw_event event = { \ 230 - { .duration = 0 } , \ 231 - .pulse = 0, \ 232 - .reset = 0, \ 233 - .timeout = 0, \ 234 - .carrier_report = 0 } 231 + #define DEFINE_IR_RAW_EVENT(event) struct ir_raw_event event = {} 235 232 236 233 static inline void init_ir_raw_event(struct ir_raw_event *ev) 237 234 { ··· 247 256 248 257 static inline void ir_raw_event_reset(struct rc_dev *dev) 249 258 { 250 - DEFINE_IR_RAW_EVENT(ev); 251 - ev.reset = true; 259 + struct ir_raw_event ev = { .reset = true }; 252 260 253 261 ir_raw_event_store(dev, &ev); 254 262 ir_raw_event_handle(dev);
+3
include/media/v4l2-dev.h
··· 92 92 /* device ops */ 93 93 const struct v4l2_file_operations *fops; 94 94 95 + /* device capabilities as used in v4l2_capabilities */ 96 + u32 device_caps; 97 + 95 98 /* sysfs */ 96 99 struct device dev; /* v4l device */ 97 100 struct cdev *cdev; /* character device */
+54 -1
include/media/v4l2-device.h
··· 196 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) \ 200 232 ({ \ 201 233 struct v4l2_subdev *__sd; \ 202 234 bool __result = false; \ 203 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) \ 251 + ({ \ 252 + struct v4l2_subdev *__sd; \ 253 + bool __result = false; \ 254 + list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ 255 + if ((grpmsk) && !(__sd->grp_id & (grpmsk))) \ 256 + continue; \ 204 257 if (v4l2_subdev_has_op(__sd, o, f)) { \ 205 258 __result = true; \ 206 259 break; \
+173
include/media/v4l2-rect.h
··· 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
+8
include/media/v4l2-subdev.h
··· 572 572 /** 573 573 * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations 574 574 * 575 + * @init_cfg: initialize the pad config to default values 575 576 * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler 576 577 * code. 577 578 * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler ··· 608 607 * may be adjusted by the subdev driver to device capabilities. 609 608 */ 610 609 struct v4l2_subdev_pad_ops { 610 + int (*init_cfg)(struct v4l2_subdev *sd, 611 + struct v4l2_subdev_pad_config *cfg); 611 612 int (*enum_mbus_code)(struct v4l2_subdev *sd, 612 613 struct v4l2_subdev_pad_config *cfg, 613 614 struct v4l2_subdev_mbus_code_enum *code); ··· 804 801 struct v4l2_subdev_format *source_fmt, 805 802 struct v4l2_subdev_format *sink_fmt); 806 803 int v4l2_subdev_link_validate(struct media_link *link); 804 + 805 + struct v4l2_subdev_pad_config * 806 + v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd); 807 + void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg); 807 808 #endif /* CONFIG_MEDIA_CONTROLLER */ 809 + 808 810 void v4l2_subdev_init(struct v4l2_subdev *sd, 809 811 const struct v4l2_subdev_ops *ops); 810 812
+17 -6
include/media/vsp1.h
··· 23 23 int vsp1_du_setup_lif(struct device *dev, unsigned int width, 24 24 unsigned int height); 25 25 26 - int vsp1_du_atomic_begin(struct device *dev); 27 - int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, u32 pixelformat, 28 - unsigned int pitch, dma_addr_t mem[2], 29 - const struct v4l2_rect *src, 30 - const struct v4l2_rect *dst); 31 - int vsp1_du_atomic_flush(struct device *dev); 26 + void vsp1_du_atomic_begin(struct device *dev); 27 + int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf, 28 + u32 pixelformat, unsigned int pitch, 29 + dma_addr_t mem[2], const struct v4l2_rect *src, 30 + const struct v4l2_rect *dst, unsigned int alpha, 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 44 #endif /* __MEDIA_VSP1_H__ */
+10 -28
include/uapi/linux/videodev2.h
··· 138 138 V4L2_BUF_TYPE_VBI_OUTPUT = 5, 139 139 V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, 140 140 V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, 141 - #if 1 142 - /* Experimental */ 143 141 V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, 144 - #endif 145 142 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, 146 143 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, 147 144 V4L2_BUF_TYPE_SDR_CAPTURE = 11, ··· 654 657 #define V4L2_FMT_FLAG_COMPRESSED 0x0001 655 658 #define V4L2_FMT_FLAG_EMULATED 0x0002 656 659 657 - #if 1 658 - /* Experimental Frame Size and frame rate enumeration */ 660 + /* Frame Size and frame rate enumeration */ 659 661 /* 660 662 * F R A M E S I Z E E N U M E R A T I O N 661 663 */ ··· 720 724 721 725 __u32 reserved[2]; /* Reserved space for future use */ 722 726 }; 723 - #endif 724 727 725 728 /* 726 729 * T I M E C O D E ··· 1723 1728 1724 1729 /* 1725 1730 * M P E G S E R V I C E S 1726 - * 1727 - * NOTE: EXPERIMENTAL API 1728 1731 */ 1729 1732 #if 1 1730 1733 #define V4L2_ENC_IDX_FRAME_I (0) ··· 2252 2259 #define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) 2253 2260 #define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) 2254 2261 2255 - /* Experimental, meant for debugging, testing and internal use. 2256 - Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. 2257 - You must be root to use these ioctls. Never use these in applications! */ 2262 + /* 2263 + * Experimental, meant for debugging, testing and internal use. 2264 + * Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. 2265 + * You must be root to use these ioctls. Never use these in applications! 2266 + */ 2258 2267 #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) 2259 2268 #define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) 2260 2269 2261 2270 #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) 2262 - 2263 2271 #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) 2264 2272 #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) 2265 2273 #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) 2266 2274 #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) 2267 2275 #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) 2268 - 2269 - /* Experimental, the below two ioctls may change over the next couple of kernel 2270 - versions */ 2271 2276 #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) 2272 2277 #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) 2273 - 2274 - /* Experimental selection API */ 2275 2278 #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) 2276 2279 #define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) 2277 - 2278 - /* Experimental, these two ioctls may change over the next couple of kernel 2279 - versions. */ 2280 2280 #define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) 2281 2281 #define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) 2282 - 2283 - /* Experimental, these three ioctls may change over the next couple of kernel 2284 - versions. */ 2285 2282 #define VIDIOC_ENUM_DV_TIMINGS _IOWR('V', 98, struct v4l2_enum_dv_timings) 2286 2283 #define VIDIOC_QUERY_DV_TIMINGS _IOR('V', 99, struct v4l2_dv_timings) 2287 2284 #define VIDIOC_DV_TIMINGS_CAP _IOWR('V', 100, struct v4l2_dv_timings_cap) 2288 - 2289 - /* Experimental, this ioctl may change over the next couple of kernel 2290 - versions. */ 2291 2285 #define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band) 2292 2286 2293 - /* Experimental, meant for debugging, testing and internal use. 2294 - Never use these in applications! */ 2287 + /* 2288 + * Experimental, meant for debugging, testing and internal use. 2289 + * Never use this in applications! 2290 + */ 2295 2291 #define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) 2296 2292 2297 2293 #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl)
+1 -1
samples/Makefile
··· 2 2 3 3 obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ 4 4 hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ 5 - configfs/ 5 + configfs/ v4l/